@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
@@ -126,11 +126,15 @@ function renderDataWidget(context: ToolRendererContext) {
126
126
  return null;
127
127
  }
128
128
 
129
- function BuiltinToolRendererSkeleton() {
129
+ function BuiltinToolRendererSkeleton({ framed = true }: { framed?: boolean }) {
130
130
  return (
131
131
  <div
132
132
  aria-label="Loading tool result"
133
- className="my-1.5 h-24 animate-pulse rounded-lg border border-border bg-muted/30"
133
+ className={
134
+ framed
135
+ ? "my-1.5 h-24 animate-pulse rounded-lg border border-border bg-muted/30"
136
+ : "h-24 animate-pulse bg-muted/30"
137
+ }
134
138
  />
135
139
  );
136
140
  }
@@ -140,7 +144,7 @@ const BuiltinDataWidgetRenderer: ToolRendererComponent = ({ context }) =>
140
144
 
141
145
  const BuiltinInlineExtensionRenderer: ToolRendererComponent = ({ context }) =>
142
146
  normalizeInlineExtensionToolResult(context) ? (
143
- <Suspense fallback={<BuiltinToolRendererSkeleton />}>
147
+ <Suspense fallback={<BuiltinToolRendererSkeleton framed={false} />}>
144
148
  <LazyInlineExtensionWidget context={context} />
145
149
  </Suspense>
146
150
  ) : null;
@@ -13,10 +13,12 @@ import React from "react";
13
13
  import ReactMarkdown, { defaultUrlTransform } from "react-markdown";
14
14
  import remarkGfm from "remark-gfm";
15
15
 
16
+ import { ActionChatUiSurface } from "../chat/action-chat-ui-surface.js";
16
17
  import { resolveToolRenderer } from "../chat/tool-render-registry.js";
17
18
  import {
18
19
  resolveBuiltinActionChatRenderer,
19
20
  resolveBuiltinFallbackToolRenderer,
21
+ isBuiltinDataWidgetActionRenderer,
20
22
  } from "../chat/widgets/builtin-tool-renderers.js";
21
23
  import {
22
24
  MessageScroller,
@@ -414,7 +416,16 @@ function ConversationToolCall({ tool }: { tool: AgentConversationToolCall }) {
414
416
  resolveToolRenderer(nativeToolContext) ??
415
417
  resolveBuiltinFallbackToolRenderer(nativeToolContext);
416
418
  if (NativeToolRenderer) {
417
- return <NativeToolRenderer context={nativeToolContext} />;
419
+ return (
420
+ <ActionChatUiSurface
421
+ context={nativeToolContext}
422
+ isBuiltinDataWidget={isBuiltinDataWidgetActionRenderer(
423
+ nativeToolContext,
424
+ )}
425
+ >
426
+ <NativeToolRenderer context={nativeToolContext} />
427
+ </ActionChatUiSurface>
428
+ );
418
429
  }
419
430
 
420
431
  const hasDetails = Boolean(tool.input || tool.result || tool.mcpApp);
@@ -21,6 +21,7 @@
21
21
  * the server normalizes + groups it. That keeps one tested source of truth for
22
22
  * grouping instead of duplicating parser logic across the wire.
23
23
  */
24
+ import { isDynamicImportFailureMessage } from "./route-chunk-recovery.js";
24
25
  import { scrubUrl } from "./url-scrub.js";
25
26
 
26
27
  export type ExceptionLevel = "fatal" | "error" | "warning" | "info" | "debug";
@@ -358,12 +359,7 @@ function shouldIgnoreAutoCapturedError(normalized: {
358
359
  // Route-chunk recovery reloads the current page after stale lazy chunks or
359
360
  // module scripts fail. Browser-level failures have no useful stack, so do
360
361
  // not retain the transient loader noise as an application issue.
361
- if (
362
- !stack &&
363
- /^(?:Importing a module script failed\.?|(?:Failed to fetch|error loading) dynamically imported module(?::.*)?)$/i.test(
364
- message,
365
- )
366
- ) {
362
+ if (!stack && isDynamicImportFailureMessage(message)) {
367
363
  return true;
368
364
  }
369
365
 
@@ -39,6 +39,18 @@ export interface McpConnectionSuggestionProps {
39
39
  integrations?: DefaultMcpIntegration[];
40
40
  }
41
41
 
42
+ export function findMcpConnectionSuggestionIntegration({
43
+ text,
44
+ contextText = "",
45
+ variant = "composer",
46
+ integrations = getDefaultMcpIntegrations(),
47
+ }: McpConnectionSuggestionProps): DefaultMcpIntegration | null {
48
+ return findMcpIntegrationForText(
49
+ variant === "response" ? contextText : text,
50
+ integrations,
51
+ );
52
+ }
53
+
42
54
  function compareUrl(value: string): string {
43
55
  try {
44
56
  const url = new URL(value.trim());
@@ -99,22 +111,16 @@ export function McpConnectionSuggestion({
99
111
  () => integrationOptions ?? getDefaultMcpIntegrations(),
100
112
  [integrationOptions],
101
113
  );
102
- const textIntegration = useMemo(
103
- () => findMcpIntegrationForText(text, integrations),
104
- [integrations, text],
105
- );
106
- const contextIntegration = useMemo(
114
+ const integration = useMemo(
107
115
  () =>
108
- contextText ? findMcpIntegrationForText(contextText, integrations) : null,
109
- [contextText, integrations],
116
+ findMcpConnectionSuggestionIntegration({
117
+ text,
118
+ contextText,
119
+ variant,
120
+ integrations,
121
+ }),
122
+ [contextText, integrations, text, variant],
110
123
  );
111
- const integration =
112
- variant === "response" &&
113
- textIntegration &&
114
- contextIntegration &&
115
- textIntegration.id !== contextIntegration.id
116
- ? null
117
- : (textIntegration ?? contextIntegration);
118
124
  const apiFallback = integration
119
125
  ? getMcpIntegrationApiFallback(integration)
120
126
  : null;
@@ -338,7 +338,11 @@ function CreateMenu({
338
338
  window.clearTimeout(skillFlyoutCloseTimerRef.current);
339
339
  skillFlyoutCloseTimerRef.current = null;
340
340
  }
341
- if (rowEl && typeof window !== "undefined") {
341
+ if (
342
+ rowEl &&
343
+ typeof window !== "undefined" &&
344
+ typeof rowEl.getBoundingClientRect === "function"
345
+ ) {
342
346
  const rect = rowEl.getBoundingClientRect();
343
347
  const FLYOUT_WIDTH = 248;
344
348
  setSkillFlyoutSide(
@@ -49,6 +49,7 @@ export interface DefaultMcpIntegration {
49
49
  templateUses?: readonly string[];
50
50
  };
51
51
  headerPlaceholder?: string;
52
+ brandAliases?: string[];
52
53
  aliases?: string[];
53
54
  keywords: string[];
54
55
  }
@@ -138,16 +139,6 @@ export const DEFAULT_MCP_INTEGRATIONS: DefaultMcpIntegration[] = [
138
139
  logoUrl: mcpIntegrationLogo("granola"),
139
140
  docsUrl: "https://docs.granola.ai/help-center/sharing/integrations/mcp",
140
141
  setupNoteKey: "mcpIntegrations.catalog.granola.setupNote",
141
- aliases: [
142
- "meeting notes",
143
- "meeting recordings",
144
- "recordings",
145
- "transcripts",
146
- "action items",
147
- "follow-ups",
148
- "follow ups",
149
- "decisions",
150
- ],
151
142
  keywords: [
152
143
  "meetings",
153
144
  "meeting notes",
@@ -210,7 +201,7 @@ export const DEFAULT_MCP_INTEGRATIONS: DefaultMcpIntegration[] = [
210
201
  docsUrl:
211
202
  "https://developer.atlassian.com/cloud/rovo-mcp/guides/getting-started/",
212
203
  setupNoteKey: "mcpIntegrations.catalog.atlassian.setupNote",
213
- aliases: ["jira", "confluence", "rovo"],
204
+ brandAliases: ["Jira", "Confluence", "Rovo"],
214
205
  keywords: ["atlassian", "jira", "confluence", "issues", "tickets"],
215
206
  },
216
207
  {
@@ -721,6 +712,8 @@ export function filterMcpIntegrations(
721
712
  integration.description,
722
713
  integration.useCase,
723
714
  integration.url,
715
+ ...(integration.brandAliases ?? []),
716
+ ...(integration.aliases ?? []),
724
717
  ...integration.keywords,
725
718
  ]
726
719
  .join(" ")
@@ -802,12 +795,9 @@ export function findMcpIntegrationForText(
802
795
  isMcpConnectionFailureText(normalizedText);
803
796
  if (!hasResourceIntent) return null;
804
797
  const matchesCanonicalName = (integration: DefaultMcpIntegration) =>
805
- [
806
- integration.name,
807
- integration.provider,
808
- integration.id,
809
- ...(integration.aliases ?? []),
810
- ].some((alias) => textContainsTerm(normalizedText, alias));
798
+ [integration.name, ...(integration.brandAliases ?? [])].some((alias) =>
799
+ textContainsTerm(normalizedText, alias),
800
+ );
811
801
  const canonicalMatch = integrations.find(matchesCanonicalName);
812
802
  if (canonicalMatch) return canonicalMatch;
813
803
  return null;
@@ -24,8 +24,8 @@ const LOGOS = {
24
24
  data: "PHN2ZyBmaWxsPSIjMDAwMDAwIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+Tm90aW9uPC90aXRsZT48cGF0aCBkPSJNNC40NTkgNC4yMDhjLjc0Ni42MDYgMS4wMjYuNTYgMi40MjguNDY2bDEzLjIxNS0uNzkzYy4yOCAwIC4wNDctLjI4LS4wNDYtLjMyNkwxNy44NiAxLjk2OGMtLjQyLS4zMjYtLjk4MS0uNy0yLjA1NS0uNjA3TDMuMDEgMi4yOTVjLS40NjYuMDQ2LS41Ni4yOC0uMzc0LjQ2NnptLjc5MyAzLjA4djEzLjkwNGMwIC43NDcuMzczIDEuMDI3IDEuMjE0Ljk4bDE0LjUyMy0uODRjLjg0MS0uMDQ2LjkzNS0uNTYuOTM1LTEuMTY3VjYuMzU0YzAtLjYwNi0uMjMzLS45MzMtLjc0OC0uODg3bC0xNS4xNzcuODg3Yy0uNTYuMDQ3LS43NDcuMzI3LS43NDcuOTMzem0xNC4zMzcuNzQ1Yy4wOTMuNDIgMCAuODQtLjQyLjg4OGwtLjcuMTR2MTAuMjY0Yy0uNjA4LjMyNy0xLjE2OC41MTQtMS42MzUuNTE0LS43NDggMC0uOTM1LS4yMzQtMS40OTUtLjkzM2wtNC41NzctNy4xODZ2Ni45NTJMMTIuMjEgMTlzMCAuODQtMS4xNjguODRsLTMuMjIyLjE4NmMtLjA5My0uMTg2IDAtLjY1My4zMjctLjc0NmwuODQtLjIzM1Y5Ljg1NEw3LjgyMiA5Ljc2Yy0uMDk0LS40Mi4xNC0xLjAyNi43OTMtMS4wNzNsMy40NTYtLjIzMyA0Ljc2NCA3LjI3OXYtNi40NGwtMS4yMTUtLjEzOWMtLjA5My0uNTE0LjI4LS44ODcuNzQ3LS45MzN6TTEuOTM2IDEuMDM1bDEzLjMxLS45OGMxLjYzNC0uMTQgMi4wNTUtLjA0NyAzLjA4Mi43bDQuMjQ5IDIuOTg2Yy43LjUxMy45MzQuNjUzLjkzNCAxLjIxM3YxNi4zNzhjMCAxLjAyNi0uMzczIDEuNjM0LTEuNjggMS43MjZsLTE1LjQ1OC45MzRjLS45OC4wNDctMS40NDgtLjA5My0xLjk2Mi0uNzQ3bC0zLjEyOS00LjA2Yy0uNTYtLjc0Ny0uNzkzLTEuMzA2LS43OTMtMS45NlYyLjY2N2MwLS44MzkuMzc0LTEuNTQgMS40NDctMS42MzJ6Ii8+PC9zdmc+",
25
25
  },
26
26
  granola: {
27
- mime: "image/svg+xml",
28
- data: "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHJlY3Qgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiByeD0iNiIgZmlsbD0iI2Y0ZWZlNyIvPjxwYXRoIGQ9Ik00IDkuNWMyLjEtMi42IDQuOC0zLjkgOC0zLjlzNS45IDEuMyA4IDMuOWMtMi4xIDIuNi00LjggMy45LTggMy45cy01LjktMS4zLTgtMy45WiIgZmlsbD0iIzI4YTg3OCIvPjxwYXRoIGQ9Ik01LjMgMTIuMmMxLjkgMS43IDQuMSAyLjYgNi43IDIuNnM0LjgtLjkgNi43LTIuNmMtLjUgMy44LTMuMSA2LjItNi43IDYuMnMtNi4yLTIuNC02LjctNi4yWiIgZmlsbD0iIzEzOGY2OCIvPjxjaXJjbGUgY3g9IjkiIGN5PSI5LjUiIHI9IjEiIGZpbGw9IiNmZmYiLz48Y2lyY2xlIGN4PSIxMiIgY3k9IjkuNSIgcj0iMSIgZmlsbD0iI2ZmZiIvPjxjaXJjbGUgY3g9IjE1IiBjeT0iOS41IiByPSIxIiBmaWxsPSIjZmZmIi8+PC9zdmc+",
27
+ mime: "image/png",
28
+ data: "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",
29
29
  },
30
30
  linear: {
31
31
  mime: "image/svg+xml",
@@ -33,10 +33,12 @@ export function isRouteModuleReloadMessage(value: unknown): boolean {
33
33
 
34
34
  export function isDynamicImportFailureMessage(value: unknown): boolean {
35
35
  if (typeof value !== "string") return false;
36
+ const message = value.toLowerCase();
36
37
  return (
37
- value.includes("Failed to fetch dynamically imported module") ||
38
- value.includes("error loading dynamically imported module") ||
39
- value.includes("Importing a module script failed")
38
+ message.includes("failed to fetch dynamically imported module") ||
39
+ message.includes("error loading dynamically imported module") ||
40
+ message.includes("importing a module script failed") ||
41
+ message.includes("failed to fetch dynamically imported")
40
42
  );
41
43
  }
42
44
 
@@ -1158,13 +1158,13 @@ function updateReplayResourceNode(
1158
1158
  ): ReplayResourceNode {
1159
1159
  return {
1160
1160
  tagName: current.tagName,
1161
- rel: Object.hasOwn(attributes, "rel")
1161
+ rel: Object.prototype.hasOwnProperty.call(attributes, "rel")
1162
1162
  ? replayAttributeString(attributes, "rel")
1163
1163
  : current.rel,
1164
- as: Object.hasOwn(attributes, "as")
1164
+ as: Object.prototype.hasOwnProperty.call(attributes, "as")
1165
1165
  ? replayAttributeString(attributes, "as")
1166
1166
  : current.as,
1167
- type: Object.hasOwn(attributes, "type")
1167
+ type: Object.prototype.hasOwnProperty.call(attributes, "type")
1168
1168
  ? replayAttributeString(attributes, "type")
1169
1169
  : current.type,
1170
1170
  };
@@ -1119,12 +1119,7 @@ function LLMSectionInner({
1119
1119
  label="Connect Builder.io"
1120
1120
  />
1121
1121
  {!builderConnected && (
1122
- <ManualSetupCard
1123
- hint={manualSetupHint}
1124
- docsUrl={PROVIDER_DOCS[selectedEngine]}
1125
- sourceBadge={sourceBadge}
1126
- docsLabel="Get an API key"
1127
- >
1122
+ <ManualSetupCard hint={manualSetupHint} sourceBadge={sourceBadge}>
1128
1123
  <div className="space-y-2 mb-1">
1129
1124
  <SettingsSelect
1130
1125
  label="Provider"
@@ -1330,6 +1325,20 @@ function LLMSectionInner({
1330
1325
  "Test"
1331
1326
  )}
1332
1327
  </Button>
1328
+ {PROVIDER_DOCS[selectedEngine] ? (
1329
+ <a
1330
+ href={PROVIDER_DOCS[selectedEngine]}
1331
+ target="_blank"
1332
+ rel="noopener noreferrer"
1333
+ className={cn(
1334
+ pillButtonClass(isPage, "outline"),
1335
+ "no-underline",
1336
+ )}
1337
+ >
1338
+ Get an API key
1339
+ <IconExternalLink size={isPage ? 14 : 10} />
1340
+ </a>
1341
+ ) : null}
1333
1342
  {engineChanged && (
1334
1343
  <Button
1335
1344
  intent="primary"
@@ -6,9 +6,9 @@
6
6
  * stop when the user hits stop. The accumulated transcript is available
7
7
  * immediately — no round-trip to Whisper needed.
8
8
  *
9
- * Higher-quality backends (Groq Whisper, OpenAI Whisper, Deepgram) can
10
- * refine the result afterward, but this gives users something useful
11
- * from second zero even without an API key.
9
+ * Builder can transcribe the original recording afterward if native capture
10
+ * produces no text, but this gives users something useful from second zero
11
+ * without a cloud transcription request.
12
12
  */
13
13
 
14
14
  import { useCallback, useEffect, useRef, useState } from "react";
@@ -58,12 +58,21 @@ export function useLiveTranscription(
58
58
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
59
59
  const recognitionRef = useRef<any>(null);
60
60
  const transcriptRef = useRef("");
61
+ const interimRef = useRef("");
61
62
  const stoppedManuallyRef = useRef(false);
62
63
  const stopWaiterRef = useRef<((text: string) => void) | null>(null);
63
64
  const restartTimerRef = useRef<number | null>(null);
64
65
  const networkErrorCountRef = useRef(0);
65
66
  const restartDelayRef = useRef(0);
66
67
 
68
+ const currentTranscript = useCallback(
69
+ () =>
70
+ [transcriptRef.current.trim(), interimRef.current.trim()]
71
+ .filter(Boolean)
72
+ .join(" "),
73
+ [],
74
+ );
75
+
67
76
  const supported = !!getSpeechRecognitionCtor();
68
77
 
69
78
  const start = useCallback(() => {
@@ -89,6 +98,7 @@ export function useLiveTranscription(
89
98
  recognition.lang = lang;
90
99
  recognitionRef.current = recognition;
91
100
  transcriptRef.current = "";
101
+ interimRef.current = "";
92
102
  stoppedManuallyRef.current = false;
93
103
  networkErrorCountRef.current = 0;
94
104
  restartDelayRef.current = 0;
@@ -107,6 +117,7 @@ export function useLiveTranscription(
107
117
  interim += text;
108
118
  }
109
119
  }
120
+ interimRef.current = interim;
110
121
  setInterimText(interim);
111
122
  if (event.results.length > 0) {
112
123
  networkErrorCountRef.current = 0;
@@ -167,7 +178,7 @@ export function useLiveTranscription(
167
178
  }
168
179
  setIsActive(false);
169
180
  if (stopWaiterRef.current) {
170
- stopWaiterRef.current(transcriptRef.current);
181
+ stopWaiterRef.current(currentTranscript());
171
182
  }
172
183
  };
173
184
 
@@ -177,14 +188,16 @@ export function useLiveTranscription(
177
188
  } catch {
178
189
  /* browser may block without user gesture */
179
190
  }
180
- }, [lang]);
191
+ }, [currentTranscript, lang]);
181
192
 
182
193
  const stop = useCallback((): string => {
194
+ const text = currentTranscript();
183
195
  stoppedManuallyRef.current = true;
184
196
  if (restartTimerRef.current !== null) {
185
197
  window.clearTimeout(restartTimerRef.current);
186
198
  restartTimerRef.current = null;
187
199
  }
200
+ interimRef.current = "";
188
201
  setInterimText("");
189
202
  if (recognitionRef.current) {
190
203
  try {
@@ -195,51 +208,57 @@ export function useLiveTranscription(
195
208
  recognitionRef.current = null;
196
209
  }
197
210
  setIsActive(false);
198
- return transcriptRef.current;
199
- }, []);
211
+ return text;
212
+ }, [currentTranscript]);
200
213
 
201
- const stopAndWait = useCallback((timeoutMs = 1200): Promise<string> => {
202
- stoppedManuallyRef.current = true;
203
- if (restartTimerRef.current !== null) {
204
- window.clearTimeout(restartTimerRef.current);
205
- restartTimerRef.current = null;
206
- }
207
- setInterimText("");
208
-
209
- const recognition = recognitionRef.current;
210
- if (!recognition) {
211
- setIsActive(false);
212
- return Promise.resolve(transcriptRef.current);
213
- }
214
+ const stopAndWait = useCallback(
215
+ (timeoutMs = 1200): Promise<string> => {
216
+ stoppedManuallyRef.current = true;
217
+ if (restartTimerRef.current !== null) {
218
+ window.clearTimeout(restartTimerRef.current);
219
+ restartTimerRef.current = null;
220
+ }
221
+ setInterimText("");
214
222
 
215
- return new Promise((resolve) => {
216
- let settled = false;
217
- const finish = (text: string) => {
218
- if (settled) return;
219
- settled = true;
220
- window.clearTimeout(timeout);
221
- if (stopWaiterRef.current === finish) {
222
- stopWaiterRef.current = null;
223
- }
224
- if (recognitionRef.current === recognition) {
225
- recognitionRef.current = null;
226
- }
223
+ const recognition = recognitionRef.current;
224
+ if (!recognition) {
225
+ const text = currentTranscript();
226
+ interimRef.current = "";
227
227
  setIsActive(false);
228
- resolve(text);
229
- };
228
+ return Promise.resolve(text);
229
+ }
230
230
 
231
- const timeout = window.setTimeout(() => {
232
- finish(transcriptRef.current);
233
- }, timeoutMs);
231
+ return new Promise((resolve) => {
232
+ let settled = false;
233
+ const finish = (text: string) => {
234
+ if (settled) return;
235
+ settled = true;
236
+ window.clearTimeout(timeout);
237
+ if (stopWaiterRef.current === finish) {
238
+ stopWaiterRef.current = null;
239
+ }
240
+ if (recognitionRef.current === recognition) {
241
+ recognitionRef.current = null;
242
+ }
243
+ interimRef.current = "";
244
+ setIsActive(false);
245
+ resolve(text);
246
+ };
234
247
 
235
- stopWaiterRef.current = finish;
236
- try {
237
- recognition.stop();
238
- } catch {
239
- finish(transcriptRef.current);
240
- }
241
- });
242
- }, []);
248
+ const timeout = window.setTimeout(() => {
249
+ finish(currentTranscript());
250
+ }, timeoutMs);
251
+
252
+ stopWaiterRef.current = finish;
253
+ try {
254
+ recognition.stop();
255
+ } catch {
256
+ finish(currentTranscript());
257
+ }
258
+ });
259
+ },
260
+ [currentTranscript],
261
+ );
243
262
 
244
263
  const pause = useCallback(() => {
245
264
  if (!recognitionRef.current) return;
@@ -1805,7 +1805,8 @@ async function buildCloudflarePages() {
1805
1805
  // fails: context-xray token counts fall back to char/4 estimates and the
1806
1806
  // OG image route falls back to SVG.
1807
1807
  const heavyClientExternals = CLOUDFLARE_WORKER_ESBUILD_EXTERNALS.filter(
1808
- (p) => !Object.hasOwn(CLOUDFLARE_WORKER_STUB_MODULES, p),
1808
+ (p) =>
1809
+ !Object.prototype.hasOwnProperty.call(CLOUDFLARE_WORKER_STUB_MODULES, p),
1809
1810
  ).map((p) => `--external:${p}`);
1810
1811
 
1811
1812
  execFileSync(
@@ -103,7 +103,7 @@ export function scanDbToolScoping(options: DbToolScopingOptions): GuardResult {
103
103
  const tables = extractTableCalls(contents);
104
104
  for (const table of tables) {
105
105
  if (hasRawDbScope(table.body)) continue;
106
- if (Object.hasOwn(denylist, table.sqlName)) {
106
+ if (Object.prototype.hasOwnProperty.call(denylist, table.sqlName)) {
107
107
  seenAllowed.add(table.sqlName);
108
108
  continue;
109
109
  }
@@ -45,6 +45,17 @@ const SLACK_IDENTITY_CACHE_TTL_MS = 10 * 60 * 1_000;
45
45
  // API blip must not fail-close a sender's identity (and DMs) for 10 minutes.
46
46
  const SLACK_IDENTITY_NEGATIVE_CACHE_TTL_MS = 30 * 1_000;
47
47
  const SLACK_IDENTITY_CACHE_MAX_ENTRIES = 1_000;
48
+ const SLACK_TOKEN_IDENTITY_CACHE_TTL_MS = 10 * 60 * 1_000;
49
+ const SLACK_TOKEN_IDENTITY_NEGATIVE_CACHE_TTL_MS = 30 * 1_000;
50
+
51
+ type SlackTokenIdentity = {
52
+ teamId: string | null;
53
+ appId: string | null;
54
+ valid: boolean;
55
+ expiresAt: number;
56
+ };
57
+
58
+ const slackTokenIdentityCache = new Map<string, SlackTokenIdentity>();
48
59
 
49
60
  interface SlackUserIdentity {
50
61
  email: string | null;
@@ -116,8 +127,7 @@ export function slackAdapter(
116
127
  ): PlatformAdapter {
117
128
  const resolveBotToken = async (incoming: IncomingMessage) =>
118
129
  (await options.resolveBotToken?.(incoming)) ??
119
- (await resolveManagedSlackBotToken(incoming)) ??
120
- (await resolveSecret("SLACK_BOT_TOKEN")) ??
130
+ (await resolveSlackBotTokenForIncoming(incoming)) ??
121
131
  undefined;
122
132
 
123
133
  return {
@@ -713,6 +723,19 @@ function parseAllowlistEnv(name: string): Set<string> | null {
713
723
  return new Set(values);
714
724
  }
715
725
 
726
+ export async function resolveSlackBotTokenForIncoming(
727
+ incoming: IncomingMessage,
728
+ ): Promise<string | undefined> {
729
+ const managedToken = await resolveManagedSlackBotToken(incoming);
730
+ if (managedToken) return managedToken;
731
+
732
+ const legacyToken = await resolveSecret("SLACK_BOT_TOKEN");
733
+ if (!legacyToken) return undefined;
734
+ return (await isSlackTokenForIncoming(legacyToken, incoming))
735
+ ? legacyToken
736
+ : undefined;
737
+ }
738
+
716
739
  async function resolveManagedSlackBotToken(
717
740
  incoming: IncomingMessage,
718
741
  ): Promise<string | undefined> {
@@ -736,13 +759,13 @@ async function resolveManagedSlackBotToken(
736
759
  slackInstallationKey({ teamId, enterpriseId, apiAppId }),
737
760
  )
738
761
  : null;
739
- if (!installation && teamId) {
762
+ if (!installation && !apiAppId && teamId) {
740
763
  installation = await getActiveIntegrationInstallationForTenant(
741
764
  "slack",
742
765
  teamId,
743
766
  );
744
767
  }
745
- if (!installation && enterpriseId) {
768
+ if (!installation && !apiAppId && enterpriseId) {
746
769
  installation = await getActiveIntegrationInstallationForTenant(
747
770
  "slack",
748
771
  enterpriseId,
@@ -757,6 +780,62 @@ async function resolveManagedSlackBotToken(
757
780
  }
758
781
  }
759
782
 
783
+ async function isSlackTokenForIncoming(
784
+ token: string,
785
+ incoming: IncomingMessage,
786
+ ): Promise<boolean> {
787
+ const teamId = slackIdentityValue(incoming.platformContext.teamId);
788
+ const apiAppId = slackIdentityValue(incoming.platformContext.apiAppId);
789
+ if (!teamId && !apiAppId) return true;
790
+
791
+ const cached = slackTokenIdentityCache.get(token);
792
+ if (cached && cached.expiresAt > Date.now()) {
793
+ return (
794
+ cached.valid &&
795
+ (!teamId || cached.teamId === teamId) &&
796
+ (!apiAppId || cached.appId === apiAppId)
797
+ );
798
+ }
799
+
800
+ const auth = await slackJson(token, "auth.test", {});
801
+ const authTeamId = slackIdentityValue(auth?.team_id);
802
+ const botId = slackIdentityValue(auth?.bot_id);
803
+ let appId: string | null = null;
804
+ let valid = !!auth;
805
+
806
+ if (valid && apiAppId) {
807
+ const bot = botId
808
+ ? await slackJson(token, "bots.info", { bot: botId })
809
+ : null;
810
+ appId = slackIdentityValue(bot?.bot?.app_id);
811
+ valid = !!appId;
812
+ }
813
+
814
+ const identity: SlackTokenIdentity = {
815
+ teamId: authTeamId,
816
+ appId,
817
+ valid,
818
+ expiresAt:
819
+ Date.now() +
820
+ (valid
821
+ ? SLACK_TOKEN_IDENTITY_CACHE_TTL_MS
822
+ : SLACK_TOKEN_IDENTITY_NEGATIVE_CACHE_TTL_MS),
823
+ };
824
+ slackTokenIdentityCache.set(token, identity);
825
+
826
+ return (
827
+ valid &&
828
+ (!teamId || identity.teamId === teamId) &&
829
+ (!apiAppId || identity.appId === apiAppId)
830
+ );
831
+ }
832
+
833
+ function slackIdentityValue(value: unknown): string | null {
834
+ if (typeof value !== "string") return null;
835
+ const normalized = value.trim();
836
+ return normalized && normalized !== "unknown" ? normalized : null;
837
+ }
838
+
760
839
  let _missingAllowlistWarned = false;
761
840
 
762
841
  /**
@@ -1079,7 +1158,7 @@ async function resolveSlackThreadPermalink(
1079
1158
  if (typeof channelId !== "string" || typeof threadTs !== "string") {
1080
1159
  return undefined;
1081
1160
  }
1082
- const token = resolvedToken ?? (await resolveSecret("SLACK_BOT_TOKEN"));
1161
+ const token = resolvedToken;
1083
1162
  if (!token) return undefined;
1084
1163
 
1085
1164
  try {
@@ -114,7 +114,11 @@ export type {
114
114
  } from "./remote-types.js";
115
115
 
116
116
  // Adapters
117
- export { slackAdapter, type SlackAdapterOptions } from "./adapters/slack.js";
117
+ export {
118
+ resolveSlackBotTokenForIncoming,
119
+ slackAdapter,
120
+ type SlackAdapterOptions,
121
+ } from "./adapters/slack.js";
118
122
  export { telegramAdapter } from "./adapters/telegram.js";
119
123
  export { whatsappAdapter } from "./adapters/whatsapp.js";
120
124
  export { discordAdapter } from "./adapters/discord.js";
@@ -806,7 +806,7 @@ const messages = {
806
806
  connected: "Connected",
807
807
  configure: "Configure",
808
808
  connect: "Connect",
809
- connectWithOAuth: "Connect with OAuth",
809
+ connectWithOAuth: "Connect",
810
810
  useApiToken: "Use API token",
811
811
  connectSuggestion: "Connect {{name}} to use it in chat",
812
812
  connectSuggestionWithApiToken: