@agent-native/core 0.114.16 → 0.115.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (456) hide show
  1. package/agent-native.eject.json +2 -0
  2. package/corpus/README.md +3 -3
  3. package/corpus/core/CHANGELOG.md +29 -0
  4. package/corpus/core/agent-native.eject.json +2 -0
  5. package/corpus/core/docs/content/agent-native-toolkit.mdx +16 -0
  6. package/corpus/core/docs/content/recurring-jobs.mdx +35 -6
  7. package/corpus/core/export-snapshot.json +4 -0
  8. package/corpus/core/package.json +5 -1
  9. package/corpus/core/src/action.ts +22 -1
  10. package/corpus/core/src/agent/production-agent.ts +105 -3
  11. package/corpus/core/src/cli/templates-meta.ts +12 -0
  12. package/corpus/core/src/client/AssistantChat.tsx +53 -26
  13. package/corpus/core/src/client/agent-page/AgentJobsTab.tsx +19 -0
  14. package/corpus/core/src/client/agent-page/use-jobs.ts +1 -0
  15. package/corpus/core/src/client/chat/message-components.tsx +35 -1
  16. package/corpus/core/src/client/chat/tool-call-display.tsx +38 -3
  17. package/corpus/core/src/connections/catalog.ts +20 -1
  18. package/corpus/core/src/connections/reader.ts +65 -0
  19. package/corpus/core/src/dashboard-storage/index.ts +27 -0
  20. package/corpus/core/src/dashboard-storage/panel-source.ts +168 -0
  21. package/corpus/core/src/dashboard-storage/schema.ts +62 -0
  22. package/corpus/core/src/dashboard-storage/store.ts +333 -0
  23. package/corpus/core/src/deploy/build.ts +95 -16
  24. package/corpus/core/src/eject/provider-api-definitions.ts +1 -0
  25. package/corpus/core/src/eject/workspace-connections.ts +1 -0
  26. package/corpus/core/src/extensions/actions.ts +199 -73
  27. package/corpus/core/src/jobs/actions/list-recurring-jobs.ts +2 -0
  28. package/corpus/core/src/jobs/scheduler.ts +71 -4
  29. package/corpus/core/src/jobs/tools.ts +31 -1
  30. package/corpus/core/src/localization/default-messages.ts +1 -0
  31. package/corpus/core/src/mcp-client/index.ts +6 -0
  32. package/corpus/core/src/provider-api/actions/provider-api.ts +1 -1
  33. package/corpus/core/src/provider-api/index.ts +190 -5
  34. package/corpus/core/src/secrets/register-framework-secrets.ts +8 -0
  35. package/corpus/core/src/server/agent-chat/context-tools.ts +9 -0
  36. package/corpus/core/src/server/agent-chat/framework-prompts.ts +2 -2
  37. package/corpus/core/src/server/agent-chat-plugin.ts +22 -2
  38. package/corpus/core/src/server/core-routes-plugin.ts +1 -0
  39. package/corpus/core/src/server/credential-provider.ts +9 -3
  40. package/corpus/core/src/server/workspace-provider-oauth.ts +181 -4
  41. package/corpus/core/src/styles/agent-native.css +45 -2
  42. package/corpus/core/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +27 -0
  43. package/corpus/core/src/templates/default/.agents/skills/app-branding/SKILL.md +159 -0
  44. package/corpus/core/src/templates/default/.agents/skills/app-permissions/SKILL.md +155 -0
  45. package/corpus/core/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +27 -0
  46. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +27 -0
  47. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +31 -18
  48. package/corpus/core/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +15 -0
  49. package/corpus/core/src/triggers/actions.ts +11 -2
  50. package/corpus/core/src/triggers/dispatcher.ts +20 -1
  51. package/corpus/core/src/triggers/types.ts +5 -0
  52. package/corpus/core/src/vite/action-types-plugin.ts +9 -1
  53. package/corpus/templates/analytics/.agents/skills/agent-native-docs/SKILL.md +115 -0
  54. package/corpus/templates/analytics/AGENTS.md +11 -11
  55. package/corpus/templates/analytics/_gitignore +39 -0
  56. package/corpus/templates/analytics/actions/query-dashboard-panel.ts +30 -0
  57. package/corpus/templates/analytics/actions/update-dashboard.ts +2 -1
  58. package/corpus/templates/analytics/app/lib/sql-query.ts +11 -25
  59. package/corpus/templates/analytics/changelog/2026-07-21-fixed-extension-updates-failing-before-changes-could-be-appl.md +6 -0
  60. package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +1 -0
  61. package/corpus/templates/analytics/server/lib/dashboard-panel-source-resolver.ts +51 -0
  62. package/corpus/templates/analytics/server/lib/prometheus.ts +1 -1
  63. package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -1
  64. package/corpus/templates/assets/.agents/skills/agent-native-docs/SKILL.md +115 -0
  65. package/corpus/templates/brain/.agents/skills/agent-native-docs/SKILL.md +115 -0
  66. package/corpus/templates/calendar/.agents/skills/agent-native-docs/SKILL.md +115 -0
  67. package/corpus/templates/calendar/_gitignore +39 -0
  68. package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +27 -0
  69. package/corpus/templates/chat/AGENTS.md +1 -1
  70. package/corpus/templates/clips/.agents/skills/agent-native-docs/SKILL.md +115 -0
  71. package/corpus/templates/clips/AGENTS.md +7 -0
  72. package/corpus/templates/clips/actions/prepare-crm-call-evidence.ts +58 -0
  73. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +88 -11
  74. package/corpus/templates/clips/changelog/2026-07-21-crm-call-evidence-handoff.md +6 -0
  75. package/corpus/templates/clips/changelog/2026-07-21-recording-retries-and-restarts-keep-their-upload-session-so-.md +6 -0
  76. package/corpus/templates/clips/chrome-extension/src/background.ts +20 -5
  77. package/corpus/templates/clips/chrome-extension/src/native-recording-state.ts +19 -0
  78. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +8 -0
  79. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +9 -0
  80. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +54 -28
  81. package/corpus/templates/clips/server/plugins/agent-chat.ts +1 -0
  82. package/corpus/templates/content/.agents/skills/agent-native-docs/SKILL.md +115 -0
  83. package/corpus/templates/content/_gitignore +39 -0
  84. package/corpus/templates/content/learnings.defaults.md +5 -0
  85. package/corpus/templates/crm/.agents/skills/agent-native-docs/SKILL.md +115 -0
  86. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  87. package/corpus/templates/crm/.agents/skills/crm/SKILL.md +128 -0
  88. package/corpus/templates/crm/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  89. package/corpus/templates/crm/.agents/skills/feature-flags/SKILL.md +169 -0
  90. package/corpus/templates/crm/.agents/skills/upgrade-agent-native/SKILL.md +100 -0
  91. package/corpus/templates/crm/.env.example +5 -0
  92. package/corpus/templates/crm/AGENTS.md +120 -0
  93. package/corpus/templates/crm/CHANGELOG.md +1 -0
  94. package/corpus/templates/crm/DEVELOPING.md +66 -0
  95. package/corpus/templates/crm/README.md +106 -0
  96. package/corpus/templates/crm/_gitignore +12 -0
  97. package/corpus/templates/crm/actions/_crm-action-utils.ts +87 -0
  98. package/corpus/templates/crm/actions/_crm-dashboard.ts +69 -0
  99. package/corpus/templates/crm/actions/_crm-signal-utils.ts +79 -0
  100. package/corpus/templates/crm/actions/apply-crm-proposals.ts +203 -0
  101. package/corpus/templates/crm/actions/attach-call-evidence.ts +170 -0
  102. package/corpus/templates/crm/actions/configure-crm-connection.ts +126 -0
  103. package/corpus/templates/crm/actions/configure-native-crm.ts +44 -0
  104. package/corpus/templates/crm/actions/create-crm-record.ts +148 -0
  105. package/corpus/templates/crm/actions/create-crm-signal-tracker.ts +58 -0
  106. package/corpus/templates/crm/actions/delete-staged-dataset.ts +14 -0
  107. package/corpus/templates/crm/actions/get-crm-automation-recipe.ts +36 -0
  108. package/corpus/templates/crm/actions/get-crm-dashboard-panel.ts +33 -0
  109. package/corpus/templates/crm/actions/get-crm-dashboard.ts +14 -0
  110. package/corpus/templates/crm/actions/get-crm-overview.ts +13 -0
  111. package/corpus/templates/crm/actions/get-crm-pipeline-data.ts +61 -0
  112. package/corpus/templates/crm/actions/get-crm-record.ts +75 -0
  113. package/corpus/templates/crm/actions/install-crm-pipeline-dashboard.ts +81 -0
  114. package/corpus/templates/crm/actions/list-crm-dashboard-revisions.ts +15 -0
  115. package/corpus/templates/crm/actions/list-crm-dashboards.ts +15 -0
  116. package/corpus/templates/crm/actions/list-crm-proposals.ts +31 -0
  117. package/corpus/templates/crm/actions/list-crm-records.ts +79 -0
  118. package/corpus/templates/crm/actions/list-crm-saved-views.ts +15 -0
  119. package/corpus/templates/crm/actions/list-crm-signal-hits.ts +43 -0
  120. package/corpus/templates/crm/actions/list-crm-signal-trackers.ts +32 -0
  121. package/corpus/templates/crm/actions/list-crm-tasks.ts +22 -0
  122. package/corpus/templates/crm/actions/list-staged-datasets.ts +14 -0
  123. package/corpus/templates/crm/actions/list-workspace-connections.ts +47 -0
  124. package/corpus/templates/crm/actions/manage-crm-signal-tracker.ts +87 -0
  125. package/corpus/templates/crm/actions/manage-crm-task.ts +132 -0
  126. package/corpus/templates/crm/actions/navigate.ts +63 -0
  127. package/corpus/templates/crm/actions/provider-api-catalog.ts +22 -0
  128. package/corpus/templates/crm/actions/provider-api-docs.ts +54 -0
  129. package/corpus/templates/crm/actions/provider-api-request.ts +92 -0
  130. package/corpus/templates/crm/actions/query-staged-dataset.ts +44 -0
  131. package/corpus/templates/crm/actions/record-crm-call-insight.ts +160 -0
  132. package/corpus/templates/crm/actions/record-crm-smart-signal.ts +150 -0
  133. package/corpus/templates/crm/actions/restore-crm-dashboard-revision.ts +23 -0
  134. package/corpus/templates/crm/actions/review-crm-signal.ts +31 -0
  135. package/corpus/templates/crm/actions/run-crm-saved-view-program.ts +103 -0
  136. package/corpus/templates/crm/actions/run-crm-signal-trackers.ts +275 -0
  137. package/corpus/templates/crm/actions/run.ts +11 -0
  138. package/corpus/templates/crm/actions/save-crm-dashboard.ts +51 -0
  139. package/corpus/templates/crm/actions/save-crm-saved-view.ts +119 -0
  140. package/corpus/templates/crm/actions/sync-crm.ts +146 -0
  141. package/corpus/templates/crm/actions/update-crm-record.ts +508 -0
  142. package/corpus/templates/crm/actions/view-screen.ts +218 -0
  143. package/corpus/templates/crm/agent-native.app-skill.json +58 -0
  144. package/corpus/templates/crm/app/components/crm/CreateCrmRecordDialog.tsx +158 -0
  145. package/corpus/templates/crm/app/components/crm/CrmDashboardPanel.tsx +83 -0
  146. package/corpus/templates/crm/app/components/crm/CrmSignalsPanel.tsx +225 -0
  147. package/corpus/templates/crm/app/components/crm/IntelligenceSettings.tsx +413 -0
  148. package/corpus/templates/crm/app/components/crm/RecordActions.tsx +510 -0
  149. package/corpus/templates/crm/app/components/crm/RecordGrid.tsx +134 -0
  150. package/corpus/templates/crm/app/components/crm/RecordWorkspace.tsx +367 -0
  151. package/corpus/templates/crm/app/components/crm/SavedViewDataProgram.tsx +92 -0
  152. package/corpus/templates/crm/app/components/crm/Surface.tsx +96 -0
  153. package/corpus/templates/crm/app/components/crm/WorkOverview.tsx +180 -0
  154. package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +106 -0
  155. package/corpus/templates/crm/app/components/layout/CrmSidebar.tsx +84 -0
  156. package/corpus/templates/crm/app/entry.client.tsx +16 -0
  157. package/corpus/templates/crm/app/entry.server.tsx +10 -0
  158. package/corpus/templates/crm/app/global.css +167 -0
  159. package/corpus/templates/crm/app/hooks/use-navigation-state.ts +60 -0
  160. package/corpus/templates/crm/app/i18n/en-US.ts +89 -0
  161. package/corpus/templates/crm/app/i18n/index.ts +34 -0
  162. package/corpus/templates/crm/app/lib/dashboard.ts +13 -0
  163. package/corpus/templates/crm/app/lib/navigation.ts +54 -0
  164. package/corpus/templates/crm/app/lib/tab-id.ts +1 -0
  165. package/corpus/templates/crm/app/lib/types.ts +172 -0
  166. package/corpus/templates/crm/app/lib/utils.ts +1 -0
  167. package/corpus/templates/crm/app/root.tsx +88 -0
  168. package/corpus/templates/crm/app/routes/_index.tsx +26 -0
  169. package/corpus/templates/crm/app/routes/accounts.tsx +41 -0
  170. package/corpus/templates/crm/app/routes/agent.tsx +5 -0
  171. package/corpus/templates/crm/app/routes/ask.tsx +53 -0
  172. package/corpus/templates/crm/app/routes/dashboard.tsx +118 -0
  173. package/corpus/templates/crm/app/routes/opportunities.tsx +41 -0
  174. package/corpus/templates/crm/app/routes/people.tsx +41 -0
  175. package/corpus/templates/crm/app/routes/proposals.tsx +266 -0
  176. package/corpus/templates/crm/app/routes/records.$recordId.tsx +35 -0
  177. package/corpus/templates/crm/app/routes/settings.tsx +63 -0
  178. package/corpus/templates/crm/app/routes/setup.tsx +308 -0
  179. package/corpus/templates/crm/app/routes/tasks.tsx +252 -0
  180. package/corpus/templates/crm/app/routes/views.tsx +333 -0
  181. package/corpus/templates/crm/app/routes.ts +17 -0
  182. package/corpus/templates/crm/app/vite-env.d.ts +6 -0
  183. package/corpus/templates/crm/changelog/2026-07-21-agent-native-crm.md +6 -0
  184. package/corpus/templates/crm/changelog/2026-07-21-clips-call-evidence-review-recipe.md +6 -0
  185. package/corpus/templates/crm/changelog/2026-07-21-crm-can-now-find-and-review-evidence-grounded-call-signals-w.md +6 -0
  186. package/corpus/templates/crm/changelog/2026-07-21-crm-can-now-manage-keyword-and-smart-call-signal-trackers-fr.md +6 -0
  187. package/corpus/templates/crm/changelog/2026-07-21-delegated-local-crm-automation.md +6 -0
  188. package/corpus/templates/crm/changelog/2026-07-21-native-sql.md +6 -0
  189. package/corpus/templates/crm/changelog/2026-07-21-pipeline-dashboard.md +6 -0
  190. package/corpus/templates/crm/changelog/2026-07-21-pipeline-dashboards-now-install-correctly-from-the-crm-actio.md +6 -0
  191. package/corpus/templates/crm/changelog/2026-07-21-salesforce-connection.md +6 -0
  192. package/corpus/templates/crm/components.json +20 -0
  193. package/corpus/templates/crm/docs/architecture/crm-contract.md +180 -0
  194. package/corpus/templates/crm/learnings.defaults.md +5 -0
  195. package/corpus/templates/crm/package.json +59 -0
  196. package/corpus/templates/crm/public/favicon.svg +1 -0
  197. package/corpus/templates/crm/public/icon-180.svg +1 -0
  198. package/corpus/templates/crm/public/manifest.json +11 -0
  199. package/corpus/templates/crm/react-router.config.ts +7 -0
  200. package/corpus/templates/crm/server/crm/adapter.ts +32 -0
  201. package/corpus/templates/crm/server/crm/crm-field-firewall.ts +64 -0
  202. package/corpus/templates/crm/server/crm/crm-mirror.ts +711 -0
  203. package/corpus/templates/crm/server/crm/hubspot-adapter.ts +1143 -0
  204. package/corpus/templates/crm/server/crm/native-adapter.ts +1715 -0
  205. package/corpus/templates/crm/server/crm/read-through.ts +207 -0
  206. package/corpus/templates/crm/server/crm/salesforce-adapter.ts +1255 -0
  207. package/corpus/templates/crm/server/db/crm-store.ts +1170 -0
  208. package/corpus/templates/crm/server/db/index.ts +169 -0
  209. package/corpus/templates/crm/server/db/schema.ts +441 -0
  210. package/corpus/templates/crm/server/lib/intelligence/default-detectors.ts +65 -0
  211. package/corpus/templates/crm/server/lib/intelligence/evidence.ts +105 -0
  212. package/corpus/templates/crm/server/lib/intelligence/keyword-detector.ts +100 -0
  213. package/corpus/templates/crm/server/lib/intelligence/smart-detector.ts +144 -0
  214. package/corpus/templates/crm/server/lib/intelligence/summary.ts +141 -0
  215. package/corpus/templates/crm/server/lib/provider-api.ts +64 -0
  216. package/corpus/templates/crm/server/middleware/auth.ts +4 -0
  217. package/corpus/templates/crm/server/plugins/agent-chat.ts +68 -0
  218. package/corpus/templates/crm/server/plugins/auth.ts +14 -0
  219. package/corpus/templates/crm/server/plugins/core-routes.ts +17 -0
  220. package/corpus/templates/crm/server/plugins/db.ts +454 -0
  221. package/corpus/templates/crm/server/routes/[...page].get.ts +5 -0
  222. package/corpus/templates/crm/shared/crm-automation-recipes.ts +132 -0
  223. package/corpus/templates/crm/shared/crm-contract.ts +254 -0
  224. package/corpus/templates/crm/shared/crm-sales-config.ts +63 -0
  225. package/corpus/templates/crm/ssr-entry.ts +11 -0
  226. package/corpus/templates/crm/tsconfig.json +24 -0
  227. package/corpus/templates/crm/vite.config.ts +15 -0
  228. package/corpus/templates/crm/vitest.config.ts +5 -0
  229. package/corpus/templates/design/.agents/skills/agent-native-docs/SKILL.md +115 -0
  230. package/corpus/templates/dispatch/.agents/skills/agent-native-docs/SKILL.md +115 -0
  231. package/corpus/templates/forms/.agents/skills/agent-native-docs/SKILL.md +115 -0
  232. package/corpus/templates/forms/_gitignore +39 -0
  233. package/corpus/templates/forms/learnings.defaults.md +5 -0
  234. package/corpus/templates/macros/.agents/skills/agent-native-docs/SKILL.md +115 -0
  235. package/corpus/templates/macros/_gitignore +39 -0
  236. package/corpus/templates/macros/learnings.defaults.md +5 -0
  237. package/corpus/templates/mail/.agents/skills/agent-native-docs/SKILL.md +115 -0
  238. package/corpus/templates/mail/_gitignore +39 -0
  239. package/corpus/templates/plan/.agents/skills/agent-native-docs/SKILL.md +115 -0
  240. package/corpus/templates/slides/.agents/skills/agent-native-docs/SKILL.md +115 -0
  241. package/corpus/templates/slides/_gitignore +39 -0
  242. package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +27 -0
  243. package/corpus/templates/tasks/_gitignore +39 -0
  244. package/corpus/toolkit/CHANGELOG.md +12 -0
  245. package/corpus/toolkit/README.md +30 -0
  246. package/corpus/toolkit/agent-native.eject.json +33 -0
  247. package/corpus/toolkit/package.json +15 -1
  248. package/corpus/toolkit/src/dashboard/DataTable.tsx +273 -0
  249. package/corpus/toolkit/src/dashboard/DateRangePicker.tsx +57 -0
  250. package/corpus/toolkit/src/dashboard/GenericChartPanel.tsx +461 -0
  251. package/corpus/toolkit/src/dashboard/MetricCard.tsx +54 -0
  252. package/corpus/toolkit/src/dashboard/StatsCard.tsx +49 -0
  253. package/corpus/toolkit/src/dashboard/dashboard-layout.ts +329 -0
  254. package/corpus/toolkit/src/dashboard/index.ts +6 -0
  255. package/corpus/toolkit/src/index.ts +1 -0
  256. package/corpus/toolkit/src/ui/calendar.tsx +8 -8
  257. package/corpus/toolkit/src/ui/date-picker.tsx +4 -1
  258. package/dist/action.d.ts +14 -1
  259. package/dist/action.d.ts.map +1 -1
  260. package/dist/action.js.map +1 -1
  261. package/dist/agent/production-agent.d.ts +3 -1
  262. package/dist/agent/production-agent.d.ts.map +1 -1
  263. package/dist/agent/production-agent.js +83 -3
  264. package/dist/agent/production-agent.js.map +1 -1
  265. package/dist/cli/templates-meta.d.ts.map +1 -1
  266. package/dist/cli/templates-meta.js +12 -0
  267. package/dist/cli/templates-meta.js.map +1 -1
  268. package/dist/client/AssistantChat.d.ts +4 -0
  269. package/dist/client/AssistantChat.d.ts.map +1 -1
  270. package/dist/client/AssistantChat.js +30 -17
  271. package/dist/client/AssistantChat.js.map +1 -1
  272. package/dist/client/agent-page/AgentJobsTab.d.ts.map +1 -1
  273. package/dist/client/agent-page/AgentJobsTab.js +3 -1
  274. package/dist/client/agent-page/AgentJobsTab.js.map +1 -1
  275. package/dist/client/agent-page/use-jobs.d.ts +1 -0
  276. package/dist/client/agent-page/use-jobs.d.ts.map +1 -1
  277. package/dist/client/agent-page/use-jobs.js.map +1 -1
  278. package/dist/client/chat/message-components.d.ts +5 -0
  279. package/dist/client/chat/message-components.d.ts.map +1 -1
  280. package/dist/client/chat/message-components.js +17 -1
  281. package/dist/client/chat/message-components.js.map +1 -1
  282. package/dist/client/chat/tool-call-display.d.ts +3 -1
  283. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  284. package/dist/client/chat/tool-call-display.js +17 -7
  285. package/dist/client/chat/tool-call-display.js.map +1 -1
  286. package/dist/collab/awareness.d.ts +2 -2
  287. package/dist/collab/awareness.d.ts.map +1 -1
  288. package/dist/collab/routes.d.ts +1 -1
  289. package/dist/collab/struct-routes.d.ts +1 -1
  290. package/dist/connections/catalog.d.ts +17 -3
  291. package/dist/connections/catalog.d.ts.map +1 -1
  292. package/dist/connections/catalog.js +16 -1
  293. package/dist/connections/catalog.js.map +1 -1
  294. package/dist/connections/reader.d.ts +18 -0
  295. package/dist/connections/reader.d.ts.map +1 -1
  296. package/dist/connections/reader.js +41 -0
  297. package/dist/connections/reader.js.map +1 -1
  298. package/dist/dashboard-storage/index.d.ts +4 -0
  299. package/dist/dashboard-storage/index.d.ts.map +1 -0
  300. package/dist/dashboard-storage/index.js +4 -0
  301. package/dist/dashboard-storage/index.js.map +1 -0
  302. package/dist/dashboard-storage/panel-source.d.ts +68 -0
  303. package/dist/dashboard-storage/panel-source.d.ts.map +1 -0
  304. package/dist/dashboard-storage/panel-source.js +76 -0
  305. package/dist/dashboard-storage/panel-source.js.map +1 -0
  306. package/dist/dashboard-storage/schema.d.ts +562 -0
  307. package/dist/dashboard-storage/schema.d.ts.map +1 -0
  308. package/dist/dashboard-storage/schema.js +32 -0
  309. package/dist/dashboard-storage/schema.js.map +1 -0
  310. package/dist/dashboard-storage/store.d.ts +62 -0
  311. package/dist/dashboard-storage/store.d.ts.map +1 -0
  312. package/dist/dashboard-storage/store.js +227 -0
  313. package/dist/dashboard-storage/store.js.map +1 -0
  314. package/dist/deploy/build.d.ts +7 -0
  315. package/dist/deploy/build.d.ts.map +1 -1
  316. package/dist/deploy/build.js +78 -14
  317. package/dist/deploy/build.js.map +1 -1
  318. package/dist/eject/provider-api-definitions.d.ts +2 -1
  319. package/dist/eject/provider-api-definitions.d.ts.map +1 -1
  320. package/dist/eject/provider-api-definitions.js +1 -0
  321. package/dist/eject/provider-api-definitions.js.map +1 -1
  322. package/dist/eject/workspace-connections.d.ts.map +1 -1
  323. package/dist/eject/workspace-connections.js +1 -0
  324. package/dist/eject/workspace-connections.js.map +1 -1
  325. package/dist/extensions/actions.d.ts.map +1 -1
  326. package/dist/extensions/actions.js +165 -67
  327. package/dist/extensions/actions.js.map +1 -1
  328. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  329. package/dist/jobs/actions/list-recurring-jobs.d.ts +1 -0
  330. package/dist/jobs/actions/list-recurring-jobs.d.ts.map +1 -1
  331. package/dist/jobs/actions/list-recurring-jobs.js +1 -0
  332. package/dist/jobs/actions/list-recurring-jobs.js.map +1 -1
  333. package/dist/jobs/scheduler.d.ts +17 -2
  334. package/dist/jobs/scheduler.d.ts.map +1 -1
  335. package/dist/jobs/scheduler.js +51 -2
  336. package/dist/jobs/scheduler.js.map +1 -1
  337. package/dist/jobs/tools.d.ts.map +1 -1
  338. package/dist/jobs/tools.js +32 -2
  339. package/dist/jobs/tools.js.map +1 -1
  340. package/dist/localization/default-messages.d.ts +1 -0
  341. package/dist/localization/default-messages.d.ts.map +1 -1
  342. package/dist/localization/default-messages.js +1 -0
  343. package/dist/localization/default-messages.js.map +1 -1
  344. package/dist/mcp-client/index.d.ts +2 -0
  345. package/dist/mcp-client/index.d.ts.map +1 -1
  346. package/dist/mcp-client/index.js +5 -0
  347. package/dist/mcp-client/index.js.map +1 -1
  348. package/dist/notifications/routes.d.ts +3 -3
  349. package/dist/observability/routes.d.ts +5 -5
  350. package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
  351. package/dist/provider-api/actions/provider-api.d.ts +8 -6
  352. package/dist/provider-api/actions/provider-api.d.ts.map +1 -1
  353. package/dist/provider-api/actions/provider-api.js +1 -1
  354. package/dist/provider-api/actions/provider-api.js.map +1 -1
  355. package/dist/provider-api/index.d.ts +11 -7
  356. package/dist/provider-api/index.d.ts.map +1 -1
  357. package/dist/provider-api/index.js +143 -5
  358. package/dist/provider-api/index.js.map +1 -1
  359. package/dist/resources/handlers.d.ts +1 -1
  360. package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
  361. package/dist/secrets/register-framework-secrets.js +7 -0
  362. package/dist/secrets/register-framework-secrets.js.map +1 -1
  363. package/dist/secrets/routes.d.ts +9 -9
  364. package/dist/server/agent-chat/context-tools.d.ts.map +1 -1
  365. package/dist/server/agent-chat/context-tools.js +9 -0
  366. package/dist/server/agent-chat/context-tools.js.map +1 -1
  367. package/dist/server/agent-chat/framework-prompts.js +2 -2
  368. package/dist/server/agent-chat/framework-prompts.js.map +1 -1
  369. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  370. package/dist/server/agent-chat-plugin.js +18 -2
  371. package/dist/server/agent-chat-plugin.js.map +1 -1
  372. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  373. package/dist/server/core-routes-plugin.js +1 -0
  374. package/dist/server/core-routes-plugin.js.map +1 -1
  375. package/dist/server/credential-provider.d.ts +4 -3
  376. package/dist/server/credential-provider.d.ts.map +1 -1
  377. package/dist/server/credential-provider.js +9 -3
  378. package/dist/server/credential-provider.js.map +1 -1
  379. package/dist/server/transcribe-voice.d.ts +1 -1
  380. package/dist/server/workspace-provider-oauth.d.ts +6 -1
  381. package/dist/server/workspace-provider-oauth.d.ts.map +1 -1
  382. package/dist/server/workspace-provider-oauth.js +141 -4
  383. package/dist/server/workspace-provider-oauth.js.map +1 -1
  384. package/dist/styles/agent-native.css +45 -2
  385. package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +27 -0
  386. package/dist/templates/chat/AGENTS.md +1 -1
  387. package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +27 -0
  388. package/dist/templates/default/.agents/skills/app-branding/SKILL.md +159 -0
  389. package/dist/templates/default/.agents/skills/app-permissions/SKILL.md +155 -0
  390. package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +27 -0
  391. package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +27 -0
  392. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +31 -18
  393. package/dist/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +15 -0
  394. package/dist/triggers/actions.d.ts.map +1 -1
  395. package/dist/triggers/actions.js +10 -2
  396. package/dist/triggers/actions.js.map +1 -1
  397. package/dist/triggers/dispatcher.d.ts.map +1 -1
  398. package/dist/triggers/dispatcher.js +15 -0
  399. package/dist/triggers/dispatcher.js.map +1 -1
  400. package/dist/triggers/types.d.ts +5 -0
  401. package/dist/triggers/types.d.ts.map +1 -1
  402. package/dist/triggers/types.js.map +1 -1
  403. package/dist/vite/action-types-plugin.d.ts.map +1 -1
  404. package/dist/vite/action-types-plugin.js +4 -1
  405. package/dist/vite/action-types-plugin.js.map +1 -1
  406. package/docs/content/agent-native-toolkit.mdx +16 -0
  407. package/docs/content/recurring-jobs.mdx +35 -6
  408. package/package.json +6 -2
  409. package/src/action.ts +22 -1
  410. package/src/agent/production-agent.ts +105 -3
  411. package/src/cli/templates-meta.ts +12 -0
  412. package/src/client/AssistantChat.tsx +53 -26
  413. package/src/client/agent-page/AgentJobsTab.tsx +19 -0
  414. package/src/client/agent-page/use-jobs.ts +1 -0
  415. package/src/client/chat/message-components.tsx +35 -1
  416. package/src/client/chat/tool-call-display.tsx +38 -3
  417. package/src/connections/catalog.ts +20 -1
  418. package/src/connections/reader.ts +65 -0
  419. package/src/dashboard-storage/index.ts +27 -0
  420. package/src/dashboard-storage/panel-source.ts +168 -0
  421. package/src/dashboard-storage/schema.ts +62 -0
  422. package/src/dashboard-storage/store.ts +333 -0
  423. package/src/deploy/build.ts +95 -16
  424. package/src/eject/provider-api-definitions.ts +1 -0
  425. package/src/eject/workspace-connections.ts +1 -0
  426. package/src/extensions/actions.ts +199 -73
  427. package/src/jobs/actions/list-recurring-jobs.ts +2 -0
  428. package/src/jobs/scheduler.ts +71 -4
  429. package/src/jobs/tools.ts +31 -1
  430. package/src/localization/default-messages.ts +1 -0
  431. package/src/mcp-client/index.ts +6 -0
  432. package/src/provider-api/actions/provider-api.ts +1 -1
  433. package/src/provider-api/index.ts +190 -5
  434. package/src/secrets/register-framework-secrets.ts +8 -0
  435. package/src/server/agent-chat/context-tools.ts +9 -0
  436. package/src/server/agent-chat/framework-prompts.ts +2 -2
  437. package/src/server/agent-chat-plugin.ts +22 -2
  438. package/src/server/core-routes-plugin.ts +1 -0
  439. package/src/server/credential-provider.ts +9 -3
  440. package/src/server/workspace-provider-oauth.ts +181 -4
  441. package/src/styles/agent-native.css +45 -2
  442. package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +27 -0
  443. package/src/templates/chat/AGENTS.md +1 -1
  444. package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +27 -0
  445. package/src/templates/default/.agents/skills/app-branding/SKILL.md +159 -0
  446. package/src/templates/default/.agents/skills/app-permissions/SKILL.md +155 -0
  447. package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +27 -0
  448. package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +27 -0
  449. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +31 -18
  450. package/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +15 -0
  451. package/src/triggers/actions.ts +11 -2
  452. package/src/triggers/dispatcher.ts +20 -1
  453. package/src/triggers/types.ts +5 -0
  454. package/src/vite/action-types-plugin.ts +9 -1
  455. package/corpus/templates/analytics/server/handlers/sql-query.ts +0 -36
  456. package/corpus/templates/analytics/server/routes/api/sql-query.post.ts +0 -1
