@agent-native/core 0.115.4 → 0.116.0

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 (408) hide show
  1. package/agent-native.eject.json +1 -0
  2. package/corpus/README.md +3 -3
  3. package/corpus/core/CHANGELOG.md +28 -0
  4. package/corpus/core/agent-native.eject.json +1 -0
  5. package/corpus/core/docs/AGENTS.md +1 -1
  6. package/corpus/core/docs/content/agent-mentions.mdx +2 -2
  7. package/corpus/core/docs/content/{workspace.mdx → agent-resources.mdx} +1 -7
  8. package/corpus/core/docs/content/agent-teams.mdx +4 -4
  9. package/corpus/core/docs/content/dispatch.mdx +10 -10
  10. package/corpus/core/docs/content/drop-in-agent.mdx +4 -4
  11. package/corpus/core/docs/content/external-agents.mdx +1 -1
  12. package/corpus/core/docs/content/frames.mdx +1 -1
  13. package/corpus/core/docs/content/integrations.mdx +13 -2
  14. package/corpus/core/docs/content/key-concepts.mdx +2 -2
  15. package/corpus/core/docs/content/mcp-clients.mdx +7 -1
  16. package/corpus/core/docs/content/multi-app-workspace.mdx +3 -3
  17. package/corpus/core/docs/content/real-time-collaboration.mdx +33 -15
  18. package/corpus/core/docs/content/recurring-jobs.mdx +7 -7
  19. package/corpus/core/docs/content/skills-guide.mdx +4 -4
  20. package/corpus/core/docs/content/template-brain.mdx +1 -1
  21. package/corpus/core/docs/content/toolkit-collaboration.mdx +1 -1
  22. package/corpus/core/docs/content/using-your-agent.mdx +1 -1
  23. package/corpus/core/docs/content/what-is-agent-native.mdx +4 -4
  24. package/corpus/core/docs/content/workspace-management.mdx +4 -4
  25. package/corpus/core/package.json +1 -1
  26. package/corpus/core/src/agent/production-agent.ts +13 -3
  27. package/corpus/core/src/cli/doctor.ts +6 -1
  28. package/corpus/core/src/client/AgentPanel.tsx +79 -41
  29. package/corpus/core/src/client/AssistantChat.tsx +71 -25
  30. package/corpus/core/src/client/FeedbackButton.tsx +33 -7
  31. package/corpus/core/src/client/MultiTabAssistantChat.tsx +6 -8
  32. package/corpus/core/src/client/agent-chat-adapter.ts +11 -2
  33. package/corpus/core/src/client/agent-page/AgentTabFrame.tsx +22 -3
  34. package/corpus/core/src/client/agent-page/AgentTabsPage.tsx +34 -19
  35. package/corpus/core/src/client/chat/message-components.tsx +43 -16
  36. package/corpus/core/src/client/chat/tool-call-display.tsx +30 -18
  37. package/corpus/core/src/client/chat/tool-render-registry.tsx +2 -0
  38. package/corpus/core/src/client/resources/McpConnectionSuggestion.tsx +19 -2
  39. package/corpus/core/src/client/resources/ResourceTree.tsx +7 -10
  40. package/corpus/core/src/client/resources/ResourcesPanel.tsx +33 -70
  41. package/corpus/core/src/client/resources/mcp-connection-resume.ts +107 -0
  42. package/corpus/core/src/client/resources/mcp-integration-catalog.ts +65 -12
  43. package/corpus/core/src/client/resources/mcp-integration-logos.ts +4 -0
  44. package/corpus/core/src/client/sse-event-processor.ts +50 -14
  45. package/corpus/core/src/client/use-db-sync.ts +16 -6
  46. package/corpus/core/src/connections/catalog.ts +7 -1
  47. package/corpus/core/src/eject/remote-mcp-presets.ts +37 -5
  48. package/corpus/core/src/guards/explicit-collab-access.ts +229 -0
  49. package/corpus/core/src/guards/index.ts +1 -0
  50. package/corpus/core/src/localization/default-messages.ts +54 -5
  51. package/corpus/core/src/mcp/connect-route.ts +34 -51
  52. package/corpus/core/src/provider-api/index.ts +1 -1
  53. package/corpus/core/src/server/collab-plugin.ts +137 -18
  54. package/corpus/core/src/server/index.ts +2 -0
  55. package/corpus/core/src/styles/agent-native.css +40 -0
  56. package/corpus/core/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  57. package/corpus/core/src/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
  58. package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  59. package/corpus/core/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  60. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  61. package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
  62. package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  63. package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
  64. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  65. package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +1 -1
  66. package/corpus/templates/analytics/AGENTS.md +7 -2
  67. package/corpus/templates/analytics/actions/export-dashboard-panel-to-google-sheet.ts +144 -0
  68. package/corpus/templates/analytics/app/components/layout/Layout.tsx +7 -88
  69. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +34 -37
  70. package/corpus/templates/analytics/app/global.css +0 -4
  71. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +2 -7
  72. package/corpus/templates/analytics/app/i18n-data.ts +107 -0
  73. package/corpus/templates/analytics/app/lib/data-source-status.ts +9 -0
  74. package/corpus/templates/analytics/app/lib/sql-query.ts +1 -2
  75. package/corpus/templates/analytics/app/pages/Ask.tsx +2 -7
  76. package/corpus/templates/analytics/app/pages/DataSources.tsx +48 -0
  77. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +59 -0
  78. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +2 -0
  79. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/report-panel-window.ts +3 -1
  80. package/corpus/templates/analytics/changelog/2026-07-22-clear-background-chat-progress.md +6 -0
  81. package/corpus/templates/analytics/changelog/2026-07-22-daily-dashboard-email-query-batches.md +6 -0
  82. package/corpus/templates/analytics/changelog/2026-07-22-export-table-panels-directly-to-google-sheets.md +6 -0
  83. package/corpus/templates/analytics/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  84. package/corpus/templates/analytics/changelog/2026-07-22-recent-chats-can-expand-in-the-sidebar.md +6 -0
  85. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +8 -8
  86. package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +31 -0
  87. package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +3 -5
  88. package/corpus/templates/analytics/server/lib/dashboard-report.ts +12 -0
  89. package/corpus/templates/analytics/server/lib/first-party-dashboard-repair.ts +3 -5
  90. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +150 -21
  91. package/corpus/templates/analytics/server/lib/google-sheets-export.ts +188 -0
  92. package/corpus/templates/analytics/server/lib/provider-api.ts +7 -2
  93. package/corpus/templates/analytics/server/plugins/collab.ts +6 -3
  94. package/corpus/templates/analytics/shared/sql-query-limits.ts +1 -0
  95. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  96. package/corpus/templates/assets/.agents/skills/real-time-collab/SKILL.md +35 -13
  97. package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +1 -1
  98. package/corpus/templates/assets/app/components/layout/Layout.tsx +1 -1
  99. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +54 -62
  100. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +2 -6
  101. package/corpus/templates/assets/app/routes/_index.tsx +8 -5
  102. package/corpus/templates/assets/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  103. package/corpus/templates/assets/changelog/2026-07-22-recent-chats-expand-from-a-compact-list.md +6 -0
  104. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  105. package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +1 -1
  106. package/corpus/templates/brain/actions/rotate-source-ingest-token.ts +77 -0
  107. package/corpus/templates/brain/app/components/layout/Layout.tsx +5 -1
  108. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +38 -51
  109. package/corpus/templates/brain/app/hooks/use-navigation-state.ts +2 -9
  110. package/corpus/templates/brain/app/i18n-data.ts +120 -0
  111. package/corpus/templates/brain/app/routes/sources.tsx +156 -5
  112. package/corpus/templates/brain/changelog/2026-07-22-chat-runs-always-end-with-an-answer.md +6 -0
  113. package/corpus/templates/brain/changelog/2026-07-22-clear-background-chat-progress.md +6 -0
  114. package/corpus/templates/brain/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  115. package/corpus/templates/brain/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  116. package/corpus/templates/brain/changelog/2026-07-22-long-chat-titles-stay-inside-the-sidebar.md +6 -0
  117. package/corpus/templates/brain/changelog/2026-07-22-new-clips-and-webhook-sources-now-show-their-secure-connecti.md +6 -0
  118. package/corpus/templates/brain/jobs/emit-netlify-brain-queue-cron.ts +125 -0
  119. package/corpus/templates/brain/netlify.toml +5 -1
  120. package/corpus/templates/brain/scripts/configure-prod-clips-source.ts +50 -0
  121. package/corpus/templates/brain/server/lib/capture-sanitization.ts +64 -6
  122. package/corpus/templates/brain/server/plugins/agent-chat.ts +4 -0
  123. package/corpus/templates/brain/server/plugins/brain-jobs.ts +1 -0
  124. package/corpus/templates/brain/server/routes/api/brain/queue/run.post.ts +55 -0
  125. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  126. package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +1 -1
  127. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  128. package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
  129. package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -0
  130. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +43 -67
  131. package/corpus/templates/chat/app/hooks/use-navigation-state.ts +2 -7
  132. package/corpus/templates/chat/app/routes/_index.tsx +8 -5
  133. package/corpus/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  134. package/corpus/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  135. package/corpus/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
  136. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  137. package/corpus/templates/clips/AGENTS.md +9 -1
  138. package/corpus/templates/clips/actions/export-to-brain.ts +82 -6
  139. package/corpus/templates/clips/actions/request-transcript.ts +25 -14
  140. package/corpus/templates/clips/changelog/2026-07-22-clips-transcripts-now-retry-brain-export.md +5 -0
  141. package/corpus/templates/clips/changelog/2026-07-22-german-umlauts-and-other-non-ascii-characters-now-paste-corr.md +6 -0
  142. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +26 -3
  143. package/corpus/templates/clips/jobs/emit-netlify-brain-export-cron.ts +118 -0
  144. package/corpus/templates/clips/netlify.toml +4 -1
  145. package/corpus/templates/clips/scripts/configure-prod-brain-export.ts +92 -0
  146. package/corpus/templates/clips/server/jobs/brain-export.ts +182 -0
  147. package/corpus/templates/clips/server/lib/brain-export-state.ts +42 -0
  148. package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +5 -1
  149. package/corpus/templates/clips/server/plugins/calendar-jobs.ts +2 -0
  150. package/corpus/templates/clips/server/register-secrets.ts +42 -0
  151. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +10 -1
  152. package/corpus/templates/clips/server/routes/api/clips/brain-export/run.post.ts +45 -0
  153. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  154. package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +1 -1
  155. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +1 -1
  156. package/corpus/templates/content/server/plugins/collab.ts +1 -1
  157. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  158. package/corpus/templates/crm/actions/_crm-data-program-actions.ts +15 -0
  159. package/corpus/templates/crm/actions/get-crm-dashboard-panel.ts +2 -0
  160. package/corpus/templates/crm/actions/run.ts +2 -6
  161. package/corpus/templates/crm/actions/update-crm-record.ts +4 -2
  162. package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +6 -0
  163. package/corpus/templates/crm/changelog/2026-07-22-crm-field-validation-now-explains-which-fields-cannot-be-edi.md +6 -0
  164. package/corpus/templates/crm/changelog/2026-07-22-fixed-hubspot-contact-syncs-missing-records-updated-after-th.md +6 -0
  165. package/corpus/templates/crm/changelog/2026-07-22-fixed-pipeline-dashboard-panels-so-their-opportunity-data-lo.md +6 -0
  166. package/corpus/templates/crm/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  167. package/corpus/templates/crm/server/crm/hubspot-adapter.ts +4 -1
  168. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  169. package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
  170. package/corpus/templates/design/server/plugins/collab.ts +11 -8
  171. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  172. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  173. package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +1 -1
  174. package/corpus/templates/forms/app/components/layout/Layout.tsx +1 -0
  175. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +1 -1
  176. package/corpus/templates/forms/app/hooks/use-navigation-state.ts +2 -9
  177. package/corpus/templates/forms/app/root.tsx +1 -6
  178. package/corpus/templates/forms/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  179. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  180. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  181. package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +1 -1
  182. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +2 -2
  183. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  184. package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +1 -1
  185. package/corpus/templates/plan/app/components/layout/Layout.tsx +5 -1
  186. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +57 -72
  187. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +2 -9
  188. package/corpus/templates/plan/app/lib/create-plan-routing.ts +2 -2
  189. package/corpus/templates/plan/app/pages/PlanChatPage.tsx +0 -1
  190. package/corpus/templates/plan/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  191. package/corpus/templates/plan/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  192. package/corpus/templates/plan/changelog/2026-07-22-recent-chats-and-sidebar-controls-are-more-compact.md +6 -0
  193. package/corpus/templates/plan/server/plugins/collab.ts +5 -2
  194. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  195. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +1 -1
  196. package/corpus/templates/slides/server/plugins/collab.ts +11 -8
  197. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  198. package/corpus/templates/tasks/.agents/skills/real-time-sync/SKILL.md +1 -1
  199. package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +5 -22
  200. package/corpus/templates/tasks/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  201. package/corpus/toolkit/CHANGELOG.md +7 -0
  202. package/corpus/toolkit/README.md +12 -3
  203. package/corpus/toolkit/package.json +1 -1
  204. package/corpus/toolkit/src/chat-history/ChatHistoryRail.tsx +89 -0
  205. package/corpus/toolkit/src/chat-history/index.ts +5 -0
  206. package/corpus/toolkit/src/chat-history.css +59 -0
  207. package/corpus/toolkit/src/composer/RealtimeVoiceMode.tsx +106 -36
  208. package/corpus/toolkit/src/composer/VoiceButton.tsx +49 -0
  209. package/corpus/toolkit/src/composer/realtime-voice-audio-level.ts +2 -1
  210. package/corpus/toolkit/src/composer/useRealtimeVoiceMode.tsx +5 -3
  211. package/corpus/toolkit/src/styles.css +35 -0
  212. package/dist/agent/production-agent.d.ts.map +1 -1
  213. package/dist/agent/production-agent.js +13 -3
  214. package/dist/agent/production-agent.js.map +1 -1
  215. package/dist/cli/doctor.d.ts +1 -1
  216. package/dist/cli/doctor.d.ts.map +1 -1
  217. package/dist/cli/doctor.js +5 -2
  218. package/dist/cli/doctor.js.map +1 -1
  219. package/dist/client/AgentPanel.d.ts +1 -0
  220. package/dist/client/AgentPanel.d.ts.map +1 -1
  221. package/dist/client/AgentPanel.js +38 -18
  222. package/dist/client/AgentPanel.js.map +1 -1
  223. package/dist/client/AssistantChat.d.ts.map +1 -1
  224. package/dist/client/AssistantChat.js +55 -20
  225. package/dist/client/AssistantChat.js.map +1 -1
  226. package/dist/client/FeedbackButton.d.ts +4 -2
  227. package/dist/client/FeedbackButton.d.ts.map +1 -1
  228. package/dist/client/FeedbackButton.js +18 -2
  229. package/dist/client/FeedbackButton.js.map +1 -1
  230. package/dist/client/MultiTabAssistantChat.d.ts +1 -1
  231. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  232. package/dist/client/MultiTabAssistantChat.js +2 -3
  233. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  234. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  235. package/dist/client/agent-chat-adapter.js +11 -3
  236. package/dist/client/agent-chat-adapter.js.map +1 -1
  237. package/dist/client/agent-page/AgentTabFrame.d.ts +3 -1
  238. package/dist/client/agent-page/AgentTabFrame.d.ts.map +1 -1
  239. package/dist/client/agent-page/AgentTabFrame.js +3 -2
  240. package/dist/client/agent-page/AgentTabFrame.js.map +1 -1
  241. package/dist/client/agent-page/AgentTabsPage.d.ts +2 -0
  242. package/dist/client/agent-page/AgentTabsPage.d.ts.map +1 -1
  243. package/dist/client/agent-page/AgentTabsPage.js +26 -15
  244. package/dist/client/agent-page/AgentTabsPage.js.map +1 -1
  245. package/dist/client/chat/message-components.d.ts +6 -1
  246. package/dist/client/chat/message-components.d.ts.map +1 -1
  247. package/dist/client/chat/message-components.js +17 -11
  248. package/dist/client/chat/message-components.js.map +1 -1
  249. package/dist/client/chat/tool-call-display.d.ts +11 -1
  250. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  251. package/dist/client/chat/tool-call-display.js +16 -17
  252. package/dist/client/chat/tool-call-display.js.map +1 -1
  253. package/dist/client/chat/tool-render-registry.d.ts +2 -0
  254. package/dist/client/chat/tool-render-registry.d.ts.map +1 -1
  255. package/dist/client/chat/tool-render-registry.js.map +1 -1
  256. package/dist/client/resources/McpConnectionSuggestion.d.ts.map +1 -1
  257. package/dist/client/resources/McpConnectionSuggestion.js +15 -1
  258. package/dist/client/resources/McpConnectionSuggestion.js.map +1 -1
  259. package/dist/client/resources/ResourceTree.d.ts.map +1 -1
  260. package/dist/client/resources/ResourceTree.js +3 -3
  261. package/dist/client/resources/ResourceTree.js.map +1 -1
  262. package/dist/client/resources/ResourcesPanel.d.ts +1 -0
  263. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  264. package/dist/client/resources/ResourcesPanel.js +34 -20
  265. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  266. package/dist/client/resources/mcp-connection-resume.d.ts +11 -0
  267. package/dist/client/resources/mcp-connection-resume.d.ts.map +1 -0
  268. package/dist/client/resources/mcp-connection-resume.js +95 -0
  269. package/dist/client/resources/mcp-connection-resume.js.map +1 -0
  270. package/dist/client/resources/mcp-integration-catalog.d.ts +1 -0
  271. package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
  272. package/dist/client/resources/mcp-integration-catalog.js +63 -8
  273. package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
  274. package/dist/client/resources/mcp-integration-logos.d.ts.map +1 -1
  275. package/dist/client/resources/mcp-integration-logos.js +4 -0
  276. package/dist/client/resources/mcp-integration-logos.js.map +1 -1
  277. package/dist/client/sse-event-processor.d.ts +5 -0
  278. package/dist/client/sse-event-processor.d.ts.map +1 -1
  279. package/dist/client/sse-event-processor.js +39 -13
  280. package/dist/client/sse-event-processor.js.map +1 -1
  281. package/dist/client/use-db-sync.d.ts +3 -2
  282. package/dist/client/use-db-sync.d.ts.map +1 -1
  283. package/dist/client/use-db-sync.js +17 -6
  284. package/dist/client/use-db-sync.js.map +1 -1
  285. package/dist/collab/routes.d.ts +1 -1
  286. package/dist/connections/catalog.d.ts +1 -1
  287. package/dist/connections/catalog.d.ts.map +1 -1
  288. package/dist/connections/catalog.js +7 -1
  289. package/dist/connections/catalog.js.map +1 -1
  290. package/dist/eject/remote-mcp-presets.d.ts.map +1 -1
  291. package/dist/eject/remote-mcp-presets.js +33 -3
  292. package/dist/eject/remote-mcp-presets.js.map +1 -1
  293. package/dist/guards/explicit-collab-access.d.ts +8 -0
  294. package/dist/guards/explicit-collab-access.d.ts.map +1 -0
  295. package/dist/guards/explicit-collab-access.js +214 -0
  296. package/dist/guards/explicit-collab-access.js.map +1 -0
  297. package/dist/guards/index.d.ts +1 -0
  298. package/dist/guards/index.d.ts.map +1 -1
  299. package/dist/guards/index.js +1 -0
  300. package/dist/guards/index.js.map +1 -1
  301. package/dist/localization/default-messages.d.ts +43 -0
  302. package/dist/localization/default-messages.d.ts.map +1 -1
  303. package/dist/localization/default-messages.js +48 -5
  304. package/dist/localization/default-messages.js.map +1 -1
  305. package/dist/mcp/connect-route.d.ts.map +1 -1
  306. package/dist/mcp/connect-route.js +34 -48
  307. package/dist/mcp/connect-route.js.map +1 -1
  308. package/dist/notifications/routes.d.ts +3 -3
  309. package/dist/observability/routes.d.ts +1 -1
  310. package/dist/progress/routes.d.ts +1 -1
  311. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  312. package/dist/provider-api/actions/provider-api.d.ts +7 -7
  313. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  314. package/dist/provider-api/index.js +1 -1
  315. package/dist/provider-api/index.js.map +1 -1
  316. package/dist/server/collab-plugin.d.ts +34 -3
  317. package/dist/server/collab-plugin.d.ts.map +1 -1
  318. package/dist/server/collab-plugin.js +65 -12
  319. package/dist/server/collab-plugin.js.map +1 -1
  320. package/dist/server/index.d.ts +1 -1
  321. package/dist/server/index.d.ts.map +1 -1
  322. package/dist/server/index.js.map +1 -1
  323. package/dist/styles/agent-native.css +40 -0
  324. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  325. package/dist/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
  326. package/dist/templates/chat/app/components/layout/Layout.tsx +1 -0
  327. package/dist/templates/chat/app/components/layout/Sidebar.tsx +43 -67
  328. package/dist/templates/chat/app/hooks/use-navigation-state.ts +2 -7
  329. package/dist/templates/chat/app/routes/_index.tsx +8 -5
  330. package/dist/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  331. package/dist/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  332. package/dist/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
  333. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  334. package/dist/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
  335. package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  336. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  337. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  338. package/dist/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
  339. package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  340. package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
  341. package/docs/AGENTS.md +1 -1
  342. package/docs/content/agent-mentions.mdx +2 -2
  343. package/docs/content/{workspace.mdx → agent-resources.mdx} +1 -7
  344. package/docs/content/agent-teams.mdx +4 -4
  345. package/docs/content/dispatch.mdx +10 -10
  346. package/docs/content/drop-in-agent.mdx +4 -4
  347. package/docs/content/external-agents.mdx +1 -1
  348. package/docs/content/frames.mdx +1 -1
  349. package/docs/content/integrations.mdx +13 -2
  350. package/docs/content/key-concepts.mdx +2 -2
  351. package/docs/content/mcp-clients.mdx +7 -1
  352. package/docs/content/multi-app-workspace.mdx +3 -3
  353. package/docs/content/real-time-collaboration.mdx +33 -15
  354. package/docs/content/recurring-jobs.mdx +7 -7
  355. package/docs/content/skills-guide.mdx +4 -4
  356. package/docs/content/template-brain.mdx +1 -1
  357. package/docs/content/toolkit-collaboration.mdx +1 -1
  358. package/docs/content/using-your-agent.mdx +1 -1
  359. package/docs/content/what-is-agent-native.mdx +4 -4
  360. package/docs/content/workspace-management.mdx +4 -4
  361. package/package.json +3 -3
  362. package/src/agent/production-agent.ts +13 -3
  363. package/src/cli/doctor.ts +6 -1
  364. package/src/client/AgentPanel.tsx +79 -41
  365. package/src/client/AssistantChat.tsx +71 -25
  366. package/src/client/FeedbackButton.tsx +33 -7
  367. package/src/client/MultiTabAssistantChat.tsx +6 -8
  368. package/src/client/agent-chat-adapter.ts +11 -2
  369. package/src/client/agent-page/AgentTabFrame.tsx +22 -3
  370. package/src/client/agent-page/AgentTabsPage.tsx +34 -19
  371. package/src/client/chat/message-components.tsx +43 -16
  372. package/src/client/chat/tool-call-display.tsx +30 -18
  373. package/src/client/chat/tool-render-registry.tsx +2 -0
  374. package/src/client/resources/McpConnectionSuggestion.tsx +19 -2
  375. package/src/client/resources/ResourceTree.tsx +7 -10
  376. package/src/client/resources/ResourcesPanel.tsx +33 -70
  377. package/src/client/resources/mcp-connection-resume.ts +107 -0
  378. package/src/client/resources/mcp-integration-catalog.ts +65 -12
  379. package/src/client/resources/mcp-integration-logos.ts +4 -0
  380. package/src/client/sse-event-processor.ts +50 -14
  381. package/src/client/use-db-sync.ts +16 -6
  382. package/src/connections/catalog.ts +7 -1
  383. package/src/eject/remote-mcp-presets.ts +37 -5
  384. package/src/guards/explicit-collab-access.ts +229 -0
  385. package/src/guards/index.ts +1 -0
  386. package/src/localization/default-messages.ts +54 -5
  387. package/src/mcp/connect-route.ts +34 -51
  388. package/src/provider-api/index.ts +1 -1
  389. package/src/server/collab-plugin.ts +137 -18
  390. package/src/server/index.ts +2 -0
  391. package/src/styles/agent-native.css +40 -0
  392. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  393. package/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
  394. package/src/templates/chat/app/components/layout/Layout.tsx +1 -0
  395. package/src/templates/chat/app/components/layout/Sidebar.tsx +43 -67
  396. package/src/templates/chat/app/hooks/use-navigation-state.ts +2 -7
  397. package/src/templates/chat/app/routes/_index.tsx +8 -5
  398. package/src/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  399. package/src/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  400. package/src/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
  401. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  402. package/src/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
  403. package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  404. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  405. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  406. package/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
  407. package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  408. package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
