@agent-native/core 0.121.2 → 0.122.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (588) hide show
  1. package/README.md +4 -12
  2. package/corpus/README.md +2 -2
  3. package/corpus/core/CHANGELOG.md +148 -0
  4. package/corpus/core/docs/content/actions.mdx +2 -2
  5. package/corpus/core/docs/content/agent-surfaces.mdx +1 -1
  6. package/corpus/core/docs/content/authentication.mdx +2 -0
  7. package/corpus/core/docs/content/deployment.mdx +36 -0
  8. package/corpus/core/docs/content/http-api.mdx +266 -0
  9. package/corpus/core/docs/content/syncing-template-changes.mdx +159 -0
  10. package/corpus/core/package.json +2 -1
  11. package/corpus/core/src/a2a/activity.ts +38 -27
  12. package/corpus/core/src/a2a/client.ts +57 -4
  13. package/corpus/core/src/agent/engine/builder-engine.ts +35 -4
  14. package/corpus/core/src/agent/run-manager.ts +20 -1
  15. package/corpus/core/src/agent/run-store.ts +4 -1
  16. package/corpus/core/src/agent/types.ts +28 -8
  17. package/corpus/core/src/chat-threads/store.ts +45 -0
  18. package/corpus/core/src/checkpoints/index.ts +2 -0
  19. package/corpus/core/src/checkpoints/route-match.ts +13 -0
  20. package/corpus/core/src/cli/create.ts +105 -17
  21. package/corpus/core/src/cli/index.ts +20 -0
  22. package/corpus/core/src/cli/template-baseline.ts +410 -0
  23. package/corpus/core/src/cli/template-sync.ts +1004 -0
  24. package/corpus/core/src/cli/templates-meta.ts +1 -0
  25. package/corpus/core/src/client/AssistantChat.tsx +38 -12
  26. package/corpus/core/src/client/NewWorkspaceAppFlow.tsx +75 -10
  27. package/corpus/core/src/client/chat/message-components.tsx +127 -66
  28. package/corpus/core/src/client/chat/tool-call-display.tsx +29 -5
  29. package/corpus/core/src/client/error-format.ts +18 -0
  30. package/corpus/core/src/client/org/OrgSwitcher.tsx +30 -8
  31. package/corpus/core/src/client/org/TeamPage.tsx +7 -6
  32. package/corpus/core/src/client/settings/SettingsPanel.tsx +9 -9
  33. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +12 -2
  34. package/corpus/core/src/client/sse-event-processor.ts +3 -0
  35. package/corpus/core/src/data-widgets/index.ts +41 -0
  36. package/corpus/core/src/deploy/build.ts +11 -9
  37. package/corpus/core/src/extensions/url-safety.ts +67 -4
  38. package/corpus/core/src/integrations/webhook-handler.ts +63 -9
  39. package/corpus/core/src/org/auto-join-domain.ts +4 -3
  40. package/corpus/core/src/org/context.ts +108 -39
  41. package/corpus/core/src/org/index.ts +5 -0
  42. package/corpus/core/src/org/service-identity.ts +60 -0
  43. package/corpus/core/src/provider-api/index.ts +22 -1
  44. package/corpus/core/src/scripts/docs/search.ts +12 -1
  45. package/corpus/core/src/server/agent-chat/context-tools.ts +9 -4
  46. package/corpus/core/src/server/agent-chat/framework-prompts.ts +38 -66
  47. package/corpus/core/src/server/agent-chat-plugin.ts +17 -10
  48. package/corpus/core/src/server/agents-bundle.ts +84 -5
  49. package/corpus/core/src/server/auth.ts +4 -3
  50. package/corpus/core/src/server/builder-browser.ts +47 -19
  51. package/corpus/core/src/server/core-routes-plugin.ts +2 -2
  52. package/corpus/core/src/server/credential-provider.ts +209 -68
  53. package/corpus/core/src/server/index.ts +3 -0
  54. package/corpus/core/src/server/prompts/framework-core-compact.ts +6 -13
  55. package/corpus/core/src/server/prompts/framework-core.ts +9 -21
  56. package/corpus/core/src/server/prompts/index.ts +0 -1
  57. package/corpus/core/src/server/prompts/shared-rules.ts +19 -11
  58. package/corpus/core/src/server/ssr-handler.ts +13 -2
  59. package/corpus/core/src/settings/user-settings.ts +13 -1
  60. package/corpus/core/src/shared/cache-control.ts +141 -0
  61. package/corpus/core/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  62. package/corpus/core/src/templates/chat/_gitignore +1 -0
  63. package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +0 -7
  64. package/corpus/core/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  65. package/corpus/core/src/templates/default/app/root.tsx +1 -1
  66. package/corpus/core/src/templates/default/public/manifest.json +2 -2
  67. package/corpus/core/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  68. package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +19 -0
  69. package/corpus/core/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  70. package/corpus/core/src/templates/workspace-core/.agents/skills/visual-answer/SKILL.md +1 -0
  71. package/corpus/core/src/vite/agents-bundle-plugin.ts +7 -6
  72. package/corpus/core/src/vite/client.ts +69 -3
  73. package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +4 -5
  74. package/corpus/templates/analytics/.agents/skills/admin-surfaces/SKILL.md +55 -0
  75. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +10 -0
  76. package/corpus/templates/analytics/.agents/skills/dashboard-management/references/template-catalog-and-demo.md +62 -0
  77. package/corpus/templates/analytics/.agents/skills/dashboard-ops/SKILL.md +85 -0
  78. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +27 -2
  79. package/corpus/templates/analytics/.agents/skills/data-querying/references/inline-chart-embeds.md +139 -0
  80. package/corpus/templates/analytics/.agents/skills/monitoring/SKILL.md +77 -0
  81. package/corpus/templates/analytics/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  82. package/corpus/templates/analytics/AGENTS.md +91 -563
  83. package/corpus/templates/analytics/_gitignore +1 -0
  84. package/corpus/templates/analytics/actions/bigquery.ts +12 -4
  85. package/corpus/templates/analytics/actions/generate-chart.ts +5 -5
  86. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +30 -1
  87. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +1 -23
  88. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +3 -0
  89. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +1 -1
  90. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +1 -0
  91. package/corpus/templates/analytics/app/routes/_index.tsx +1 -1
  92. package/corpus/templates/analytics/changelog/2026-07-24-analytics-finds-saved-dashboards-and-queries-far-more-reliab.md +6 -0
  93. package/corpus/templates/analytics/changelog/2026-07-24-notion-access-errors-now-explain-that-a-page-needs-sharing-w.md +6 -0
  94. package/corpus/templates/analytics/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  95. package/corpus/templates/analytics/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  96. package/corpus/templates/analytics/package.json +1 -1
  97. package/corpus/templates/analytics/public/manifest.json +1 -1
  98. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +7 -0
  99. package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +191 -30
  100. package/corpus/templates/analytics/server/lib/bigquery.ts +11 -1
  101. package/corpus/templates/analytics/server/lib/notion.ts +15 -4
  102. package/corpus/templates/analytics/server/plugins/agent-chat.ts +10 -0
  103. package/corpus/templates/analytics/server/plugins/auth.ts +1 -1
  104. package/corpus/templates/assets/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  105. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +0 -2
  106. package/corpus/templates/assets/app/routes/_index.tsx +1 -1
  107. package/corpus/templates/assets/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  108. package/corpus/templates/assets/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  109. package/corpus/templates/assets/server/plugins/auth.ts +1 -1
  110. package/corpus/templates/brain/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  111. package/corpus/templates/brain/_gitignore +1 -0
  112. package/corpus/templates/brain/app/lib/brain.ts +0 -7
  113. package/corpus/templates/brain/app/routes/_index.tsx +1 -2
  114. package/corpus/templates/brain/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  115. package/corpus/templates/brain/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  116. package/corpus/templates/brain/package.json +1 -1
  117. package/corpus/templates/brain/public/manifest.json +1 -1
  118. package/corpus/templates/brain/server/plugins/auth.ts +1 -1
  119. package/corpus/templates/calendar/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  120. package/corpus/templates/calendar/_gitignore +1 -0
  121. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +0 -6
  122. package/corpus/templates/calendar/app/routes/_app._index.tsx +1 -1
  123. package/corpus/templates/calendar/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  124. package/corpus/templates/calendar/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  125. package/corpus/templates/calendar/package.json +1 -1
  126. package/corpus/templates/calendar/public/manifest.json +1 -1
  127. package/corpus/templates/calendar/server/plugins/auth.ts +1 -1
  128. package/corpus/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  129. package/corpus/templates/chat/_gitignore +1 -0
  130. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +0 -7
  131. package/corpus/templates/chat/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  132. package/corpus/templates/clips/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  133. package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +34 -0
  134. package/corpus/templates/clips/AGENTS.md +5 -4
  135. package/corpus/templates/clips/_gitignore +1 -0
  136. package/corpus/templates/clips/actions/cleanup-transcript.ts +5 -0
  137. package/corpus/templates/clips/actions/get-recording-insights.ts +44 -8
  138. package/corpus/templates/clips/actions/get-recording-player-data.ts +39 -70
  139. package/corpus/templates/clips/actions/import-loom-recording.ts +53 -98
  140. package/corpus/templates/clips/actions/lib/loom-import-job.ts +260 -0
  141. package/corpus/templates/clips/actions/list-clip-views.ts +2 -4
  142. package/corpus/templates/clips/actions/list-recordings.ts +69 -19
  143. package/corpus/templates/clips/actions/list-viewers.ts +5 -2
  144. package/corpus/templates/clips/actions/regenerate-summary.ts +5 -1
  145. package/corpus/templates/clips/actions/request-transcript.ts +28 -1
  146. package/corpus/templates/clips/app/components/editor/stitch-manager.tsx +21 -1
  147. package/corpus/templates/clips/app/components/library/library-layout.tsx +0 -7
  148. package/corpus/templates/clips/app/components/meetings/quick-ask-sidebar.tsx +14 -1
  149. package/corpus/templates/clips/app/components/player/insights-panel.tsx +8 -20
  150. package/corpus/templates/clips/app/components/player/recording-views-badge.tsx +335 -0
  151. package/corpus/templates/clips/app/components/player/video-player.tsx +13 -8
  152. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +2 -1
  153. package/corpus/templates/clips/app/i18n/en-US.ts +13 -2
  154. package/corpus/templates/clips/app/lib/capture-permissions.ts +110 -0
  155. package/corpus/templates/clips/app/lib/recording-link.ts +32 -0
  156. package/corpus/templates/clips/app/routes/_app.library._index.tsx +1 -1
  157. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +27 -0
  158. package/corpus/templates/clips/app/routes/_index.tsx +1 -1
  159. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +52 -15
  160. package/corpus/templates/clips/app/routes/record.tsx +82 -31
  161. package/corpus/templates/clips/app/routes/share.$shareId.tsx +42 -31
  162. package/corpus/templates/clips/changelog/2026-07-24-clip-pages-now-show-a-view-count-with-viewer-avatars-next-to.md +6 -0
  163. package/corpus/templates/clips/changelog/2026-07-24-clip-summaries-read-like-a-description-you-d-write-yourself-.md +6 -0
  164. package/corpus/templates/clips/changelog/2026-07-24-clip-view-counts-now-separate-human-views-from-agent-views-s.md +6 -0
  165. package/corpus/templates/clips/changelog/2026-07-24-clips-actions-can-now-be-called-by-org-service-tokens-so-ext.md +6 -0
  166. package/corpus/templates/clips/changelog/2026-07-24-clips-no-longer-briefly-shows-a-dock-icon-while-launching.md +6 -0
  167. package/corpus/templates/clips/changelog/2026-07-24-fixed-owner-and-editor-share-links-redirecting-to-the-record.md +6 -0
  168. package/corpus/templates/clips/changelog/2026-07-24-meeting-and-note-recordings-now-start-as-a-compact-pill-on-t.md +6 -0
  169. package/corpus/templates/clips/changelog/2026-07-24-new-clips-now-copy-a-shareable-link-instead-of-the-owner-onl.md +6 -0
  170. package/corpus/templates/clips/changelog/2026-07-24-opening-a-share-link-as-the-clip-s-owner-now-goes-straight-t.md +6 -0
  171. package/corpus/templates/clips/changelog/2026-07-24-permissions-and-rewind-controls-now-use-compact-consistent-h.md +6 -0
  172. package/corpus/templates/clips/changelog/2026-07-24-quitting-the-desktop-app-no-longer-shows-a-false-macos-crash.md +6 -0
  173. package/corpus/templates/clips/changelog/2026-07-24-screen-recording-permission-errors-now-name-the-exact-app-to.md +6 -0
  174. package/corpus/templates/clips/changelog/2026-07-24-the-desktop-app-now-copies-a-new-clip-s-share-link-to-your-c.md +6 -0
  175. package/corpus/templates/clips/changelog/2026-07-24-the-recording-toolbar-now-stays-above-other-apps-including-o.md +6 -0
  176. package/corpus/templates/clips/changelog/2026-07-24-transcript-captions-now-use-real-speech-timings-instead-of-a.md +6 -0
  177. package/corpus/templates/clips/changelog/2026-07-24-video-playback-no-longer-stutters-and-replays-the-last-momen.md +6 -0
  178. package/corpus/templates/clips/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  179. package/corpus/templates/clips/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  180. package/corpus/templates/clips/chrome-extension/src/background.ts +17 -1
  181. package/corpus/templates/clips/desktop/package.json +2 -0
  182. package/corpus/templates/clips/desktop/src/app.tsx +89 -0
  183. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +9 -3
  184. package/corpus/templates/clips/desktop/src/lib/audio-meter.ts +51 -0
  185. package/corpus/templates/clips/desktop/src/lib/native-notification.ts +44 -0
  186. package/corpus/templates/clips/desktop/src/lib/recording-link.ts +67 -0
  187. package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +35 -35
  188. package/corpus/templates/clips/desktop/src/overlays/live-transcript.tsx +3 -2
  189. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +47 -46
  190. package/corpus/templates/clips/desktop/src/styles.css +127 -78
  191. package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +7 -0
  192. package/corpus/templates/clips/desktop/src-tauri/Info.plist +6 -0
  193. package/corpus/templates/clips/desktop/src-tauri/capabilities/default.json +1 -0
  194. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +7 -3
  195. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +4 -1
  196. package/corpus/templates/clips/desktop/src-tauri/src/main.rs +8 -0
  197. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +21 -10
  198. package/corpus/templates/clips/desktop/src-tauri/src/util.rs +40 -0
  199. package/corpus/templates/clips/server/db/schema.ts +27 -0
  200. package/corpus/templates/clips/server/lib/agent-views.ts +145 -0
  201. package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +2 -1
  202. package/corpus/templates/clips/server/lib/public-agent-context.ts +7 -0
  203. package/corpus/templates/clips/server/lib/recording-share-grant.ts +79 -0
  204. package/corpus/templates/clips/server/lib/recordings.ts +51 -3
  205. package/corpus/templates/clips/server/plugins/auth.ts +1 -1
  206. package/corpus/templates/clips/server/plugins/db.ts +31 -0
  207. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +56 -3
  208. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +49 -17
  209. package/corpus/templates/clips/shared/recording-link.ts +43 -0
  210. package/corpus/templates/clips/shared/share-attribution.ts +4 -0
  211. package/corpus/templates/clips/shared/share-dashboard-redirect.ts +42 -0
  212. package/corpus/templates/clips/shared/view-analytics.ts +26 -0
  213. package/corpus/templates/content/.agents/skills/content/SKILL.md +5 -0
  214. package/corpus/templates/content/.agents/skills/content/references/local-file-mode.md +135 -0
  215. package/corpus/templates/content/.agents/skills/document-editing/SKILL.md +12 -0
  216. package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +238 -0
  217. package/corpus/templates/content/.agents/skills/document-editing/references/document-behavior.md +91 -0
  218. package/corpus/templates/content/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  219. package/corpus/templates/content/AGENTS.md +62 -583
  220. package/corpus/templates/content/_gitignore +1 -0
  221. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +1 -39
  222. package/corpus/templates/content/app/routes/_app._index.tsx +1 -2
  223. package/corpus/templates/content/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  224. package/corpus/templates/content/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  225. package/corpus/templates/content/package.json +1 -1
  226. package/corpus/templates/content/public/manifest.json +1 -1
  227. package/corpus/templates/content/server/plugins/auth.ts +1 -1
  228. package/corpus/templates/design/.agents/skills/creative-context/SKILL.md +11 -0
  229. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +50 -8
  230. package/corpus/templates/design/.agents/skills/design-generation/references/code-layers.md +81 -0
  231. package/corpus/templates/design/.agents/skills/design-generation/references/code-workspace.md +42 -0
  232. package/corpus/templates/design/.agents/skills/design-generation/references/editor-extensions.md +34 -0
  233. package/corpus/templates/design/.agents/skills/responsive-breakpoints/SKILL.md +4 -1
  234. package/corpus/templates/design/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  235. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +17 -0
  236. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +8196 -0
  237. package/corpus/templates/design/.generated/bridge/embedded-wheel.generated.ts +265 -0
  238. package/corpus/templates/design/.generated/bridge/hit-test.generated.ts +642 -0
  239. package/corpus/templates/design/.generated/bridge/motion-preview.generated.ts +571 -0
  240. package/corpus/templates/design/.generated/bridge/nav.generated.ts +91 -0
  241. package/corpus/templates/design/.generated/bridge/sample.generated.ts +23 -0
  242. package/corpus/templates/design/.generated/bridge/shader-fill-preview.generated.ts +263 -0
  243. package/corpus/templates/design/.generated/bridge/shader-runtime.generated.ts +518 -0
  244. package/corpus/templates/design/.generated/bridge/tweak.generated.ts +20 -0
  245. package/corpus/templates/design/.generated/bridge/zoom.generated.ts +32 -0
  246. package/corpus/templates/design/AGENTS.md +88 -503
  247. package/corpus/templates/design/_gitignore +1 -0
  248. package/corpus/templates/design/app/components/layout/Sidebar.tsx +0 -2
  249. package/corpus/templates/design/app/routes/_index.tsx +1 -1
  250. package/corpus/templates/design/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  251. package/corpus/templates/design/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  252. package/corpus/templates/design/server/plugins/auth.ts +1 -1
  253. package/corpus/templates/dispatch/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  254. package/corpus/templates/dispatch/_gitignore +1 -0
  255. package/corpus/templates/dispatch/app/dispatch-extensions.tsx +1 -10
  256. package/corpus/templates/dispatch/app/routes/overview.tsx +1 -1
  257. package/corpus/templates/dispatch/changelog/2026-07-24-signing-in-now-puts-you-in-your-companys-workspace.md +6 -0
  258. package/corpus/templates/dispatch/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  259. package/corpus/templates/dispatch/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  260. package/corpus/templates/dispatch/package.json +1 -1
  261. package/corpus/templates/dispatch/public/manifest.json +1 -1
  262. package/corpus/templates/forms/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  263. package/corpus/templates/forms/_gitignore +1 -0
  264. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +0 -35
  265. package/corpus/templates/forms/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  266. package/corpus/templates/forms/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  267. package/corpus/templates/forms/package.json +1 -1
  268. package/corpus/templates/forms/public/manifest.json +1 -1
  269. package/corpus/templates/forms/server/lib/public-form-ssr.ts +2 -2
  270. package/corpus/templates/forms/server/plugins/auth.ts +1 -1
  271. package/corpus/templates/macros/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  272. package/corpus/templates/macros/_gitignore +1 -0
  273. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +0 -2
  274. package/corpus/templates/macros/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  275. package/corpus/templates/macros/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  276. package/corpus/templates/macros/package.json +1 -1
  277. package/corpus/templates/macros/server/plugins/auth.ts +2 -2
  278. package/corpus/templates/mail/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  279. package/corpus/templates/mail/_gitignore +1 -0
  280. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +0 -39
  281. package/corpus/templates/mail/app/routes/$view.$threadId.tsx +1 -1
  282. package/corpus/templates/mail/app/routes/$view.tsx +1 -1
  283. package/corpus/templates/mail/app/routes/_index.tsx +1 -1
  284. package/corpus/templates/mail/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  285. package/corpus/templates/mail/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  286. package/corpus/templates/mail/package.json +1 -1
  287. package/corpus/templates/mail/public/manifest.json +1 -1
  288. package/corpus/templates/mail/server/plugins/auth.ts +1 -1
  289. package/corpus/templates/plan/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  290. package/corpus/templates/plan/_gitignore +1 -0
  291. package/corpus/templates/plan/agent-native.app-skill.json +1 -1
  292. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +4 -9
  293. package/corpus/templates/plan/app/lib/app-config.ts +1 -1
  294. package/corpus/templates/plan/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  295. package/corpus/templates/plan/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  296. package/corpus/templates/plan/package.json +1 -1
  297. package/corpus/templates/plan/public/manifest.json +1 -1
  298. package/corpus/templates/plan/server/plugins/auth.ts +1 -1
  299. package/corpus/templates/slides/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  300. package/corpus/templates/slides/_gitignore +1 -0
  301. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +0 -2
  302. package/corpus/templates/slides/app/routes/_index.tsx +1 -1
  303. package/corpus/templates/slides/changelog/2026-07-25-app-branding-now-uses-the-product-name-without-the-agent-nat.md +6 -0
  304. package/corpus/templates/slides/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  305. package/corpus/templates/slides/package.json +1 -1
  306. package/corpus/templates/slides/public/manifest.json +1 -1
  307. package/corpus/templates/slides/server/plugins/auth.ts +1 -1
  308. package/corpus/templates/slides/server/plugins/db.ts +4 -0
  309. package/corpus/templates/tasks/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  310. package/corpus/templates/tasks/AGENTS.md +1 -1
  311. package/corpus/templates/tasks/_gitignore +1 -0
  312. package/dist/a2a/activity.d.ts +4 -1
  313. package/dist/a2a/activity.d.ts.map +1 -1
  314. package/dist/a2a/activity.js +27 -16
  315. package/dist/a2a/activity.js.map +1 -1
  316. package/dist/a2a/client.d.ts.map +1 -1
  317. package/dist/a2a/client.js +58 -4
  318. package/dist/a2a/client.js.map +1 -1
  319. package/dist/agent/engine/builder-engine.d.ts +1 -0
  320. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  321. package/dist/agent/engine/builder-engine.js +31 -4
  322. package/dist/agent/engine/builder-engine.js.map +1 -1
  323. package/dist/agent/run-manager.d.ts.map +1 -1
  324. package/dist/agent/run-manager.js +18 -1
  325. package/dist/agent/run-manager.js.map +1 -1
  326. package/dist/agent/run-store.d.ts +1 -0
  327. package/dist/agent/run-store.d.ts.map +1 -1
  328. package/dist/agent/run-store.js +2 -1
  329. package/dist/agent/run-store.js.map +1 -1
  330. package/dist/agent/types.d.ts +12 -1
  331. package/dist/agent/types.d.ts.map +1 -1
  332. package/dist/agent/types.js +21 -1
  333. package/dist/agent/types.js.map +1 -1
  334. package/dist/chat-threads/store.d.ts +10 -0
  335. package/dist/chat-threads/store.d.ts.map +1 -1
  336. package/dist/chat-threads/store.js +41 -0
  337. package/dist/chat-threads/store.js.map +1 -1
  338. package/dist/checkpoints/index.d.ts +1 -0
  339. package/dist/checkpoints/index.d.ts.map +1 -1
  340. package/dist/checkpoints/index.js +1 -0
  341. package/dist/checkpoints/index.js.map +1 -1
  342. package/dist/checkpoints/route-match.d.ts +8 -0
  343. package/dist/checkpoints/route-match.d.ts.map +1 -0
  344. package/dist/checkpoints/route-match.js +13 -0
  345. package/dist/checkpoints/route-match.js.map +1 -0
  346. package/dist/cli/create.d.ts +35 -4
  347. package/dist/cli/create.d.ts.map +1 -1
  348. package/dist/cli/create.js +69 -19
  349. package/dist/cli/create.js.map +1 -1
  350. package/dist/cli/index.js +19 -0
  351. package/dist/cli/index.js.map +1 -1
  352. package/dist/cli/template-baseline.d.ts +54 -0
  353. package/dist/cli/template-baseline.d.ts.map +1 -0
  354. package/dist/cli/template-baseline.js +334 -0
  355. package/dist/cli/template-baseline.js.map +1 -0
  356. package/dist/cli/template-sync.d.ts +57 -0
  357. package/dist/cli/template-sync.d.ts.map +1 -0
  358. package/dist/cli/template-sync.js +787 -0
  359. package/dist/cli/template-sync.js.map +1 -0
  360. package/dist/cli/templates-meta.d.ts.map +1 -1
  361. package/dist/cli/templates-meta.js +1 -0
  362. package/dist/cli/templates-meta.js.map +1 -1
  363. package/dist/client/AssistantChat.d.ts +2 -1
  364. package/dist/client/AssistantChat.d.ts.map +1 -1
  365. package/dist/client/AssistantChat.js +38 -10
  366. package/dist/client/AssistantChat.js.map +1 -1
  367. package/dist/client/NewWorkspaceAppFlow.d.ts.map +1 -1
  368. package/dist/client/NewWorkspaceAppFlow.js +32 -2
  369. package/dist/client/NewWorkspaceAppFlow.js.map +1 -1
  370. package/dist/client/chat/message-components.d.ts +20 -0
  371. package/dist/client/chat/message-components.d.ts.map +1 -1
  372. package/dist/client/chat/message-components.js +81 -46
  373. package/dist/client/chat/message-components.js.map +1 -1
  374. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  375. package/dist/client/chat/tool-call-display.js +14 -6
  376. package/dist/client/chat/tool-call-display.js.map +1 -1
  377. package/dist/client/error-format.d.ts.map +1 -1
  378. package/dist/client/error-format.js +13 -0
  379. package/dist/client/error-format.js.map +1 -1
  380. package/dist/client/org/OrgSwitcher.d.ts +8 -1
  381. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  382. package/dist/client/org/OrgSwitcher.js +3 -2
  383. package/dist/client/org/OrgSwitcher.js.map +1 -1
  384. package/dist/client/org/TeamPage.d.ts.map +1 -1
  385. package/dist/client/org/TeamPage.js +1 -1
  386. package/dist/client/org/TeamPage.js.map +1 -1
  387. package/dist/client/settings/SettingsPanel.js +9 -9
  388. package/dist/client/settings/SettingsPanel.js.map +1 -1
  389. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
  390. package/dist/client/settings/SettingsTabsPage.js +7 -4
  391. package/dist/client/settings/SettingsTabsPage.js.map +1 -1
  392. package/dist/client/sse-event-processor.d.ts.map +1 -1
  393. package/dist/client/sse-event-processor.js +3 -0
  394. package/dist/client/sse-event-processor.js.map +1 -1
  395. package/dist/collab/awareness.d.ts +2 -2
  396. package/dist/collab/awareness.d.ts.map +1 -1
  397. package/dist/collab/struct-routes.d.ts +1 -1
  398. package/dist/data-widgets/index.d.ts +3 -0
  399. package/dist/data-widgets/index.d.ts.map +1 -1
  400. package/dist/data-widgets/index.js +33 -0
  401. package/dist/data-widgets/index.js.map +1 -1
  402. package/dist/deploy/build.d.ts.map +1 -1
  403. package/dist/deploy/build.js +11 -7
  404. package/dist/deploy/build.js.map +1 -1
  405. package/dist/eject/provider-api-definitions.d.ts +1 -0
  406. package/dist/eject/provider-api-definitions.d.ts.map +1 -1
  407. package/dist/extensions/url-safety.d.ts +9 -16
  408. package/dist/extensions/url-safety.d.ts.map +1 -1
  409. package/dist/extensions/url-safety.js +48 -4
  410. package/dist/extensions/url-safety.js.map +1 -1
  411. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  412. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  413. package/dist/integrations/webhook-handler.js +46 -9
  414. package/dist/integrations/webhook-handler.js.map +1 -1
  415. package/dist/notifications/routes.d.ts +2 -2
  416. package/dist/observability/routes.d.ts +3 -3
  417. package/dist/org/auto-join-domain.d.ts +3 -2
  418. package/dist/org/auto-join-domain.d.ts.map +1 -1
  419. package/dist/org/auto-join-domain.js +1 -1
  420. package/dist/org/auto-join-domain.js.map +1 -1
  421. package/dist/org/context.d.ts.map +1 -1
  422. package/dist/org/context.js +84 -28
  423. package/dist/org/context.js.map +1 -1
  424. package/dist/org/index.d.ts +1 -0
  425. package/dist/org/index.d.ts.map +1 -1
  426. package/dist/org/index.js +1 -0
  427. package/dist/org/index.js.map +1 -1
  428. package/dist/org/service-identity.d.ts +43 -0
  429. package/dist/org/service-identity.d.ts.map +1 -0
  430. package/dist/org/service-identity.js +34 -0
  431. package/dist/org/service-identity.js.map +1 -0
  432. package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
  433. package/dist/provider-api/actions/provider-api.d.ts +13 -11
  434. package/dist/provider-api/actions/provider-api.d.ts.map +1 -1
  435. package/dist/provider-api/index.d.ts +4 -0
  436. package/dist/provider-api/index.d.ts.map +1 -1
  437. package/dist/provider-api/index.js +17 -1
  438. package/dist/provider-api/index.js.map +1 -1
  439. package/dist/scripts/docs/search.d.ts.map +1 -1
  440. package/dist/scripts/docs/search.js +12 -1
  441. package/dist/scripts/docs/search.js.map +1 -1
  442. package/dist/server/agent-chat/context-tools.d.ts.map +1 -1
  443. package/dist/server/agent-chat/context-tools.js +3 -3
  444. package/dist/server/agent-chat/context-tools.js.map +1 -1
  445. package/dist/server/agent-chat/framework-prompts.d.ts +8 -3
  446. package/dist/server/agent-chat/framework-prompts.d.ts.map +1 -1
  447. package/dist/server/agent-chat/framework-prompts.js +33 -62
  448. package/dist/server/agent-chat/framework-prompts.js.map +1 -1
  449. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  450. package/dist/server/agent-chat-plugin.js +16 -10
  451. package/dist/server/agent-chat-plugin.js.map +1 -1
  452. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  453. package/dist/server/agents-bundle.d.ts +18 -0
  454. package/dist/server/agents-bundle.d.ts.map +1 -1
  455. package/dist/server/agents-bundle.js +70 -4
  456. package/dist/server/agents-bundle.js.map +1 -1
  457. package/dist/server/auth.d.ts.map +1 -1
  458. package/dist/server/auth.js +4 -3
  459. package/dist/server/auth.js.map +1 -1
  460. package/dist/server/builder-browser.d.ts.map +1 -1
  461. package/dist/server/builder-browser.js +43 -19
  462. package/dist/server/builder-browser.js.map +1 -1
  463. package/dist/server/core-routes-plugin.js +2 -2
  464. package/dist/server/core-routes-plugin.js.map +1 -1
  465. package/dist/server/credential-provider.d.ts +38 -2
  466. package/dist/server/credential-provider.d.ts.map +1 -1
  467. package/dist/server/credential-provider.js +142 -64
  468. package/dist/server/credential-provider.js.map +1 -1
  469. package/dist/server/index.d.ts +1 -1
  470. package/dist/server/index.d.ts.map +1 -1
  471. package/dist/server/index.js +1 -1
  472. package/dist/server/index.js.map +1 -1
  473. package/dist/server/prompts/framework-core-compact.d.ts +1 -1
  474. package/dist/server/prompts/framework-core-compact.d.ts.map +1 -1
  475. package/dist/server/prompts/framework-core-compact.js +7 -13
  476. package/dist/server/prompts/framework-core-compact.js.map +1 -1
  477. package/dist/server/prompts/framework-core.d.ts +1 -1
  478. package/dist/server/prompts/framework-core.d.ts.map +1 -1
  479. package/dist/server/prompts/framework-core.js +10 -21
  480. package/dist/server/prompts/framework-core.js.map +1 -1
  481. package/dist/server/prompts/index.d.ts +1 -1
  482. package/dist/server/prompts/index.d.ts.map +1 -1
  483. package/dist/server/prompts/index.js +1 -1
  484. package/dist/server/prompts/index.js.map +1 -1
  485. package/dist/server/prompts/shared-rules.d.ts +16 -10
  486. package/dist/server/prompts/shared-rules.d.ts.map +1 -1
  487. package/dist/server/prompts/shared-rules.js +19 -10
  488. package/dist/server/prompts/shared-rules.js.map +1 -1
  489. package/dist/server/ssr-handler.d.ts +1 -1
  490. package/dist/server/ssr-handler.d.ts.map +1 -1
  491. package/dist/server/ssr-handler.js +10 -3
  492. package/dist/server/ssr-handler.js.map +1 -1
  493. package/dist/server/transcribe-voice.d.ts +1 -1
  494. package/dist/settings/user-settings.d.ts.map +1 -1
  495. package/dist/settings/user-settings.js +13 -1
  496. package/dist/settings/user-settings.js.map +1 -1
  497. package/dist/shared/cache-control.d.ts +52 -0
  498. package/dist/shared/cache-control.d.ts.map +1 -1
  499. package/dist/shared/cache-control.js +107 -0
  500. package/dist/shared/cache-control.js.map +1 -1
  501. package/dist/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  502. package/dist/templates/chat/_gitignore +1 -0
  503. package/dist/templates/chat/app/components/layout/Sidebar.tsx +0 -7
  504. package/dist/templates/chat/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  505. package/dist/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  506. package/dist/templates/default/app/root.tsx +1 -1
  507. package/dist/templates/default/public/manifest.json +2 -2
  508. package/dist/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  509. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +19 -0
  510. package/dist/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  511. package/dist/templates/workspace-core/.agents/skills/visual-answer/SKILL.md +1 -0
  512. package/dist/vite/agents-bundle-plugin.d.ts.map +1 -1
  513. package/dist/vite/agents-bundle-plugin.js +8 -7
  514. package/dist/vite/agents-bundle-plugin.js.map +1 -1
  515. package/dist/vite/client.d.ts.map +1 -1
  516. package/dist/vite/client.js +66 -1
  517. package/dist/vite/client.js.map +1 -1
  518. package/docs/content/actions.mdx +2 -2
  519. package/docs/content/agent-surfaces.mdx +1 -1
  520. package/docs/content/authentication.mdx +2 -0
  521. package/docs/content/deployment.mdx +36 -0
  522. package/docs/content/http-api.mdx +266 -0
  523. package/docs/content/syncing-template-changes.mdx +159 -0
  524. package/package.json +4 -3
  525. package/src/a2a/activity.ts +38 -27
  526. package/src/a2a/client.ts +57 -4
  527. package/src/agent/engine/builder-engine.ts +35 -4
  528. package/src/agent/run-manager.ts +20 -1
  529. package/src/agent/run-store.ts +4 -1
  530. package/src/agent/types.ts +28 -8
  531. package/src/chat-threads/store.ts +45 -0
  532. package/src/checkpoints/index.ts +2 -0
  533. package/src/checkpoints/route-match.ts +13 -0
  534. package/src/cli/create.ts +105 -17
  535. package/src/cli/index.ts +20 -0
  536. package/src/cli/template-baseline.ts +410 -0
  537. package/src/cli/template-sync.ts +1004 -0
  538. package/src/cli/templates-meta.ts +1 -0
  539. package/src/client/AssistantChat.tsx +38 -12
  540. package/src/client/NewWorkspaceAppFlow.tsx +75 -10
  541. package/src/client/chat/message-components.tsx +127 -66
  542. package/src/client/chat/tool-call-display.tsx +29 -5
  543. package/src/client/error-format.ts +18 -0
  544. package/src/client/org/OrgSwitcher.tsx +30 -8
  545. package/src/client/org/TeamPage.tsx +7 -6
  546. package/src/client/settings/SettingsPanel.tsx +9 -9
  547. package/src/client/settings/SettingsTabsPage.tsx +12 -2
  548. package/src/client/sse-event-processor.ts +3 -0
  549. package/src/data-widgets/index.ts +41 -0
  550. package/src/deploy/build.ts +11 -9
  551. package/src/extensions/url-safety.ts +67 -4
  552. package/src/integrations/webhook-handler.ts +63 -9
  553. package/src/org/auto-join-domain.ts +4 -3
  554. package/src/org/context.ts +108 -39
  555. package/src/org/index.ts +5 -0
  556. package/src/org/service-identity.ts +60 -0
  557. package/src/provider-api/index.ts +22 -1
  558. package/src/scripts/docs/search.ts +12 -1
  559. package/src/server/__snapshots__/agent-chat-plugin.surface.spec.ts.snap +25 -36
  560. package/src/server/agent-chat/context-tools.ts +9 -4
  561. package/src/server/agent-chat/framework-prompts.ts +38 -66
  562. package/src/server/agent-chat-plugin.ts +17 -10
  563. package/src/server/agents-bundle.ts +84 -5
  564. package/src/server/auth.ts +4 -3
  565. package/src/server/builder-browser.ts +47 -19
  566. package/src/server/core-routes-plugin.ts +2 -2
  567. package/src/server/credential-provider.ts +209 -68
  568. package/src/server/index.ts +3 -0
  569. package/src/server/prompts/framework-core-compact.ts +6 -13
  570. package/src/server/prompts/framework-core.ts +9 -21
  571. package/src/server/prompts/index.ts +0 -1
  572. package/src/server/prompts/shared-rules.ts +19 -11
  573. package/src/server/ssr-handler.ts +13 -2
  574. package/src/settings/user-settings.ts +13 -1
  575. package/src/shared/cache-control.ts +141 -0
  576. package/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  577. package/src/templates/chat/_gitignore +1 -0
  578. package/src/templates/chat/app/components/layout/Sidebar.tsx +0 -7
  579. package/src/templates/chat/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  580. package/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  581. package/src/templates/default/app/root.tsx +1 -1
  582. package/src/templates/default/public/manifest.json +2 -2
  583. package/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  584. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +19 -0
  585. package/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  586. package/src/templates/workspace-core/.agents/skills/visual-answer/SKILL.md +1 -0
  587. package/src/vite/agents-bundle-plugin.ts +7 -6
  588. package/src/vite/client.ts +69 -3