@@ -0,0 +1,115 @@
1
+ ---
2
+ name: agent-native-docs
3
+ description: >-
4
+ How to find version-matched Agent Native framework docs and source bundled in
5
+ node_modules. Use before implementing or answering questions about
6
+ @agent-native/core APIs, generated apps, workspaces, templates, or advanced
7
+ features.
8
+ scope: dev
9
+ metadata:
10
+ internal: true
11
+ ---
12
+
13
+ # Agent Native Docs Lookup
14
+
15
+ ## Rule
16
+
17
+ Before implementing or explaining non-trivial Agent Native behavior, read the
18
+ version-matched docs installed with `@agent-native/core`. When examples,
19
+ imports, or implementation details matter, inspect the packaged source corpus
20
+ too.
21
+
22
+ ## Why
23
+
24
+ Generated apps and workspaces may be on a different framework version than the
25
+ public docs or model memory. The installed package is the source that matches
26
+ the app in front of you. It also includes a source-only corpus of core and
27
+ first-party templates so agents can replicate current best-practice patterns
28
+ without needing the framework monorepo checkout.
29
+
30
+ ## How
31
+
32
+ From a generated app directory:
33
+
34
+ ```bash
35
+ pnpm action docs-search --query "<feature>"
36
+ pnpm action docs-search --slug <slug>
37
+ pnpm action docs-search --list
38
+ pnpm action source-search --query "<pattern>"
39
+ pnpm action source-search --path templates/plan/AGENTS.md
40
+ pnpm action source-search --path toolkit/src/index.ts
41
+ pnpm action source-search --list
42
+ ```
43
+
44
+ The headless `pnpm agent` loop and built-in app agent also expose a read-only
45
+ `docs-search` tool with the same `query`, `slug`, and `list` options, plus a
46
+ read-only `source-search` tool with `query`, `path`, and `list`.
47
+
48
+ If the action runner is unavailable, search the package directly:
49
+
50
+ ```bash
51
+ rg -n "actions|automations|a2a|sharing" node_modules/@agent-native/core/docs
52
+ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
53
+ ```
54
+
55
+ Then read `node_modules/@agent-native/core/docs/AGENTS.md` or the matching file
56
+ under `node_modules/@agent-native/core/docs/content/`. For source examples,
57
+ read files under `node_modules/@agent-native/core/corpus/core/` or
58
+ `node_modules/@agent-native/core/corpus/templates/`.
59
+
60
+ Toolkit source is searchable at `toolkit/` in the Core corpus and also ships as
61
+ readable TypeScript under `node_modules/@agent-native/toolkit/src/`. Read
62
+ `customizing-agent-native` before taking ownership of a shared component: inspect package
63
+ source as a read-only reference, then configure, compose, or eject the smallest
64
+ supported unit into app-owned source. Preserve public actions, application
65
+ state, auth, and agent-chat runtime contracts. Never edit `node_modules` or
66
+ deep-import its private source. Manual copying is only the fallback described by
67
+ an unknown third-party package's add-style blueprint.
68
+
69
+ ## Reuse Proven Patterns (rg + cp)
70
+
71
+ Version-matched installed source outranks web docs or memory: it is the exact
72
+ code shipping with this app. `node_modules/@agent-native/core/corpus/templates/`
73
+ holds source for every first-party template, not just the one this app started
74
+ from, so a pattern from the mail template is fair game for a tasks app. Grep
75
+ across it, then copy a whole file as a starting point instead of writing the
76
+ pattern from scratch:
77
+
78
+ ```bash
79
+ # Find how other templates solved a similar problem
80
+ rg -n "drag.*drop|reorder" node_modules/@agent-native/core/corpus/templates
81
+
82
+ # Grab a proven action file as a starting point, then adapt names/schema
83
+ cp node_modules/@agent-native/core/corpus/templates/mail/actions/archive-email.ts \
84
+ actions/archive-item.ts
85
+
86
+ # Read the full framework source behind an API, not just the corpus copy
87
+ rg -n "defineAction" node_modules/@agent-native/core/src/action.ts
88
+ ```
89
+
90
+ Copying template-level app code (actions, components, skill files) is the
91
+ expected reuse path — templates exist to be forked. This is different from
92
+ copying `core`/`toolkit` **runtime internals**: for those, follow
93
+ `customizing-agent-native`'s configure/compose/eject ladder instead of
94
+ hand-duplicating framework logic.
95
+
96
+ ## Useful Slugs
97
+
98
+ | Need | Slugs |
99
+ | ------------------------------ | ------------------------------------------------------------- |
100
+ | Actions and typed client calls | `actions`, `client` |
101
+ | SQL, auth, access, sharing | `database`, `authentication`, `security`, `sharing` |
102
+ | UI state visible to the agent | `context-awareness` |
103
+ | Headless and chat-first apps | `pure-agent-apps`, `agent-surfaces`, `using-your-agent` |
104
+ | Automations and schedules | `automations`, `recurring-jobs` |
105
+ | Cross-app and external agents | `a2a-protocol`, `external-agents`, `mcp-protocol`, `mcp-apps` |
106
+ | Skills and instructions | `skills-guide`, `writing-agent-instructions` |
107
+
108
+ ## Don't
109
+
110
+ - Do not rely on memory for framework APIs when package docs are present.
111
+ - Do not add custom REST wrappers for app data before reading `actions`.
112
+ - Do not add inline LLM calls before reading `using-your-agent` and
113
+ `agent-surfaces`.
114
+ - Do not copy framework runtime internals when a public API or narrow UI copy
115
+ will do; read `customizing-agent-native` for the supported override ladder.
@@ -21,6 +21,13 @@ ladder.
21
21
  - Never hardcode API keys, tokens, webhook URLs, signing secrets, private Builder/internal data, customer data, or credential-looking literals. Use secrets/OAuth/runtime configuration and obvious placeholders in examples.
