@agent-native/core 0.115.4 → 0.117.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 (487) hide show
  1. package/agent-native.eject.json +1 -0
  2. package/corpus/README.md +3 -3
  3. package/corpus/core/CHANGELOG.md +43 -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 +4 -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/analytics.ts +7 -0
  36. package/corpus/core/src/client/chat/message-components.tsx +43 -16
  37. package/corpus/core/src/client/chat/tool-call-display.tsx +30 -18
  38. package/corpus/core/src/client/chat/tool-render-registry.tsx +2 -0
  39. package/corpus/core/src/client/resources/McpConnectionSuggestion.tsx +19 -2
  40. package/corpus/core/src/client/resources/ResourceTree.tsx +7 -10
  41. package/corpus/core/src/client/resources/ResourcesPanel.tsx +33 -70
  42. package/corpus/core/src/client/resources/mcp-connection-resume.ts +107 -0
  43. package/corpus/core/src/client/resources/mcp-integration-catalog.ts +65 -12
  44. package/corpus/core/src/client/resources/mcp-integration-logos.ts +4 -0
  45. package/corpus/core/src/client/sse-event-processor.ts +50 -14
  46. package/corpus/core/src/client/use-db-sync.ts +370 -21
  47. package/corpus/core/src/collab/client.ts +26 -2
  48. package/corpus/core/src/connections/catalog.ts +7 -1
  49. package/corpus/core/src/db/ddl-guard.ts +49 -10
  50. package/corpus/core/src/deploy/build.ts +25 -2
  51. package/corpus/core/src/eject/remote-mcp-presets.ts +37 -5
  52. package/corpus/core/src/guards/explicit-collab-access.ts +229 -0
  53. package/corpus/core/src/guards/index.ts +1 -0
  54. package/corpus/core/src/localization/default-messages.ts +54 -5
  55. package/corpus/core/src/mcp/connect-route.ts +34 -51
  56. package/corpus/core/src/provider-api/index.ts +1 -1
  57. package/corpus/core/src/realtime-protocol.ts +92 -0
  58. package/corpus/core/src/server/collab-plugin.ts +137 -18
  59. package/corpus/core/src/server/core-routes-plugin.ts +7 -0
  60. package/corpus/core/src/server/index.ts +2 -0
  61. package/corpus/core/src/server/poll-events.ts +29 -8
  62. package/corpus/core/src/server/poll.ts +1123 -865
  63. package/corpus/core/src/server/realtime-token.ts +106 -0
  64. package/corpus/core/src/server/sentry-config.ts +40 -0
  65. package/corpus/core/src/server/short-lived-token.ts +156 -0
  66. package/corpus/core/src/server/sse.ts +15 -0
  67. package/corpus/core/src/server/ssr-handler.ts +9 -3
  68. package/corpus/core/src/styles/agent-native.css +40 -0
  69. package/corpus/core/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  70. package/corpus/core/src/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
  71. package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  72. package/corpus/core/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  73. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  74. package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
  75. package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  76. package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
  77. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  78. package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +1 -1
  79. package/corpus/templates/analytics/AGENTS.md +7 -2
  80. package/corpus/templates/analytics/actions/export-dashboard-panel-to-google-sheet.ts +144 -0
  81. package/corpus/templates/analytics/app/components/layout/Layout.tsx +7 -88
  82. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +34 -37
  83. package/corpus/templates/analytics/app/global.css +0 -4
  84. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +2 -7
  85. package/corpus/templates/analytics/app/i18n-data.ts +107 -0
  86. package/corpus/templates/analytics/app/lib/data-source-status.ts +9 -0
  87. package/corpus/templates/analytics/app/lib/sql-query.ts +1 -2
  88. package/corpus/templates/analytics/app/pages/Ask.tsx +2 -7
  89. package/corpus/templates/analytics/app/pages/DataSources.tsx +48 -0
  90. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +59 -0
  91. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +2 -0
  92. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/report-panel-window.ts +3 -1
  93. package/corpus/templates/analytics/changelog/2026-07-22-clear-background-chat-progress.md +6 -0
  94. package/corpus/templates/analytics/changelog/2026-07-22-daily-dashboard-email-query-batches.md +6 -0
  95. package/corpus/templates/analytics/changelog/2026-07-22-export-table-panels-directly-to-google-sheets.md +6 -0
  96. package/corpus/templates/analytics/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  97. package/corpus/templates/analytics/changelog/2026-07-22-recent-chats-can-expand-in-the-sidebar.md +6 -0
  98. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +8 -8
  99. package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +31 -0
  100. package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +3 -5
  101. package/corpus/templates/analytics/server/lib/dashboard-report.ts +12 -0
  102. package/corpus/templates/analytics/server/lib/first-party-dashboard-repair.ts +3 -5
  103. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +150 -21
  104. package/corpus/templates/analytics/server/lib/google-sheets-export.ts +188 -0
  105. package/corpus/templates/analytics/server/lib/provider-api.ts +7 -2
  106. package/corpus/templates/analytics/server/plugins/collab.ts +6 -3
  107. package/corpus/templates/analytics/shared/sql-query-limits.ts +1 -0
  108. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  109. package/corpus/templates/assets/.agents/skills/real-time-collab/SKILL.md +35 -13
  110. package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +1 -1
  111. package/corpus/templates/assets/app/components/layout/Layout.tsx +1 -1
  112. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +54 -62
  113. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +2 -6
  114. package/corpus/templates/assets/app/routes/_index.tsx +8 -5
  115. package/corpus/templates/assets/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  116. package/corpus/templates/assets/changelog/2026-07-22-recent-chats-expand-from-a-compact-list.md +6 -0
  117. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  118. package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +1 -1
  119. package/corpus/templates/brain/actions/rotate-source-ingest-token.ts +77 -0
  120. package/corpus/templates/brain/app/components/layout/Layout.tsx +5 -1
  121. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +38 -51
  122. package/corpus/templates/brain/app/hooks/use-navigation-state.ts +2 -9
  123. package/corpus/templates/brain/app/i18n-data.ts +120 -0
  124. package/corpus/templates/brain/app/routes/sources.tsx +156 -5
  125. package/corpus/templates/brain/changelog/2026-07-22-chat-runs-always-end-with-an-answer.md +6 -0
  126. package/corpus/templates/brain/changelog/2026-07-22-clear-background-chat-progress.md +6 -0
  127. package/corpus/templates/brain/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  128. package/corpus/templates/brain/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  129. package/corpus/templates/brain/changelog/2026-07-22-long-chat-titles-stay-inside-the-sidebar.md +6 -0
  130. package/corpus/templates/brain/changelog/2026-07-22-new-clips-and-webhook-sources-now-show-their-secure-connecti.md +6 -0
  131. package/corpus/templates/brain/jobs/emit-netlify-brain-queue-cron.ts +125 -0
  132. package/corpus/templates/brain/netlify.toml +5 -1
  133. package/corpus/templates/brain/scripts/configure-prod-clips-source.ts +50 -0
  134. package/corpus/templates/brain/server/lib/capture-sanitization.ts +64 -6
  135. package/corpus/templates/brain/server/plugins/agent-chat.ts +4 -0
  136. package/corpus/templates/brain/server/plugins/brain-jobs.ts +1 -0
  137. package/corpus/templates/brain/server/routes/api/brain/queue/run.post.ts +55 -0
  138. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  139. package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +1 -1
  140. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  141. package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
  142. package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -0
  143. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +43 -67
  144. package/corpus/templates/chat/app/hooks/use-navigation-state.ts +2 -7
  145. package/corpus/templates/chat/app/routes/_index.tsx +8 -5
  146. package/corpus/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  147. package/corpus/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  148. package/corpus/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
  149. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  150. package/corpus/templates/clips/AGENTS.md +9 -1
  151. package/corpus/templates/clips/actions/export-to-brain.ts +82 -6
  152. package/corpus/templates/clips/actions/request-transcript.ts +25 -14
  153. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +12 -0
  154. package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
  155. package/corpus/templates/clips/changelog/2026-07-22-clips-transcripts-now-retry-brain-export.md +5 -0
  156. package/corpus/templates/clips/changelog/2026-07-22-german-umlauts-and-other-non-ascii-characters-now-paste-corr.md +6 -0
  157. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +26 -3
  158. package/corpus/templates/clips/jobs/emit-netlify-brain-export-cron.ts +118 -0
  159. package/corpus/templates/clips/netlify.toml +4 -1
  160. package/corpus/templates/clips/scripts/configure-prod-brain-export.ts +92 -0
  161. package/corpus/templates/clips/server/jobs/brain-export.ts +182 -0
  162. package/corpus/templates/clips/server/lib/brain-export-state.ts +42 -0
  163. package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +5 -1
  164. package/corpus/templates/clips/server/plugins/calendar-jobs.ts +2 -0
  165. package/corpus/templates/clips/server/register-secrets.ts +42 -0
  166. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +10 -1
  167. package/corpus/templates/clips/server/routes/api/clips/brain-export/run.post.ts +45 -0
  168. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  169. package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +1 -1
  170. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +566 -299
  171. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +14 -0
  172. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +1 -1
  173. package/corpus/templates/content/app/i18n-data.ts +90 -0
  174. package/corpus/templates/content/server/plugins/collab.ts +1 -1
  175. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  176. package/corpus/templates/crm/actions/_crm-data-program-actions.ts +15 -0
  177. package/corpus/templates/crm/actions/get-crm-dashboard-panel.ts +2 -0
  178. package/corpus/templates/crm/actions/run.ts +2 -6
  179. package/corpus/templates/crm/actions/update-crm-record.ts +4 -2
  180. package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +6 -0
  181. package/corpus/templates/crm/changelog/2026-07-22-crm-field-validation-now-explains-which-fields-cannot-be-edi.md +6 -0
  182. package/corpus/templates/crm/changelog/2026-07-22-fixed-hubspot-contact-syncs-missing-records-updated-after-th.md +6 -0
  183. package/corpus/templates/crm/changelog/2026-07-22-fixed-pipeline-dashboard-panels-so-their-opportunity-data-lo.md +6 -0
  184. package/corpus/templates/crm/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  185. package/corpus/templates/crm/server/crm/hubspot-adapter.ts +4 -1
  186. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  187. package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
  188. package/corpus/templates/design/server/plugins/collab.ts +11 -8
  189. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  190. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  191. package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +1 -1
  192. package/corpus/templates/forms/app/components/layout/Layout.tsx +1 -0
  193. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +1 -1
  194. package/corpus/templates/forms/app/hooks/use-navigation-state.ts +2 -9
  195. package/corpus/templates/forms/app/root.tsx +1 -6
  196. package/corpus/templates/forms/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  197. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  198. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  199. package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +1 -1
  200. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +2 -2
  201. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  202. package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +1 -1
  203. package/corpus/templates/plan/app/components/layout/Layout.tsx +5 -1
  204. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +57 -72
  205. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +2 -9
  206. package/corpus/templates/plan/app/lib/create-plan-routing.ts +2 -2
  207. package/corpus/templates/plan/app/pages/PlanChatPage.tsx +0 -1
  208. package/corpus/templates/plan/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  209. package/corpus/templates/plan/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  210. package/corpus/templates/plan/changelog/2026-07-22-recent-chats-and-sidebar-controls-are-more-compact.md +6 -0
  211. package/corpus/templates/plan/server/plugins/collab.ts +5 -2
  212. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  213. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +1 -1
  214. package/corpus/templates/slides/server/plugins/collab.ts +11 -8
  215. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  216. package/corpus/templates/tasks/.agents/skills/real-time-sync/SKILL.md +1 -1
  217. package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +5 -22
  218. package/corpus/templates/tasks/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  219. package/corpus/toolkit/CHANGELOG.md +7 -0
  220. package/corpus/toolkit/README.md +12 -3
  221. package/corpus/toolkit/package.json +1 -1
  222. package/corpus/toolkit/src/chat-history/ChatHistoryRail.tsx +89 -0
  223. package/corpus/toolkit/src/chat-history/index.ts +5 -0
  224. package/corpus/toolkit/src/chat-history.css +59 -0
  225. package/corpus/toolkit/src/composer/RealtimeVoiceMode.tsx +106 -36
  226. package/corpus/toolkit/src/composer/VoiceButton.tsx +49 -0
  227. package/corpus/toolkit/src/composer/realtime-voice-audio-level.ts +2 -1
  228. package/corpus/toolkit/src/composer/useRealtimeVoiceMode.tsx +5 -3
  229. package/corpus/toolkit/src/styles.css +35 -0
  230. package/dist/agent/production-agent.d.ts.map +1 -1
  231. package/dist/agent/production-agent.js +13 -3
  232. package/dist/agent/production-agent.js.map +1 -1
  233. package/dist/cli/doctor.d.ts +1 -1
  234. package/dist/cli/doctor.d.ts.map +1 -1
  235. package/dist/cli/doctor.js +5 -2
  236. package/dist/cli/doctor.js.map +1 -1
  237. package/dist/client/AgentPanel.d.ts +1 -0
  238. package/dist/client/AgentPanel.d.ts.map +1 -1
  239. package/dist/client/AgentPanel.js +38 -18
  240. package/dist/client/AgentPanel.js.map +1 -1
  241. package/dist/client/AssistantChat.d.ts.map +1 -1
  242. package/dist/client/AssistantChat.js +55 -20
  243. package/dist/client/AssistantChat.js.map +1 -1
  244. package/dist/client/FeedbackButton.d.ts +4 -2
  245. package/dist/client/FeedbackButton.d.ts.map +1 -1
  246. package/dist/client/FeedbackButton.js +18 -2
  247. package/dist/client/FeedbackButton.js.map +1 -1
  248. package/dist/client/MultiTabAssistantChat.d.ts +1 -1
  249. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  250. package/dist/client/MultiTabAssistantChat.js +2 -3
  251. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  252. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  253. package/dist/client/agent-chat-adapter.js +11 -3
  254. package/dist/client/agent-chat-adapter.js.map +1 -1
  255. package/dist/client/agent-page/AgentTabFrame.d.ts +3 -1
  256. package/dist/client/agent-page/AgentTabFrame.d.ts.map +1 -1
  257. package/dist/client/agent-page/AgentTabFrame.js +3 -2
  258. package/dist/client/agent-page/AgentTabFrame.js.map +1 -1
  259. package/dist/client/agent-page/AgentTabsPage.d.ts +2 -0
  260. package/dist/client/agent-page/AgentTabsPage.d.ts.map +1 -1
  261. package/dist/client/agent-page/AgentTabsPage.js +26 -15
  262. package/dist/client/agent-page/AgentTabsPage.js.map +1 -1
  263. package/dist/client/analytics.d.ts +10 -0
  264. package/dist/client/analytics.d.ts.map +1 -1
  265. package/dist/client/analytics.js.map +1 -1
  266. package/dist/client/chat/message-components.d.ts +6 -1
  267. package/dist/client/chat/message-components.d.ts.map +1 -1
  268. package/dist/client/chat/message-components.js +17 -11
  269. package/dist/client/chat/message-components.js.map +1 -1
  270. package/dist/client/chat/tool-call-display.d.ts +11 -1
  271. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  272. package/dist/client/chat/tool-call-display.js +16 -17
  273. package/dist/client/chat/tool-call-display.js.map +1 -1
  274. package/dist/client/chat/tool-render-registry.d.ts +2 -0
  275. package/dist/client/chat/tool-render-registry.d.ts.map +1 -1
  276. package/dist/client/chat/tool-render-registry.js.map +1 -1
  277. package/dist/client/resources/McpConnectionSuggestion.d.ts.map +1 -1
  278. package/dist/client/resources/McpConnectionSuggestion.js +15 -1
  279. package/dist/client/resources/McpConnectionSuggestion.js.map +1 -1
  280. package/dist/client/resources/ResourceTree.d.ts.map +1 -1
  281. package/dist/client/resources/ResourceTree.js +3 -3
  282. package/dist/client/resources/ResourceTree.js.map +1 -1
  283. package/dist/client/resources/ResourcesPanel.d.ts +1 -0
  284. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  285. package/dist/client/resources/ResourcesPanel.js +34 -20
  286. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  287. package/dist/client/resources/mcp-connection-resume.d.ts +11 -0
  288. package/dist/client/resources/mcp-connection-resume.d.ts.map +1 -0
  289. package/dist/client/resources/mcp-connection-resume.js +95 -0
  290. package/dist/client/resources/mcp-connection-resume.js.map +1 -0
  291. package/dist/client/resources/mcp-integration-catalog.d.ts +1 -0
  292. package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
  293. package/dist/client/resources/mcp-integration-catalog.js +63 -8
  294. package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
  295. package/dist/client/resources/mcp-integration-logos.d.ts.map +1 -1
  296. package/dist/client/resources/mcp-integration-logos.js +4 -0
  297. package/dist/client/resources/mcp-integration-logos.js.map +1 -1
  298. package/dist/client/sse-event-processor.d.ts +5 -0
  299. package/dist/client/sse-event-processor.d.ts.map +1 -1
  300. package/dist/client/sse-event-processor.js +39 -13
  301. package/dist/client/sse-event-processor.js.map +1 -1
  302. package/dist/client/use-db-sync.d.ts +4 -3
  303. package/dist/client/use-db-sync.d.ts.map +1 -1
  304. package/dist/client/use-db-sync.js +332 -21
  305. package/dist/client/use-db-sync.js.map +1 -1
  306. package/dist/collab/client.d.ts.map +1 -1
  307. package/dist/collab/client.js +26 -2
  308. package/dist/collab/client.js.map +1 -1
  309. package/dist/collab/routes.d.ts +1 -1
  310. package/dist/connections/catalog.d.ts +1 -1
  311. package/dist/connections/catalog.d.ts.map +1 -1
  312. package/dist/connections/catalog.js +7 -1
  313. package/dist/connections/catalog.js.map +1 -1
  314. package/dist/db/ddl-guard.d.ts +7 -2
  315. package/dist/db/ddl-guard.d.ts.map +1 -1
  316. package/dist/db/ddl-guard.js +21 -9
  317. package/dist/db/ddl-guard.js.map +1 -1
  318. package/dist/deploy/build.d.ts.map +1 -1
  319. package/dist/deploy/build.js +25 -2
  320. package/dist/deploy/build.js.map +1 -1
  321. package/dist/eject/remote-mcp-presets.d.ts.map +1 -1
  322. package/dist/eject/remote-mcp-presets.js +33 -3
  323. package/dist/eject/remote-mcp-presets.js.map +1 -1
  324. package/dist/guards/explicit-collab-access.d.ts +8 -0
  325. package/dist/guards/explicit-collab-access.d.ts.map +1 -0
  326. package/dist/guards/explicit-collab-access.js +214 -0
  327. package/dist/guards/explicit-collab-access.js.map +1 -0
  328. package/dist/guards/index.d.ts +1 -0
  329. package/dist/guards/index.d.ts.map +1 -1
  330. package/dist/guards/index.js +1 -0
  331. package/dist/guards/index.js.map +1 -1
  332. package/dist/localization/default-messages.d.ts +43 -0
  333. package/dist/localization/default-messages.d.ts.map +1 -1
  334. package/dist/localization/default-messages.js +48 -5
  335. package/dist/localization/default-messages.js.map +1 -1
  336. package/dist/mcp/connect-route.d.ts.map +1 -1
  337. package/dist/mcp/connect-route.js +34 -48
  338. package/dist/mcp/connect-route.js.map +1 -1
  339. package/dist/observability/routes.d.ts +5 -5
  340. package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
  341. package/dist/provider-api/actions/provider-api.d.ts +7 -7
  342. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  343. package/dist/provider-api/index.js +1 -1
  344. package/dist/provider-api/index.js.map +1 -1
  345. package/dist/realtime-protocol.d.ts +40 -0
  346. package/dist/realtime-protocol.d.ts.map +1 -0
  347. package/dist/realtime-protocol.js +69 -0
  348. package/dist/realtime-protocol.js.map +1 -0
  349. package/dist/resources/handlers.d.ts +1 -1
  350. package/dist/secrets/routes.d.ts +3 -3
  351. package/dist/server/collab-plugin.d.ts +34 -3
  352. package/dist/server/collab-plugin.d.ts.map +1 -1
  353. package/dist/server/collab-plugin.js +65 -12
  354. package/dist/server/collab-plugin.js.map +1 -1
  355. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  356. package/dist/server/core-routes-plugin.js +3 -0
  357. package/dist/server/core-routes-plugin.js.map +1 -1
  358. package/dist/server/index.d.ts +1 -1
  359. package/dist/server/index.d.ts.map +1 -1
  360. package/dist/server/index.js.map +1 -1
  361. package/dist/server/poll-events.d.ts +7 -1
  362. package/dist/server/poll-events.d.ts.map +1 -1
  363. package/dist/server/poll-events.js +24 -7
  364. package/dist/server/poll-events.js.map +1 -1
  365. package/dist/server/poll.d.ts +223 -42
  366. package/dist/server/poll.d.ts.map +1 -1
  367. package/dist/server/poll.js +849 -737
  368. package/dist/server/poll.js.map +1 -1
  369. package/dist/server/realtime-token.d.ts +34 -0
  370. package/dist/server/realtime-token.d.ts.map +1 -0
  371. package/dist/server/realtime-token.js +85 -0
  372. package/dist/server/realtime-token.js.map +1 -0
  373. package/dist/server/sentry-config.d.ts +12 -0
  374. package/dist/server/sentry-config.d.ts.map +1 -1
  375. package/dist/server/sentry-config.js +34 -0
  376. package/dist/server/sentry-config.js.map +1 -1
  377. package/dist/server/short-lived-token.d.ts +46 -0
  378. package/dist/server/short-lived-token.d.ts.map +1 -1
  379. package/dist/server/short-lived-token.js +104 -0
  380. package/dist/server/short-lived-token.js.map +1 -1
  381. package/dist/server/sse.d.ts +1 -1
  382. package/dist/server/sse.d.ts.map +1 -1
  383. package/dist/server/sse.js +4 -0
  384. package/dist/server/sse.js.map +1 -1
  385. package/dist/server/ssr-handler.d.ts.map +1 -1
  386. package/dist/server/ssr-handler.js +5 -3
  387. package/dist/server/ssr-handler.js.map +1 -1
  388. package/dist/server/transcribe-voice.d.ts +1 -1
  389. package/dist/styles/agent-native.css +40 -0
  390. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  391. package/dist/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
  392. package/dist/templates/chat/app/components/layout/Layout.tsx +1 -0
  393. package/dist/templates/chat/app/components/layout/Sidebar.tsx +43 -67
  394. package/dist/templates/chat/app/hooks/use-navigation-state.ts +2 -7
  395. package/dist/templates/chat/app/routes/_index.tsx +8 -5
  396. package/dist/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  397. package/dist/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  398. package/dist/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
  399. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  400. package/dist/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
  401. package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  402. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  403. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  404. package/dist/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
  405. package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  406. package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
  407. package/docs/AGENTS.md +1 -1
  408. package/docs/content/agent-mentions.mdx +2 -2
  409. package/docs/content/{workspace.mdx → agent-resources.mdx} +1 -7
  410. package/docs/content/agent-teams.mdx +4 -4
  411. package/docs/content/dispatch.mdx +10 -10
  412. package/docs/content/drop-in-agent.mdx +4 -4
  413. package/docs/content/external-agents.mdx +1 -1
  414. package/docs/content/frames.mdx +1 -1
  415. package/docs/content/integrations.mdx +13 -2
  416. package/docs/content/key-concepts.mdx +2 -2
  417. package/docs/content/mcp-clients.mdx +7 -1
  418. package/docs/content/multi-app-workspace.mdx +3 -3
  419. package/docs/content/real-time-collaboration.mdx +33 -15
  420. package/docs/content/recurring-jobs.mdx +7 -7
  421. package/docs/content/skills-guide.mdx +4 -4
  422. package/docs/content/template-brain.mdx +1 -1
  423. package/docs/content/toolkit-collaboration.mdx +1 -1
  424. package/docs/content/using-your-agent.mdx +1 -1
  425. package/docs/content/what-is-agent-native.mdx +4 -4
  426. package/docs/content/workspace-management.mdx +4 -4
  427. package/package.json +6 -3
  428. package/src/agent/production-agent.ts +13 -3
  429. package/src/cli/doctor.ts +6 -1
  430. package/src/client/AgentPanel.tsx +79 -41
  431. package/src/client/AssistantChat.tsx +71 -25
  432. package/src/client/FeedbackButton.tsx +33 -7
  433. package/src/client/MultiTabAssistantChat.tsx +6 -8
  434. package/src/client/agent-chat-adapter.ts +11 -2
  435. package/src/client/agent-page/AgentTabFrame.tsx +22 -3
  436. package/src/client/agent-page/AgentTabsPage.tsx +34 -19
  437. package/src/client/analytics.ts +7 -0
  438. package/src/client/chat/message-components.tsx +43 -16
  439. package/src/client/chat/tool-call-display.tsx +30 -18
  440. package/src/client/chat/tool-render-registry.tsx +2 -0
  441. package/src/client/resources/McpConnectionSuggestion.tsx +19 -2
  442. package/src/client/resources/ResourceTree.tsx +7 -10
  443. package/src/client/resources/ResourcesPanel.tsx +33 -70
  444. package/src/client/resources/mcp-connection-resume.ts +107 -0
  445. package/src/client/resources/mcp-integration-catalog.ts +65 -12
  446. package/src/client/resources/mcp-integration-logos.ts +4 -0
  447. package/src/client/sse-event-processor.ts +50 -14
  448. package/src/client/use-db-sync.ts +370 -21
  449. package/src/collab/client.ts +26 -2
  450. package/src/connections/catalog.ts +7 -1
  451. package/src/db/ddl-guard.ts +49 -10
  452. package/src/deploy/build.ts +25 -2
  453. package/src/eject/remote-mcp-presets.ts +37 -5
  454. package/src/guards/explicit-collab-access.ts +229 -0
  455. package/src/guards/index.ts +1 -0
  456. package/src/localization/default-messages.ts +54 -5
  457. package/src/mcp/connect-route.ts +34 -51
  458. package/src/provider-api/index.ts +1 -1
  459. package/src/realtime-protocol.ts +92 -0
  460. package/src/server/collab-plugin.ts +137 -18
  461. package/src/server/core-routes-plugin.ts +7 -0
  462. package/src/server/index.ts +2 -0
  463. package/src/server/poll-events.ts +29 -8
  464. package/src/server/poll.ts +1123 -865
  465. package/src/server/realtime-token.ts +106 -0
  466. package/src/server/sentry-config.ts +40 -0
  467. package/src/server/short-lived-token.ts +156 -0
  468. package/src/server/sse.ts +15 -0
  469. package/src/server/ssr-handler.ts +9 -3
  470. package/src/styles/agent-native.css +40 -0
  471. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  472. package/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
  473. package/src/templates/chat/app/components/layout/Layout.tsx +1 -0
  474. package/src/templates/chat/app/components/layout/Sidebar.tsx +43 -67
  475. package/src/templates/chat/app/hooks/use-navigation-state.ts +2 -7
  476. package/src/templates/chat/app/routes/_index.tsx +8 -5
  477. package/src/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  478. package/src/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  479. package/src/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
  480. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  481. package/src/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
  482. package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  483. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  484. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
  485. package/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
  486. package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  487. package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