@@ -3001,18 +3001,10 @@ export function useAgentSettingsTabs(): SettingsTabItem[] {
3001
3001
  const organization = searchTab("organization");
3002
3002
  const workspace = searchTab("workspace");
3003
3003
  return [
3004
- {
3005
- ...agent,
3006
- icon: IconHierarchy2,
3007
- group: "agent",
3008
- href: "/agent#settings",
3009
- searchEntries: undefined,
3010
- content: <Navigate to="/agent#settings" replace />,
3011
- },
3012
3004
  {
3013
3005
  ...connections,
3014
3006
  icon: IconPlugConnected,
3015
- group: "agent",
3007
+ group: "workspace",
3016
3008
  content: <ConnectionsSettingsContent settingsPanelProps={baseProps} />,
3017
3009
  },
3018
3010
  {
@@ -3047,6 +3039,14 @@ export function useAgentSettingsTabs(): SettingsTabItem[] {
3047
3039
  keywords: "extensions widgets mini apps tools sandboxed apps",
3048
3040
  content: <ExtensionsSettingsContent />,
3049
3041
  },
3042
+ {
3043
+ ...agent,
3044
+ icon: IconHierarchy2,
3045
+ group: "manage-agent",
3046
+ href: "/agent#settings",
3047
+ searchEntries: undefined,
3048
+ content: <Navigate to="/agent#settings" replace />,
3049
+ },
3050
3050
  ];
3051
3051
  }, [baseProps]);