22
22
  - Use actions for recording metadata, transcripts, cleanup, summaries, chapters,
23
23
  comments, spaces/folders, meetings, and sharing. Do not bypass access helpers.
24
+ - Use `prepare-crm-call-evidence` only for a viewer-accessible recording
25
+ explicitly identified by a user action or the exact approved CRM A2A recipe.
26
+ It returns an opaque clip ID, durable HTTPS `/r/<id>` page, and optional
27
+ capture time for CRM; it never returns the event media URL, a transcript,
28
+ temporary token, quote, or summary. A CRM recipe may install a Clips-owned
29
+ `clip.created` trigger only through an exact user-approved A2A automation
30
+ definition.
24
31
  - Organization admins can use `set-organization-branding` with
25
32
  `defaultVisibility=public|org|private` to choose the visibility applied when
26
33
  new recordings omit an explicit visibility. The default remains `public`, and
@@ -0,0 +1,58 @@
1
+ import { defineAction } from "@agent-native/core/action";
2
+ import { getRequestContext } from "@agent-native/core/server";
3
+ import { assertAccess } from "@agent-native/core/sharing";
4
+ import { z } from "zod";
5
+
6
+ import { getServerAppBasePath } from "../server/lib/public-agent-context.js";
7
+
8
+ function clipsOrigin(): string {
9
+ const raw = getRequestContext()?.requestOrigin || process.env.APP_URL;
10
+ if (!raw) {
11
+ throw new Error(
12
+ "Clips needs an HTTPS APP_URL before it can prepare CRM evidence links.",
13
+ );
14
+ }
15
+ let url: URL;
16
+ try {
17
+ url = new URL(raw);
18
+ } catch {
19
+ throw new Error(
20
+ "Clips needs a valid HTTPS APP_URL before it can prepare CRM evidence links.",
21
+ );
22
+ }
23
+ if (url.protocol !== "https:") {
24
+ throw new Error(
25
+ "Clips needs an HTTPS APP_URL before it can prepare CRM evidence links.",
26
+ );
27
+ }
28
+ return url.origin;
29
+ }
30
+
31
+ export default defineAction({
32
+ description:
33
+ "Prepare one access-gated Clips recording as bounded CRM call evidence. Returns only an opaque recording id, durable HTTPS recording page, and optional capture time; never media, a transcript, or a temporary access token.",
34
+ schema: z.object({
35
+ recordingId: z.string().trim().min(1).max(256),
36
+ }),
37
+ readOnly: true,
38
+ run: async ({ recordingId }) => {
39
+ const access = await assertAccess("recording", recordingId, "viewer");
40
+ const recording = access.resource as {
41
+ id: string;
42
+ createdAt?: string | null;
43
+ archivedAt?: string | null;
44
+ trashedAt?: string | null;
45
+ };
46
+ if (recording.archivedAt || recording.trashedAt) {
47
+ throw new Error("Archived or trashed Clips cannot be attached to CRM.");
48
+ }
49
+ const sourceUrl = `${clipsOrigin()}${getServerAppBasePath()}/r/${encodeURIComponent(recording.id)}`;
50
+ return {
51
+ sourceApp: "clips" as const,
52
+ artifactType: "call-evidence" as const,
53
+ artifactId: recording.id,
54
+ sourceUrl,
55
+ ...(recording.createdAt ? { capturedAt: recording.createdAt } : {}),
56
+ };
57
+ },
58
+ });
@@ -1524,25 +1524,32 @@ export class RecorderEngine {
1524
1524
  return this.compressAndReupload(meta);
1525
1525
  }