@@ -0,0 +1,55 @@
1
+ import { timingSafeEqual } from "node:crypto";
2
+
3
+ import { createError, defineEventHandler, getHeader } from "h3";
4
+
5
+ import { processBrainIngestQueueOnce } from "../../../../../jobs/process-ingest-queue.js";
6
+ import { syncDueBrainSourcesOnce } from "../../../../jobs/sync-sources.js";
7
+ import { expireSensitivityQuarantines } from "../../../../lib/brain.js";
8
+
9
+ declare global {
10
+ var __AGENT_NATIVE_BRAIN_SCHEDULED_RUNTIME__: boolean | undefined;
11
+ }
12
+
13
+ function productionLike() {
14
+ return (
15
+ process.env.NODE_ENV === "production" || process.env.NETLIFY === "true"
16
+ );
17
+ }
18
+
19
+ function scheduledFunctionRuntime() {
20
+ return globalThis.__AGENT_NATIVE_BRAIN_SCHEDULED_RUNTIME__ === true;
21
+ }
22
+
23
+ function headerMatchesSecret(header: string | undefined, secret: string) {
24
+ const expected = `Bearer ${secret}`;
25
+ const value = header?.trim() ?? "";
26
+ return (
27
+ value.length === expected.length &&
28
+ timingSafeEqual(Buffer.from(value), Buffer.from(expected))
29
+ );
30
+ }
31
+
32
+ export default defineEventHandler(async (event) => {
33
+ const secret = process.env.BRAIN_JOBS_SECRET?.trim(); // guard:allow-env-credential — deployment-level scheduler route secret
34
+ const scheduled = scheduledFunctionRuntime();
35
+ if (!secret && productionLike() && !scheduled) {
36
+ throw createError({
37
+ statusCode: 503,
38
+ statusMessage: "BRAIN_JOBS_SECRET is required",
39
+ });
40
+ }
41
+ if (
42
+ secret &&
43
+ !scheduled &&
44
+ !headerMatchesSecret(getHeader(event, "authorization"), secret)
45
+ ) {
46
+ throw createError({ statusCode: 401, statusMessage: "Unauthorized" });
47
+ }
48
+
49
+ const [sync, queue, expiredSensitivityQuarantines] = await Promise.all([
50
+ syncDueBrainSourcesOnce({ system: true, limit: 5 }),
51
+ processBrainIngestQueueOnce({ limit: 1, runDistillation: true }),
52
+ expireSensitivityQuarantines(),
53
+ ]);
54
+ return { ok: true, sync, queue, expiredSensitivityQuarantines };
55
+ });
@@ -85,7 +85,10 @@ in the moment of agent use.
85
85
  approval, generative UI, progress, and screen-state exposure.
