@agent-native/core 0.118.0 → 0.118.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 (375) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +21 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/a2a/client.ts +32 -10
  5. package/corpus/core/src/cli/index.ts +18 -10
  6. package/corpus/core/src/cli/multi-frontier-runs.ts +5 -3
  7. package/corpus/core/src/cli/templates-meta.ts +0 -12
  8. package/corpus/core/src/cli/workspace-dev.ts +1 -1
  9. package/corpus/core/src/client/AgentPanel.tsx +9 -1
  10. package/corpus/core/src/client/RunStuckBanner.tsx +39 -47
  11. package/corpus/core/src/client/chat/action-chat-ui-surface.tsx +32 -0
  12. package/corpus/core/src/client/chat/message-components.tsx +53 -8
  13. package/corpus/core/src/client/chat/tool-call-display.tsx +24 -9
  14. package/corpus/core/src/client/chat/widgets/InlineExtensionWidget.tsx +0 -1
  15. package/corpus/core/src/client/chat/widgets/builtin-tool-renderers.tsx +7 -3
  16. package/corpus/core/src/client/conversation/AgentConversation.tsx +12 -1
  17. package/corpus/core/src/client/error-capture.ts +2 -6
  18. package/corpus/core/src/client/resources/McpConnectionSuggestion.tsx +20 -14
  19. package/corpus/core/src/client/resources/ResourcesPanel.tsx +5 -1
  20. package/corpus/core/src/client/resources/mcp-integration-catalog.ts +7 -17
  21. package/corpus/core/src/client/resources/mcp-integration-logos.ts +2 -2
  22. package/corpus/core/src/client/route-chunk-recovery.ts +5 -3
  23. package/corpus/core/src/client/session-replay.ts +3 -3
  24. package/corpus/core/src/client/settings/SettingsPanel.tsx +15 -6
  25. package/corpus/core/src/client/transcription/use-live-transcription.ts +64 -45
  26. package/corpus/core/src/deploy/build.ts +2 -1
  27. package/corpus/core/src/guards/db-tool-scoping.ts +1 -1
  28. package/corpus/core/src/integrations/adapters/slack.ts +84 -5
  29. package/corpus/core/src/integrations/index.ts +5 -1
  30. package/corpus/core/src/localization/default-messages.ts +1 -1
  31. package/corpus/core/src/mcp-client/oauth-routes.ts +45 -12
  32. package/corpus/core/src/server/realtime-voice.ts +4 -1
  33. package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +7 -5
  34. package/corpus/core/src/terminal/cli-registry.ts +1 -1
  35. package/corpus/core/src/vite/client.ts +166 -1
  36. package/corpus/templates/analytics/app/hooks/use-dashboard-views.ts +13 -1
  37. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/ViewsMenu.tsx +10 -0
  38. package/corpus/templates/analytics/changelog/2026-07-22-show-a-useful-error-when-saving-a-dashboard-view-fails.md +6 -0
  39. package/corpus/templates/brain/app/routes/sources.tsx +181 -114
  40. package/corpus/templates/clips/AGENTS.md +8 -6
  41. package/corpus/templates/clips/actions/request-transcript.ts +90 -420
  42. package/corpus/templates/clips/actions/save-browser-transcript.ts +11 -28
  43. package/corpus/templates/clips/app/components/capture-install-options.tsx +5 -3
  44. package/corpus/templates/clips/app/components/player/transcript-panel.tsx +3 -136
  45. package/corpus/templates/clips/app/lib/capture-install-options.ts +15 -4
  46. package/corpus/templates/clips/app/routes/download.tsx +3 -2
  47. package/corpus/templates/clips/changelog/2026-07-22-fixed-an-intermittent-hydration-error-on-the-download-page.md +6 -0
  48. package/corpus/templates/clips/changelog/2026-07-22-fixed-transcript-generation-when-native-speech-capture-retur.md +6 -0
  49. package/corpus/templates/clips/changelog/2026-07-22-transcript-generation-now-retries-with-backup-speech-recogni.md +6 -0
  50. package/corpus/templates/clips/server/lib/public-agent-context.ts +2 -2
  51. package/corpus/templates/clips/server/register-secrets.ts +7 -6
  52. package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +16 -84
  53. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +13 -7
  54. package/corpus/templates/content/app/components/editor/extensions/ImageBlock.tsx +2 -2
  55. package/corpus/templates/content/app/i18n-data.ts +10 -0
  56. package/corpus/templates/design/server/lib/fig-file-decoder.ts +1 -0
  57. package/corpus/templates/plan/app/entry.client.tsx +3 -0
  58. package/corpus/templates/plan/changelog/2026-07-22-recover-stale-pages-after-a-deployment-refresh-automatically.md +6 -0
  59. package/corpus/templates/slides/app/hooks/use-agent-generating.ts +10 -3
  60. package/corpus/templates/slides/app/pages/Index.tsx +1 -0
  61. package/corpus/templates/slides/changelog/2026-07-22-new-deck-prompts-now-open-in-their-own-visible-chat-thread.md +6 -0
  62. package/corpus/toolkit/CHANGELOG.md +9 -0
  63. package/corpus/toolkit/package.json +1 -1
  64. package/corpus/toolkit/src/composer/PromptComposer.tsx +5 -1
  65. package/corpus/toolkit/src/composer/RealtimeVoiceMode.tsx +119 -31
  66. package/corpus/toolkit/src/composer/useRealtimeVoiceMode.tsx +30 -0
  67. package/corpus/toolkit/src/conformance/runner.tsx +153 -1
  68. package/corpus/toolkit/src/editor/SharedRichEditor.tsx +13 -2
  69. package/corpus/toolkit/src/editor/SlashCommandMenu.tsx +20 -0
  70. package/corpus/toolkit/src/editor/index.ts +2 -0
  71. package/corpus/toolkit/src/styles.css +52 -23
  72. package/dist/a2a/client.d.ts +3 -1
  73. package/dist/a2a/client.d.ts.map +1 -1
  74. package/dist/a2a/client.js +17 -12
  75. package/dist/a2a/client.js.map +1 -1
  76. package/dist/cli/index.js +18 -8
  77. package/dist/cli/index.js.map +1 -1
  78. package/dist/cli/multi-frontier-runs.js +3 -3
  79. package/dist/cli/multi-frontier-runs.js.map +1 -1
  80. package/dist/cli/templates-meta.d.ts.map +1 -1
  81. package/dist/cli/templates-meta.js +0 -12
  82. package/dist/cli/templates-meta.js.map +1 -1
  83. package/dist/cli/workspace-dev.js +1 -1
  84. package/dist/cli/workspace-dev.js.map +1 -1
  85. package/dist/client/AgentPanel.d.ts.map +1 -1
  86. package/dist/client/AgentPanel.js +4 -1
  87. package/dist/client/AgentPanel.js.map +1 -1
  88. package/dist/client/RunStuckBanner.d.ts +3 -5
  89. package/dist/client/RunStuckBanner.d.ts.map +1 -1
  90. package/dist/client/RunStuckBanner.js +17 -18
  91. package/dist/client/RunStuckBanner.js.map +1 -1
  92. package/dist/client/chat/action-chat-ui-surface.d.ts +8 -0
  93. package/dist/client/chat/action-chat-ui-surface.d.ts.map +1 -0
  94. package/dist/client/chat/action-chat-ui-surface.js +10 -0
  95. package/dist/client/chat/action-chat-ui-surface.js.map +1 -0
  96. package/dist/client/chat/message-components.d.ts +3 -0
  97. package/dist/client/chat/message-components.d.ts.map +1 -1
  98. package/dist/client/chat/message-components.js +40 -7
  99. package/dist/client/chat/message-components.js.map +1 -1
  100. package/dist/client/chat/tool-call-display.d.ts +3 -1
  101. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  102. package/dist/client/chat/tool-call-display.js +13 -9
  103. package/dist/client/chat/tool-call-display.js.map +1 -1
  104. package/dist/client/chat/widgets/InlineExtensionWidget.d.ts.map +1 -1
  105. package/dist/client/chat/widgets/InlineExtensionWidget.js +1 -1
  106. package/dist/client/chat/widgets/InlineExtensionWidget.js.map +1 -1
  107. package/dist/client/chat/widgets/builtin-tool-renderers.d.ts.map +1 -1
  108. package/dist/client/chat/widgets/builtin-tool-renderers.js +5 -3
  109. package/dist/client/chat/widgets/builtin-tool-renderers.js.map +1 -1
  110. package/dist/client/conversation/AgentConversation.d.ts.map +1 -1
  111. package/dist/client/conversation/AgentConversation.js +3 -2
  112. package/dist/client/conversation/AgentConversation.js.map +1 -1
  113. package/dist/client/error-capture.d.ts.map +1 -1
  114. package/dist/client/error-capture.js +2 -2
  115. package/dist/client/error-capture.js.map +1 -1
  116. package/dist/client/resources/McpConnectionSuggestion.d.ts +1 -0
  117. package/dist/client/resources/McpConnectionSuggestion.d.ts.map +1 -1
  118. package/dist/client/resources/McpConnectionSuggestion.js +9 -8
  119. package/dist/client/resources/McpConnectionSuggestion.js.map +1 -1
  120. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  121. package/dist/client/resources/ResourcesPanel.js +3 -1
  122. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  123. package/dist/client/resources/mcp-integration-catalog.d.ts +1 -0
  124. package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
  125. package/dist/client/resources/mcp-integration-catalog.js +4 -17
  126. package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
  127. package/dist/client/resources/mcp-integration-logos.js +2 -2
  128. package/dist/client/resources/mcp-integration-logos.js.map +1 -1
  129. package/dist/client/route-chunk-recovery.d.ts.map +1 -1
  130. package/dist/client/route-chunk-recovery.js +5 -3
  131. package/dist/client/route-chunk-recovery.js.map +1 -1
  132. package/dist/client/session-replay.js +3 -3
  133. package/dist/client/session-replay.js.map +1 -1
  134. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  135. package/dist/client/settings/SettingsPanel.js +2 -2
  136. package/dist/client/settings/SettingsPanel.js.map +1 -1
  137. package/dist/client/transcription/use-live-transcription.d.ts +3 -3
  138. package/dist/client/transcription/use-live-transcription.d.ts.map +1 -1
  139. package/dist/client/transcription/use-live-transcription.js +22 -11
  140. package/dist/client/transcription/use-live-transcription.js.map +1 -1
  141. package/dist/collab/routes.d.ts +1 -1
  142. package/dist/collab/struct-routes.d.ts +1 -1
  143. package/dist/deploy/build.d.ts.map +1 -1
  144. package/dist/deploy/build.js +1 -1
  145. package/dist/deploy/build.js.map +1 -1
  146. package/dist/guards/db-tool-scoping.js +1 -1
  147. package/dist/guards/db-tool-scoping.js.map +1 -1
  148. package/dist/integrations/adapters/slack.d.ts +1 -0
  149. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  150. package/dist/integrations/adapters/slack.js +61 -5
  151. package/dist/integrations/adapters/slack.js.map +1 -1
  152. package/dist/integrations/index.d.ts +1 -1
  153. package/dist/integrations/index.d.ts.map +1 -1
  154. package/dist/integrations/index.js +1 -1
  155. package/dist/integrations/index.js.map +1 -1
  156. package/dist/localization/default-messages.js +1 -1
  157. package/dist/localization/default-messages.js.map +1 -1
  158. package/dist/mcp-client/oauth-routes.d.ts +3 -0
  159. package/dist/mcp-client/oauth-routes.d.ts.map +1 -1
  160. package/dist/mcp-client/oauth-routes.js +41 -12
  161. package/dist/mcp-client/oauth-routes.js.map +1 -1
  162. package/dist/notifications/routes.d.ts +2 -2
  163. package/dist/observability/routes.d.ts +3 -3
  164. package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
  165. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  166. package/dist/secrets/routes.d.ts +6 -6
  167. package/dist/server/realtime-voice.d.ts.map +1 -1
  168. package/dist/server/realtime-voice.js +1 -1
  169. package/dist/server/realtime-voice.js.map +1 -1
  170. package/dist/server/transcribe-voice.d.ts +1 -1
  171. package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +7 -5
  172. package/dist/terminal/cli-registry.js +1 -1
  173. package/dist/terminal/cli-registry.js.map +1 -1
  174. package/dist/vite/client.d.ts +8 -1
  175. package/dist/vite/client.d.ts.map +1 -1
  176. package/dist/vite/client.js +113 -2
  177. package/dist/vite/client.js.map +1 -1
  178. package/package.json +2 -2
  179. package/src/a2a/client.ts +32 -10
  180. package/src/cli/index.ts +18 -10
  181. package/src/cli/multi-frontier-runs.ts +5 -3
  182. package/src/cli/templates-meta.ts +0 -12
  183. package/src/cli/workspace-dev.ts +1 -1
  184. package/src/client/AgentPanel.tsx +9 -1
  185. package/src/client/RunStuckBanner.tsx +39 -47
  186. package/src/client/chat/action-chat-ui-surface.tsx +32 -0
  187. package/src/client/chat/message-components.tsx +53 -8
  188. package/src/client/chat/tool-call-display.tsx +24 -9
  189. package/src/client/chat/widgets/InlineExtensionWidget.tsx +0 -1
  190. package/src/client/chat/widgets/builtin-tool-renderers.tsx +7 -3
  191. package/src/client/conversation/AgentConversation.tsx +12 -1
  192. package/src/client/error-capture.ts +2 -6
  193. package/src/client/resources/McpConnectionSuggestion.tsx +20 -14
  194. package/src/client/resources/ResourcesPanel.tsx +5 -1
  195. package/src/client/resources/mcp-integration-catalog.ts +7 -17
  196. package/src/client/resources/mcp-integration-logos.ts +2 -2
  197. package/src/client/route-chunk-recovery.ts +5 -3
  198. package/src/client/session-replay.ts +3 -3
  199. package/src/client/settings/SettingsPanel.tsx +15 -6
  200. package/src/client/transcription/use-live-transcription.ts +64 -45
  201. package/src/deploy/build.ts +2 -1
  202. package/src/guards/db-tool-scoping.ts +1 -1
  203. package/src/integrations/adapters/slack.ts +84 -5
  204. package/src/integrations/index.ts +5 -1
  205. package/src/localization/default-messages.ts +1 -1
  206. package/src/mcp-client/oauth-routes.ts +45 -12
  207. package/src/server/realtime-voice.ts +4 -1
  208. package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +7 -5
  209. package/src/terminal/cli-registry.ts +1 -1
  210. package/src/vite/client.ts +166 -1
  211. package/corpus/templates/crm/.agents/skills/agent-native-docs/SKILL.md +0 -115
  212. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +0 -177
  213. package/corpus/templates/crm/.agents/skills/crm/SKILL.md +0 -128
  214. package/corpus/templates/crm/.agents/skills/customizing-agent-native/SKILL.md +0 -220
  215. package/corpus/templates/crm/.agents/skills/feature-flags/SKILL.md +0 -169
  216. package/corpus/templates/crm/.agents/skills/upgrade-agent-native/SKILL.md +0 -100
  217. package/corpus/templates/crm/.env.example +0 -5
  218. package/corpus/templates/crm/AGENTS.md +0 -120
  219. package/corpus/templates/crm/CHANGELOG.md +0 -1
  220. package/corpus/templates/crm/DEVELOPING.md +0 -66
  221. package/corpus/templates/crm/README.md +0 -106
  222. package/corpus/templates/crm/_gitignore +0 -12
  223. package/corpus/templates/crm/actions/_crm-action-utils.ts +0 -87
  224. package/corpus/templates/crm/actions/_crm-dashboard.ts +0 -69
  225. package/corpus/templates/crm/actions/_crm-data-program-actions.ts +0 -15
  226. package/corpus/templates/crm/actions/_crm-signal-utils.ts +0 -79
  227. package/corpus/templates/crm/actions/apply-crm-proposals.ts +0 -203
  228. package/corpus/templates/crm/actions/attach-call-evidence.ts +0 -170
  229. package/corpus/templates/crm/actions/configure-crm-connection.ts +0 -126
  230. package/corpus/templates/crm/actions/configure-native-crm.ts +0 -44
  231. package/corpus/templates/crm/actions/create-crm-record.ts +0 -148
  232. package/corpus/templates/crm/actions/create-crm-signal-tracker.ts +0 -58
  233. package/corpus/templates/crm/actions/delete-staged-dataset.ts +0 -14
  234. package/corpus/templates/crm/actions/get-crm-automation-recipe.ts +0 -36
  235. package/corpus/templates/crm/actions/get-crm-dashboard-panel.ts +0 -35
  236. package/corpus/templates/crm/actions/get-crm-dashboard.ts +0 -14
  237. package/corpus/templates/crm/actions/get-crm-overview.ts +0 -13
  238. package/corpus/templates/crm/actions/get-crm-pipeline-data.ts +0 -61
  239. package/corpus/templates/crm/actions/get-crm-record.ts +0 -75
  240. package/corpus/templates/crm/actions/install-crm-pipeline-dashboard.ts +0 -81
  241. package/corpus/templates/crm/actions/list-crm-dashboard-revisions.ts +0 -15
  242. package/corpus/templates/crm/actions/list-crm-dashboards.ts +0 -15
  243. package/corpus/templates/crm/actions/list-crm-proposals.ts +0 -31
  244. package/corpus/templates/crm/actions/list-crm-records.ts +0 -79
  245. package/corpus/templates/crm/actions/list-crm-saved-views.ts +0 -15
  246. package/corpus/templates/crm/actions/list-crm-signal-hits.ts +0 -43
  247. package/corpus/templates/crm/actions/list-crm-signal-trackers.ts +0 -32
  248. package/corpus/templates/crm/actions/list-crm-tasks.ts +0 -22
  249. package/corpus/templates/crm/actions/list-staged-datasets.ts +0 -14
  250. package/corpus/templates/crm/actions/list-workspace-connections.ts +0 -47
  251. package/corpus/templates/crm/actions/manage-crm-signal-tracker.ts +0 -87
  252. package/corpus/templates/crm/actions/manage-crm-task.ts +0 -132
  253. package/corpus/templates/crm/actions/navigate.ts +0 -63
  254. package/corpus/templates/crm/actions/provider-api-catalog.ts +0 -22
  255. package/corpus/templates/crm/actions/provider-api-docs.ts +0 -54
  256. package/corpus/templates/crm/actions/provider-api-request.ts +0 -92
  257. package/corpus/templates/crm/actions/query-staged-dataset.ts +0 -44
  258. package/corpus/templates/crm/actions/record-crm-call-insight.ts +0 -160
  259. package/corpus/templates/crm/actions/record-crm-smart-signal.ts +0 -150
  260. package/corpus/templates/crm/actions/restore-crm-dashboard-revision.ts +0 -23
  261. package/corpus/templates/crm/actions/review-crm-signal.ts +0 -31
  262. package/corpus/templates/crm/actions/run-crm-saved-view-program.ts +0 -103
  263. package/corpus/templates/crm/actions/run-crm-signal-trackers.ts +0 -275
  264. package/corpus/templates/crm/actions/run.ts +0 -7
  265. package/corpus/templates/crm/actions/save-crm-dashboard.ts +0 -51
  266. package/corpus/templates/crm/actions/save-crm-saved-view.ts +0 -119
  267. package/corpus/templates/crm/actions/sync-crm.ts +0 -146
  268. package/corpus/templates/crm/actions/update-crm-record.ts +0 -510
  269. package/corpus/templates/crm/actions/view-screen.ts +0 -218
  270. package/corpus/templates/crm/agent-native.app-skill.json +0 -58
  271. package/corpus/templates/crm/app/components/crm/CreateCrmRecordDialog.tsx +0 -158
  272. package/corpus/templates/crm/app/components/crm/CrmDashboardPanel.tsx +0 -78
  273. package/corpus/templates/crm/app/components/crm/CrmSignalsPanel.tsx +0 -226
  274. package/corpus/templates/crm/app/components/crm/IntelligenceSettings.tsx +0 -414
  275. package/corpus/templates/crm/app/components/crm/RecordActions.tsx +0 -510
  276. package/corpus/templates/crm/app/components/crm/RecordGrid.tsx +0 -134
  277. package/corpus/templates/crm/app/components/crm/RecordWorkspace.tsx +0 -362
  278. package/corpus/templates/crm/app/components/crm/SavedViewDataProgram.tsx +0 -93
  279. package/corpus/templates/crm/app/components/crm/Surface.tsx +0 -97
  280. package/corpus/templates/crm/app/components/crm/WorkOverview.tsx +0 -180
  281. package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +0 -112
  282. package/corpus/templates/crm/app/components/layout/CrmSidebar.tsx +0 -84
  283. package/corpus/templates/crm/app/components/ui/alert-dialog.tsx +0 -1
  284. package/corpus/templates/crm/app/components/ui/badge.tsx +0 -1
  285. package/corpus/templates/crm/app/components/ui/button.tsx +0 -1
  286. package/corpus/templates/crm/app/components/ui/card.tsx +0 -1
  287. package/corpus/templates/crm/app/components/ui/dialog.tsx +0 -1
  288. package/corpus/templates/crm/app/components/ui/input.tsx +0 -1
  289. package/corpus/templates/crm/app/components/ui/label.tsx +0 -1
  290. package/corpus/templates/crm/app/components/ui/select.tsx +0 -1
  291. package/corpus/templates/crm/app/components/ui/sheet.tsx +0 -1
  292. package/corpus/templates/crm/app/components/ui/skeleton.tsx +0 -1
  293. package/corpus/templates/crm/app/components/ui/switch.tsx +0 -1
  294. package/corpus/templates/crm/app/components/ui/table.tsx +0 -1
  295. package/corpus/templates/crm/app/components/ui/tabs.tsx +0 -1
  296. package/corpus/templates/crm/app/components/ui/textarea.tsx +0 -1
  297. package/corpus/templates/crm/app/components/ui/toolkit-provider.tsx +0 -17
  298. package/corpus/templates/crm/app/design-system.ts +0 -3
  299. package/corpus/templates/crm/app/entry.client.tsx +0 -16
  300. package/corpus/templates/crm/app/entry.server.tsx +0 -10
  301. package/corpus/templates/crm/app/global.css +0 -167
  302. package/corpus/templates/crm/app/hooks/use-navigation-state.ts +0 -60
  303. package/corpus/templates/crm/app/i18n/en-US.ts +0 -89
  304. package/corpus/templates/crm/app/i18n/index.ts +0 -34
  305. package/corpus/templates/crm/app/lib/dashboard.ts +0 -13
  306. package/corpus/templates/crm/app/lib/navigation.ts +0 -54
  307. package/corpus/templates/crm/app/lib/tab-id.ts +0 -1
  308. package/corpus/templates/crm/app/lib/types.ts +0 -172
  309. package/corpus/templates/crm/app/lib/utils.ts +0 -1
  310. package/corpus/templates/crm/app/root.tsx +0 -91
  311. package/corpus/templates/crm/app/routes/_index.tsx +0 -26
  312. package/corpus/templates/crm/app/routes/accounts.tsx +0 -41
  313. package/corpus/templates/crm/app/routes/agent.tsx +0 -5
  314. package/corpus/templates/crm/app/routes/ask.tsx +0 -53
  315. package/corpus/templates/crm/app/routes/dashboard.tsx +0 -118
  316. package/corpus/templates/crm/app/routes/opportunities.tsx +0 -41
  317. package/corpus/templates/crm/app/routes/people.tsx +0 -41
  318. package/corpus/templates/crm/app/routes/proposals.tsx +0 -266
  319. package/corpus/templates/crm/app/routes/records.$recordId.tsx +0 -35
  320. package/corpus/templates/crm/app/routes/settings.tsx +0 -63
  321. package/corpus/templates/crm/app/routes/setup.tsx +0 -308
  322. package/corpus/templates/crm/app/routes/tasks.tsx +0 -252
  323. package/corpus/templates/crm/app/routes/views.tsx +0 -333
  324. package/corpus/templates/crm/app/routes.ts +0 -17
  325. package/corpus/templates/crm/app/vite-env.d.ts +0 -6
  326. package/corpus/templates/crm/changelog/2026-07-21-agent-native-crm.md +0 -6
  327. package/corpus/templates/crm/changelog/2026-07-21-clips-call-evidence-review-recipe.md +0 -6
  328. package/corpus/templates/crm/changelog/2026-07-21-crm-can-now-find-and-review-evidence-grounded-call-signals-w.md +0 -6
  329. package/corpus/templates/crm/changelog/2026-07-21-crm-can-now-manage-keyword-and-smart-call-signal-trackers-fr.md +0 -6
  330. package/corpus/templates/crm/changelog/2026-07-21-delegated-local-crm-automation.md +0 -6
  331. package/corpus/templates/crm/changelog/2026-07-21-native-sql.md +0 -6
  332. package/corpus/templates/crm/changelog/2026-07-21-pipeline-dashboard.md +0 -6
  333. package/corpus/templates/crm/changelog/2026-07-21-pipeline-dashboards-now-install-correctly-from-the-crm-actio.md +0 -6
  334. package/corpus/templates/crm/changelog/2026-07-21-salesforce-connection.md +0 -6
  335. package/corpus/templates/crm/changelog/2026-07-22-crm-field-validation-now-explains-which-fields-cannot-be-edi.md +0 -6
  336. package/corpus/templates/crm/changelog/2026-07-22-fixed-hubspot-contact-syncs-missing-records-updated-after-th.md +0 -6
  337. package/corpus/templates/crm/changelog/2026-07-22-fixed-pipeline-dashboard-panels-so-their-opportunity-data-lo.md +0 -6
  338. package/corpus/templates/crm/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +0 -6
  339. package/corpus/templates/crm/components.json +0 -20
  340. package/corpus/templates/crm/docs/architecture/crm-contract.md +0 -180
  341. package/corpus/templates/crm/learnings.defaults.md +0 -5
  342. package/corpus/templates/crm/package.json +0 -59
  343. package/corpus/templates/crm/public/favicon.svg +0 -1
  344. package/corpus/templates/crm/public/icon-180.svg +0 -1
  345. package/corpus/templates/crm/public/manifest.json +0 -11
  346. package/corpus/templates/crm/react-router.config.ts +0 -7
  347. package/corpus/templates/crm/server/crm/adapter.ts +0 -32
  348. package/corpus/templates/crm/server/crm/crm-field-firewall.ts +0 -64
  349. package/corpus/templates/crm/server/crm/crm-mirror.ts +0 -711
  350. package/corpus/templates/crm/server/crm/hubspot-adapter.ts +0 -1146
  351. package/corpus/templates/crm/server/crm/native-adapter.ts +0 -1715
  352. package/corpus/templates/crm/server/crm/read-through.ts +0 -207
  353. package/corpus/templates/crm/server/crm/salesforce-adapter.ts +0 -1255
  354. package/corpus/templates/crm/server/db/crm-store.ts +0 -1170
  355. package/corpus/templates/crm/server/db/index.ts +0 -169
  356. package/corpus/templates/crm/server/db/schema.ts +0 -441
  357. package/corpus/templates/crm/server/lib/intelligence/default-detectors.ts +0 -65
  358. package/corpus/templates/crm/server/lib/intelligence/evidence.ts +0 -105
  359. package/corpus/templates/crm/server/lib/intelligence/keyword-detector.ts +0 -100
  360. package/corpus/templates/crm/server/lib/intelligence/smart-detector.ts +0 -144
  361. package/corpus/templates/crm/server/lib/intelligence/summary.ts +0 -141
  362. package/corpus/templates/crm/server/lib/provider-api.ts +0 -64
  363. package/corpus/templates/crm/server/middleware/auth.ts +0 -4
  364. package/corpus/templates/crm/server/plugins/agent-chat.ts +0 -68
  365. package/corpus/templates/crm/server/plugins/auth.ts +0 -14
  366. package/corpus/templates/crm/server/plugins/core-routes.ts +0 -17
  367. package/corpus/templates/crm/server/plugins/db.ts +0 -454
  368. package/corpus/templates/crm/server/routes/[...page].get.ts +0 -5
  369. package/corpus/templates/crm/shared/crm-automation-recipes.ts +0 -132
  370. package/corpus/templates/crm/shared/crm-contract.ts +0 -254
  371. package/corpus/templates/crm/shared/crm-sales-config.ts +0 -63
  372. package/corpus/templates/crm/ssr-entry.ts +0 -11
  373. package/corpus/templates/crm/tsconfig.json +0 -24
  374. package/corpus/templates/crm/vite.config.ts +0 -15
  375. package/corpus/templates/crm/vitest.config.ts +0 -5