1526
1526
 
1527
- await this.resetUploadedChunks(null, signal);
1527
+ const uploadMode = await this.resetUploadedChunks(null, signal);
1528
1528
  this.transition("uploading", { progress: 0 });
1529
1529
  const assembled = new Blob(this.localChunks, { type: this.mimeType });
1530
- return this.uploadBlobInSlices(assembled, this.mimeType, meta, signal);
1530
+ return uploadMode === "streaming"
1531
+ ? this.uploadBlobInStreamingChunks(assembled, this.mimeType, meta, signal)
1532
+ : this.uploadBlobInSlices(assembled, this.mimeType, meta, signal);
1531
1533
  }
1532
1534
 
1533
1535
  private async resetUploadedChunks(
1534
1536
  compression: CompressionUploadMeta | null,
1535
1537
  signal?: AbortSignal,
1536
- ): Promise<void> {
1538
+ ): Promise<UploadMode> {
1537
1539
  const resetUrl = `${appBasePath()}/api/uploads/${
1538
1540
  this.opts.recordingId
1539
1541
  }/reset-chunks`;
1542
+ const uploadMimeType = compression?.outputMimeType || this.mimeType;
1540
1543
  let resetRes: Response;
1541
1544
  try {
1542
1545
  resetRes = await fetch(resetUrl, {
1543
1546
  method: "POST",
1544
1547
  headers: { "Content-Type": "application/json" },
1545
- body: JSON.stringify({ compression }),
1548
+ body: JSON.stringify({
1549
+ compression,
1550
+ requestStreaming: this.uploadMode === "streaming",
1551
+ mimeType: uploadMimeType,
1552
+ }),
1546
1553
  signal,
1547
1554
  });
1548
1555
  } catch (err) {
@@ -1566,6 +1573,17 @@ export class RecorderEngine {
1566
1573
  }). ${text || resetRes.statusText}`,
1567
1574
  );
1568
1575
  }
1576
+ const reset = (await resetRes.json().catch(() => null)) as {
1577
+ uploadMode?: unknown;
1578
+ } | null;
1579
+ if (reset?.uploadMode !== "streaming" && reset?.uploadMode !== "buffered") {
1580
+ throw new Error(
1581
+ "Couldn't prepare the recording for re-upload (reset-chunks returned no upload mode).",
1582
+ );
1583
+ }
1584
+ const uploadMode = reset.uploadMode;
1585
+ this.uploadMode = uploadMode;
1586
+ return uploadMode;
1569
1587
  }
1570
1588
 
1571
1589
  // -------------------------------------------------------------------------
@@ -1653,7 +1671,10 @@ export class RecorderEngine {
1653
1671
  outputMimeType: compression.outputMimeType,
1654
1672
  }
1655
1673
  : null;
1656
- await this.resetUploadedChunks(compressionPayload, abort.signal);
1674
+ const uploadMode = await this.resetUploadedChunks(
1675
+ compressionPayload,
1676
+ abort.signal,
1677
+ );
1657
1678
 
1658
1679
  if (compressionError) {
1659
1680
  // Compression itself failed — we still hold the original assembled
@@ -1680,12 +1701,19 @@ export class RecorderEngine {
1680
1701
  }
1681
1702
 
1682
1703
  this.transition("uploading", { progress: 0 });
1683
- return this.uploadBlobInSlices(
1684
- finalBlob,
1685
- compression.outputMimeType,
1686
- meta,
1687
- abort.signal,
1688
- );
1704
+ return uploadMode === "streaming"
1705
+ ? this.uploadBlobInStreamingChunks(
1706
+ finalBlob,
1707
+ compression.outputMimeType,
1708
+ meta,
1709
+ abort.signal,
1710
+ )
1711
+ : this.uploadBlobInSlices(
1712
+ finalBlob,
1713
+ compression.outputMimeType,
1714
+ meta,
1715
+ abort.signal,
1716
+ );
1689
1717
  } finally {
1690
1718
  // Always release the controller reference even on throw — otherwise
1691
1719
  // a subsequent cancel() would abort a freshly-started compression.
@@ -2025,6 +2053,55 @@ export class RecorderEngine {
2025
2053
  return results[finalSlice.index];
2026
2054
  }
2027
2055
 
2056
+ private async uploadBlobInStreamingChunks(
2057
+ blob: Blob,
2058
+ mimeType: string,
2059
+ meta: {
2060
+ durationMs: number;
2061
+ dimensions: { width: number; height: number };
2062
+ hasAudio: boolean;
2063
+ hasCamera: boolean;
2064
+ },
2065
+ signal?: AbortSignal,
2066
+ ): Promise<Record<string, unknown> | undefined> {
2067
+ if (blob.size === 0) {
2068
+ throw new Error("Cannot retry an empty recording upload.");
2069
+ }
2070
+
2071
+ this.chunkIndex = 0;
2072
+ const totalChunks = Math.ceil(blob.size / STREAM_CHUNK_BYTES);
2073
+ let result: Record<string, unknown> | undefined;
2074
+
2075
+ for (let index = 0; index < totalChunks; index++) {
2076
+ const start = index * STREAM_CHUNK_BYTES;
2077
+ const end = Math.min(start + STREAM_CHUNK_BYTES, blob.size);
2078
+ const isFinal = index === totalChunks - 1;
2079
+ const chunk = blob.slice(start, end, mimeType);
2080
+ result = await this.uploadChunk(chunk, this.chunkIndex++, {
2081
+ isFinal,
2082
+ total: totalChunks,
2083
+ mimeType,
2084
+ ...(isFinal
2085
+ ? {
2086
+ durationMs: meta.durationMs,
2087
+ width: meta.dimensions.width,
2088
+ height: meta.dimensions.height,
2089
+ hasAudio: meta.hasAudio,
2090
+ hasCamera: meta.hasCamera,
2091
+ }
2092
+ : {}),
2093
+ signal,
2094
+ });
2095
+ this.opts.onChunk?.({
2096
+ index,
2097
+ bytes: chunk.size,
2098
+ total: totalChunks,
2099
+ });
2100
+ }
2101
+
2102
+ return result;
2103
+ }
2104
+
2028
2105
  private async uploadChunk(
2029
2106
  blob: Blob,
2030
2107
  index: number,
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: added
3
+ date: 2026-07-21
4
+ ---
5
+
6
+ Clips can now prepare an access-checked recording link for bounded CRM call evidence without exposing media or transcripts.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-21
4
+ ---
5
+
6
+ Recording retries and restarts keep their upload session so they can finish saving.
@@ -1,4 +1,6 @@
1
1
  import {
2
+ restartUploadModeFromResponse,
3
+ restartUploadResetBody,
2
4
  shouldReconcilePersistedRecording,
3
5
  type OffscreenRecordingState,
4
6
  } from "./native-recording-state";
@@ -166,6 +168,7 @@ type NativeRecording = {
166
168
  // fallback so it is never lost; these describe that saved file.
167
169
  savedToDisk?: boolean;
168
170
  savedFilename?: string;
171
+ mimeType?: string;
169
172
  };
170
173
 
171
174
  type OffscreenStatusMessage = {
@@ -179,6 +182,7 @@ type OffscreenStatusMessage = {
179
182
  savedToDisk?: boolean;
180
183
  savedFilename?: string;
181
184
  recordingStep?: string;
185
+ mimeType?: string;
182
186
  };
183
187
 
184
188
  type ExtensionErrorMessage = {
@@ -1512,8 +1516,8 @@ async function handleOverlayRestart() {
1512
1516
  // so we must not leave the overlay stuck mid-recording/paused with no
1513
1517
  // recorder behind it — tear the overlay back down and release those streams,
1514
1518
  // matching the re-arm failure handling just below.
1515
- const chunksReset = await resetRecordingChunks(recording);
1516
- if (!chunksReset) {
1519
+ const uploadMode = await resetRecordingChunks(recording);
1520
+ if (!uploadMode) {
1517
1521
  recording.status = "error";
1518
1522
  recording.error =
1519
1523
  "Could not clear the previous take before restarting. Stop and start a new recording.";
@@ -1530,6 +1534,7 @@ async function handleOverlayRestart() {
1530
1534
  error: recording.error,
1531
1535
  };
1532
1536
  }
1537
+ recording.uploadMode = uploadMode;
1533
1538
  overlayPhase = "countdown";
1534
1539
  overlayBaseElapsedMs = 0;
1535
1540
  overlayBaseEpochMs = nowMs();
@@ -1579,18 +1584,25 @@ async function handleOverlayRestart() {
1579
1584
 
1580
1585
  async function resetRecordingChunks(
1581
1586
  recording: NativeRecording,
1582
- ): Promise<boolean> {
1587
+ ): Promise<UploadMode | null> {
1583
1588
  const url = `${recording.clipsBaseUrl}/api/uploads/${encodeURIComponent(
1584
1589
  recording.recordingId,
1585
1590
  )}/reset-chunks`;
1586
- const headers = await authHeaders(settingsFromRecording(recording));
1591
+ const headers = {
1592
+ ...(await authHeaders(settingsFromRecording(recording))),
1593
+ "Content-Type": "application/json",
1594
+ };
1587
1595
  const response = await fetch(url, {
1588
1596
  method: "POST",
1589
1597
  headers,
1590
1598
  credentials: "include",
1591
1599
  cache: "no-store",
1600
+ body: JSON.stringify(
1601
+ restartUploadResetBody(recording.mimeType ?? "video/webm"),
1602
+ ),
1592
1603
  }).catch(() => undefined);
1593
- return Boolean(response?.ok);
1604
+ if (!response?.ok) return null;
1605
+ return restartUploadModeFromResponse(await response.json().catch(() => null));
1594
1606
  }
1595
1607
 
1596
1608
  // Finalize a successful save: open the clip and tear down the "Saving…" overlay.
@@ -2399,6 +2411,9 @@ async function dispatchRuntimeMessage(message: unknown): Promise<unknown> {
2399
2411
  activeNativeRecording,
2400
2412
  );
2401
2413
  }
2414
+ if (typeof status.mimeType === "string") {
2415
+ activeNativeRecording.mimeType = status.mimeType;
2416
+ }
2402
2417
  if (status.status === "error") {
2403
2418
  activeNativeRecording.savedToDisk = status.savedToDisk === true;
2404
2419
  activeNativeRecording.savedFilename =
@@ -6,6 +6,8 @@ export type NativeRecordingStateStatus =
6
6
  | "complete"
7
7
  | "error";
8
8
 
9
+ export type RestartUploadMode = "streaming" | "buffered";
10
+
9
11
  export type OffscreenRecordingState = {
10
12
  activeSessionId?: string;
11
13
  preparedSessionId?: string;
@@ -30,3 +32,20 @@ export function shouldReconcilePersistedRecording(
30
32
  if (status === "error" || status === "complete") return false;
31
33
  return !hasLiveOffscreenSession(sessionId, state);
32
34
  }
35
+
36
+ export function restartUploadResetBody(mimeType: string): {
37
+ requestStreaming: true;
38
+ mimeType: string;
39
+ } {
40
+ return { requestStreaming: true, mimeType };
41
+ }
42
+
43
+ export function restartUploadModeFromResponse(
44
+ value: unknown,
45
+ ): RestartUploadMode | null {
46
+ if (!value || typeof value !== "object") return null;
47
+ const uploadMode = (value as { uploadMode?: unknown }).uploadMode;
48
+ return uploadMode === "streaming" || uploadMode === "buffered"
49
+ ? uploadMode
50
+ : null;
51
+ }
@@ -56,6 +56,8 @@ const STORAGE_SETUP_REQUIRED_MESSAGE =
56
56
  const STORAGE_SETUP_FAILURE_RE =
57
57
  /video storage is not connected|no video storage configured|file upload provider|storage provider|connect builder|s3-compatible/i;
58
58
  const CHUNK_UPLOAD_MAX_ATTEMPTS = 3;
59
+ const CHUNK_UPLOAD_TIMEOUT_MS = 60_000;
60
+ const FINAL_CHUNK_UPLOAD_TIMEOUT_MS = 180_000;
59
61
  const RETRYABLE_CHUNK_UPLOAD_STATUSES = new Set([
60
62
  408, 425, 429, 500, 502, 503, 504,
61
63
  ]);
@@ -860,6 +862,11 @@ async function uploadChunk(
860
862
  headers,
861
863
  credentials: "include",
862
864
  body,
865
+ signal: AbortSignal.timeout(
866
+ extra.isFinal
867
+ ? FINAL_CHUNK_UPLOAD_TIMEOUT_MS
868
+ : CHUNK_UPLOAD_TIMEOUT_MS,
869
+ ),
863
870
  });
864
871
  } catch (err) {
865
872
  if (attempt >= CHUNK_UPLOAD_MAX_ATTEMPTS) throw err;
@@ -1387,6 +1394,7 @@ function startRecorderNow(recording: ActiveRecording): void {
1387
1394
  height: recording.dimensions.height,
1388
1395
  hasAudio: recording.hasAudio,
1389
1396
  hasCamera: recording.hasCamera,
1397
+ mimeType: recording.mimeType,
1390
1398
  });
1391
1399
  } catch (err) {
1392
1400
  captureExtensionError(err, {
@@ -344,6 +344,14 @@ export function RecordingPill() {
344
344
  void toggleExpanded();
345
345
  };
346
346
 
347
+ const handlePillMouseUp = (e: React.MouseEvent) => {
348
+ const start = dragStartScreenPointRef.current;
349
+ if (isDirectPillClick(start, { x: e.screenX, y: e.screenY })) return;
350
+ void invoke("recording_pill_save_position").catch((err) => {
351
+ console.warn("[clips-pill] save position failed", err);
352
+ });
353
+ };
354
+
347
355
  const mm = String(Math.floor(elapsed / 60)).padStart(2, "0");
348
356
  const ss = String(elapsed % 60).padStart(2, "0");
349
357
  const stopLabel =
@@ -356,6 +364,7 @@ export function RecordingPill() {
356
364
  hovered ? " pill-hovered" : ""
357
365
  }`}
