@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
@@ -467,10 +467,6 @@ function renderConnectPage(params: {
467
467
  });
468
468
  const safeMcpUrl = escapeHtml(mcpUrl);
469
469
  const connectTemplateValues = { appName, appUrl, mcpUrl, serverId };
470
- const brandMarkSvg = agentNativeMarkSvg(
471
- "brand-mark",
472
- "agent-native-connect-brand-gradient",
473
- );
474
470
  const flowMarkSvg = agentNativeMarkSvg(
475
471
  "flow-mark",
476
472
  "agent-native-connect-flow-gradient",
@@ -561,21 +557,6 @@ function renderConnectPage(params: {
561
557
  0 30px 90px rgba(0,0,0,0.5);
562
558
  padding: 1.25rem;
563
559
  }
564
- .topbar {
565
- display: flex; align-items: center; justify-content: space-between;
566
- gap: 0.75rem; margin-bottom: 1.75rem;
567
- }
568
- .brand-lockup {
569
- display: flex; align-items: center; gap: 0.55rem;
570
- color: var(--muted); font-size: 0.78rem; font-weight: 600;
571
- }
572
- .brand-mark { width: 18px; height: auto; display: block; }
573
- .app-pill {
574
- max-width: 50%; border: 1px solid var(--border);
575
- border-radius: 999px; padding: 0.28rem 0.55rem;
576
- color: var(--subtle); font-size: 0.72rem; line-height: 1;
577
- overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
578
- }
579
560
  .hero { padding: 0 0.75rem; text-align: center; }
580
561
  .flow {
581
562
  display: flex; align-items: center; justify-content: center;
@@ -597,11 +578,6 @@ function renderConnectPage(params: {
597
578
  background: linear-gradient(90deg, transparent, var(--border-strong), transparent);
598
579
  background-position: center;
599
580
  }
600
- .eyebrow {
601
- text-align: center; font-size: 0.72rem; font-weight: 600;
602
- letter-spacing: 0.08em; text-transform: uppercase;
603
- color: var(--subtle); margin-bottom: 0.55rem;
604
- }
605
581
  h1 {
606
582
  text-align: center; font-size: 1.45rem; font-weight: 680;
607
583
  line-height: 1.25; margin-bottom: 0.7rem;
@@ -714,8 +690,7 @@ function renderConnectPage(params: {
714
690
  .connections-title { font-weight: 600; color: var(--muted); }
715
691
  .connections-state {
716
692
  margin-left: auto; color: var(--subtle); font-size: 0.73rem;
717
- border: 1px solid var(--border); border-radius: 999px;
718
- padding: 0.18rem 0.45rem; line-height: 1;
693
+ line-height: 1;
719
694
  }
720
695
  .connections .chev {
721
696
  width: 7px; height: 7px; border-right: 1.5px solid currentColor;
@@ -738,8 +713,16 @@ function renderConnectPage(params: {
738
713
  margin-bottom: 0.9rem; display: none; line-height: 1.4; }
739
714
  .msg.err { display: block; color: var(--error); background: var(--error-bg);
740
715
  border: 1px solid rgba(252,165,165,0.16); }
741
- .msg.ok { display: block; color: var(--ok); background: var(--ok-bg);
716
+ .msg.ok { display: block; background: var(--ok-bg);
742
717
  border: 1px solid var(--ok-border); }
718
+ .msg-title {
719
+ display: block; color: var(--ok); font-size: 0.95rem;
720
+ font-weight: 700; line-height: 1.25;
721
+ }
722
+ .msg-copy {
723
+ display: block; color: rgba(134,239,172,0.72); font-size: 0.78rem;
724
+ line-height: 1.4; margin-top: 0.2rem;
725
+ }
743
726
  .result-panel { padding-top: 0.15rem; }
744
727
  .result-title {
745
728
  color: var(--text); font-size: 0.95rem; font-weight: 650;
@@ -757,9 +740,7 @@ function renderConnectPage(params: {
757
740
  body { align-items: flex-start; padding: 0.75rem; }
758
741
  .card { padding: 1rem; }
759
742
  .hero { padding: 0; }
760
- .topbar { margin-bottom: 1.35rem; }
761
743
  h1 { font-size: 1.3rem; }
762
- .app-pill { max-width: 46%; }
763
744
  pre { font-size: 0.72rem; }
764
745
  }
765
746
  /* MCP URL display + per-host tabs (the non-dev path). */
@@ -861,9 +842,6 @@ function renderConnectPage(params: {
861
842
  border-color: var(--ok-border) !important;
862
843
  }
863
844
  .static-token-mint .static-token-body { padding-top: 0.5rem; }
864
- .static-token-mint > summary .connections-state {
865
- font-style: normal;
866
- }
867
845
  @media (min-width: 560px) {
868
846
  .card { max-width: 580px; }
869
847
  }
@@ -872,17 +850,8 @@ function renderConnectPage(params: {
872
850
  </head>
873
851
  <body>
874
852
  <div class="card">
875
- <div class="topbar">
876
- <div class="brand-lockup">
877
- ${brandMarkSvg}
878
- <span>Agent Native</span>
879
- </div>
880
- <div class="app-pill" title="${safeApp}">${safeApp}</div>
881
- </div>
882
-
883
853
  <div class="hero">
884
- <!-- "Connect an external agent" is kept as the accessible consent label. -->
885
- <div class="flow" role="img" aria-label="Connect an external agent to ${safeApp}">
854
+ <div class="flow" role="img" aria-label="Authorize ${safeApp}">
886
855
  <span class="tile" aria-hidden="true">
887
856
  ${flowMarkSvg}
888
857
  </span>
@@ -892,7 +861,6 @@ function renderConnectPage(params: {
892
861
  </span>
893
862
  </div>
894
863
 
895
- <div class="eyebrow">Connect an external agent</div>
896
864
  <h1>${safeUserCode ? `Authorize ${safeApp} from your terminal?` : `Use ${safeApp} from your AI assistant`}</h1>
897
865
  <p class="identity">
898
866
  <span>Signed in as <strong>${safeEmail}</strong></span>
@@ -909,7 +877,6 @@ function renderConnectPage(params: {
909
877
  <details id="staticTokenMint" class="connections static-token-mint"${safeUserCode ? " open" : ""}>
910
878
  <summary>
911
879
  <span class="connections-title">${safeUserCode ? "Authorize this device" : MCP_STATIC_TOKEN_FALLBACK.title}</span>
912
- <span class="connections-state">${safeUserCode ? "From your terminal" : MCP_STATIC_TOKEN_FALLBACK.state}</span>
913
880
  <span class="chev" aria-hidden="true"></span>
914
881
  </summary>
915
882
  <div class="static-token-body">
@@ -939,7 +906,7 @@ function renderConnectPage(params: {
939
906
  <details id="connections" class="connections">
940
907
  <summary>
941
908
  <span class="connections-title">Existing connections</span>
942
- <span id="connectionsState" class="connections-state">Checking</span>
909
+ <span id="connectionsState" class="connections-state hidden" aria-live="polite"></span>
943
910
  <span class="chev" aria-hidden="true"></span>
944
911
  </summary>
945
912
  <div id="tokenList" class="token-list"><div class="empty-state">Checking connections...</div></div>
@@ -990,8 +957,20 @@ function renderConnectPage(params: {
990
957
  }, 1400);
991
958
  });
992
959
  });
993
- function showMsg(text, kind) {
994
- msgEl.textContent = text;
960
+ function showMsg(text, kind, title) {
961
+ msgEl.textContent = "";
962
+ if (title) {
963
+ var titleEl = document.createElement("strong");
964
+ titleEl.className = "msg-title";
965
+ titleEl.textContent = title;
966
+ msgEl.appendChild(titleEl);
967
+ var copyEl = document.createElement("span");
968
+ copyEl.className = "msg-copy";
969
+ copyEl.textContent = text;
970
+ msgEl.appendChild(copyEl);
971
+ } else {
972
+ msgEl.textContent = text;
973
+ }
995
974
  msgEl.className = "msg " + (kind || "err");
996
975
  }
997
976
  function clearMsg() { msgEl.className = "msg"; msgEl.textContent = ""; }
@@ -1039,19 +1018,22 @@ function renderConnectPage(params: {
1039
1018
  var res = await fetch(BASE + "/tokens", { credentials: "same-origin" });
1040
1019
  if (!res.ok) {
1041
1020
  connectionsStateEl.textContent = "Unavailable";
1021
+ connectionsStateEl.classList.remove("hidden");
1042
1022
  listEl.innerHTML = '<div class="empty-state">Could not load connections.</div>';
1043
1023
  return;
1044
1024
  }
1045
1025
  var data = await res.json();
1046
1026
  var tokens = (data && data.tokens) || [];
1047
1027
  if (!tokens.length) {
1048
- connectionsStateEl.textContent = "None";
1028
+ connectionsStateEl.textContent = "";
1029
+ connectionsStateEl.classList.add("hidden");
1049
1030
  connectionsEl.open = false;
1050
1031
  listEl.innerHTML = '<div class="empty-state">Created connections will appear here for revoking later.</div>';
1051
1032
  return;
1052
1033
  }
1053
1034
  var activeCount = tokens.filter(function (t) { return !t.revokedAt; }).length;
1054
- connectionsStateEl.textContent = activeCount === 1 ? "1 active" : activeCount + " active";
1035
+ connectionsStateEl.textContent = activeCount ? String(activeCount) : "";
1036
+ connectionsStateEl.classList.toggle("hidden", activeCount === 0);
1055
1037
  listEl.innerHTML = "";
1056
1038
  tokens.forEach(function (t) {
1057
1039
  var div = document.createElement("div");
@@ -1082,6 +1064,7 @@ function renderConnectPage(params: {
1082
1064
  });
1083
1065
  } catch (e) {
1084
1066
  connectionsStateEl.textContent = "Unavailable";
1067
+ connectionsStateEl.classList.remove("hidden");
1085
1068
  listEl.innerHTML = '<div class="empty-state">Could not load connections.</div>';
1086
1069
  }
1087
1070
  }
@@ -1098,7 +1081,7 @@ function renderConnectPage(params: {
1098
1081
  showMsg((a.data && a.data.error) || "Could not authorize this device code.");
1099
1082
  return;
1100
1083
  }
1101
- showMsg("Device authorized — finishing connection… you can return to your terminal.", "ok");
1084
+ showMsg("Finishing connection… you can return to your terminal.", "ok", "Device authorized");
1102
1085
  btn.classList.add("hidden");
1103
1086
  document.getElementById("mintForm").classList.add("hidden");
1104
1087
  var cc = document.getElementById("codeCallout");
@@ -1133,7 +1116,7 @@ function renderConnectPage(params: {
1133
1116
  });
1134
1117
  if (fresh.length > 0) {
1135
1118
  clearInterval(iv);
1136
- showMsg("Connected. This device can now act as you — manage or revoke it below.", "ok");
1119
+ showMsg("This device can now act as you — manage or revoke it below.", "ok", "Connected");
1137
1120
  loadTokens();
1138
1121
  return;
1139
1122
  }
@@ -1100,7 +1100,7 @@ const PROVIDER_CONFIGS: Record<ProviderApiId, ProviderApiConfig> = {
1100
1100
  docsUrls: ["https://developers.google.com/drive/api/reference/rest/v3"],
1101
1101
  specUrls: ["https://www.googleapis.com/discovery/v1/apis/drive/v3/rest"],
1102
1102
  allowedHostSuffixes: ["googleapis.com"],
1103
- templateUses: ["brain", "content", "slides", "dispatch"],
1103
+ templateUses: ["brain", "content", "slides", "dispatch", "analytics"],
1104
1104
  examples: [
1105
1105
  { label: "List files", method: "GET", path: "/files" },
1106
1106
  { label: "Get file metadata", method: "GET", path: "/files/{fileId}" },
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Realtime SSE wire protocol — shared by the server SSE handlers (framework
3
+ * in-process path + the hosted Realtime Gateway) and the client transport.
4
+ *
5
+ * Pure constants, types, and parsers only — NO h3/node/browser deps — so both
6
+ * the Node server and the browser client import it.
7
+ *
8
+ * Frame taxonomy:
9
+ * - CHANGE / batch frames ride the default (unnamed) SSE `message` event and
10
+ * are parsed by the client's existing `normalizeEventPayload`. Unchanged.
11
+ * - CONTROL frames (handshake, token rotation) ride NAMED SSE events, so
12
+ * `EventSource.addEventListener(name)` routes them separately and an older
13
+ * client that only reads `onmessage` silently ignores them (backward safe).
14
+ */
15
+
16
+ export const REALTIME_PROTOCOL_VERSION = 1;
17
+
18
+ /** Named SSE event carrying the one-time handshake ({@link RealtimeHandshake}). */
19
+ export const REALTIME_SSE_HANDSHAKE_EVENT = "handshake";
20
+ /** Named SSE event carrying a rotated subscribe token ({@link RealtimeTokenFrame}). */
21
+ export const REALTIME_SSE_TOKEN_EVENT = "token";
22
+
23
+ /**
24
+ * Capability advertised by the hosted gateway: awareness/presence is NOT
25
+ * forwarded (it lives only on the in-process emitter, never in `sync_events`),
26
+ * so the collab client must keep its own presence cadence. The framework's
27
+ * in-process SSE path forwards awareness and therefore sends no handshake — the
28
+ * client treats an absent handshake as "all capabilities present."
29
+ */
30
+ export const REALTIME_CAP_NO_AWARENESS = "no-awareness";
31
+
32
+ export interface RealtimeHandshake {
33
+ protocol: number;
34
+ capabilities: string[];
35
+ }
36
+
37
+ export interface RealtimeTokenFrame {
38
+ token: string;
39
+ /** ISO expiry, informational; the client re-mints/rotates before this. */
40
+ expiresAt?: string;
41
+ }
42
+
43
+ export function buildHandshakeFrame(
44
+ capabilities: readonly string[] = [],
45
+ ): RealtimeHandshake {
46
+ return {
47
+ protocol: REALTIME_PROTOCOL_VERSION,
48
+ capabilities: [...capabilities],
49
+ };
50
+ }
51
+
52
+ export function parseHandshakeFrame(data: string): RealtimeHandshake | null {
53
+ try {
54
+ const parsed = JSON.parse(data);
55
+ if (
56
+ parsed &&
57
+ typeof parsed === "object" &&
58
+ typeof parsed.protocol === "number" &&
59
+ Array.isArray(parsed.capabilities)
60
+ ) {
61
+ return {
62
+ protocol: parsed.protocol,
63
+ capabilities: parsed.capabilities.filter(
64
+ (c: unknown): c is string => typeof c === "string",
65
+ ),
66
+ };
67
+ }
68
+ } catch {
69
+ // fall through
70
+ }
71
+ return null;
72
+ }
73
+
74
+ export function parseTokenFrame(data: string): RealtimeTokenFrame | null {
75
+ try {
76
+ const parsed = JSON.parse(data);
77
+ if (
78
+ parsed &&
79
+ typeof parsed === "object" &&
80
+ typeof parsed.token === "string"
81
+ ) {
82
+ return {
83
+ token: parsed.token,
84
+ expiresAt:
85
+ typeof parsed.expiresAt === "string" ? parsed.expiresAt : undefined,
86
+ };
87
+ }
88
+ } catch {
89
+ // fall through
90
+ }
91
+ return null;
92
+ }
@@ -5,7 +5,11 @@
5
5
  * ```ts
6
6
  * // server/plugins/collab.ts
7
7
  * import { createCollabPlugin } from "@agent-native/core/server";
8
- * export default createCollabPlugin({ table: "documents", contentColumn: "content" });
8
+ * export default createCollabPlugin({
9
+ * table: "documents",
10
+ * contentColumn: "content",
11
+ * access: { mode: "resource", resourceType: "document" },
12
+ * });
9
13
  * ```
10
14
  */
11
15
 
@@ -52,12 +56,47 @@ type CollabAwarenessScope = {
52
56
  resourceId?: string;
53
57
  };
54
58
 
59
+ export type CollabResourceIdResolver = (
60
+ docId: string,
61
+ ) => string | null | Promise<string | null>;
62
+
63
+ export type CollabAccess =
64
+ | {
65
+ mode: "resource";
66
+ /** The shareable resource type registered via `registerShareableResource`. */
67
+ resourceType: string;
68
+ /** Map a collab document id to its parent shareable resource id. */
69
+ resolveResourceId?: CollabResourceIdResolver;
70
+ }
71
+ | {
72
+ /** Deliver collaboration events to every authenticated user. */
73
+ mode: "all-authenticated";
74
+ };
75
+
76
+ type NormalizedCollabAccess =
77
+ | {
78
+ mode: "resource";
79
+ resourceType: string;
80
+ resolveResourceId?: CollabResourceIdResolver;
81
+ }
82
+ | {
83
+ mode: "all-authenticated";
84
+ explicit: boolean;
85
+ };
86
+
55
87
  /**
56
- * Whether the no-resourceType warning has already been logged once per server
57
- * process. Avoids flooding logs on every request in templates that deliberately
58
- * have no sharing model.
88
+ * Tables whose implicit all-authenticated warning has already been logged in
89
+ * this process. Avoids duplicate warnings during hot reloads while still
90
+ * identifying every affected table.
59
91
  */
60
- let _unscoped_warning_logged = false;
92
+ const COLLAB_WARNING_TABLES_KEY =
93
+ "__agentNativeImplicitCollabAccessWarningTables__";
94
+ const collabWarningGlobal = globalThis as typeof globalThis & {
95
+ [COLLAB_WARNING_TABLES_KEY]?: Set<string>;
96
+ };
97
+ const _unscoped_warning_tables = (collabWarningGlobal[
98
+ COLLAB_WARNING_TABLES_KEY
99
+ ] ??= new Set<string>());
61
100
 
62
101
  export interface CollabPluginOptions {
63
102
  /** Table name containing document content. Default: "documents" */
@@ -77,18 +116,25 @@ export interface CollabPluginOptions {
77
116
  contentType?: "text" | "json";
78
117
  /** Column name for JSON content (used when contentType is "json"). */
79
118
  jsonColumn?: string;
119
+ /**
120
+ * Access policy for collaboration routes and event delivery.
121
+ * Use `resource` for registered shareable resources, or explicitly choose
122
+ * `all-authenticated` for deployment-wide collaboration.
123
+ */
124
+ access?: CollabAccess;
80
125
  /**
81
126
  * The shareable resource type registered via `registerShareableResource`.
82
127
  * Used to enforce access checks on collab routes.
83
- * Omit only for resources that are always public (no sharing model).
128
+ * @deprecated Use `access: { mode: "resource", resourceType }`.
84
129
  */
85
130
  resourceType?: string;
86
131
  /**
87
132
  * Map the collab document id to the shareable resource id. Many templates
88
133
  * use route-specific collab ids (for example, one doc per slide inside a
89
134
  * deck) while sharing is enforced at the parent resource level.
135
+ * @deprecated Use `access: { mode: "resource", resourceType, resolveResourceId }`.
90
136
  */
91
- resolveResourceId?: (docId: string) => string | null | Promise<string | null>;
137
+ resolveResourceId?: CollabResourceIdResolver;
92
138
  /**
93
139
  * Maximum allowed body size in bytes for write operations
94
140
  * (update/text/json/patch). Requests exceeding this are rejected with 413.
@@ -97,18 +143,100 @@ export interface CollabPluginOptions {
97
143
  maxPayloadBytes?: number;
98
144
  }
99
145
 
146
+ export function normalizeCollabAccess(
147
+ options: Pick<
148
+ CollabPluginOptions,
149
+ "access" | "resourceType" | "resolveResourceId"
150
+ >,
151
+ ): NormalizedCollabAccess {
152
+ const hasLegacyAccess =
153
+ options.resourceType !== undefined ||
154
+ options.resolveResourceId !== undefined;
155
+
156
+ if (options.access && hasLegacyAccess) {
157
+ throw new Error(
158
+ 'createCollabPlugin cannot combine "access" with the deprecated root "resourceType" or "resolveResourceId" options. Move those fields into access.',
159
+ );
160
+ }
161
+
162
+ if (options.access?.mode === "resource") {
163
+ if (!options.access.resourceType.trim()) {
164
+ throw new Error(
165
+ 'createCollabPlugin access mode "resource" requires a non-empty resourceType.',
166
+ );
167
+ }
168
+ return options.access;
169
+ }
170
+
171
+ if (options.access?.mode === "all-authenticated") {
172
+ return { mode: "all-authenticated", explicit: true };
173
+ }
174
+
175
+ if (options.access) {
176
+ throw new Error(
177
+ `createCollabPlugin received an unsupported access mode: ${String((options.access as { mode?: unknown }).mode)}`,
178
+ );
179
+ }
180
+
181
+ if (options.resourceType !== undefined) {
182
+ if (!options.resourceType.trim()) {
183
+ throw new Error(
184
+ 'createCollabPlugin "resourceType" must be a non-empty string when provided.',
185
+ );
186
+ }
187
+ return {
188
+ mode: "resource",
189
+ resourceType: options.resourceType,
190
+ resolveResourceId: options.resolveResourceId,
191
+ };
192
+ }
193
+
194
+ if (options.resolveResourceId !== undefined) {
195
+ throw new Error(
196
+ 'createCollabPlugin "resolveResourceId" requires a non-empty "resourceType".',
197
+ );
198
+ }
199
+
200
+ return { mode: "all-authenticated", explicit: false };
201
+ }
202
+
203
+ function warnForImplicitAllAuthenticatedAccess(table: string): void {
204
+ if (_unscoped_warning_tables.has(table)) return;
205
+ _unscoped_warning_tables.add(table);
206
+ console.warn(
207
+ `[collab] WARNING: createCollabPlugin for table "${table}" does not declare an access policy. ` +
208
+ "Collab events will be delivered to ALL authenticated users on this deployment without document-level access scoping. " +
209
+ 'Use access: { mode: "resource", resourceType: "..." } for access-scoped delivery, ' +
210
+ 'or access: { mode: "all-authenticated" } to explicitly acknowledge deployment-wide delivery.',
211
+ );
212
+ }
213
+
100
214
  export function createCollabPlugin(
101
215
  options: CollabPluginOptions = {},
102
216
  ): NitroPluginDef {
217
+ const normalizedAccess = normalizeCollabAccess(options);
103
218
  const {
104
219
  table = "documents",
105
220
  contentColumn = "content",
106
221
  idColumn = "id",
107
222
  autoSeed = true,
108
- resourceType,
109
- resolveResourceId,
110
223
  maxPayloadBytes = DEFAULT_MAX_PAYLOAD_BYTES,
111
224
  } = options;
225
+ const resourceType =
226
+ normalizedAccess.mode === "resource"
227
+ ? normalizedAccess.resourceType
228
+ : undefined;
229
+ const resolveResourceId =
230
+ normalizedAccess.mode === "resource"
231
+ ? normalizedAccess.resolveResourceId
232
+ : undefined;
233
+
234
+ if (
235
+ normalizedAccess.mode === "all-authenticated" &&
236
+ !normalizedAccess.explicit
237
+ ) {
238
+ warnForImplicitAllAuthenticatedAccess(table);
239
+ }
112
240
 
113
241
  return async (nitroApp: any) => {
114
242
  await awaitBootstrap(nitroApp);
@@ -129,15 +257,6 @@ export function createCollabPlugin(
129
257
  // who don't match owner/org — instead of only degrading them to the
130
258
  // poll fallback.
131
259
  // See also: SECURITY comment in poll.ts on canSeeChangeForUser.
132
- if (!resourceType && !_unscoped_warning_logged) {
133
- _unscoped_warning_logged = true;
134
- console.warn(
135
- "[collab] WARNING: createCollabPlugin called without resourceType. " +
136
- "Collab events will be delivered to ALL authenticated users on this deployment " +
137
- "without document-level access scoping. Set resourceType to enable access-scoped delivery.",
138
- );
139
- }
140
-
141
260
  const collabEmitter = getCollabEmitter();
142
261
  collabEmitter.on("collab", async (event) => {
143
262
  if (!resourceType) {
@@ -170,6 +170,7 @@ import { handleIdentitySso } from "./identity-sso.js";
170
170
  import { createOpenRouteHandler } from "./open-route.js";
171
171
  import { createPollEventsHandler } from "./poll-events.js";
172
172
  import { createPollHandler } from "./poll.js";
173
+ import { createRealtimeTokenHandler } from "./realtime-token.js";
173
174
  import { runWithRequestContext } from "./request-context.js";
174
175
  import {
175
176
  findUnsupportedScopedKeyNames,
@@ -1414,6 +1415,12 @@ export function createCoreRoutesPlugin(
1414
1415
  // Polling
1415
1416
  getH3App(nitroApp).use(`${P}/poll`, createPollHandler());
1416
1417
 
1418
+ // Realtime subscribe-token mint (hosted gateway path)
1419
+ getH3App(nitroApp).use(
1420
+ `${P}/realtime-token`,
1421
+ createRealtimeTokenHandler(),
1422
+ );
1423
+
1417
1424
  // SSE
1418
1425
  if (!options.disableSSE) {
1419
1426
  for (const route of resolveFrameworkSseRoutes(options.sseRoute)) {
@@ -287,7 +287,9 @@ export {
287
287
  } from "../terminal/terminal-plugin.js";
288
288
  export {
289
289
  createCollabPlugin,
290
+ type CollabAccess,
290
291
  type CollabPluginOptions,
292
+ type CollabResourceIdResolver,
291
293
  } from "./collab-plugin.js";
292
294
 
293
295
  export {
@@ -7,10 +7,11 @@ import {
7
7
  } from "../collab/awareness.js";
8
8
  import { getSession } from "./auth.js";
9
9
  import {
10
+ type AppSyncState,
10
11
  canSeeChangeForUser,
11
- getPollEmitter,
12
- POLL_CHANGE_EVENT,
13
12
  type ChangeEvent,
13
+ getDefaultAppSyncState,
14
+ POLL_CHANGE_EVENT,
14
15
  } from "./poll.js";
15
16
 
16
17
  export function canSeeAwarenessChangeForUser(
@@ -37,8 +38,15 @@ export function canSeeAwarenessChangeForUser(
37
38
  * connected peers receive cursor moves push-style instead of waiting for
38
39
  * the next poll cycle. Polling fallback keeps working — cursors degrade
39
40
  * gracefully to poll cadence without SSE.
41
+ *
42
+ * `state` defaults to the process-wide instance so self-hosted apps are
43
+ * unchanged; the hosted gateway passes a per-app instance to fan out that
44
+ * app's events (awareness stays on the process-global emitter and is a v0
45
+ * gateway Non-Goal).
40
46
  */
41
- export function createPollEventsHandler() {
47
+ export function createPollEventsHandler(
48
+ state: AppSyncState = getDefaultAppSyncState(),
49
+ ) {
42
50
  return defineEventHandler(async (event) => {
43
51
  const session = await getSession(event).catch(() => null);
44
52
  if (!session?.email) {
@@ -60,7 +68,9 @@ export function createPollEventsHandler() {
60
68
 
61
69
  const push = (change: ChangeEvent) => {
62
70
  if (closed) return;
63
- if (!canSeeChangeForUser(change, session.email, session.orgId)) return;
71
+ if (!state.canSeeChangeForUser(change, session.email, session.orgId)) {
72
+ return;
73
+ }
64
74
  safePush(JSON.stringify(change));
65
75
  };
66
76
 
@@ -74,13 +84,24 @@ export function createPollEventsHandler() {
74
84
  safePush(JSON.stringify(change));
75
85
  };
76
86
 
77
- getPollEmitter().on(POLL_CHANGE_EVENT, push);
78
- getAwarenessEmitter().on(AWARENESS_CHANGE_EVENT, pushAwareness);
87
+ state.getPollEmitter().on(POLL_CHANGE_EVENT, push);
88
+ // Awareness lives ONLY on the process-global emitter and is filtered via the
89
+ // module-level (default-state) access path — both untenable in a multi-app
90
+ // gateway process, where they'd leak another app's presence/document id and
91
+ // resolve access against the wrong tenant. Fail closed: only the default
92
+ // (in-process) instance forwards awareness. The gateway advertises
93
+ // `no-awareness` so collab keeps its own presence cadence.
94
+ const forwardAwareness = state === getDefaultAppSyncState();
95
+ if (forwardAwareness) {
96
+ getAwarenessEmitter().on(AWARENESS_CHANGE_EVENT, pushAwareness);
97
+ }
79
98
 
80
99
  stream.onClosed(() => {
81
100
  closed = true;
82
- getPollEmitter().off(POLL_CHANGE_EVENT, push);
83
- getAwarenessEmitter().off(AWARENESS_CHANGE_EVENT, pushAwareness);
101
+ state.getPollEmitter().off(POLL_CHANGE_EVENT, push);
102
+ if (forwardAwareness) {
103
+ getAwarenessEmitter().off(AWARENESS_CHANGE_EVENT, pushAwareness);
104
+ }
84
105
  });
85
106
 
86
107
  return stream.send();