3052
3052
  }
@@ -1,5 +1,6 @@
1
1
  import { Tabs, useDesignSystem } from "@agent-native/toolkit/design-system";
2
2
  import {
3
+ IconArrowUpRight,
3
4
  IconHistory,
4
5
  IconSearch,
5
6
  IconSettings,
@@ -216,6 +217,8 @@ export function SettingsTabsPage({
216
217
  const hasOrganizationTab = extraTabs.some(
217
218
  (tab) => tab.id === "organization",
218
219
  );
220
+ const inlineTabs = extraTabs.filter((tab) => !tab.href);
221
+ const linkedTabs = extraTabs.filter((tab) => tab.href);
219
222
  const next: SettingsTabItem[] = [
220
223
  {
221
224
  id: "general",
@@ -234,7 +237,7 @@ export function SettingsTabsPage({
234
237
  keywords: "profile photo avatar identity signed in email name",
235
238
  });
236
239
  }
237
- next.push(...extraTabs);
240
+ next.push(...inlineTabs);
238
241
  if (team && !hasOrganizationTab) {
239
242
  next.push({
240
243
  id: "team",
@@ -249,10 +252,11 @@ export function SettingsTabsPage({
249
252
  id: "whats-new",
250
253
  label: whatsNewLabel,
251
254
  icon: IconHistory,
252
- group: "updates",
255
+ group: next.at(-1)?.group ?? "app",
253
256
  content: whatsNew,
254
257
  });
255
258
  }
259
+ next.push(...linkedTabs);
256
260
  return next;
257
261
  }, [
258
262
  account,
@@ -615,6 +619,12 @@ export function SettingsTabsPage({
615
619
  />
616
620
  ) : null}
617
621
  <span className="truncate">{tab.label}</span>
622
+ {tab.href ? (
623
+ <IconArrowUpRight
624
+ aria-hidden="true"
625
+ className="size-3.5 shrink-0 text-muted-foreground/80"
626
+ />
627
+ ) : null}
618
628
  </>
619
629
  );
620
630
  if (tab.href) {
@@ -625,6 +625,9 @@ function isAutoRecoverableError(ev: SSEEvent, errMsg: string): boolean {
625
625
  code === "unauthorized" ||
626
626
  code === "authentication_error" ||
627
627
  code === "permission_error" ||
628
+ code === "builder_auth_error" ||
629
+ // The account cannot use this model; another POST picks the same one.
630
+ code === "builder_model_unauthorized" ||
628
631
  code === "http_401" ||
629
632
  code === "http_403" ||
630
633
  code === "rate_limit_exceeded" ||
@@ -282,6 +282,47 @@ export function isDataWidgetResult(value: unknown): value is DataWidgetResult {
282
282
  return normalizeDataWidgetResult(value) !== null;
283
283
  }
284
284
 
285
+ export const DATA_WIDGET_MAX_ROWS = 50;
286
+ export const DATA_WIDGET_MAX_CHART_POINTS = 200;
287
+
288
+ // Widget rows arrive as tool-call arguments the model decodes token by token, so an
289
+ // uncapped table costs minutes of wall clock before anything renders. Clamp server-side
290
+ // rather than rejecting: the model has already paid for the tokens by the time we see them.
291
+ export function clampDataWidgetRows(
292
+ result: DataWidgetResult,
293
+ ): DataWidgetResult {
294
+ const source = result as Partial<DataInsightsWidgetResult>;
295
+ const table = source.table;
296
+ const chartSeries = source.chartSeries;
297
+
298
+ const clampedTable =
299
+ table && table.rows.length > DATA_WIDGET_MAX_ROWS
300
+ ? {
301
+ ...table,
302
+ rows: table.rows.slice(0, DATA_WIDGET_MAX_ROWS),
303
+ totalRows: table.totalRows ?? table.rows.length,
304
+ sampledRows: DATA_WIDGET_MAX_ROWS,
305
+ truncated: true,
306
+ }
307
+ : table;
308
+
309
+ const clampedChart =
310
+ chartSeries && chartSeries.data.length > DATA_WIDGET_MAX_CHART_POINTS
311
+ ? {
312
+ ...chartSeries,
313
+ data: chartSeries.data.slice(0, DATA_WIDGET_MAX_CHART_POINTS),
314
+ sampled: true,
315
+ }
316
+ : chartSeries;
317
+
318
+ if (clampedTable === table && clampedChart === chartSeries) return result;
319
+ return {
320
+ ...result,
321
+ ...(clampedTable ? { table: clampedTable } : {}),
322
+ ...(clampedChart ? { chartSeries: clampedChart } : {}),
323
+ } as DataWidgetResult;
324
+ }
325
+
285
326
  const dataTableColumnSchema = z
286
327
  .object({
287
328
  key: z.string().min(1),
@@ -36,10 +36,8 @@ import {
36
36
  } from "../integrations/integration-durable-dispatch-config.js";
37
37
  import { normalizeAppBasePath } from "../server/app-base-path.js";
38
38
  import {
39
- DEFAULT_SSR_CDN_CACHE_CONTROL,
40
- DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL,
41
39
  DEFAULT_SPECULATION_RULES_PATH,
42
- DEFAULT_SSR_CACHE_CONTROL,
40
+ resolveSsrCacheHeaders,
43
41
  } from "../shared/cache-control.js";
44
42
  import { mcpEmbedStaticAssetRouteRules } from "../shared/mcp-embed-headers.js";
45
43
  import {
@@ -698,6 +696,9 @@ export function generateWorkerEntry(
698
696
  options: GenerateWorkerEntryOptions = {},
699
697
  ): string {
700
698
  const includeReactRouterSsr = options.includeReactRouterSsr ?? true;
699
+ // The worker ships as a static bundle with no access to runtime env, so the
700
+ // deployment-wide SSR cache policy is baked in from this build's env.
701
+ const ssrCacheHeaders = resolveSsrCacheHeaders();
701
702
  const routeImports: string[] = [];
702
703
  const routeRegistrations: string[] = [];
703
704
 
@@ -984,9 +985,10 @@ function injectHeadScript(html, script) {
984
985
  return html.slice(0, headCloseIdx) + script + html.slice(headCloseIdx);
985
986
  }
986
987
 
987
- const DEFAULT_SSR_CACHE_CONTROL = ${JSON.stringify(DEFAULT_SSR_CACHE_CONTROL)};
988
- const DEFAULT_SSR_CDN_CACHE_CONTROL = ${JSON.stringify(DEFAULT_SSR_CDN_CACHE_CONTROL)};
989
- const DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL = ${JSON.stringify(DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL)};
988
+ // Resolved from AGENT_NATIVE_SSR_CACHE at build time.
989
+ const SSR_CACHE_CONTROL = ${JSON.stringify(ssrCacheHeaders["cache-control"])};
990
+ const SSR_CDN_CACHE_CONTROL = ${JSON.stringify(ssrCacheHeaders["cdn-cache-control"])};
991
+ const SSR_NETLIFY_CDN_CACHE_CONTROL = ${JSON.stringify(ssrCacheHeaders["netlify-cdn-cache-control"])};
990
992
  const DEFAULT_SPECULATION_RULES_PATH = ${JSON.stringify(DEFAULT_SPECULATION_RULES_PATH)};
991
993
  const IMMUTABLE_ASSET_CACHE_CONTROL = ${JSON.stringify(IMMUTABLE_ASSET_CACHE_CONTROL)};
992
994
  const IMMUTABLE_ASSET_PATHS = new Set(${JSON.stringify(
@@ -1084,13 +1086,13 @@ function applyDefaultSsrCacheHeader(headers, status, pathname) {
1084
1086
  else headers.delete("vary");
1085
1087
  }
1086
1088
 
1087
- headers.set("cache-control", DEFAULT_SSR_CACHE_CONTROL);
1088
- headers.set("cdn-cache-control", DEFAULT_SSR_CDN_CACHE_CONTROL);
1089
+ headers.set("cache-control", SSR_CACHE_CONTROL);
1090
+ headers.set("cdn-cache-control", SSR_CDN_CACHE_CONTROL);
1089
1091
  // Netlify function responses are dynamic by default and can otherwise show
1090
1092
  // Cache-Status fwd=bypass even with Cache-Control: public. Keep this
1091
1093
  // Netlify-specific header so SSR HTML/.data are served from the shared
1092
1094
  // durable CDN cache instead of stampeding origin — for every visitor.
1093
- headers.set("netlify-cdn-cache-control", DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL);
1095
+ headers.set("netlify-cdn-cache-control", SSR_NETLIFY_CDN_CACHE_CONTROL);
1094
1096
  }
1095
1097
 
1096
1098
  function applyDefaultSpeculationRulesHeader(headers, status, basePath) {
@@ -163,7 +163,32 @@ export async function isBlockedExtensionUrlWithDns(
163
163
  * runtimes); the caller should fall back to the regular `fetch` path —
164
164
  * `isBlockedExtensionUrlWithDns` will still have caught most rebinding cases.
165
165
  */
166
- export async function createSsrfSafeDispatcher(): Promise<unknown | null> {
166
+ function normalizeLookupHostname(hostname: string): string {
167
+ return hostname.toLowerCase().replace(/^\[|\]$/g, "");
168
+ }
169
+
170
+ function normalizeAllowedPrivateOriginKeys(
171
+ origins: readonly string[],
172
+ ): Set<string> {
173
+ const keys = new Set<string>();
174
+ for (const origin of origins) {
175
+ try {
176
+ const parsed = new URL(origin);
177
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
178
+ continue;
179
+ }
180
+ const port = parsed.port || (parsed.protocol === "https:" ? "443" : "80");
181
+ keys.add(`${normalizeLookupHostname(parsed.hostname)}:${port}`);
182
+ } catch {
183
+ // Ignore malformed deployment configuration and retain the private-IP guard.
184
+ }
185
+ }
186
+ return keys;
187
+ }
188
+
189
+ export async function createSsrfSafeDispatcher(
190
+ allowedPrivateOrigins: readonly string[] = [],
191
+ ): Promise<unknown | null> {
167
192
  // Keep the optional undici import opaque to Vite/Rolldown. A static
168
193
  // `import("undici")` makes browser builds try to resolve and bundle undici
169
194
  // even though this dispatcher is only useful in Node server runtimes.
@@ -182,6 +207,9 @@ export async function createSsrfSafeDispatcher(): Promise<unknown | null> {
182
207
 
183
208
  const { Agent } = undici;
184
209
  const { lookup } = dnsModule;
210
+ const allowedPrivateOriginKeys = normalizeAllowedPrivateOriginKeys(
211
+ allowedPrivateOrigins,
212
+ );
185
213
  if (!Agent || !lookup) return null;
186
214
 
187
215
  return new Agent({
@@ -209,7 +237,10 @@ export async function createSsrfSafeDispatcher(): Promise<unknown | null> {
209
237
  ? addresses
210
238
  : [{ address: addresses, family: 4 }];
211
239
  for (const record of list) {
212
- if (isPrivateHost(record.address)) {
240
+ const allowedOrigin = allowedPrivateOriginKeys.has(
241
+ `${normalizeLookupHostname(hostname)}:${String(options?.port ?? "")}`,
242
+ );
243
+ if (isPrivateHost(record.address) && !allowedOrigin) {
213
244
  const e = new Error(
214
245
  `Connect blocked: ${hostname} resolved to private address ${record.address}`,
215
246
  ) as NodeJS.ErrnoException;
@@ -264,10 +295,39 @@ export async function ssrfSafeFetch(
264
295
  maxRedirects?: number;
265
296
  httpsOnly?: boolean;
266
297
  assertUrlAllowed?: (url: string) => void | Promise<void>;
298
+ /**
299
+ * Exact origins that may resolve to a private address. A workspace runs
300
+ * every app on loopback behind one gateway, so sibling A2A calls are
301
+ * private by construction; without this they are indistinguishable from an
302
+ * SSRF attempt and get blocked. Only ever pass origins the deployment
303
+ * itself configured (never a request-supplied value).
304
+ */
305
+ allowedPrivateOrigins?: readonly string[];
267
306
  } = {},
268
307
  ): Promise<Response> {
269
308
  const maxRedirects = options.maxRedirects ?? 3;
270
- const dispatcher = (await createSsrfSafeDispatcher()) ?? undefined;
309
+ const dispatcher =
310
+ (await createSsrfSafeDispatcher(options.allowedPrivateOrigins)) ??
311
+ undefined;
312
+ const allowedPrivateOrigins = new Set(
313
+ (options.allowedPrivateOrigins ?? [])
314
+ .map((origin) => {
315
+ try {
316
+ return new URL(origin).origin;
317
+ } catch {
318
+ return "";
319
+ }
320
+ })
321
+ .filter(Boolean),
322
+ );
323
+ const isAllowedPrivateOrigin = (candidate: string): boolean => {
324
+ if (allowedPrivateOrigins.size === 0) return false;
325
+ try {
326
+ return allowedPrivateOrigins.has(new URL(candidate).origin);
327
+ } catch {
328
+ return false;
329
+ }
330
+ };
271
331
 
272
332
  let currentUrl = url;
273
333
  for (let hop = 0; hop <= maxRedirects; hop++) {
@@ -277,7 +337,10 @@ export async function ssrfSafeFetch(
277
337
  `SSRF blocked: refusing to fetch non-HTTPS address (${currentUrl})`,
278
338
  );
279
339
  }
280
- if (await isBlockedExtensionUrlWithDns(currentUrl)) {
340
+ if (
341
+ !isAllowedPrivateOrigin(currentUrl) &&
342
+ (await isBlockedExtensionUrlWithDns(currentUrl))
343
+ ) {
281
344
  throw new Error(
282
345
  `SSRF blocked: refusing to fetch private/internal address (${currentUrl})`,
283
346
  );
@@ -8,6 +8,7 @@ import {
8
8
  type A2AToolResultSummary,
9
9
  } from "../a2a/artifact-response.js";
10
10
  import { collectFinalResponseTextFromAgentEvents } from "../a2a/response-text.js";
11
+ import { isInBackgroundFunctionRuntime } from "../agent/durable-background.js";
11
12
  import {
12
13
  formatLlmCredentialErrorMessage,
13
14
  isLlmCredentialError,
@@ -41,7 +42,11 @@ import {
41
42
  threadDataToEngineMessages,
42
43
  } from "../agent/thread-data-builder.js";
43
44
  import { attachToolSearch } from "../agent/tool-search.js";
44
- import { createThread, getThread } from "../chat-threads/store.js";
45
+ import {
46
+ createThread,
47
+ getThread,
48
+ grantThreadUserShare,
49
+ } from "../chat-threads/store.js";
45
50
  import { updateThreadData } from "../chat-threads/store.js";
46
51
  import { isLocalDatabase } from "../db/client.js";
47
52
  import { getOrgA2ASecret, resolveOrgIdForEmail } from "../org/context.js";
@@ -88,6 +93,20 @@ const DEFERRED_RESPONSE_DISPATCH_SETTLE_WAIT_MS = 1_500;
88
93
  const DEFERRED_RESPONSE_MAX_HANDLER_MS = 2_500;
89
94
  const EMPTY_INTEGRATION_RESPONSE_MESSAGE =
90
95
  "The model finished without a visible answer. Try again, or open the thread in Dispatch to inspect the run.";
96
+ const CUTOFF_INTEGRATION_RESPONSE_MESSAGE =
97
+ "I ran out of time on this one before I could write up an answer — it needed more research than a single run allows. " +
98
+ "Open the thread in Dispatch to see what I gathered, or ask me again in smaller pieces (one source at a time works best).";
99
+
100
+ /**
101
+ * True when the run stopped at a continuation boundary rather than finishing:
102
+ * the run-manager's soft timeout emits `auto_continue` and aborts the loop, and
103
+ * the loop itself emits one when it hits an internal step budget. The run's
104
+ * status is still "completed", so without this check a cut-off research request
105
+ * is reported to the user as a model that answered with nothing.
106
+ */
107
+ function endedAtContinuationBoundary(run: ActiveRun): boolean {
108
+ return run.events.some((runEvent) => runEvent.event.type === "auto_continue");
109
+ }
91
110
 
92
111
  type ToolDoneEvent = {
93
112
  type: "tool_done";
@@ -789,6 +808,29 @@ async function processIncomingMessage(
789
808
  await releaseApplicableIntegrationBudgets(budgetReservations.reservations);
790
809
  throw error;
791
810
  }
811
+
812
+ // Channel conversations run as the integration service principal, so the
813
+ // thread is owned by `integration@<platform>` and not by the human who asked.
814
+ // The "Open thread" deep link we hand back would then 404 for them and the
815
+ // chat surface would silently render an empty new chat, so grant each
816
+ // verified participant an explicit share on the thread they are driving.
817
+ if (
818
+ incoming.senderVerified === true &&
819
+ incoming.senderEmail &&
820
+ incoming.senderEmail.trim().toLowerCase() !== ownerEmail.toLowerCase()
821
+ ) {
822
+ await grantThreadUserShare(
823
+ threadId,
824
+ incoming.senderEmail,
825
+ "editor",
826
+ ownerEmail,
827
+ ).catch((error) => {
828
+ console.warn(
829
+ `[integrations] Could not grant ${incoming.platform} sender access to thread ${threadId}:`,
830
+ error instanceof Error ? error.message : error,
831
+ );
832
+ });
833
+ }
792
834
  const existingMessages: EngineMessage[] = [];
793
835
  if (thread?.threadData) {
794
836
  existingMessages.push(...threadDataToEngineMessages(thread.threadData));
@@ -1051,7 +1093,10 @@ async function processIncomingMessage(
1051
1093
  "directly is the most reliable way to get an answer right now.";
1052
1094
  } else {
1053
1095
  responseText =
1054
- verifiedMutationReceipt ?? EMPTY_INTEGRATION_RESPONSE_MESSAGE;
1096
+ verifiedMutationReceipt ??
1097
+ (endedAtContinuationBoundary(completedRun)
1098
+ ? CUTOFF_INTEGRATION_RESPONSE_MESSAGE
1099
+ : EMPTY_INTEGRATION_RESPONSE_MESSAGE);
1055
1100
  }
1056
1101
  }
1057
1102
  if (approval?.type === "approval_required") {
@@ -1346,13 +1391,22 @@ async function processIncomingMessage(
1346
1391
  resolve(outcome);
1347
1392
  }
1348
1393
  },
1349
- // Integration workers are ordinary self-dispatched serverless requests,
1350
- // not a Netlify background-function route. Without the hosted soft
1351
- // timeout, a wedged model connection can outlive the worker and leave
1352
- // Slack's native stream in "working" forever when the host kills the
1353
- // process. Checkpoint at the foreground-safe boundary so onComplete can
1354
- // always close the provider progress surface before the function wall.
1355
- { useHostedSoftTimeoutDefault: true },
1394
+ // Without the hosted soft timeout, a wedged model connection can outlive
1395
+ // the worker and leave Slack's native stream in "working" forever when
1396
+ // the host kills the process. Checkpoint at the safe boundary so
1397
+ // onComplete can always close the provider progress surface first.
1398
+ //
1399
+ // Which boundary that is depends on where this task is actually running:
1400
+ // when durable dispatch routes it to the emitted `-background` function
1401
+ // it has ~15min, and clamping it to the 40s foreground budget anyway cut
1402
+ // off every research-shaped request (multi-source sweeps, long tool
1403
+ // chains) with no visible answer. `isInBackgroundFunctionRuntime()` is
1404
+ // the runtime proof — never a config guess — so the wider ceiling is
1405
+ // taken only where the ~60s synchronous wall genuinely does not apply.
1406
+ {
1407
+ useHostedSoftTimeoutDefault: true,
1408
+ backgroundFunction: isInBackgroundFunctionRuntime(),
1409
+ },
1356
1410
  );
1357
1411
  });
1358
1412
  }
@@ -14,9 +14,10 @@ export interface AutoJoinDomainOptions {
14
14
  /**
15
15
  * The signup hook should not clobber an org selected by an invite flow, but
16
16
  * request-time org resolution may need to move an existing account from a
17
- * personal workspace into its newly matched company org.
17
+ * personal workspace into its newly matched company org. `"never"` joins
18
+ * without touching `active-org-id` — the caller decides activation itself.
18
19
  */
19
- activateJoinedOrg?: "if-missing" | "always";
20
+ activateJoinedOrg?: "if-missing" | "always" | "never";
20
21
  }
21
22
 
22
23
  /**
@@ -96,7 +97,7 @@ export async function autoJoinDomainMatchingOrgs(
96
97
  // one, unless the caller is request-time org resolution intentionally moving
97
98
  // an existing account into its newly matched company org.
98
99
  let activeOrgId: string | null = null;
99
- if (joined[0]) {
100
+ if (joined[0] && options.activateJoinedOrg !== "never") {
100
101
  try {
101
102
  const existing = await getUserSetting(email, "active-org-id");
102
103
  const hasActive = Boolean(existing?.orgId);
@@ -20,12 +20,33 @@ function normalizeOrgRole(value: unknown): OrgRole | null {
20
20
  : null;
21
21
  }
22
22
 
23
- function isLikelyPersonalWorkspace(
24
- membership: { orgName: string },
25
- email: string,
26
- session: { name?: string } | null,
27
- ): boolean {
28
- return membership.orgName.trim() === defaultOrgName(email, session);
23
+ function emailDomainOf(email: string): string | null {
24
+ return email.split("@")[1]?.toLowerCase() || null;
25
+ }
26
+
27
+ /**
28
+ * A workspace the user owns that nobody else has joined is a default/personal
29
+ * workspace whatever it happens to be named, so moving the user into their
30
+ * company org is safe. An org with other members is a team they deliberately
31
+ * belong to — join the domain org in the background but leave them there.
32
+ */
33
+ async function isSoloOwnedWorkspace(
34
+ exec: ReturnType<typeof getDbExec>,
35
+ orgId: string,
36
+ memberships: MembershipRow[],
37
+ ): Promise<boolean> {
38
+ const membership = memberships.find((m) => m.orgId === orgId);
39
+ if (!membership || membership.role !== "owner") return false;
40
+ try {
41
+ const { rows } = await exec.execute({
42
+ sql: `SELECT COUNT(*) AS "memberCount" FROM org_members WHERE org_id = ?`,
43
+ args: [orgId],
44
+ });
45
+ const row = rows[0] as any;
46
+ return Number(row?.memberCount ?? row?.membercount ?? 0) <= 1;
47
+ } catch {
48
+ return false;
49
+ }
29
50
  }
30
51
 
31
52
  function autoCreateDefaultOrgEnabled(): boolean {
@@ -61,7 +82,12 @@ export async function getOrgContext(event: H3Event): Promise<OrgContext> {
61
82
  return (ctx.__anOrgContextCache ??= resolveOrgContextUncached(event));
62
83
  }
63
84
 
64
- type MembershipRow = { orgId: string; role: OrgRole; orgName: string };
85
+ type MembershipRow = {
86
+ orgId: string;
87
+ role: OrgRole;
88
+ orgName: string;
89
+ allowedDomain: string | null;
90
+ };
65
91
 
66
92
  const MEMBERSHIPS_CACHE_KEY = "__anOrgMembershipsCache";
67
93
  const ACTIVE_ORG_SETTING_CACHE_KEY = "__anActiveOrgSettingCache";
@@ -157,17 +183,26 @@ async function resolveOrgContextUncached(event: H3Event): Promise<OrgContext> {
157
183
  return { email, orgId: null, orgName: null, role: null };
158
184
  }
159
185
 
160
- const shouldTryDomainAutoJoin =
161
- memberships.length === 0 ||
162
- (memberships.length === 1 &&
163
- isLikelyPersonalWorkspace(memberships[0], email, session));
164
186
  const activeOrgSetting = await loadActiveOrgSettingForEvent(event, email);
165
- if (activeOrgSetting?.orgId === null) {
166
- return { email, orgId: null, orgName: null, role: null };
167
- }
168
- if (activeOrgSetting?.orgId) {
187
+ const explicitPersonal = activeOrgSetting?.orgId === null;
188
+
189
+ const emailDomain = emailDomainOf(email);
190
+ // Membership in a domain-matched org is the only durable "already joined"
191
+ // signal. Recognizing the personal workspace by its *name* instead breaks the
192
+ // moment the provider display name or the workspace name changes, which
193
+ // strands an existing user in Personal with no way into their company org.
194
+ const shouldTryDomainAutoJoin =
195
+ !explicitPersonal &&
196
+ emailDomain !== null &&
197
+ !memberships.some((m) => m.allowedDomain?.toLowerCase() === emailDomain);
198
+
199
+ if (
200
+ !explicitPersonal &&
201
+ activeOrgSetting?.orgId &&
202
+ !shouldTryDomainAutoJoin
203
+ ) {
169
204
  const active = memberships.find((m) => m.orgId === activeOrgSetting.orgId);
170
- if (active && !shouldTryDomainAutoJoin) {
205
+ if (active) {
171
206
  return {
172
207
  email,
173
208
  orgId: active.orgId,
@@ -182,30 +217,63 @@ async function resolveOrgContextUncached(event: H3Event): Promise<OrgContext> {
182
217
  : null;
183
218
 
184
219
  if (shouldTryDomainAutoJoin) {
220
+ const membershipsBeforeJoin = memberships;
185
221
  const joined = await autoJoinDomainMatchingOrgs(email, {
186
- activateJoinedOrg: "always",
222
+ activateJoinedOrg: "never",
187
223
  });
188
- if (joined.joined.length > 0) {
224
+ const joinedOrgId = joined.joined[0]?.orgId ?? null;
225
+ if (joinedOrgId) {
189
226
  const refreshed = await loadMemberships(exec, email);
190
227
  if (refreshed !== null) {
191
228
  memberships = refreshed;
192
229
  updateMembershipsForEvent(event, email, refreshed);
193
230
  }
194
- }
195
231
 
196
- if (joined.activeOrgId) {
197
- const active = memberships.find((m) => m.orgId === joined.activeOrgId);
198
- if (active) {
199
- return {
200
- email,
201
- orgId: active.orgId,
202
- orgName: active.orgName,
203
- role: active.role,
204
- };
232
+ const currentOrgId =
233
+ activeOrgSetting?.orgId ??
234
+ sessionOrgId ??
235
+ membershipsBeforeJoin[0]?.orgId ??
236
+ null;
237
+ const shouldActivate =
238
+ !explicitPersonal &&
239
+ (currentOrgId === null ||
240
+ (await isSoloOwnedWorkspace(
241
+ exec,
242
+ currentOrgId,
243
+ membershipsBeforeJoin,
244
+ )));
245
+
246
+ if (shouldActivate) {
247
+ await putUserSetting(email, "active-org-id", { orgId: joinedOrgId });
248
+ const active = memberships.find((m) => m.orgId === joinedOrgId);
249
+ if (active) {
250
+ return {
251
+ email,
252
+ orgId: active.orgId,
253
+ orgName: active.orgName,
254
+ role: active.role,
255
+ };
256
+ }
205
257
  }
206
258
  }
207
259
  }
208
260
 
261
+ if (explicitPersonal) {
262
+ return { email, orgId: null, orgName: null, role: null };
263
+ }
264
+
265
+ if (activeOrgSetting?.orgId) {
266
+ const active = memberships.find((m) => m.orgId === activeOrgSetting.orgId);
267
+ if (active) {
268
+ return {
269
+ email,
270
+ orgId: active.orgId,
271
+ orgName: active.orgName,
272
+ role: active.role,
273
+ };
274
+ }
275
+ }
276
+
209
277
  if (sessionOrgId) {
210
278
  const active =
211
279
  sessionMembership ?? memberships.find((m) => m.orgId === sessionOrgId);
@@ -247,24 +315,25 @@ async function resolveOrgContextUncached(event: H3Event): Promise<OrgContext> {
247
315
  async function loadMemberships(
248
316
  exec: ReturnType<typeof getDbExec>,
249
317
  email: string,
250
- ): Promise<Array<{
251
- orgId: string;
252
- role: OrgRole;
253
- orgName: string;
254
- }> | null> {
318
+ ): Promise<MembershipRow[] | null> {
255
319
  try {
256
320
  const { rows } = await exec.execute({
257
- sql: `SELECT m.org_id AS "orgId", m.role AS role, o.name AS "orgName"
321
+ sql: `SELECT m.org_id AS "orgId", m.role AS role, o.name AS "orgName",
322
+ o.allowed_domain AS "allowedDomain"
258
323
  FROM org_members m
259
324
  INNER JOIN organizations o ON m.org_id = o.id
260
325
  WHERE LOWER(m.email) = ?`,
261
326
  args: [email.toLowerCase()],
262
327
  });
263
- return rows.map((r: any) => ({
264
- orgId: String(r.orgId ?? r.org_id),
265
- role: String(r.role) as OrgRole,
266
- orgName: String(r.orgName ?? r.org_name),
267
- }));
328
+ return rows.map((r: any) => {
329
+ const domain = r.allowedDomain ?? r.allowed_domain;
330
+ return {
331
+ orgId: String(r.orgId ?? r.org_id),
332
+ role: String(r.role) as OrgRole,
333
+ orgName: String(r.orgName ?? r.org_name),
334
+ allowedDomain: domain ? String(domain) : null,
335
+ };
336
+ });
268
337
  } catch {
269
338
  // Tables may not exist yet on first boot before migrations finish.
270
339
  return null;
package/src/org/index.ts CHANGED
@@ -28,6 +28,11 @@ export {
28
28
  createOrganization,
29
29
  } from "./context.js";
30
30
 
31
+ export {
32
+ implicitServiceOrgRole,
33
+ parseServiceIdentityEmail,
34
+ } from "./service-identity.js";
35
+
31
36
  export { acceptPendingInvitationsForEmail } from "./accept-pending.js";
32
37
  export type { AcceptPendingResult } from "./accept-pending.js";
33
38