@@ -1,203 +0,0 @@
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
- });
@@ -1,170 +0,0 @@
1
- import { defineAction } from "@agent-native/core/action";
2
- import { assertAccess } from "@agent-native/core/sharing";
3
- import { and, eq, inArray } from "drizzle-orm";
4
- import { z } from "zod";
5
-
6
- import { isSafeCrmEvidenceExcerpt } from "../server/crm/crm-field-firewall.js";
7
- import { getDb, schema } from "../server/db/index.js";
8
- import { isDurableClipsEvidenceUrl } from "../shared/crm-automation-recipes.js";
9
- import { requireCrmScope } from "./_crm-action-utils.js";
10
-
11
- const httpsUrl = z
12
- .string()
13
- .url()
14
- .max(2_048)
15
- .refine(
16
- (value) => /^https:\/\//i.test(value),
17
- "sourceUrl must be an https URL",
18
- );
19
-
20
- export default defineAction({
21
- description:
22
- "Attach bounded call evidence to a CRM record. Store only an artifact reference, URL, optional short quote, speaker, timestamp, and summary; never submit a transcript or media payload.",
23
- schema: z
24
- .object({
25
- recordId: z.string().trim().min(1).max(128).optional(),
26
- recordIds: z
27
- .array(z.string().trim().min(1).max(128))
28
- .min(1)
29
- .max(20)
30
- .optional(),
31
- interactionId: z.string().trim().min(1).max(128).optional(),
32
- artifactId: z.string().trim().min(1).max(256),
33
- sourceUrl: httpsUrl,
34
- sourceApp: z.string().trim().min(1).max(80).default("clips"),
35
- artifactType: z.string().trim().min(1).max(80).default("call-evidence"),
36
- quote: z
37
- .string()
38
- .trim()
39
- .max(1_200)
40
- .refine(
41
- isSafeCrmEvidenceExcerpt,
42
- "quote must be a bounded human-readable excerpt, not transcript, media, binary, base64, or data-url content",
43
- )
44
- .optional(),
45
- speaker: z.string().trim().max(240).optional(),
46
- startSeconds: z.number().finite().min(0).max(86_400).optional(),
47
- endSeconds: z.number().finite().min(0).max(86_400).optional(),
48
- summary: z
49
- .string()
50
- .trim()
51
- .max(2_000)
52
- .refine(
53
- isSafeCrmEvidenceExcerpt,
54
- "summary must be a bounded human-readable excerpt, not transcript, media, binary, base64, or data-url content",
55
- )
56
- .optional(),
57
- capturedAt: z.string().datetime({ offset: true }).optional(),
58
- })
59
- .superRefine((value, issue) => {
60
- if (
61
- (!value.recordId && !value.recordIds) ||
62
- (value.recordId && value.recordIds)
63
- ) {
64
- issue.addIssue({
65
- code: "custom",
66
- message: "Provide exactly one of recordId or recordIds",
67
- path: ["recordId"],
68
- });
69
- }
70
- if (
71
- value.endSeconds !== undefined &&
72
- value.startSeconds !== undefined &&
73
- value.endSeconds < value.startSeconds
74
- ) {
75
- issue.addIssue({
76
- code: "custom",
77
- message: "endSeconds must be after startSeconds",
78
- path: ["endSeconds"],
79
- });
80
- }
81
- if (
82
- value.sourceApp.trim().toLowerCase() === "clips" &&
83
- !isDurableClipsEvidenceUrl(value.sourceUrl)
84
- ) {
85
- issue.addIssue({
86
- code: "custom",
87
- message:
88
- "Clips evidence must use a durable /share/<id> or /r/<id> page URL without an access token, media endpoint, or transcript fragment",
89
- path: ["sourceUrl"],
90
- });
91
- }
92
- }),
93
- audit: {
94
- target: (args, result) => {
95
- const value = result as {
96
- evidence?: Array<{
97
- ownerEmail: string;
98
- orgId: string | null;
99
- visibility: "private" | "org";
100
- }>;
101
- ownerEmail: string;
102
- orgId: string | null;
103
- visibility: "private" | "org";
104
- };
105
- const evidence = value.evidence?.[0] ?? value;
106
- return {
107
- type: "crm-record",
108
- id: args.recordId ?? args.recordIds?.[0] ?? "unknown",
109
- ownerEmail: evidence.ownerEmail,
110
- orgId: evidence.orgId,
111
- visibility: evidence.visibility,
112
- };
113
- },
114
- summary: (args) =>
115
- `Attached call evidence to ${args.recordIds?.length ?? 1} CRM record${args.recordIds?.length === 1 ? "" : "s"}`,
116
- recordInputs: false,
117
- },
118
- run: async (args, ctx) => {
119
- const recordIds = args.recordId
120
- ? [args.recordId]
121
- : [...new Set(args.recordIds ?? [])];
122
- await Promise.all(
123
- recordIds.map((recordId) =>
124
- assertAccess("crm-record", recordId, "editor"),
125
- ),
126
- );
127
- if (args.interactionId)
128
- await assertAccess("crm-interaction", args.interactionId, "viewer");
129
- const db = getDb();
130
- const scope = requireCrmScope(ctx);
131
- const now = new Date().toISOString();
132
- const rows = recordIds.map((recordId) => ({
133
- id: crypto.randomUUID(),
134
- interactionId: args.interactionId ?? null,
135
- recordId,
136
- sourceApp: args.sourceApp,
137
- artifactType: args.artifactType,
138
- artifactId: args.artifactId,
139
- sourceUrl: args.sourceUrl,
140
- quote: args.quote ?? "",
141
- speaker: args.speaker ?? null,
142
- startSeconds: args.startSeconds ?? null,
143
- endSeconds: args.endSeconds ?? null,
144
- summary: args.summary ?? "",
145
- capturedAt: args.capturedAt ?? now,
146
- ...scope,
147
- createdAt: now,
148
- updatedAt: now,
149
- }));
150
- await db.transaction(async (tx) => {
151
- await tx.insert(schema.crmCallEvidence).values(rows);
152
- });
153
- const evidence = await db
154
- .select()
155
- .from(schema.crmCallEvidence)
156
- .where(
157
- and(
158
- inArray(
159
- schema.crmCallEvidence.id,
160
- rows.map((row) => row.id),
161
- ),
162
- eq(schema.crmCallEvidence.ownerEmail, scope.ownerEmail),
163
- ),
164
- )
165
- .limit(recordIds.length);
166
- if (evidence.length !== recordIds.length)
167
- throw new Error("Call evidence could not be verified after saving.");
168
- return args.recordId ? evidence[0] : { evidence };
169
- },
170
- });
@@ -1,126 +0,0 @@
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 { createConnectedCrmAdapter } from "../server/crm/adapter.js";
7
- import { getDb, schema } from "../server/db/index.js";
8
- import { requireCrmScope, toJson } from "./_crm-action-utils.js";
9
-
10
- const idList = z.array(z.string().trim().min(1).max(160)).max(50).default([]);
11
-
12
- export default defineAction({
13
- description:
14
- "Register an authorized HubSpot or Salesforce workspace Connection as a scoped CRM companion connection. Provider credentials remain in workspace Connections.",
15
- schema: z.object({
16
- provider: z.enum(["hubspot", "salesforce"]).default("hubspot"),
17
- workspaceConnectionId: z.string().trim().min(1).max(160).optional(),
18
- label: z.string().trim().min(1).max(160).optional(),
19
- mode: z.enum(["connected", "hybrid"]).default("connected"),
20
- selectedPipelineIds: idList,
21
- selectedObjectTypes: z
22
- .array(z.string().trim().min(1).max(120))
23
- .min(1)
24
- .max(50)
25
- .optional(),
26
- }),
27
- audit: {
28
- target: (_args, result) => {
29
- const connection = result as {
30
- id: string;
31
- ownerEmail: string;
32
- orgId: string | null;
33
- visibility: "private" | "org";
34
- };
35
- return {
36
- type: "crm-connection",
37
- id: connection.id,
38
- ownerEmail: connection.ownerEmail,
39
- orgId: connection.orgId,
40
- visibility: connection.visibility,
41
- };
42
- },
43
- summary: (_args, result) =>
44
- `Configured CRM connection ${(result as { id?: string })?.id ?? ""}`,
45
- recordInputs: false,
46
- },
47
- run: async (args, ctx?: ActionRunContext) => {
48
- const scope = requireCrmScope(ctx);
49
- const adapter = await createConnectedCrmAdapter({
50
- provider: args.provider,
51
- connectionId: args.workspaceConnectionId,
52
- userEmail: scope.ownerEmail,
53
- orgId: scope.orgId,
54
- });
55
- const id = adapter.connection.connectionId;
56
- const db = getDb();
57
- const [existing] = await db
58
- .select({ id: schema.crmConnections.id })
59
- .from(schema.crmConnections)
60
- .where(
61
- and(
62
- eq(schema.crmConnections.workspaceConnectionId, id),
63
- accessFilter(schema.crmConnections, schema.crmConnectionShares),
64
- ),
65
- )
66
- .limit(1);
67
- const now = new Date().toISOString();
68
- const selectedObjectTypes =
69
- args.selectedObjectTypes ??
70
- (args.provider === "hubspot"
71
- ? ["companies", "contacts", "deals"]
72
- : ["Account", "Contact", "Opportunity"]);
73
- const accessScopeKey = `workspace:${id}:${adapter.connection.actorId ?? scope.ownerEmail}`;
74
- const values = {
75
- provider: args.provider,
76
- workspaceConnectionId: id,
77
- label:
78
- args.label ?? (args.provider === "hubspot" ? "HubSpot" : "Salesforce"),
79
- accountId: adapter.connection.accountId ?? null,
80
- mode: args.mode,
81
- status: "connected" as const,
82
- selectedPipelinesJson: toJson(args.selectedPipelineIds, 8_000),
83
- selectedObjectTypesJson: toJson(selectedObjectTypes, 8_000),
84
- accessScopeKey,
85
- accessScopeJson: toJson(
86
- {
87
- key: accessScopeKey,
88
- actorId: adapter.connection.actorId,
89
- mode: adapter.connection.actorId ? "user" : "service-account",
90
- recordVisibility: adapter.connection.actorId ? "actor" : "unknown",
91
- },
92
- 4_000,
93
- ),
94
- lastError: null,
95
- updatedAt: now,
96
- };
97
- const localId = existing?.id ?? id;
98
-
99
- if (existing) {
100
- await assertAccess("crm-connection", existing.id, "editor");
101
- await db
102
- .update(schema.crmConnections)
103
- .set(values)
104
- .where(
105
- and(
106
- eq(schema.crmConnections.id, existing.id),
107
- accessFilter(
108
- schema.crmConnections,
109
- schema.crmConnectionShares,
110
- undefined,
111
- "editor",
112
- ),
113
- ),
114
- );
115
- } else {
116
- await db.insert(schema.crmConnections).values({
117
- id: localId,
118
- ...values,
119
- ...scope,
120
- createdAt: now,
121
- });
122
- }
123
-
124
- return { id: localId, ...scope, provider: args.provider };
125
- },
126
- });
@@ -1,44 +0,0 @@
1
- import { defineAction, type ActionRunContext } from "@agent-native/core/action";
2
- import { z } from "zod";
3
-
4
- import { configureNativeCrmConnection } from "../server/crm/native-adapter.js";
5
- import { requireCrmScope } from "./_crm-action-utils.js";
6
-
7
- export default defineAction({
8
- description:
9
- "Initialize a local-authoritative Native SQL CRM with accounts, people, and opportunities. It requires no provider connection or credential and uses the configured SQLite, Postgres, or D1 database.",
10
- schema: z.object({
11
- label: z.string().trim().min(1).max(160).optional(),
12
- }),
13
- audit: {
14
- target: (_args, result) => {
15
- const connection = result as {
16
- id: string;
17
- ownerEmail: string;
18
- orgId: string | null;
19
- visibility: "private" | "org";
20
- };
21
- return {
22
- type: "crm-connection",
23
- id: connection.id,
24
- ownerEmail: connection.ownerEmail,
25
- orgId: connection.orgId,
26
- visibility: connection.visibility,
27
- };
28
- },
29
- summary: (_args, result) =>
30
- `Configured Native SQL CRM ${(result as { id?: string })?.id ?? ""}`,
31
- recordInputs: false,
32
- },
33
- run: async (args, ctx?: ActionRunContext) => {
34
- const result = await configureNativeCrmConnection({
35
- label: args.label,
36
- ownership: requireCrmScope(ctx),
37
- });
38
- return {
39
- ...result,
40
- provider: "native" as const,
41
- mode: "native" as const,
42
- };
43
- },
44
- });
@@ -1,148 +0,0 @@
1
- import { defineAction, type ActionRunContext } from "@agent-native/core/action";
2
- import { accessFilter } from "@agent-native/core/sharing";
3
- import { and, eq } from "drizzle-orm";
4
- import { z } from "zod";
5
-
6
- import {
7
- configureNativeCrmConnection,
8
- createNativeCrmAdapter,
9
- } from "../server/crm/native-adapter.js";
10
- import { getDb, schema } from "../server/db/index.js";
11
- import type { CrmValue } from "../shared/crm-contract.js";
12
- import {
13
- crmInitiatedBy,
14
- isSafeCrmMutationFields,
15
- MAX_CRM_FIELDS_PER_MUTATION,
16
- requireCrmScope,
17
- scopedCrmIdempotencyKey,
18
- } from "./_crm-action-utils.js";
19
-
20
- const kindToObjectType = {
21
- account: "accounts",
22
- person: "people",
23
- opportunity: "opportunities",
24
- } as const;
25
-
26
- export const nativeRecordFieldsSchema = z
27
- .record(z.string().trim().min(1).max(120), z.unknown())
28
- .refine(
29
- (fields) => Object.keys(fields).length <= MAX_CRM_FIELDS_PER_MUTATION,
30
- `Provide at most ${MAX_CRM_FIELDS_PER_MUTATION} fields.`,
31
- )
32
- .refine(
33
- isSafeCrmMutationFields,
34
- "CRM fields and values cannot contain media, transcripts, data URLs, base64, or oversized JSON.",
35
- );
36
-
37
- export default defineAction({
38
- description:
39
- "Create an account, person, or opportunity in Native SQL CRM. The record is local-authoritative, access-scoped, idempotent, audited, and has no upstream provider write.",
40
- schema: z.object({
41
- connectionId: z.string().trim().min(1).max(128).optional(),
42
- kind: z.enum(["account", "person", "opportunity"]),
43
- displayName: z.string().trim().min(1).max(500),
44
- fields: nativeRecordFieldsSchema.optional(),
45
- idempotencyKey: z.string().trim().min(1).max(256).optional(),
46
- }),
47
- audit: {
48
- target: (_args, result) => {
49
- const record = 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: record.recordId,
58
- ownerEmail: record.ownerEmail,
59
- orgId: record.orgId,
60
- visibility: record.visibility,
61
- };
62
- },
63
- summary: (args) =>
64
- `Created Native SQL CRM ${args.kind} ${args.displayName}`,
65
- recordInputs: false,
66
- },
67
- run: async (args, ctx?: ActionRunContext) => {
68
- const ownership = requireCrmScope(ctx);
69
- const db = getDb();
70
- const connectionRows = await db
71
- .select({ id: schema.crmConnections.id })
72
- .from(schema.crmConnections)
73
- .where(
74
- and(
75
- eq(schema.crmConnections.provider, "native"),
76
- ...(args.connectionId
77
- ? [eq(schema.crmConnections.id, args.connectionId)]
78
- : []),
79
- accessFilter(
80
- schema.crmConnections,
81
- schema.crmConnectionShares,
82
- undefined,
83
- "editor",
84
- ),
85
- ),
86
- )
87
- .limit(args.connectionId ? 1 : 2);
88
- if (!connectionRows.length && args.connectionId) {
89
- throw new Error(
90
- "The selected Native SQL CRM is unavailable or you do not have editor access.",
91
- );
92
- }
93
- if (!args.connectionId && connectionRows.length > 1) {
94
- throw new Error(
95
- "More than one Native SQL CRM is available. Provide connectionId to choose one.",
96
- );
97
- }
98
- const connectionId =
99
- connectionRows[0]?.id ??
100
- (
101
- await configureNativeCrmConnection({
102
- ownership,
103
- })
104
- ).id;
105
- const objectType = kindToObjectType[args.kind];
106
- const remoteId = crypto.randomUUID();
107
- const fields = {
108
- ...(args.fields as Record<string, CrmValue> | undefined),
109
- displayName: args.displayName,
110
- ...(args.kind === "person" ? {} : { name: args.displayName }),
111
- };
112
- const idempotencyKey = await scopedCrmIdempotencyKey({
113
- ...ownership,
114
- recordId: `${connectionId}:${objectType}`,
115
- key: args.idempotencyKey ?? crypto.randomUUID(),
116
- });
117
- const adapter = await createNativeCrmAdapter({
118
- connectionId,
119
- initiatedBy: crmInitiatedBy(ctx),
120
- });
121
- const result = await adapter.applyMutation({
122
- operation: "create",
123
- record: {
124
- connectionId,
125
- provider: "native",
126
- objectType,
127
- kind: args.kind,
128
- remoteId,
129
- },
130
- fields,
131
- idempotencyKey,
132
- });
133
- if (result.status !== "applied" || !result.record?.ref.localId) {
134
- throw new Error(
135
- result.message ?? "Native SQL CRM record was not created.",
136
- );
137
- }
138
- return {
139
- recordId: result.record.ref.localId,
140
- connectionId,
141
- provider: "native" as const,
142
- kind: args.kind,
143
- displayName: result.record.displayName,
144
- revision: result.remoteRevision,
145
- ...ownership,
146
- };
147
- },
148
- });