86
86
  - **Chat history kit**: presentational chat lists and recent-chat rails belong
87
87
  in Toolkit; Core keeps thread persistence, agent execution, transport, and
88
- page-to-sidebar handoff. Apps inject routing, labels, and domain actions.
88
+ page-to-sidebar handoff. Use Toolkit's `ChatHistoryRail` for the standard
89
+ five-item sidebar preview and a footer row with New chat followed by an
90
+ ellipsis disclosure up to fifteen. Apps inject routing, labels, and domain
91
+ actions.
89
92
  - **Agent page kit**: the full-page `/agent` surface (`AgentTabsPage` from
90
93
  `@agent-native/core/client`) with Context, Files, Connections, Jobs, and
91
94
  Access tabs plus a Personal/Organization scope toggle. The canonical home
@@ -72,7 +72,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
72
72
  });
73
73
  ```
74
74
 
75
- `useDbSync` and every `subscribeSyncEvents` subscriber share one `EventSource` and one fallback poll loop per tab — this is how collaborative documents receive doc updates and cursor/awareness events.
75
+ `useDbSync` and every `subscribeSyncEvents` subscriber share one `EventSource` and one fallback poll loop per tab — this is how collaborative documents receive doc updates and cursor/awareness events. Hidden tabs keep that shared transport alive by default: SSE stays connected and active fallback polling relaxes to a 10-second floor (idle polling remains once per minute). Pass `pauseWhenHidden: true` only for a consumer that explicitly must stop all hidden-tab sync.
76
76
 
77
77
  ## Which sources to depend on
78
78
 
@@ -85,7 +85,10 @@ in the moment of agent use.
85
85
  approval, generative UI, progress, and screen-state exposure.
86
86
  - **Chat history kit**: presentational chat lists and recent-chat rails belong
87
87
  in Toolkit; Core keeps thread persistence, agent execution, transport, and
88
- page-to-sidebar handoff. Apps inject routing, labels, and domain actions.
88
+ page-to-sidebar handoff. Use Toolkit's `ChatHistoryRail` for the standard
89
+ five-item sidebar preview and a footer row with New chat followed by an
90
+ ellipsis disclosure up to fifteen. Apps inject routing, labels, and domain
91
+ actions.
89
92
  - **Agent page kit**: the full-page `/agent` surface (`AgentTabsPage` from
90
93
  `@agent-native/core/client`) with Context, Files, Connections, Jobs, and
91
94
  Access tabs plus a Personal/Organization scope toggle. The canonical home
@@ -72,7 +72,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
72
72
  });
73
73
  ```