358
366
  onMouseDown={handlePillMouseDown}
367
+ onMouseUp={handlePillMouseUp}
359
368
  >
360
369
  <div
361
370
  className={`pill-header${
@@ -130,20 +130,32 @@ fn pill_detached_position_path(app: &AppHandle) -> Option<PathBuf> {
130
130
  Some(dir.join("pill-position-detached.json"))
131
131
  }
132
132
 
133
- fn load_meeting_position(app: &AppHandle) -> Option<(i32, i32)> {
133
+ #[derive(Deserialize)]
134
+ struct MeetingPillPosition {
135
+ x: i32,
136
+ y: i32,
137
+ #[serde(default)]
138
+ anchor: Option<String>,
139
+ #[serde(default)]
140
+ width: Option<u32>,
141
+ }
142
+
143
+ fn load_meeting_position(app: &AppHandle) -> Option<MeetingPillPosition> {
134
144
  let path = pill_meeting_position_path(app)?;
135
145
  let bytes = std::fs::read(&path).ok()?;
136
- let value: serde_json::Value = serde_json::from_slice(&bytes).ok()?;
137
- let x = value.get("x")?.as_i64()? as i32;
138
- let y = value.get("y")?.as_i64()? as i32;
139
- Some((x, y))
146
+ serde_json::from_slice(&bytes).ok()
140
147
  }
141
148
 
142
- fn save_meeting_position_to_disk(app: &AppHandle, x: i32, y: i32) {
149
+ fn save_meeting_position_to_disk(app: &AppHandle, x: i32, y: i32, width: u32) {
143
150
  let Some(path) = pill_meeting_position_path(app) else {
144
151
  return;
145
152
  };
146
- let body = match serde_json::to_vec(&serde_json::json!({ "x": x, "y": y })) {
153
+ let body = match serde_json::to_vec(&serde_json::json!({
154
+ "x": x + width as i32,
155
+ "y": y,
156
+ "anchor": "right",
157
+ "width": width,
158
+ })) {
147
159
  Ok(b) => b,
148
160
  Err(_) => return,
149
161
  };
@@ -313,7 +325,28 @@ fn anchored_rect(
313
325
  let (_, h_exp) = pill_size_physical(app, true);
314
326
  let max_y_exp = (my + mh as i32 - h_exp as i32).max(my);
315
327
  let (x, y) = match load_meeting_position(app) {
316
- Some((sx, sy)) => (sx.clamp(mx, max_x), sy.clamp(my, max_y_exp)),
328
+ Some(position) if position.anchor.as_deref() == Some("right") => {
329
+ let saved_width = position.width.unwrap_or(w);
330
+ (
331
+ (position.x - saved_width as i32).clamp(mx, max_x),
332
+ position.y.clamp(my, max_y_exp),
333
+ )
334
+ }
335
+ Some(position) => {
336
+ let (expanded_w, _) = pill_size_physical(app, true);
337
+ let right_margin = (PILL_RIGHT_MARGIN_LOGICAL as f64 * scale_factor(app)) as i32;
338
+ let legacy_right_edge = position.x + expanded_w as i32;
339
+ let monitor_right = mx + mw as i32;
340
+ if (legacy_right_edge - (monitor_right - right_margin)).abs() <= 4 {
341
+ save_meeting_position_to_disk(app, position.x, position.y, expanded_w);
342
+ (
343
+ (legacy_right_edge - w as i32).clamp(mx, max_x),
344
+ position.y.clamp(my, max_y_exp),
345
+ )
346
+ } else {
347
+ (position.x.clamp(mx, max_x), position.y.clamp(my, max_y_exp))
348
+ }
349
+ }
317
350
  None => default_center_right(app, w, h),
318
351
  };
319
352
  return (w, h, x, y);
@@ -492,35 +525,28 @@ pub async fn recording_pill_expand(app: AppHandle, expanded: bool) -> Result<(),
492
525
  pub async fn recording_pill_hide(app: AppHandle) -> Result<(), String> {
493
526
  stop_pill_hover_tracking();
494
527
  if let Some(w) = app.get_webview_window(PILL_LABEL) {
495
- // Snapshot current position before close so the next show re-opens
496
- // at the user's chosen spot.
497
- if let Ok(pos) = w.outer_position() {
498
- if PILL_DETACHED.load(Ordering::Relaxed) {
499
- save_detached_position_to_disk(&app, pos.x, pos.y);
500
- } else if PILL_RIGHT_SIDE.load(Ordering::Relaxed) {
501
- save_meeting_position_to_disk(&app, pos.x, pos.y);
502
- } else {
503
- save_pill_position_to_disk(&app, pos.x, pos.y);
504
- }
505
- }
506
528
  let _ = w.close();
507
529
  }
508
530
  Ok(())
509
531
  }
510
532
 
511
- /// Persist the pill's current position. Called by the React side after the
512
- /// user drag-moves it (mouseup) so the next `show` reopens at the chosen
513
- /// spot.
514
533
  #[tauri::command]
515
- pub async fn recording_pill_save_position(app: AppHandle, x: i32, y: i32) -> Result<(), String> {
516
- // Persist to the right slot — detached drags shouldn't overwrite the
517
- // user's preferred bottom-center position and vice versa.
534
+ pub async fn recording_pill_save_position(app: AppHandle) -> Result<(), String> {
535
+ let Some(window) = app.get_webview_window(PILL_LABEL) else {
536
+ return Ok(());
537
+ };
538
+ let Ok(position) = window.outer_position() else {
539
+ return Ok(());
540
+ };
541
+
518
542
  if PILL_DETACHED.load(Ordering::Relaxed) {
519
- save_detached_position_to_disk(&app, x, y);
543
+ save_detached_position_to_disk(&app, position.x, position.y);
520
544
  } else if PILL_RIGHT_SIDE.load(Ordering::Relaxed) {
521
- save_meeting_position_to_disk(&app, x, y);
545
+ if let Ok(size) = window.outer_size() {
546
+ save_meeting_position_to_disk(&app, position.x, position.y, size.width);
547
+ }
522
548
  } else {
523
- save_pill_position_to_disk(&app, x, y);
549
+ save_pill_position_to_disk(&app, position.x, position.y);
524
550
  }
525
551
  Ok(())
526
552
  }
@@ -18,6 +18,7 @@ const INITIAL_TOOL_NAMES = [
18
18
  "list-recordings",
19
19
  "search-recordings",
20
20
  "get-recording-player-data",
21
+ "prepare-crm-call-evidence",
21
22
  "request-transcript",
22
23
  "create-recording",
23
24
  "import-loom-recording",