@@ -403,6 +403,18 @@ const enUS = {
403
403
  noCapturesTitle: "No captures match this view",
404
404
  noCapturesDetail:
405
405
  "Try another status, run a source sync, or import a transcript.",
406
+ rotateIngestToken: "Rotate ingest token",
407
+ connectIngestSource: "Connect {{source}}",
408
+ ingestHandoffDescription:
409
+ "Save these values in the sending app now. The ingest token is shown only once and cannot be recovered after this dialog closes.",
410
+ endpoint: "Endpoint",
411
+ sourceKey: "Source key",
412
+ ingestToken: "Ingest token",
413
+ copied: "Copied",
414
+ copy: "Copy",
415
+ ingestTokenSecurity:
416
+ "For security, Brain stores only a hash of this token. Rotate the token whenever the receiving app needs a new credential.",
417
+ ingestHandoffSaved: "I saved these values",
406
418
  tuneSource: "Tune source",
407
419
  setupDescription:
408
420
  "Configure what Brain may ingest. Credentials stay in the workspace credential store; this form only saves allow-lists, cursors, and review rules.",
@@ -3052,6 +3064,18 @@ const exactEnglishDebtOverrides: Partial<
3052
3064
  noCapturesDetail:
3053
3065
  "جرب حالة أخرى، أو قم بتشغيل مزامنة المصدر، أو قم باستيراد نص.",
3054
3066
  noCapturesTitle: "لا توجد لقطات تطابق هذا الرأي",
3067
+ rotateIngestToken: "تدوير رمز الإدخال",
3068
+ connectIngestSource: "ربط {{source}}",
3069
+ ingestHandoffDescription:
3070
+ "احفظ هذه القيم في التطبيق المرسل الآن. سيُعرض رمز الإدخال مرة واحدة فقط ولا يمكن استعادته بعد إغلاق هذا الحوار.",
3071
+ endpoint: "نقطة النهاية",
3072
+ sourceKey: "مفتاح المصدر",
3073
+ ingestToken: "رمز الإدخال",
3074
+ copied: "تم النسخ",
3075
+ copy: "نسخ",
3076
+ ingestTokenSecurity:
3077
+ "لأسباب أمنية، يخزّن Brain تجزئة هذا الرمز فقط. أدر الرمز كلما احتاج التطبيق المستلم إلى بيانات اعتماد جديدة.",
3078
+ ingestHandoffSaved: "حفظت هذه القيم",
3055
3079
  noConnectionProviders:
3056
3080
  "لا يتوفر أي موفري اتصال Brain من الكتالوج المشترك.",
3057
3081
  noCredentialKeysRequired: "لا توجد مفاتيح الاعتماد المطلوبة",
@@ -3467,6 +3491,18 @@ const exactEnglishDebtOverrides: Partial<
3467
3491
  noCapturesDetail:
3468
3492
  "Versuchen Sie es mit einem anderen Status, führen Sie eine Quellsynchronisierung durch oder importieren Sie ein Transkript.",
3469
3493
  noCapturesTitle: "Keine Aufnahmen stimmen mit dieser Ansicht überein",
3494
+ rotateIngestToken: "Aufnahmetoken drehen",
3495
+ connectIngestSource: "{{source}} verbinden",
3496
+ ingestHandoffDescription:
3497
+ "Speichern Sie diese Werte jetzt in der sendenden App. Das Aufnahmetoken wird nur einmal angezeigt und kann nach dem Schließen dieses Dialogs nicht wiederhergestellt werden.",
3498
+ endpoint: "Endpunkt",
3499
+ sourceKey: "Quellschlüssel",
3500
+ ingestToken: "Aufnahmetoken",
3501
+ copied: "Kopiert",
3502
+ copy: "Kopieren",
3503
+ ingestTokenSecurity:
3504
+ "Aus Sicherheitsgründen speichert Brain nur einen Hash dieses Tokens. Drehen Sie das Token, sobald die empfangende App neue Anmeldedaten benötigt.",
3505
+ ingestHandoffSaved: "Ich habe diese Werte gespeichert",
3470
3506
  noConnectionProviders:
3471
3507
  "Im freigegebenen Katalog sind keine Brain-Verbindungsanbieter verfügbar.",
3472
3508
  noCredentialKeysRequired:
@@ -3891,6 +3927,18 @@ const exactEnglishDebtOverrides: Partial<
3891
3927
  noCapturesDetail:
3892
3928
  "Pruebe con otro estado, ejecute una sincronización de origen o importe una transcripción.",
3893
3929
  noCapturesTitle: "Ninguna captura coincide con esta vista.",
3930
+ rotateIngestToken: "Rotar token de ingesta",
3931
+ connectIngestSource: "Conectar {{source}}",
3932
+ ingestHandoffDescription:
3933
+ "Guarde estos valores ahora en la aplicación emisora. El token de ingesta se muestra una sola vez y no se puede recuperar después de cerrar este diálogo.",
3934
+ endpoint: "Punto final",
3935
+ sourceKey: "Clave de origen",
3936
+ ingestToken: "Token de ingesta",
3937
+ copied: "Copiado",
3938
+ copy: "Copiar",
3939
+ ingestTokenSecurity:
3940
+ "Por seguridad, Brain solo almacena un hash de este token. Rote el token cuando la aplicación receptora necesite una credencial nueva.",
3941
+ ingestHandoffSaved: "He guardado estos valores",
3894
3942
  noConnectionProviders:
3895
3943
  "No hay proveedores de conexión Brain disponibles en el catálogo compartido.",
3896
3944
  noCredentialKeysRequired: "No se requieren claves de credenciales",
@@ -4316,6 +4364,18 @@ const exactEnglishDebtOverrides: Partial<
4316
4364
  noCapturesDetail:
4317
4365
  "Essayez un autre statut, exécutez une synchronisation source ou importez une transcription.",
4318
4366
  noCapturesTitle: "Aucune capture ne correspond à cette vue",
4367
+ rotateIngestToken: "Faire pivoter le jeton d’ingestion",
4368
+ connectIngestSource: "Connecter {{source}}",
4369
+ ingestHandoffDescription:
4370
+ "Enregistrez maintenant ces valeurs dans l’application émettrice. Le jeton d’ingestion ne s’affiche qu’une seule fois et ne peut pas être récupéré après la fermeture de cette boîte de dialogue.",
4371
+ endpoint: "Point de terminaison",
4372
+ sourceKey: "Clé de source",
4373
+ ingestToken: "Jeton d’ingestion",
4374
+ copied: "Copié",
4375
+ copy: "Copier",
4376
+ ingestTokenSecurity:
4377
+ "Pour des raisons de sécurité, Brain ne stocke que le hachage de ce jeton. Faites pivoter le jeton lorsque l’application destinataire a besoin d’un nouvel identifiant.",
4378
+ ingestHandoffSaved: "J’ai enregistré ces valeurs",
4319
4379
  noConnectionProviders:
4320
4380
  "Aucun fournisseur de connexion Brain n’est disponible dans le catalogue partagé.",
4321
4381
  noCredentialKeysRequired: "Aucune clé d'identification requise",
@@ -4717,6 +4777,18 @@ const exactEnglishDebtOverrides: Partial<
4717
4777
  noCapturesDetail:
4718
4778
  "कोई अन्य स्थिति आज़माएँ, स्रोत सिंक चलाएँ, या एक प्रतिलेख आयात करें।",
4719
4779
  noCapturesTitle: "कोई भी कैप्चर इस दृश्य से मेल नहीं खाता",
4780
+ rotateIngestToken: "इंजेस्ट टोकन घुमाएँ",
4781
+ connectIngestSource: "कनेक्ट करें: {{source}}",
4782
+ ingestHandoffDescription:
4783
+ "इन मानों को अभी भेजने वाले ऐप में सहेजें। इंजेस्ट टोकन केवल एक बार दिखाया जाता है और यह संवाद बंद होने के बाद इसे पुनर्प्राप्त नहीं किया जा सकता।",
4784
+ endpoint: "एंडपॉइंट",
4785
+ sourceKey: "सोर्स कुंजी",
4786
+ ingestToken: "इंजेस्ट टोकन",
4787
+ copied: "कॉपी किया गया",
4788
+ copy: "कॉपी करें",
4789
+ ingestTokenSecurity:
4790
+ "सुरक्षा के लिए, Brain इस टोकन का केवल हैश संग्रहीत करता है। जब प्राप्त करने वाले ऐप को नए क्रेडेंशियल की आवश्यकता हो, तब टोकन घुमाएँ।",
4791
+ ingestHandoffSaved: "मैंने ये मान सहेज लिए हैं",
4720
4792
  noConnectionProviders: "साझा कैटलॉग से कोई Brain कनेक्शन प्रदाता उपलब्ध नहीं हैं।",
4721
4793
  noCredentialKeysRequired: "किसी क्रेडेंशियल कुंजी की आवश्यकता नहीं है",
4722
4794
  noCredentialRefs: "इस संबंध पर कोई क्रेडेंशियल संदर्भ नहीं है",
@@ -5111,6 +5183,18 @@ const exactEnglishDebtOverrides: Partial<
5111
5183
  noCapturesDetail:
5112
5184
  "別のステータスを試すか、ソース同期を実行するか、トランスクリプトをインポートしてください。",
5113
5185
  noCapturesTitle: "このビューに一致するキャプチャはありません",
5186
+ rotateIngestToken: "取り込みトークンをローテーション",
5187
+ connectIngestSource: "「{{source}}」を接続",
5188
+ ingestHandoffDescription:
5189
+ "これらの値を今すぐ送信元アプリに保存してください。取り込みトークンは一度しか表示されず、このダイアログを閉じると復元できません。",
5190
+ endpoint: "エンドポイント",
5191
+ sourceKey: "ソースキー",
5192
+ ingestToken: "取り込みトークン",
5193
+ copied: "コピーしました",
5194
+ copy: "コピー",
5195
+ ingestTokenSecurity:
5196
+ "セキュリティのため、Brain はこのトークンのハッシュのみを保存します。受信アプリに新しい認証情報が必要になったら、トークンをローテーションしてください。",
5197
+ ingestHandoffSaved: "これらの値を保存しました",
5114
5198
  noConnectionProviders:
5115
5199
  "共有カタログから使用できる Brain 接続プロバイダーはありません。",
5116
5200
  noCredentialKeysRequired: "認証キーは必要ありません",
@@ -5511,6 +5595,18 @@ const exactEnglishDebtOverrides: Partial<
5511
5595
  noCapturesDetail:
5512
5596
  "다른 상태를 시도하거나, 소스 동기화를 실행하거나, 스크립트를 가져오세요.",
5513
5597
  noCapturesTitle: "이 보기와 일치하는 캡처가 없습니다.",
5598
+ rotateIngestToken: "수집 토큰 교체",
5599
+ connectIngestSource: "{{source}} 연결",
5600
+ ingestHandoffDescription:
5601
+ "지금 이 값을 보내는 앱에 저장하세요. 수집 토큰은 한 번만 표시되며 이 대화상자를 닫으면 복구할 수 없습니다.",
5602
+ endpoint: "엔드포인트",
5603
+ sourceKey: "소스 키",
5604
+ ingestToken: "수집 토큰",
5605
+ copied: "복사됨",
5606
+ copy: "복사",
5607
+ ingestTokenSecurity:
5608
+ "보안을 위해 Brain은 이 토큰의 해시만 저장합니다. 수신 앱에 새 자격 증명이 필요할 때 토큰을 교체하세요.",
5609
+ ingestHandoffSaved: "이 값을 저장했습니다",
5514
5610
  noConnectionProviders:
5515
5611
  "공유 카탈로그에서는 Brain 연결 공급자를 사용할 수 없습니다.",
5516
5612
  noCredentialKeysRequired: "자격 증명 키가 필요하지 않습니다",
@@ -5921,6 +6017,18 @@ const exactEnglishDebtOverrides: Partial<
5921
6017
  noCapturesDetail:
5922
6018
  "Tente outro status, execute uma sincronização de origem ou importe uma transcrição.",
5923
6019
  noCapturesTitle: "Nenhuma captura corresponde a esta visualização",
6020
+ rotateIngestToken: "Alternar token de ingestão",
6021
+ connectIngestSource: "Conectar {{source}}",
6022
+ ingestHandoffDescription:
6023
+ "Salve estes valores agora no aplicativo emissor. O token de ingestão é exibido apenas uma vez e não pode ser recuperado depois que esta caixa de diálogo for fechada.",
6024
+ endpoint: "Endpoint",
6025
+ sourceKey: "Chave da fonte",
6026
+ ingestToken: "Token de ingestão",
6027
+ copied: "Copiado",
6028
+ copy: "Copiar",
6029
+ ingestTokenSecurity:
6030
+ "Por segurança, o Brain armazena apenas um hash deste token. Alterne o token sempre que o aplicativo receptor precisar de uma nova credencial.",
6031
+ ingestHandoffSaved: "Salvei estes valores",
5924
6032
  noConnectionProviders:
5925
6033
  "Nenhum provedor de conexão Brain está disponível no catálogo compartilhado.",
5926
6034
  noCredentialKeysRequired: "Nenhuma chave de credencial necessária",
@@ -6300,6 +6408,18 @@ const exactEnglishDebtOverrides: Partial<
6300
6408
  noBrainSourcesYet: "还没有 Brain 来源",
6301
6409
  noCapturesDetail: "尝试其他状态、运行源同步或导入转录本。",
6302
6410
  noCapturesTitle: "没有与此视图匹配的捕获",
6411
+ rotateIngestToken: "轮换摄取令牌",
6412
+ connectIngestSource: "连接 {{source}}",
6413
+ ingestHandoffDescription:
6414
+ "现在将这些值保存到发送应用中。摄取令牌只显示一次,关闭此对话框后将无法恢复。",
6415
+ endpoint: "端点",
6416
+ sourceKey: "源密钥",
6417
+ ingestToken: "摄取令牌",
6418
+ copied: "已复制",
6419
+ copy: "复制",
6420
+ ingestTokenSecurity:
6421
+ "出于安全考虑,Brain 只存储此令牌的哈希值。当接收应用需要新的凭据时,请轮换令牌。",
6422
+ ingestHandoffSaved: "我已保存这些值",
6303
6423
  noConnectionProviders: "共享目录中没有可用的 Brain 连接提供程序。",
6304
6424
  noCredentialKeysRequired: "无需凭证密钥",
6305
6425
  noCredentialRefs: "此连接上没有凭据参考",
@@ -3,6 +3,14 @@ import {
3
3
  useActionQuery,
4
4
  } from "@agent-native/core/client/hooks";
5
5
  import { useT } from "@agent-native/core/client/i18n";
6
+ import {
7
+ Dialog,
8
+ DialogContent,
9
+ DialogDescription,
10
+ DialogFooter,
11
+ DialogHeader,
12
+ DialogTitle,
13
+ } from "@agent-native/toolkit/ui/dialog";
6
14
  import {
7
15
  IconAlertTriangle,
8
16
  IconArchive,
@@ -12,6 +20,7 @@ import {
12
20
  IconCircleCheck,
13
21
  IconCircleDashed,
14
22
  IconClock,
23
+ IconCopy,
15
24
  IconDatabaseImport,
16
25
  IconDotsVertical,
17
26
  IconExternalLink,
@@ -73,6 +82,7 @@ import {
73
82
  type BrainCaptureReviewItem,
74
83
  type EnqueueCapturesDistillationResponse,
75
84
  type CapturesResponse,
85
+ type CreateSourceResponse,
76
86
  type BrainSource,
77
87
  type BrainWorkspaceConnectionGrantState,
78
88
  type BrainWorkspaceConnectionStatus,
@@ -90,6 +100,10 @@ import {
90
100
  sourceReviewRequired,
91
101
  sourceType,
92
102
  } from "@/lib/brain";
103
+ import {
104
+ createOneTimeIngestHandoff,
105
+ type OneTimeIngestHandoff,
106
+ } from "@/lib/ingest-handoff";
93
107
 
94
108
  type Provider = "manual" | "generic" | "clips" | "slack" | "granola" | "github";
95
109
  type CaptureStatusFilter = BrainCaptureReviewStatus | "all";
@@ -1499,16 +1513,25 @@ function SourceFact({ label, value }: { label: string; value: ReactNode }) {
1499
1513
  );
1500
1514
  }
1501
1515
 
1516
+ function ingestSourceKey(source: BrainSource) {
1517
+ const sourceKey = source.config?.sourceKey;
1518
+ return typeof sourceKey === "string" && sourceKey.trim()
1519
+ ? sourceKey.trim()
1520
+ : null;
1521
+ }
1522
+
1502
1523
  function SourceListItem({
1503
1524
  source,
1504
1525
  syncPending,
1505
1526
  onReview,
1527
+ onRotateIngestToken,
1506
1528
  onSync,
1507
1529
  onTune,
1508
1530
  }: {
1509
1531
  source: BrainSource;
1510
1532
  syncPending: boolean;
1511
1533
  onReview: () => void;
1534
+ onRotateIngestToken?: () => void;
1512
1535
  onSync: () => void;
1513
1536
  onTune: () => void;
1514
1537
  }) {
@@ -1602,6 +1625,12 @@ function SourceListItem({
1602
1625
  <IconSettings2 className="size-4" />
1603
1626
  {t("sources.tuneSource")}
1604
1627
  </DropdownMenuItem>
1628
+ {onRotateIngestToken ? (
1629
+ <DropdownMenuItem onSelect={onRotateIngestToken}>
1630
+ <IconRefresh className="size-4" />
1631
+ {t("sources.rotateIngestToken")}
1632
+ </DropdownMenuItem>
1633
+ ) : null}
1605
1634
  </DropdownMenuContent>
1606
1635
  </DropdownMenu>
1607
1636
  </div>
@@ -1633,6 +1662,11 @@ export default function SourcesRoute() {
1633
1662
  const type = params.get("type") ?? "all";
1634
1663
  const [advancedOpen, setAdvancedOpen] = useState(false);
1635
1664
  const [setupOpen, setSetupOpen] = useState(false);
1665
+ const [ingestHandoff, setIngestHandoff] =
1666
+ useState<OneTimeIngestHandoff | null>(null);
1667
+ const [copiedHandoffField, setCopiedHandoffField] = useState<string | null>(
1668
+ null,
1669
+ );
1636
1670
  const [editingSource, setEditingSource] = useState<BrainSource | null>(null);
1637
1671
  const [reviewSource, setReviewSource] = useState<BrainSource | null>(null);
1638
1672
  const [captureStatus, setCaptureStatus] =
@@ -1672,7 +1706,7 @@ export default function SourcesRoute() {
1672
1706
  }
1673
1707
  >("update-source" as any);
1674
1708
  const createSource = useActionMutation<
1675
- unknown,
1709
+ CreateSourceResponse,
1676
1710
  {
1677
1711
  title: string;
1678
1712
  provider: Provider;
@@ -1681,6 +1715,10 @@ export default function SourcesRoute() {
1681
1715
  sourceKey?: string;
1682
1716
  }
1683
1717
  >("create-source" as any);
1718
+ const rotateSourceIngestToken = useActionMutation<
1719
+ CreateSourceResponse,
1720
+ { sourceId: string }
1721
+ >("rotate-source-ingest-token" as any);
1684
1722
  const syncSource = useActionMutation<unknown, { sourceId: string }>(
1685
1723
  "sync-source" as any,
1686
1724
  );
@@ -1818,10 +1856,20 @@ export default function SourcesRoute() {
1818
1856
  setForm((current) => ({ ...current, ...patch }));
1819
1857
  }
1820
1858
 
1821
- function submitSource() {
1859
+ function closeIngestHandoff() {
1860
+ setIngestHandoff(null);
1861
+ setCopiedHandoffField(null);
1862
+ }
1863
+
1864
+ async function copyIngestHandoffValue(value: string, field: string) {
1865
+ await navigator.clipboard.writeText(value);
1866
+ setCopiedHandoffField(field);
1867
+ }
1868
+
1869
+ async function submitSource() {
1822
1870
  const config = buildConfig(form);
1823
1871
  if (editingSource) {
1824
- updateSource.mutate({
1872
+ await updateSource.mutateAsync({
1825
1873
  id: editingSource.id,
1826
1874
  title: form.title.trim() || defaultTitle(form.provider, t),
1827
1875
  status:
@@ -1829,17 +1877,39 @@ export default function SourcesRoute() {
1829
1877
  config,
1830
1878
  });
1831
1879
  } else {
1832
- createSource.mutate({
1880
+ const result = await createSource.mutateAsync({
1833
1881
  title: form.title.trim() || defaultTitle(form.provider, t),
1834
1882
  provider: form.provider,
1835
1883
  visibility: "org",
1836
1884
  config,
1837
1885
  sourceKey: form.sourceKey.trim() || undefined,
1838
1886
  });
1887
+ const handoff = createOneTimeIngestHandoff({
1888
+ origin: window.location.origin,
1889
+ provider: form.provider,
1890
+ result,
1891
+ sourceKey: form.sourceKey,
1892
+ });
1893
+ if (handoff) setIngestHandoff(handoff);
1839
1894
  }
1840
1895
  setSetupOpen(false);
1841
1896
  }
1842
1897
 
1898
+ async function rotateIngestToken(source: BrainSource) {
1899
+ const sourceKey = ingestSourceKey(source);
1900
+ if (!sourceKey) return;
1901
+ const result = await rotateSourceIngestToken.mutateAsync({
1902
+ sourceId: source.id,
1903
+ });
1904
+ const handoff = createOneTimeIngestHandoff({
1905
+ origin: window.location.origin,
1906
+ provider: source.provider ?? "",
1907
+ result,
1908
+ sourceKey,
1909
+ });
1910
+ if (handoff) setIngestHandoff(handoff);
1911
+ }
1912
+
1843
1913
  function toggleCaptureSelection(captureId: string, checked: boolean) {
1844
1914
  setSelectedCaptureIds((current) => {
1845
1915
  const next = new Set(current);
@@ -1909,8 +1979,17 @@ export default function SourcesRoute() {
1909
1979
  <SourceListItem
1910
1980
  key={source.id}
1911
1981
  source={source}
1912
- syncPending={syncSource.isPending}
1982
+ syncPending={
1983
+ syncSource.isPending || rotateSourceIngestToken.isPending
1984
+ }
1913
1985
  onReview={() => openCaptureReview(source)}
1986
+ onRotateIngestToken={
1987
+ (source.provider === "clips" ||
1988
+ source.provider === "generic") &&
1989
+ ingestSourceKey(source)
1990
+ ? () => void rotateIngestToken(source)
1991
+ : undefined
1992
+ }
1914
1993
  onSync={() => syncSource.mutate({ sourceId: source.id })}
1915
1994
  onTune={() => openEdit(source)}
1916
1995
  />
@@ -1928,6 +2007,7 @@ export default function SourcesRoute() {
1928
2007
  connectionProvidersQuery.isError ||
1929
2008
  updateSource.isError ||
1930
2009
  createSource.isError ||
2010
+ rotateSourceIngestToken.isError ||
1931
2011
  syncSource.isError ||
1932
2012
  syncDueSources.isError ||
1933
2013
  enqueueCapturesDistillation.isError ? (
@@ -2302,6 +2382,77 @@ export default function SourcesRoute() {
2302
2382
  </SheetContent>
2303
2383
  </Sheet>
2304
2384
 
2385
+ <Dialog
2386
+ open={Boolean(ingestHandoff)}
2387
+ onOpenChange={(open) => {
2388
+ if (!open) closeIngestHandoff();
2389
+ }}
2390
+ >
2391
+ {ingestHandoff ? (
2392
+ <DialogContent className="max-w-xl gap-5">
2393
+ <DialogHeader>
2394
+ <DialogTitle>
2395
+ {t("sources.connectIngestSource", {
2396
+ source: ingestHandoff.source.title,
2397
+ })}
2398
+ </DialogTitle>
2399
+ <DialogDescription>
2400
+ {t("sources.ingestHandoffDescription")}
2401
+ </DialogDescription>
2402
+ </DialogHeader>
2403
+
2404
+ <div className="grid gap-4">
2405
+ {[
2406
+ [t("sources.endpoint"), ingestHandoff.endpoint, "endpoint"],
2407
+ [t("sources.sourceKey"), ingestHandoff.sourceKey, "source-key"],
2408
+ [
2409
+ t("sources.ingestToken"),
2410
+ ingestHandoff.ingestToken,
2411
+ "ingest-token",
2412
+ ],
2413
+ ].map(([label, value, field]) => (
2414
+ <div key={field} className="grid gap-2">
2415
+ <Label htmlFor={`ingest-handoff-${field}`}>{label}</Label>
2416
+ <div className="flex gap-2">
2417
+ <Input
2418
+ id={`ingest-handoff-${field}`}
2419
+ value={value}
2420
+ readOnly
2421
+ className="min-w-0 font-mono text-xs"
2422
+ />
2423
+ <Button
2424
+ type="button"
2425
+ variant="outline"
2426
+ className="shrink-0"
2427
+ onClick={() => void copyIngestHandoffValue(value, field)}
2428
+ >
2429
+ {copiedHandoffField === field ? (
2430
+ <IconChecks className="size-4" />
2431
+ ) : (
2432
+ <IconCopy className="size-4" />
2433
+ )}
2434
+ {copiedHandoffField === field
2435
+ ? t("sources.copied")
2436
+ : t("sources.copy")}
2437
+ </Button>
2438
+ </div>
2439
+ </div>
2440
+ ))}
2441
+ </div>
2442
+
2443
+ <div className="rounded-md border border-border bg-muted/25 p-3 text-sm leading-6 text-muted-foreground">
2444
+ {t("sources.ingestTokenSecurity")}
2445
+ </div>
2446
+
2447
+ <DialogFooter>
2448
+ <Button type="button" onClick={closeIngestHandoff}>
2449
+ {t("sources.ingestHandoffSaved")}
2450
+ </Button>
2451
+ </DialogFooter>
2452
+ </DialogContent>
2453
+ ) : null}
2454
+ </Dialog>
2455
+
2305
2456
  <Sheet open={setupOpen} onOpenChange={setSetupOpen}>
2306
2457
  <SheetContent className="w-full overflow-y-auto sm:max-w-xl">
2307
2458
  <SheetHeader>
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-22
4
+ ---
5
+
6
+ Chat runs now keep working through long source syncs and always end with a visible answer.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-22
4
+ ---
5
+
6
+ Chat stays current in background tabs and keeps its latest tool visibly active without covering the first message.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-22
4
+ ---
5
+
6
+ The sidebar footer now keeps Feedback and the collapse control on one compact row.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-22
4
+ ---
5
+
6
+ Full-page chat keeps the active conversation when moving to and from the sidebar.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-22
4
+ ---
5
+
6
+ Long chat titles now stay inside the sidebar, and recent chats expand from a compact five-item list.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: added
3
+ date: 2026-07-22
4
+ ---
5
+
6
+ New Clips and webhook sources now show their secure connection details once, with copy controls and token rotation.
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env tsx
2
+
3
+ import { randomBytes } from "node:crypto";
4
+ import { cpSync, existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
5
+ import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
9
+ const FUNCTIONS_DIR = path.join(ROOT, ".netlify", "functions-internal");
10
+ const SERVER_DIR = path.join(FUNCTIONS_DIR, "server");
11
+ export const SCHEDULED_NAME = "brain-queue-cron";
12
+ export const WORKER_NAME = "brain-queue-sweep-background";
13
+ export const ROUTE_PATH = "/api/brain/queue/run";
14
+ export const SCHEDULE = "* * * * *";
15
+
16
+ function ensureDir(dir: string) {
17
+ mkdirSync(dir, { recursive: true });
18
+ }
19
+
20
+ export function scheduledTriggerSource(token: string) {
21
+ return `const WORKER_PATH = "/.netlify/functions/${WORKER_NAME}";
22
+ const CRON_TOKEN = ${JSON.stringify(token)};
23
+
24
+ function siteOrigin(request) {
25
+ return new URL(request.url).origin;
26
+ }
27
+
28
+ export default async function handler(request) {
29
+ const response = await fetch(new URL(WORKER_PATH, siteOrigin(request)), {
30
+ method: "POST",
31
+ headers: { "content-type": "application/json", "x-agent-native-brain-cron": CRON_TOKEN },
32
+ body: JSON.stringify({ scheduled: true }),
33
+ });
34
+ if (!response.ok && response.status !== 202) {
35
+ console.error("[brain-queue-cron] Background sweep trigger failed:", response.status);
36
+ }
37
+ }
38
+
39
+ export const config = {
40
+ name: "brain queue cron trigger",
41
+ generator: "agent-native brain build",
42
+ schedule: ${JSON.stringify(SCHEDULE)},
43
+ };
44
+ `;
45
+ }
46
+
47
+ export function backgroundWorkerSource(token: string) {
48
+ return `globalThis.__AGENT_NATIVE_BRAIN_SCHEDULED_RUNTIME__ = true;
49
+ const CRON_TOKEN = ${JSON.stringify(token)};
50
+ const ROUTE_PATH = ${JSON.stringify(ROUTE_PATH)};
51
+ let cachedHandler;
52
+
53
+ function timingSafeEquals(a, b) {
54
+ if (a.length !== b.length) return false;
55
+ let diff = 0;
56
+ for (let i = 0; i < a.length; i += 1) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
57
+ return diff === 0;
58
+ }
59
+
60
+ export default async function handler(request, context) {
61
+ const token = request.headers.get("x-agent-native-brain-cron") || "";
62
+ if (!timingSafeEquals(token, CRON_TOKEN)) return new Response("Unauthorized", { status: 401 });
63
+ cachedHandler ??= (await import("./main.mjs")).default;
64
+ const url = new URL(request.url);
65
+ url.pathname = ROUTE_PATH;
66
+ url.search = "";
67
+ return cachedHandler(new Request(url, {
68
+ method: "POST",
69
+ headers: { "content-type": "application/json" },
70
+ body: JSON.stringify({ scheduled: true }),
71
+ }), context);
72
+ }
73
+
74
+ export const config = {
75
+ name: "brain queue background sweep",
76
+ generator: "agent-native brain build",
77
+ background: true,
78
+ nodeBundler: "none",
79
+ includedFiles: ["**"],
80
+ preferStatic: false,
81
+ };
82
+ `;
83
+ }
84
+
85
+ export function emitNetlifyBrainQueueCron(
86
+ options: {
87
+ functionsDir?: string;
88
+ serverDir?: string;
89
+ token?: string;
90
+ } = {},
91
+ ) {
92
+ const functionsDir = options.functionsDir ?? FUNCTIONS_DIR;
93
+ const serverDir = options.serverDir ?? SERVER_DIR;
94
+ if (!existsSync(serverDir)) {
95
+ throw new Error(
96
+ "Expected Nitro Netlify server output before emitting Brain cron functions.",
97
+ );
98
+ }
99
+ const token = options.token ?? randomBytes(32).toString("hex");
100
+ const scheduledDir = path.join(functionsDir, SCHEDULED_NAME);
101
+ const workerDir = path.join(functionsDir, WORKER_NAME);
102
+ rmSync(scheduledDir, { recursive: true, force: true });
103
+ rmSync(workerDir, { recursive: true, force: true });
104
+ ensureDir(scheduledDir);
105
+ cpSync(serverDir, workerDir, { recursive: true });
106
+ rmSync(path.join(workerDir, "server.mjs"), { force: true });
107
+ writeFileSync(
108
+ path.join(scheduledDir, `${SCHEDULED_NAME}.mjs`),
109
+ scheduledTriggerSource(token),
110
+ );
111
+ writeFileSync(
112
+ path.join(workerDir, `${WORKER_NAME}.mjs`),
113
+ backgroundWorkerSource(token),
114
+ );
115
+ }
116
+
117
+ if (
118
+ process.argv[1] &&
119
+ path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)
120
+ ) {
121
+ emitNetlifyBrainQueueCron();
122
+ console.log(
123
+ "[brain-queue-cron] Emitted scheduled queue sweep and background worker.",
124
+ );
125
+ }
@@ -1,6 +1,6 @@
1
1
  [build]
2
2
  ignore = "node ./scripts/netlify-ignore-build.mjs brain"
3
- command = "export DATABASE_URL=${NETLIFY_DATABASE_URL:-$DATABASE_URL} && pnpm install && NITRO_PRESET=netlify pnpm --filter brain build"
3
+ command = "export DATABASE_URL=${NETLIFY_DATABASE_URL:-$DATABASE_URL} && pnpm install && NITRO_PRESET=netlify pnpm --filter brain build && pnpm exec tsx templates/brain/jobs/emit-netlify-brain-queue-cron.ts"
4
4
  publish = "templates/brain/dist"
5
5
  functions = "templates/brain/.netlify/functions-internal"
6
6
 
@@ -15,3 +15,7 @@ NPM_CONFIG_PRODUCTION = "false"
15
15
  # auto-continuation path can hand off before Netlify kills the function.
16
16
  [functions."*"]
17
17
  timeout = 75
18
+
19
+ [functions.brain-queue-sweep-background]
20
+ timeout = 900
21
+ memory = "2gb"