74
74
 
75
- `useDbSync` and every `subscribeSyncEvents` subscriber share one `EventSource` and one fallback poll loop per tab — this is how collaborative documents receive doc updates and cursor/awareness events.
75
+ `useDbSync` and every `subscribeSyncEvents` subscriber share one `EventSource` and one fallback poll loop per tab — this is how collaborative documents receive doc updates and cursor/awareness events. Hidden tabs keep that shared transport alive by default: SSE stays connected and active fallback polling relaxes to a 10-second floor (idle polling remains once per minute). Pass `pauseWhenHidden: true` only for a consumer that explicitly must stop all hidden-tab sync.
76
76
 
77
77
  ## Which sources to depend on
78
78
 
@@ -60,6 +60,7 @@ export function Layout({ children }: LayoutProps) {
60
60
  useAgentChatHomeHandoffLinks({
61
61
  storageKey: "chat",
62
62
  isChatPath: (pathname) => pathname === "/" || pathname.startsWith("/chat/"),
63
+ requireActiveHandoff: false,
63
64
  });
64
65
 
65
66
  useEffect(() => {
@@ -9,7 +9,7 @@ import { useT } from "@agent-native/core/client/i18n";
9
9
  import { OrgSwitcher } from "@agent-native/core/client/org";
10
10
  import { FeedbackButton } from "@agent-native/core/client/ui";
11
11
  import {
12
- ChatHistoryList,
12
+ ChatHistoryRail,
13
13
  type ChatHistoryItem,
14
14
  } from "@agent-native/toolkit/chat-history";
15
15
  import {
@@ -17,7 +17,6 @@ import {
17
17
  IconLayoutSidebarLeftCollapse,
18
18
  IconLayoutSidebarLeftExpand,
19
19
  IconMessageCircle,
20
- IconPlus,
21
20
  IconSettings,
22
21
  } from "@tabler/icons-react";
23
22
  import { useEffect, useMemo } from "react";
@@ -104,6 +103,12 @@ function persistedActiveThreadId() {
104
103
  }
105
104
  }
106
105
 
106
+ function persistActiveThreadId(threadId: string) {
107
+ try {
108
+ localStorage.setItem(CHAT_ACTIVE_THREAD_KEY, threadId);
109
+ } catch {}
110
+ }
111
+
107
112
  function threadIdFromPath(pathname: string) {
108
113
  const match = pathname.match(/^\/chat\/([^/]+)/);
109
114
  if (!match) return null;
@@ -142,7 +147,7 @@ function ChatThreadsSection() {
142
147
  threads
143
148
  .filter((thread) => thread.messageCount > 0 && !thread.archivedAt)
144
149
  .sort(compareThreads)
145
- .slice(0, 12),
150
+ .slice(0, 15),
146
151
  [threads],
147
152
  );
148
153
  const displayedActiveThreadId =
@@ -184,6 +189,7 @@ function ChatThreadsSection() {
184
189
 
185
190
  function openThread(threadId: string, options?: { isNew?: boolean }) {
186
191
  switchThread(threadId);
192
+ persistActiveThreadId(threadId);
187
193
  navigateWithAgentChatViewTransition(
188
194
  navigate,
189
195
  options?.isNew ? "/" : chatThreadPath(threadId),
@@ -223,50 +229,35 @@ function ChatThreadsSection() {
223
229
 
224
230
  return (
225
231
  <div className="mt-2 border-s border-sidebar-border/70 ps-3">
226
- <div className="mb-1 flex h-7 items-center gap-2 pe-1">
227
- <div className="min-w-0 flex-1 text-xs font-medium text-sidebar-foreground/70">
228
- {t("chat.chats")}
229
- </div>
230
- <Tooltip>
231
- <TooltipTrigger asChild>
232
- <button
233
- type="button"
234
- onClick={handleNewChat}
235
- className="flex size-6 shrink-0 items-center justify-center rounded-md text-sidebar-foreground/65 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
236
- aria-label={t("chat.newChat")}
237
- >
238
- <IconPlus className="size-3.5" />
239
- </button>
240
- </TooltipTrigger>
241
- <TooltipContent>{t("chat.newChat")}</TooltipContent>
242
- </Tooltip>
243
- </div>
244
- {visibleThreads.length > 0 && (
245
- <ChatHistoryList
246
- items={chatItems}
247
- activeId={displayedActiveThreadId}
248
- onSelect={(threadId) => openThread(threadId)}
249
- renameMaxLength={160}
250
- onTogglePin={(threadId) => {
251
- const thread = visibleThreads.find((item) => item.id === threadId);
252
- if (thread) void pinThread(threadId, !thread.pinnedAt);
253
- }}
254
- onRename={handleRenameThread}
255
- onDelete={(threadId) => void handleArchiveThread(threadId)}
256
- labels={{
257
- options: (item) =>
258
- t("chat.optionsFor", { title: item.titleText ?? "" }),
259
- renameInput: (item) =>
260
- t("chat.renameThread", { title: item.titleText ?? "" }),
261
- rename: t("chat.renameChat"),
262
- pin: t("chat.pinChat"),
263
- unpin: t("chat.unpinChat"),
264
- delete: t("chat.archiveChat"),
265
- }}
266
- variant="rail"
267
- className="min-w-0"
268
- />
269
- )}
232
+ <ChatHistoryRail
233
+ items={chatItems}
234
+ activeId={displayedActiveThreadId}
235
+ onSelect={(threadId) => openThread(threadId)}
236
+ onNewChat={() => void handleNewChat()}
237
+ railLabels={{
238
+ newChat: t("chat.newChat"),
239
+ showMore: t("chat.chats"),
240
+ showLess: t("chat.chats"),
241
+ }}
242
+ renameMaxLength={160}
243
+ onTogglePin={(threadId) => {
244
+ const thread = visibleThreads.find((item) => item.id === threadId);
245
+ if (thread) void pinThread(threadId, !thread.pinnedAt);
246
+ }}
247
+ onRename={handleRenameThread}
248
+ onDelete={(threadId) => void handleArchiveThread(threadId)}
249
+ labels={{
250
+ options: (item) =>
251
+ t("chat.optionsFor", { title: item.titleText ?? "" }),
252
+ renameInput: (item) =>
253
+ t("chat.renameThread", { title: item.titleText ?? "" }),
254
+ rename: t("chat.renameChat"),
255
+ pin: t("chat.pinChat"),
256
+ unpin: t("chat.unpinChat"),
257
+ delete: t("chat.archiveChat"),
258
+ }}
259
+ className="min-w-0"
260
+ />
270
261
  </div>
271
262
  );
272
263
  }
@@ -445,28 +436,13 @@ export function Sidebar({
445
436
  />
446
437
  </div>
447
438
 
448
- <div
449
- className={cn(
450
- collapsed ? "flex justify-center px-1 py-1" : "px-3 py-2",
451
- )}
452
- >
453
- <FeedbackButton
454
- variant={collapsed ? "icon" : "sidebar"}
455
- side="right"
456
- align={collapsed ? "center" : "end"}
457
- />
458
- </div>
459
-
460
- {collapseButton ? (
461
- <div
462
- className={cn(
463
- collapsed
464
- ? "flex justify-center px-1 py-1"
465
- : "flex justify-end px-3 py-2",
466
- )}
467
- >
439
+ {!collapsed ? (
440
+ <div className="flex items-center justify-end gap-1 px-3 py-2">
441
+ <FeedbackButton className="min-w-0 flex-1" side="right" />
468
442
  {collapseButton}
469
443
  </div>
444
+ ) : collapseButton ? (
445
+ <div className="flex justify-center px-1 py-1">{collapseButton}</div>
470
446
  ) : null}
471
447
  </div>
472
448
  </aside>
@@ -1,7 +1,4 @@
1
- import {
2
- isAgentChatHomeHandoffActive,
3
- markAgentChatHomeHandoff,
4
- } from "@agent-native/core/client/agent-chat";
1
+ import { markAgentChatHomeHandoff } from "@agent-native/core/client/agent-chat";
5
2
  import { appBasePath, appPath } from "@agent-native/core/client/api-path";
6
3
  import { useAgentRouteState } from "@agent-native/core/client/navigation";
7
4
  import { useLocation } from "react-router";
@@ -34,9 +31,7 @@ export function useNavigationState() {
34
31
  isChatPath(location.pathname) &&
35
32
  !isChatPath(pathnameFromPath(path))
36
33
  ) {
37
- if (isAgentChatHomeHandoffActive("chat")) {
38
- markAgentChatHomeHandoff("chat");
39
- }
34
+ markAgentChatHomeHandoff("chat");
40
35
  }
41
36
  },
42
37
  });
@@ -36,6 +36,13 @@ export default function ChatRoute() {
36
36
  const { threadId } = useParams();
37
37
  const navigate = useNavigate();
38
38
  const t = useT();
39
+ const threadUrlSync = threadId
40
+ ? {
41
+ routeThreadId: threadId,
42
+ getPath: chatThreadPath,
43
+ navigate,
44
+ }
45
+ : undefined;
39
46
 
40
47
  useEffect(() => {
41
48
  function handleChatRunning(event: Event) {
@@ -56,11 +63,7 @@ export default function ChatRoute() {
56
63
  className="h-full"
57
64
  defaultMode="chat"
58
65
  storageKey="chat"
59
- threadUrlSync={{
60
- routeThreadId: threadId ?? null,
61
- getPath: chatThreadPath,
62
- navigate,
63
- }}
66
+ threadUrlSync={threadUrlSync}
64
67
  browserTabId={TAB_ID}
65
68
  showHeader={false}
66
69
  showTabBar={false}
@@ -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: improved
3
+ date: 2026-07-22
4
+ ---
5
+
6
+ Recent chats now expand from a compact five-item list with New chat anchored at the bottom.
@@ -85,7 +85,10 @@ in the moment of agent use.
85
85
  approval, generative UI, progress, and screen-state exposure.
86
86
  - **Chat history kit**: presentational chat lists and recent-chat rails belong
87
87
  in Toolkit; Core keeps thread persistence, agent execution, transport, and
88
- page-to-sidebar handoff. Apps inject routing, labels, and domain actions.
88
+ page-to-sidebar handoff. Use Toolkit's `ChatHistoryRail` for the standard
89
+ five-item sidebar preview and a footer row with New chat followed by an
90
+ ellipsis disclosure up to fifteen. Apps inject routing, labels, and domain
91
+ actions.
89
92
  - **Agent page kit**: the full-page `/agent` surface (`AgentTabsPage` from
90
93
  `@agent-native/core/client`) with Context, Files, Connections, Jobs, and
91
94
  Access tabs plus a Personal/Organization scope toggle. The canonical home
@@ -69,7 +69,15 @@ ladder.
69
69
  current-user recordings with ready transcripts in the active organization
70
70
  and reports exported, quarantined, skipped, and failed counts. Both
71
71
  `BRAIN_INGEST_URL` and `BRAIN_INGEST_TOKEN` must be available as scoped Clips
72
- secrets.
72
+ secrets. Transcript completion persists a pending export before handing it to
73
+ the durable post-finalize worker; delivery receipts include the Brain capture
74
+ or sensitivity receipt id, while transient failures are swept and retried.
75
+ The sweep also discovers ready transcripts from the last seven days that
76
+ predate export-state tracking, in bounded batches, so recent recordings are
77
+ backfilled after the connection is configured.
78
+ Netlify builds emit a protected per-minute scheduled sweep because in-process
79
+ intervals are not durable there. Other serverless hosts must invoke
80
+ `runBrainExportSweepOnce` from their own scheduler.
73
81
  - The transcript embedded by `view-screen` is a bounded preview. If
74
82
  `previewTruncated` is true, it may end mid-sentence and does not show where
75
83
  transcription ended. Call `get-recording-player-data` before judging
@@ -18,6 +18,7 @@ import { and, asc, eq, gt, gte, isNull, lte, or, sql } from "drizzle-orm";
18
18
  import { z } from "zod";
19
19
 
20
20
  import { getDb, schema } from "../server/db/index.js";
21
+ import { writeBrainExportState } from "../server/lib/brain-export-state.js";
21
22
  import {
22
23
  getActiveOrganizationId,
23
24
  getCurrentOwnerEmail,
@@ -232,6 +233,11 @@ async function buildPayload(
232
233
  .orderBy(asc(schema.recordingTags.tag)),
233
234
  ]);
234
235
 
236
+ const summary = meeting?.summaryMd?.trim();
237
+ const captureText = summary
238
+ ? `Summary\n${summary}\n\nTranscript\n${transcriptText}`
239
+ : transcriptText;
240
+
235
241
  return {
236
242
  sourceKey: "clips",
237
243
  externalId: `clips:recording:${recording.id}`,
@@ -246,7 +252,7 @@ async function buildPayload(
246
252
  meeting?.scheduledStart ||
247
253
  recording.createdAt ||
248
254
  new Date().toISOString(),
249
- transcript: transcriptText,
255
+ transcript: captureText,
250
256
  segments,
251
257
  sourceUrl: resolveSourceUrl(recording.id),
252
258
  tags: tags.map((row) => row.tag).filter(Boolean),
@@ -346,14 +352,17 @@ async function exportRecording(
346
352
  recording: Recording,
347
353
  transcript: RecordingTranscript,
348
354
  destination: BrainDestination,
355
+ attempt = 1,
349
356
  ): Promise<BrainExportResult> {
350
357
  const payload = await buildPayload(recording, transcript);
351
358
  if (!payload) {
352
- return {
359
+ const result: BrainExportResult = {
353
360
  recordingId: recording.id,
354
361
  status: "skipped",
355
362
  reason: "empty-transcript",
356
363
  };
364
+ await persistBrainExportResult(result, attempt);
365
+ return result;
357
366
  }
358
367
 
359
368
  try {
@@ -370,7 +379,9 @@ async function exportRecording(
370
379
  },
371
380
  { maxRedirects: 0 },
372
381
  );
373
- return interpretBrainResponse(recording.id, response);
382
+ const result = await interpretBrainResponse(recording.id, response);
383
+ await persistBrainExportResult(result, attempt);
384
+ return result;
374
385
  } catch (err) {
375
386
  const reason =
376
387
  (err as Error)?.name === "TimeoutError" ||
@@ -382,10 +393,65 @@ async function exportRecording(
382
393
  reason,
383
394
  error: (err as Error)?.message ?? String(err),
384
395
  });
385
- return { recordingId: recording.id, status: "failed", reason };
396
+ const result: BrainExportResult = {
397
+ recordingId: recording.id,
398
+ status: "failed",
399
+ reason,
400
+ };
401
+ await persistBrainExportResult(result, attempt);
402
+ return result;
386
403
  }
387
404
  }
388
405
 
406
+ async function persistBrainExportResult(
407
+ result: BrainExportResult,
408
+ attempts: number,
409
+ ): Promise<void> {
410
+ const updatedAt = new Date().toISOString();
411
+ await writeBrainExportState({
412
+ recordingId: result.recordingId,
413
+ status: result.status,
414
+ attempts,
415
+ updatedAt,
416
+ ...(result.status === "exported" ? { captureId: result.captureId } : {}),
417
+ ...(result.status === "quarantined"
418
+ ? {
419
+ sensitivityReceiptId: result.sensitivityReceiptId,
420
+ sensitivityDisposition: result.sensitivityDisposition,
421
+ }
422
+ : {}),
423
+ ...(result.status === "failed"
424
+ ? {
425
+ reason: result.reason,
426
+ nextAttemptAt: new Date(
427
+ Date.now() +
428
+ Math.min(15 * 60_000, 30_000 * 2 ** Math.max(0, attempts - 1)),
429
+ ).toISOString(),
430
+ }
431
+ : result.status === "skipped"
432
+ ? { reason: result.reason }
433
+ : {}),
434
+ });
435
+ }
436
+
437
+ async function persistRetryableBrainExportFailure(
438
+ recordingId: string,
439
+ reason: string,
440
+ attempts: number,
441
+ ): Promise<void> {
442
+ await writeBrainExportState({
443
+ recordingId,
444
+ status: "failed",
445
+ attempts,
446
+ reason,
447
+ updatedAt: new Date().toISOString(),
448
+ nextAttemptAt: new Date(
449
+ Date.now() +
450
+ Math.min(15 * 60_000, 30_000 * 2 ** Math.max(0, attempts - 1)),
451
+ ).toISOString(),
452
+ });
453
+ }
454
+
389
455
  async function mapWithConcurrency<T, R>(
390
456
  values: T[],
391
457
  concurrency: number,
@@ -535,6 +601,7 @@ export default defineAction({
535
601
  .min(1)
536
602
  .max(8)
537
603
  .default(DEFAULT_CONCURRENCY),
604
+ retryAttempt: z.coerce.number().int().min(1).max(8).optional(),
538
605
  cursor: z
539
606
  .string()
540
607
  .min(1)
@@ -552,11 +619,17 @@ export default defineAction({
552
619
  );
553
620
  const destinationResult = await resolveBrainDestination();
554
621
  if (!destinationResult.destination) {
555
- return {
622
+ const result: BrainExportResult = {
556
623
  recordingId: args.recordingId,
557
624
  status: "skipped" as const,
558
625
  reason: destinationResult.reason,
559
626
  };
627
+ await persistRetryableBrainExportFailure(
628
+ result.recordingId,
629
+ result.reason,
630
+ 0,
631
+ );
632
+ return result;
560
633
  }
561
634
  const [transcript] = await getDb()
562
635
  .select()
@@ -564,16 +637,19 @@ export default defineAction({
564
637
  .where(eq(schema.recordingTranscripts.recordingId, args.recordingId))
565
638
  .limit(1);
566
639
  if (!transcript) {
567
- return {
640
+ const result: BrainExportResult = {
568
641
  recordingId: args.recordingId,
569
642
  status: "skipped" as const,
570
643
  reason: "empty-transcript",
571
644
  };
645
+ await persistBrainExportResult(result, args.retryAttempt ?? 0);
646
+ return result;
572
647
  }
573
648
  return exportRecording(
574
649
  access.resource as Recording,
575
650
  transcript,
576
651
  destinationResult.destination,
652
+ args.retryAttempt ?? 1,
577
653
  );
578
654
  }
579
655
 
@@ -53,6 +53,7 @@ import { and, eq } from "drizzle-orm";
53
53
  import { z } from "zod";
54
54
 
55
55
  import { getDb, schema } from "../server/db/index.js";
56
+ import { writeBrainExportState } from "../server/lib/brain-export-state.js";
56
57
  import { dispatchPostFinalizeJob } from "../server/lib/post-finalize-dispatch.js";
57
58
  import {
58
59
  getCurrentOwnerEmail,
@@ -66,7 +67,6 @@ import {
66
67
  parseTranscriptSegments,
67
68
  } from "../shared/transcript-segments.js";
68
69
  import cleanupTranscript from "./cleanup-transcript.js";
69
- import exportToBrain from "./export-to-brain.js";
70
70
  import { loadAgentsMdContext } from "./lib/agents-md-context.js";
71
71
  import {
72
72
  AudioOnlyExtractionError,
@@ -309,15 +309,26 @@ function scheduleAutoTranscriptRetry({
309
309
  });
310
310
  }
311
311
 
312
- function queueBrainExport(recordingId: string): void {
313
- void Promise.resolve(exportToBrain.run({ recordingId })).catch(
314
- (err: unknown) => {
315
- console.warn(
316
- `[clips] Brain export skipped for ${recordingId}:`,
317
- (err as Error)?.message ?? String(err),
318
- );
319
- },
320
- );
312
+ async function queueBrainExport(recordingId: string): Promise<void> {
313
+ await writeBrainExportState({
314
+ recordingId,
315
+ status: "pending",
316
+ attempts: 0,
317
+ updatedAt: new Date().toISOString(),
318
+ nextAttemptAt: new Date(Date.now() + 60_000).toISOString(),
319
+ });
320
+ try {
321
+ await dispatchPostFinalizeJob({
322
+ recordingId,
323
+ kind: "brain-export",
324
+ requireAccepted: true,
325
+ });
326
+ } catch (error) {
327
+ console.warn(
328
+ `[clips] Brain export dispatch failed for ${recordingId}:`,
329
+ error instanceof Error ? error.message : String(error),
330
+ );
331
+ }
321
332
  }
322
333
 
323
334
  function verboseTranscriptErrors(): boolean {
@@ -542,7 +553,7 @@ export async function importLoomTranscriptForRecording({
542
553
  now,
543
554
  });
544
555
  await writeAppState("refresh-signal", { ts: Date.now() });
545
- queueBrainExport(recordingId);
556
+ await queueBrainExport(recordingId);
546
557
  return {
547
558
  recordingId,
548
559
  status: "ready" as const,
@@ -955,7 +966,7 @@ async function completeReadyTranscript({
955
966
  // (`transcript-cleanup-${recordingId}`) before its next 2s tick lands —
956
967
  // otherwise the "Cleaning up…" badge can lag for one full poll interval.
957
968
  await writeAppState("refresh-signal", { ts: Date.now() });
958
- queueBrainExport(recordingId);
969
+ await queueBrainExport(recordingId);
959
970
 
960
971
  return {
961
972
  recordingId,
@@ -1385,7 +1396,7 @@ const requestTranscriptAction = defineAction({
1385
1396
  now,
1386
1397
  });
1387
1398
  await writeAppState("refresh-signal", { ts: Date.now() });
1388
- queueBrainExport(args.recordingId);
1399
+ await queueBrainExport(args.recordingId);
1389
1400
  await clearBuilderCreditsExhausted();
1390
1401
 
1391
1402
  // Re-read title fresh — `rec.title` was fetched before the 30+ s
@@ -1647,7 +1658,7 @@ const requestTranscriptAction = defineAction({
1647
1658
  });
1648
1659
 
1649
1660
  await writeAppState("refresh-signal", { ts: Date.now() });
1650
- queueBrainExport(args.recordingId);
1661
+ await queueBrainExport(args.recordingId);
1651
1662
 
1652
1663
  // Generate transcript-backed metadata without replacing a human title or
1653
1664
  // description. The title action keeps any local heuristic replaceable
@@ -7,6 +7,7 @@ import {
7
7
  IconCheck,
8
8
  IconCopy,
9
9
  IconLock,
10
+ IconSend2,
10
11
  IconTrash,
11
12
  IconUsersGroup,
12
13
  IconWorld,
@@ -414,6 +415,17 @@ export function SharePeopleTab({
414
415
  ))}
415
416
  </SelectContent>
416
417
  </Select>
418
+ <Button
419
+ type="button"
420
+ size="icon"
421
+ onClick={handleAdd}
422
+ disabled={!hasInviteEmail || share.isPending}
423
+ aria-label={t("shareUi.invite")}
424
+ title={t("shareUi.invite")}
425
+ className="h-9 w-9 shrink-0"
426
+ >
427
+ <IconSend2 size={16} />
428
+ </Button>
417
429
  </div>
418
430
  {hasInviteEmail ? (
419
431
  <label className="flex items-center gap-2 text-xs text-muted-foreground">
@@ -481,6 +481,7 @@ const messages = {
481
481
  makePublicAndCopy: "Make public and copy",
482
482
  copy: "Copy",
483
483
  addPeopleByEmail: "Add people by email",
484
+ invite: "Invite",
484
485
  notifyPeople: "Notify people",
485
486
  peopleWithAccess: "People with access",
486
487
  ownerRole: "Owner",