@agent-native/core 0.117.1 → 0.117.2

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 (347) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +10 -0
  3. package/corpus/core/package.json +2 -1
  4. package/corpus/core/src/cli/context-xray-local.ts +1 -1
  5. package/corpus/core/src/client/extensions/ExtensionViewer.tsx +4 -4
  6. package/corpus/core/src/client/extensions/ExtensionsSidebarSection.tsx +11 -11
  7. package/corpus/core/src/client/extensions/agent-native-extension-runtime.ts +1 -1
  8. package/corpus/core/src/client/extensions/delete-extension.ts +2 -2
  9. package/corpus/core/src/client/org/OrgSwitcher.tsx +25 -1
  10. package/corpus/core/src/client/settings/SettingsPanel.tsx +102 -10
  11. package/corpus/core/src/client/sharing/ShareButton.tsx +7 -6
  12. package/corpus/core/src/db/client.ts +13 -10
  13. package/corpus/core/src/extensions/actions.ts +13 -5
  14. package/corpus/core/src/extensions/local.ts +1 -0
  15. package/corpus/core/src/extensions/routes.ts +10 -5
  16. package/corpus/core/src/extensions/schema.ts +5 -0
  17. package/corpus/core/src/extensions/slots/store.ts +14 -4
  18. package/corpus/core/src/extensions/store.ts +55 -19
  19. package/corpus/core/src/extensions/theme.ts +1 -1
  20. package/corpus/core/src/file-upload/registry.ts +9 -0
  21. package/corpus/core/src/index.browser.ts +5 -0
  22. package/corpus/core/src/index.ts +1 -0
  23. package/corpus/core/src/localization/default-messages.ts +23 -6
  24. package/corpus/core/src/server/action-discovery.ts +8 -0
  25. package/corpus/core/src/server/better-auth-instance.ts +7 -2
  26. package/corpus/core/src/server/email-template.ts +18 -0
  27. package/corpus/core/src/server/email-templates.ts +3 -0
  28. package/corpus/core/src/server/email.ts +40 -4
  29. package/corpus/core/src/sharing/actions/share-resource.ts +1 -0
  30. package/corpus/core/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  31. package/corpus/core/src/templates/default/app/global.css +1 -1
  32. package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +6 -6
  33. package/corpus/core/src/templates/default/app/i18n/de-DE.ts +6 -6
  34. package/corpus/core/src/templates/default/app/i18n/en-US.ts +6 -6
  35. package/corpus/core/src/templates/default/app/i18n/es-ES.ts +6 -6
  36. package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +6 -6
  37. package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +6 -6
  38. package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +6 -6
  39. package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +6 -6
  40. package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +6 -6
  41. package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +7 -7
  42. package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +7 -7
  43. package/corpus/core/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  44. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  45. package/corpus/core/src/user-profile/actions/get-user-profile.ts +16 -0
  46. package/corpus/core/src/user-profile/actions/update-user-profile.ts +24 -0
  47. package/corpus/core/src/user-profile/index.ts +5 -0
  48. package/corpus/core/src/user-profile/shared.ts +14 -0
  49. package/corpus/core/src/user-profile/store.ts +50 -0
  50. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  51. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  52. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +2 -2
  53. package/corpus/templates/assets/app/global.css +1 -1
  54. package/corpus/templates/assets/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  55. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  56. package/corpus/templates/brain/app/global.css +2 -2
  57. package/corpus/templates/brain/app/lib/brain.ts +2 -2
  58. package/corpus/templates/brain/app/root.tsx +2 -2
  59. package/corpus/templates/brain/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  60. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  61. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +6 -2
  62. package/corpus/templates/calendar/app/global.css +1 -1
  63. package/corpus/templates/calendar/app/root.tsx +2 -2
  64. package/corpus/templates/calendar/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  65. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  66. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +2 -2
  67. package/corpus/templates/chat/app/global.css +1 -1
  68. package/corpus/templates/chat/app/root.tsx +2 -2
  69. package/corpus/templates/chat/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  70. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  71. package/corpus/templates/clips/actions/export-to-brain.ts +1 -1
  72. package/corpus/templates/clips/actions/invite-member.ts +1 -0
  73. package/corpus/templates/clips/app/components/library/library-layout.tsx +2 -2
  74. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +20 -11
  75. package/corpus/templates/clips/app/global.css +1 -1
  76. package/corpus/templates/clips/app/root.tsx +7 -2
  77. package/corpus/templates/clips/app/routes/record.tsx +2 -88
  78. package/corpus/templates/clips/changelog/2026-07-22-builder-connected-recordings-start-resumable-upload-sessions.md +6 -0
  79. package/corpus/templates/clips/changelog/2026-07-22-clip-thumbnails-now-come-from-the-recording-instead-of-the-p.md +6 -0
  80. package/corpus/templates/clips/changelog/2026-07-22-clips-emails-now-render-the-agent-native-logo-in-gmail-and-o.md +6 -0
  81. package/corpus/templates/clips/changelog/2026-07-22-dismissed-zoom-and-teams-meeting-note-prompts-now-stay-dismi.md +6 -0
  82. package/corpus/templates/clips/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  83. package/corpus/templates/clips/changelog/2026-07-22-quieter-permissions-and-rewind-controls.md +6 -0
  84. package/corpus/templates/clips/desktop/src/app.tsx +86 -52
  85. package/corpus/templates/clips/desktop/src/lib/meeting-notification-dismissal.ts +31 -0
  86. package/corpus/templates/clips/desktop/src/lib/recorder.ts +4 -167
  87. package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +10 -1
  88. package/corpus/templates/clips/desktop/src/styles.css +98 -36
  89. package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +67 -4
  90. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +1 -1
  91. package/corpus/templates/clips/desktop/src-tauri/src/meetings_watcher.rs +51 -0
  92. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +5 -1
  93. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +0 -189
  94. package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +62 -0
  95. package/corpus/templates/clips/server/plugins/db.ts +6 -2
  96. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  97. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +3 -3
  98. package/corpus/templates/content/app/global.css +1 -1
  99. package/corpus/templates/content/app/root.tsx +2 -2
  100. package/corpus/templates/content/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  101. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  102. package/corpus/templates/crm/app/global.css +1 -1
  103. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  104. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +19 -1
  105. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +12 -1
  106. package/corpus/templates/design/app/components/design/EditPanel.tsx +177 -52
  107. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +179 -59
  108. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +74 -27
  109. package/corpus/templates/design/app/components/design/multi-screen/types.ts +2 -0
  110. package/corpus/templates/design/app/components/layout/Sidebar.tsx +2 -2
  111. package/corpus/templates/design/app/global.css +1 -1
  112. package/corpus/templates/design/app/hooks/use-navigation-state.ts +6 -5
  113. package/corpus/templates/design/app/root.tsx +2 -2
  114. package/corpus/templates/design/changelog/2026-07-22-design-owners-can-keep-editing-their-designs-after-switching.md +6 -0
  115. package/corpus/templates/design/changelog/2026-07-22-inspector-tabs-keep-their-text-labels-at-narrow-widths.md +6 -0
  116. package/corpus/templates/design/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  117. package/corpus/templates/design/changelog/2026-07-22-narrow-breakpoint-previews-keep-their-device-labels-readable.md +6 -0
  118. package/corpus/templates/design/changelog/2026-07-22-removed-the-draft-status-chip-from-the-design-editor.md +6 -0
  119. package/corpus/templates/design/changelog/2026-07-22-responsive-breakpoint-controls-stay-within-narrow-sidebars.md +6 -0
  120. package/corpus/templates/design/changelog/2026-07-22-responsive-peers-now-use-a-softer-selection-highlight-withou.md +6 -0
  121. package/corpus/templates/design/changelog/2026-07-22-rotate-from-context-menu.md +6 -0
  122. package/corpus/templates/design/changelog/2026-07-22-the-selection-outline-now-stays-attached-while-moving-screen.md +6 -0
  123. package/corpus/templates/design/changelog/2026-07-22-view-only-designs-now-support-figma-style-layer-inspection-w.md +6 -0
  124. package/corpus/templates/design/server/db/index.ts +4 -0
  125. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  126. package/corpus/templates/dispatch/app/dispatch-extensions.tsx +2 -2
  127. package/corpus/templates/dispatch/app/global.css +1 -1
  128. package/corpus/templates/dispatch/app/root.tsx +2 -2
  129. package/corpus/templates/dispatch/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  130. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  131. package/corpus/templates/forms/app/components/layout/Layout.tsx +1 -1
  132. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +3 -3
  133. package/corpus/templates/forms/app/global.css +1 -1
  134. package/corpus/templates/forms/app/hooks/use-forms.ts +55 -2
  135. package/corpus/templates/forms/app/i18n/en-US.ts +2 -0
  136. package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +3 -3
  137. package/corpus/templates/forms/app/pages/FormsListPage.tsx +23 -6
  138. package/corpus/templates/forms/app/root.tsx +2 -2
  139. package/corpus/templates/forms/changelog/2026-07-22-forms-now-archive-with-optimistic-feedback.md +6 -0
  140. package/corpus/templates/forms/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  141. package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -1
  142. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  143. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +2 -2
  144. package/corpus/templates/macros/app/root.tsx +2 -2
  145. package/corpus/templates/macros/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  146. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  147. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +3 -3
  148. package/corpus/templates/mail/app/components/layout/CommandPalette.tsx +2 -2
  149. package/corpus/templates/mail/app/global.css +1 -1
  150. package/corpus/templates/mail/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  151. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  152. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +2 -2
  153. package/corpus/templates/plan/app/global.css +1 -1
  154. package/corpus/templates/plan/app/root.tsx +2 -2
  155. package/corpus/templates/plan/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  156. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  157. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +2 -2
  158. package/corpus/templates/slides/app/root.tsx +2 -2
  159. package/corpus/templates/slides/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  160. package/corpus/templates/slides/changelog/2026-07-22-slides-no-longer-fail-intermittently-on-fresh-server-instances.md +6 -0
  161. package/corpus/templates/slides/changelog/2026-07-22-uploaded-screenshots-can-now-be-analyzed-and-recreated-as-ed.md +6 -0
  162. package/corpus/templates/slides/server/lib/chat-attachments.ts +7 -3
  163. package/corpus/templates/slides/server/plugins/db.ts +44 -17
  164. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  165. package/corpus/templates/tasks/app/global.css +1 -1
  166. package/dist/cli/context-xray-local.js +1 -1
  167. package/dist/cli/context-xray-local.js.map +1 -1
  168. package/dist/client/extensions/ExtensionViewer.js +2 -2
  169. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  170. package/dist/client/extensions/ExtensionsSidebarSection.js +11 -11
  171. package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
  172. package/dist/client/extensions/agent-native-extension-runtime.js +1 -1
  173. package/dist/client/extensions/agent-native-extension-runtime.js.map +1 -1
  174. package/dist/client/extensions/delete-extension.d.ts +1 -1
  175. package/dist/client/extensions/delete-extension.d.ts.map +1 -1
  176. package/dist/client/extensions/delete-extension.js +1 -1
  177. package/dist/client/extensions/delete-extension.js.map +1 -1
  178. package/dist/client/org/OrgSwitcher.d.ts +3 -1
  179. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  180. package/dist/client/org/OrgSwitcher.js +12 -4
  181. package/dist/client/org/OrgSwitcher.js.map +1 -1
  182. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  183. package/dist/client/settings/SettingsPanel.js +37 -4
  184. package/dist/client/settings/SettingsPanel.js.map +1 -1
  185. package/dist/client/sharing/ShareButton.d.ts +3 -4
  186. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  187. package/dist/client/sharing/ShareButton.js +3 -2
  188. package/dist/client/sharing/ShareButton.js.map +1 -1
  189. package/dist/collab/awareness.d.ts +2 -2
  190. package/dist/collab/awareness.d.ts.map +1 -1
  191. package/dist/db/client.d.ts +7 -7
  192. package/dist/db/client.d.ts.map +1 -1
  193. package/dist/db/client.js +13 -10
  194. package/dist/db/client.js.map +1 -1
  195. package/dist/extensions/actions.d.ts.map +1 -1
  196. package/dist/extensions/actions.js +8 -5
  197. package/dist/extensions/actions.js.map +1 -1
  198. package/dist/extensions/local.d.ts.map +1 -1
  199. package/dist/extensions/local.js +1 -0
  200. package/dist/extensions/local.js.map +1 -1
  201. package/dist/extensions/routes.d.ts.map +1 -1
  202. package/dist/extensions/routes.js +9 -4
  203. package/dist/extensions/routes.js.map +1 -1
  204. package/dist/extensions/schema.d.ts +23 -2
  205. package/dist/extensions/schema.d.ts.map +1 -1
  206. package/dist/extensions/schema.js +5 -0
  207. package/dist/extensions/schema.js.map +1 -1
  208. package/dist/extensions/slots/store.d.ts +1 -1
  209. package/dist/extensions/slots/store.d.ts.map +1 -1
  210. package/dist/extensions/slots/store.js +4 -4
  211. package/dist/extensions/slots/store.js.map +1 -1
  212. package/dist/extensions/store.d.ts +1 -0
  213. package/dist/extensions/store.d.ts.map +1 -1
  214. package/dist/extensions/store.js +38 -21
  215. package/dist/extensions/store.js.map +1 -1
  216. package/dist/extensions/theme.js +1 -1
  217. package/dist/extensions/theme.js.map +1 -1
  218. package/dist/file-upload/registry.d.ts.map +1 -1
  219. package/dist/file-upload/registry.js +9 -0
  220. package/dist/file-upload/registry.js.map +1 -1
  221. package/dist/index.browser.d.ts +1 -0
  222. package/dist/index.browser.d.ts.map +1 -1
  223. package/dist/index.browser.js +1 -0
  224. package/dist/index.browser.js.map +1 -1
  225. package/dist/index.d.ts +1 -0
  226. package/dist/index.d.ts.map +1 -1
  227. package/dist/index.js +1 -0
  228. package/dist/index.js.map +1 -1
  229. package/dist/localization/default-messages.d.ts +16 -0
  230. package/dist/localization/default-messages.d.ts.map +1 -1
  231. package/dist/localization/default-messages.js +22 -6
  232. package/dist/localization/default-messages.js.map +1 -1
  233. package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
  234. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  235. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  236. package/dist/secrets/routes.d.ts +6 -6
  237. package/dist/server/action-discovery.d.ts.map +1 -1
  238. package/dist/server/action-discovery.js +8 -0
  239. package/dist/server/action-discovery.js.map +1 -1
  240. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  241. package/dist/server/better-auth-instance.d.ts +7 -2
  242. package/dist/server/better-auth-instance.d.ts.map +1 -1
  243. package/dist/server/better-auth-instance.js.map +1 -1
  244. package/dist/server/email-template.d.ts +3 -0
  245. package/dist/server/email-template.d.ts.map +1 -1
  246. package/dist/server/email-template.js +13 -0
  247. package/dist/server/email-template.js.map +1 -1
  248. package/dist/server/email-templates.d.ts.map +1 -1
  249. package/dist/server/email-templates.js +3 -0
  250. package/dist/server/email-templates.js.map +1 -1
  251. package/dist/server/email.d.ts.map +1 -1
  252. package/dist/server/email.js +27 -4
  253. package/dist/server/email.js.map +1 -1
  254. package/dist/sharing/actions/share-resource.js +1 -0
  255. package/dist/sharing/actions/share-resource.js.map +1 -1
  256. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  257. package/dist/templates/chat/app/components/layout/Sidebar.tsx +2 -2
  258. package/dist/templates/chat/app/global.css +1 -1
  259. package/dist/templates/chat/app/root.tsx +2 -2
  260. package/dist/templates/chat/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  261. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  262. package/dist/templates/default/app/global.css +1 -1
  263. package/dist/templates/default/app/i18n/ar-SA.ts +6 -6
  264. package/dist/templates/default/app/i18n/de-DE.ts +6 -6
  265. package/dist/templates/default/app/i18n/en-US.ts +6 -6
  266. package/dist/templates/default/app/i18n/es-ES.ts +6 -6
  267. package/dist/templates/default/app/i18n/fr-FR.ts +6 -6
  268. package/dist/templates/default/app/i18n/hi-IN.ts +6 -6
  269. package/dist/templates/default/app/i18n/ja-JP.ts +6 -6
  270. package/dist/templates/default/app/i18n/ko-KR.ts +6 -6
  271. package/dist/templates/default/app/i18n/pt-BR.ts +6 -6
  272. package/dist/templates/default/app/i18n/zh-CN.ts +7 -7
  273. package/dist/templates/default/app/i18n/zh-TW.ts +7 -7
  274. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  275. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  276. package/dist/user-profile/actions/get-user-profile.d.ts +4 -0
  277. package/dist/user-profile/actions/get-user-profile.d.ts.map +1 -0
  278. package/dist/user-profile/actions/get-user-profile.js +14 -0
  279. package/dist/user-profile/actions/get-user-profile.js.map +1 -0
  280. package/dist/user-profile/actions/update-user-profile.d.ts +6 -0
  281. package/dist/user-profile/actions/update-user-profile.d.ts.map +1 -0
  282. package/dist/user-profile/actions/update-user-profile.js +20 -0
  283. package/dist/user-profile/actions/update-user-profile.js.map +1 -0
  284. package/dist/user-profile/index.d.ts +2 -0
  285. package/dist/user-profile/index.d.ts.map +1 -0
  286. package/dist/user-profile/index.js +2 -0
  287. package/dist/user-profile/index.js.map +1 -0
  288. package/dist/user-profile/shared.d.ts +7 -0
  289. package/dist/user-profile/shared.d.ts.map +1 -0
  290. package/dist/user-profile/shared.js +6 -0
  291. package/dist/user-profile/shared.js.map +1 -0
  292. package/dist/user-profile/store.d.ts +4 -0
  293. package/dist/user-profile/store.d.ts.map +1 -0
  294. package/dist/user-profile/store.js +38 -0
  295. package/dist/user-profile/store.js.map +1 -0
  296. package/package.json +2 -1
  297. package/src/cli/context-xray-local.ts +1 -1
  298. package/src/client/extensions/ExtensionViewer.tsx +4 -4
  299. package/src/client/extensions/ExtensionsSidebarSection.tsx +11 -11
  300. package/src/client/extensions/agent-native-extension-runtime.ts +1 -1
  301. package/src/client/extensions/delete-extension.ts +2 -2
  302. package/src/client/org/OrgSwitcher.tsx +25 -1
  303. package/src/client/settings/SettingsPanel.tsx +102 -10
  304. package/src/client/sharing/ShareButton.tsx +7 -6
  305. package/src/db/client.ts +13 -10
  306. package/src/extensions/actions.ts +13 -5
  307. package/src/extensions/local.ts +1 -0
  308. package/src/extensions/routes.ts +10 -5
  309. package/src/extensions/schema.ts +5 -0
  310. package/src/extensions/slots/store.ts +14 -4
  311. package/src/extensions/store.ts +55 -19
  312. package/src/extensions/theme.ts +1 -1
  313. package/src/file-upload/registry.ts +9 -0
  314. package/src/index.browser.ts +5 -0
  315. package/src/index.ts +1 -0
  316. package/src/localization/default-messages.ts +23 -6
  317. package/src/server/action-discovery.ts +8 -0
  318. package/src/server/better-auth-instance.ts +7 -2
  319. package/src/server/email-template.ts +18 -0
  320. package/src/server/email-templates.ts +3 -0
  321. package/src/server/email.ts +40 -4
  322. package/src/sharing/actions/share-resource.ts +1 -0
  323. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  324. package/src/templates/chat/app/components/layout/Sidebar.tsx +2 -2
  325. package/src/templates/chat/app/global.css +1 -1
  326. package/src/templates/chat/app/root.tsx +2 -2
  327. package/src/templates/chat/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  328. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  329. package/src/templates/default/app/global.css +1 -1
  330. package/src/templates/default/app/i18n/ar-SA.ts +6 -6
  331. package/src/templates/default/app/i18n/de-DE.ts +6 -6
  332. package/src/templates/default/app/i18n/en-US.ts +6 -6
  333. package/src/templates/default/app/i18n/es-ES.ts +6 -6
  334. package/src/templates/default/app/i18n/fr-FR.ts +6 -6
  335. package/src/templates/default/app/i18n/hi-IN.ts +6 -6
  336. package/src/templates/default/app/i18n/ja-JP.ts +6 -6
  337. package/src/templates/default/app/i18n/ko-KR.ts +6 -6
  338. package/src/templates/default/app/i18n/pt-BR.ts +6 -6
  339. package/src/templates/default/app/i18n/zh-CN.ts +7 -7
  340. package/src/templates/default/app/i18n/zh-TW.ts +7 -7
  341. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  342. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  343. package/src/user-profile/actions/get-user-profile.ts +16 -0
  344. package/src/user-profile/actions/update-user-profile.ts +24 -0
  345. package/src/user-profile/index.ts +5 -0
  346. package/src/user-profile/shared.ts +14 -0
  347. package/src/user-profile/store.ts +50 -0
@@ -839,7 +839,11 @@ export function createExtensionActionEntries(): Record<string, ActionEntry> {
839
839
 
840
840
  await ensureExtensionsTables();
841
841
  const access = await resolveAccess("extension", extensionId);
842
- if (!access || access.role === "viewer")
842
+ if (
843
+ !access ||
844
+ (access.resource as ExtensionRow | undefined)?.archivedAt ||
845
+ access.role === "viewer"
846
+ )
843
847
  return `Error: editor access required for extension ${extensionId}.`;
844
848
 
845
849
  const userEmail = getRequestUserEmail()?.toLowerCase() ?? "";
@@ -942,7 +946,11 @@ export function createExtensionActionEntries(): Record<string, ActionEntry> {
942
946
 
943
947
  await ensureExtensionsTables();
944
948
  const access = await resolveAccess("extension", extensionId);
945
- if (!access) return `Error: no access to extension ${extensionId}.`;
949
+ if (
950
+ !access ||
951
+ (access.resource as ExtensionRow | undefined)?.archivedAt
952
+ )
953
+ return `Error: no access to extension ${extensionId}.`;
946
954
 
947
955
  const userEmail = getRequestUserEmail()?.toLowerCase() ?? "";
948
956
  const scope = args?.scope ?? "user";
@@ -1012,14 +1020,14 @@ export function createExtensionActionEntries(): Record<string, ActionEntry> {
1012
1020
  "delete-extension": {
1013
1021
  tool: {
1014
1022
  description:
1015
- "Permanently delete an extension everywhere it is shared. Requires owner/admin access. If the user only wants a shared extension removed from their own sidebar/list, use hide-extension instead.",
1023
+ "Archive an extension everywhere it is shared. Archiving is a soft delete: the extension and its history, data, sharing, and slot configuration are retained, but it disappears from normal lists. Requires owner/admin access. If the user only wants a shared extension removed from their own sidebar/list, use hide-extension instead.",
1016
1024
  parameters: {
1017
1025
  type: "object",
1018
1026
  properties: {
1019
1027
  id: {
1020
1028
  type: "string",
1021
1029
  description:
1022
- "Extension id to permanently delete. Use list-extensions first if you only know the display name.",
1030
+ "Extension id to archive. Use list-extensions first if you only know the display name.",
1023
1031
  },
1024
1032
  },
1025
1033
  required: ["id"],
@@ -1036,7 +1044,7 @@ export function createExtensionActionEntries(): Record<string, ActionEntry> {
1036
1044
  try {
1037
1045
  const ok = await deleteExtension(id);
1038
1046
  if (!ok) return `Error: extension not found: ${id}`;
1039
- return { ok: true, deleted: summarizeDeletedExtension(extension) };
1047
+ return { ok: true, archived: summarizeDeletedExtension(extension) };
1040
1048
  } catch (err: any) {
1041
1049
  return {
1042
1050
  ok: false,
@@ -322,6 +322,7 @@ async function readLocalExtensionFolder(options: {
322
322
  icon: typeof manifest.icon === "string" ? manifest.icon : null,
323
323
  createdAt,
324
324
  updatedAt,
325
+ archivedAt: null,
325
326
  hiddenAt: null,
326
327
  hiddenBy: null,
327
328
  ownerEmail: "local-files",
@@ -227,8 +227,8 @@ async function dispatch(
227
227
  }
228
228
 
229
229
  const access = await resolveAccess("extension", parts[0]);
230
- const extension = access?.resource;
231
- if (!extension) {
230
+ const extension = access?.resource as ExtensionRow | undefined;
231
+ if (!access || !extension || extension.archivedAt) {
232
232
  setResponseStatus(event, 404);
233
233
  return { error: "Extension not found" };
234
234
  }
@@ -317,11 +317,12 @@ async function dispatch(
317
317
  }
318
318
 
319
319
  const access = await resolveAccess("extension", parts[0]);
320
- if (!access) {
320
+ const extension = access?.resource as ExtensionRow | undefined;
321
+ if (!access || !extension || extension.archivedAt) {
321
322
  setResponseStatus(event, 404);
322
323
  return { error: "Extension not found" };
323
324
  }
324
- return extensionResponse(access.resource as ExtensionRow, access.role);
325
+ return extensionResponse(extension, access.role);
325
326
  }
326
327
 
327
328
  // POST /:id/hide — remove from the current user's Extensions list/sidebar
@@ -433,7 +434,7 @@ async function dispatch(
433
434
  setResponseStatus(event, 404);
434
435
  return { error: "Extension not found" };
435
436
  }
436
- return { ok: true };
437
+ return { ok: true, archived: true };
437
438
  }
438
439
 
439
440
  setResponseStatus(event, 404);
@@ -662,6 +663,10 @@ async function requireExtensionDataAccess(
662
663
  minRole: ShareRole,
663
664
  ): Promise<{ ok: true } | { ok: false; response: unknown }> {
664
665
  const access = await resolveAccess("extension", extensionId);
666
+ if (access?.resource && (access.resource as ExtensionRow).archivedAt) {
667
+ setResponseStatus(event, 404);
668
+ return { ok: false, response: { error: "Extension not found" } };
669
+ }
665
670
  if (access) {
666
671
  if (ROLE_RANK[access.role] < ROLE_RANK[minRole]) {
667
672
  setResponseStatus(event, 403);
@@ -27,6 +27,7 @@ export const extensions = table("tools", {
27
27
  icon: text("icon"),
28
28
  createdAt: text("created_at").notNull().default(now()),
29
29
  updatedAt: text("updated_at").notNull().default(now()),
30
+ archivedAt: text("archived_at"),
30
31
  hiddenAt: text("hidden_at"),
31
32
  hiddenBy: text("hidden_by"),
32
33
  ...ownableColumns(),
@@ -66,6 +67,7 @@ export const EXTENSIONS_CREATE_SQL = `CREATE TABLE IF NOT EXISTS tools (
66
67
  icon TEXT,
67
68
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
68
69
  updated_at TEXT NOT NULL DEFAULT (datetime('now')),
70
+ archived_at TEXT,
69
71
  hidden_at TEXT,
70
72
  hidden_by TEXT,
71
73
  owner_email TEXT NOT NULL DEFAULT 'local@localhost',
@@ -81,6 +83,7 @@ export const EXTENSIONS_CREATE_SQL_PG = `CREATE TABLE IF NOT EXISTS tools (
81
83
  icon TEXT,
82
84
  created_at TEXT NOT NULL DEFAULT now(),
83
85
  updated_at TEXT NOT NULL DEFAULT now(),
86
+ archived_at TEXT,
84
87
  hidden_at TEXT,
85
88
  hidden_by TEXT,
86
89
  owner_email TEXT NOT NULL DEFAULT 'local@localhost',
@@ -162,6 +165,8 @@ export const EXTENSION_DATA_DROP_OLD_INDEX_SQL_PG = `DROP INDEX IF EXISTS tool_d
162
165
  export const EXTENSIONS_OWNER_INDEX_SQL = `CREATE INDEX IF NOT EXISTS tools_owner_idx ON tools (owner_email)`;
163
166
  export const EXTENSIONS_ORG_INDEX_SQL = `CREATE INDEX IF NOT EXISTS tools_org_idx ON tools (org_id)`;
164
167
  export const EXTENSIONS_UPDATED_INDEX_SQL = `CREATE INDEX IF NOT EXISTS tools_updated_at_idx ON tools (updated_at)`;
168
+ export const EXTENSIONS_ARCHIVED_AT_COLUMN_SQL = `ALTER TABLE tools ADD COLUMN IF NOT EXISTS archived_at TEXT`;
169
+ export const EXTENSIONS_ARCHIVED_AT_INDEX_SQL = `CREATE INDEX IF NOT EXISTS tools_archived_at_idx ON tools (archived_at)`;
165
170
 
166
171
  // Global (admin) hide: when set, the extension row is hidden from EVERYONE's
167
172
  // list, distinct from the per-user `tool_hidden_extensions` table. Additive
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
 
3
- import { and, eq, inArray, sql } from "drizzle-orm";
3
+ import { and, eq, inArray, isNull, sql } from "drizzle-orm";
4
4
 
5
5
  import { getDbExec, isPostgres } from "../../db/client.js";
6
6
  import { createGetDb } from "../../db/create-get-db.js";
@@ -203,7 +203,12 @@ export async function listExtensionsForSlot(slotId: string): Promise<
203
203
  icon: extensions.icon,
204
204
  })
205
205
  .from(extensions)
206
- .where(accessFilter(extensions, extensionShares));
206
+ .where(
207
+ and(
208
+ accessFilter(extensions, extensionShares),
209
+ isNull(extensions.archivedAt),
210
+ ),
211
+ );
207
212
  const localRows = (await listLocalExtensions())
208
213
  .filter((extension) => extension.source.slots.includes(slotId))
209
214
  .map((extension) => ({
@@ -397,7 +402,12 @@ export async function listSlotInstallsForUser(slotId: string): Promise<
397
402
  updatedAt: extensions.updatedAt,
398
403
  })
399
404
  .from(extensions)
400
- .where(accessFilter(extensions, extensionShares));
405
+ .where(
406
+ and(
407
+ accessFilter(extensions, extensionShares),
408
+ isNull(extensions.archivedAt),
409
+ ),
410
+ );
401
411
  const byId = new Map(accessible.map((t: any) => [t.id, t]));
402
412
 
403
413
  const sqlInstalls = (installs as ExtensionSlotInstallRow[])
@@ -419,7 +429,7 @@ export async function listSlotInstallsForUser(slotId: string): Promise<
419
429
  return [...localInstalls, ...sqlInstalls];
420
430
  }
421
431
 
422
- /** Delete every slot/install row referencing a extension. Called from deleteExtension. */
432
+ /** Delete every slot/install row referencing an extension for maintenance. */
423
433
  export async function cascadeDeleteExtensionSlots(
424
434
  extensionId: string,
425
435
  ): Promise<void> {
@@ -52,6 +52,8 @@ import {
52
52
  EXTENSIONS_OWNER_INDEX_SQL,
53
53
  EXTENSIONS_ORG_INDEX_SQL,
54
54
  EXTENSIONS_UPDATED_INDEX_SQL,
55
+ EXTENSIONS_ARCHIVED_AT_COLUMN_SQL,
56
+ EXTENSIONS_ARCHIVED_AT_INDEX_SQL,
55
57
  EXTENSIONS_HIDDEN_AT_COLUMN_SQL,
56
58
  EXTENSIONS_HIDDEN_BY_COLUMN_SQL,
57
59
  EXTENSIONS_HIDDEN_AT_INDEX_SQL,
@@ -103,6 +105,11 @@ export async function ensureExtensionsTables(): Promise<void> {
103
105
  "tools_updated_at_idx",
104
106
  EXTENSIONS_UPDATED_INDEX_SQL,
105
107
  );
108
+ await ensureExtensionsArchivedColumn(client, pg);
109
+ await ensureIndexExists(
110
+ "tools_archived_at_idx",
111
+ EXTENSIONS_ARCHIVED_AT_INDEX_SQL,
112
+ );
106
113
  await ensureExtensionsGlobalHideColumns(client, pg); // ADD COLUMN — guarded inside
107
114
  await ensureIndexExists(
108
115
  "tools_hidden_at_idx",
@@ -176,6 +183,10 @@ export async function ensureExtensionsTables(): Promise<void> {
176
183
  await retryOnDdlRace(() => client.execute(EXTENSIONS_OWNER_INDEX_SQL));
177
184
  await retryOnDdlRace(() => client.execute(EXTENSIONS_ORG_INDEX_SQL));
178
185
  await retryOnDdlRace(() => client.execute(EXTENSIONS_UPDATED_INDEX_SQL));
186
+ await ensureExtensionsArchivedColumn(client, pg);
187
+ await retryOnDdlRace(() =>
188
+ client.execute(EXTENSIONS_ARCHIVED_AT_INDEX_SQL),
189
+ );
179
190
  await ensureExtensionsGlobalHideColumns(client, pg);
180
191
  await retryOnDdlRace(() =>
181
192
  client.execute(EXTENSIONS_HIDDEN_AT_INDEX_SQL),
@@ -346,6 +357,31 @@ async function ensureExtensionsGlobalHideColumns(
346
357
  await addCol(EXTENSIONS_HIDDEN_BY_COLUMN_SQL, "hidden_by", "TEXT");
347
358
  }
348
359
 
360
+ async function ensureExtensionsArchivedColumn(
361
+ client: ReturnType<typeof getDbExec>,
362
+ pg: boolean,
363
+ ): Promise<void> {
364
+ if (pg) {
365
+ await ensureColumnExists(
366
+ "tools",
367
+ "archived_at",
368
+ EXTENSIONS_ARCHIVED_AT_COLUMN_SQL,
369
+ );
370
+ return;
371
+ }
372
+ await client
373
+ .execute("ALTER TABLE tools ADD COLUMN archived_at TEXT")
374
+ .catch((err: any) => {
375
+ if (
376
+ !String(err?.message ?? err)
377
+ .toLowerCase()
378
+ .includes("duplicate")
379
+ ) {
380
+ throw err;
381
+ }
382
+ });
383
+ }
384
+
349
385
  export function registerExtensionsShareable() {
350
386
  registerShareableResource({
351
387
  type: "extension",
@@ -373,6 +409,7 @@ export interface ExtensionRow {
373
409
  icon: string | null;
374
410
  createdAt: string;
375
411
  updatedAt: string;
412
+ archivedAt: string | null;
376
413
  hiddenAt: string | null;
377
414
  hiddenBy: string | null;
378
415
  ownerEmail: string;
@@ -881,9 +918,10 @@ export async function listExtensions(
881
918
  // on repeated `.where()` calls, so combine the access filter and the
882
919
  // global-hidden filter into one condition.
883
920
  const base = accessFilter(extensions, extensionShares);
921
+ const visible = and(base, isNull(extensions.archivedAt));
884
922
  const where = options.includeGloballyHidden
885
- ? base
886
- : and(base, isNull(extensions.hiddenAt));
923
+ ? visible
924
+ : and(visible, isNull(extensions.hiddenAt));
887
925
  const rows = (await db
888
926
  .select()
889
927
  .from(extensions)
@@ -899,7 +937,8 @@ export async function listExtensions(
899
937
  export async function getExtension(id: string): Promise<ExtensionRow | null> {
900
938
  await ensureExtensionsTables();
901
939
  const access = await resolveAccess("extension", id);
902
- return (access?.resource as ExtensionRow | undefined) ?? null;
940
+ const resource = access?.resource as ExtensionRow | undefined;
941
+ return resource?.archivedAt ? null : (resource ?? null);
903
942
  }
904
943
 
905
944
  export interface ListExtensionHistoryOptions {
@@ -983,7 +1022,7 @@ export async function restoreExtensionHistoryVersion(
983
1022
  .from(extensions)
984
1023
  .where(eq(extensions.id, id));
985
1024
  const existing = existingRows[0] as ExtensionRow | undefined;
986
- if (!existing) return null;
1025
+ if (!existing || existing.archivedAt) return null;
987
1026
 
988
1027
  await ensureExtensionHistoryBaseline(existing);
989
1028
  const target = await getPersistedHistoryEntry(id, version, true);
@@ -1045,6 +1084,7 @@ export async function createExtension(
1045
1084
  icon: data.icon ?? null,
1046
1085
  createdAt: now,
1047
1086
  updatedAt: now,
1087
+ archivedAt: null,
1048
1088
  hiddenAt: null,
1049
1089
  hiddenBy: null,
1050
1090
  ownerEmail: userEmail,
@@ -1098,6 +1138,7 @@ export async function findRecentDuplicateExtension(data: {
1098
1138
  eq(extensions.description, description),
1099
1139
  icon === null ? isNull(extensions.icon) : eq(extensions.icon, icon),
1100
1140
  gte(extensions.createdAt, fiveMinutesAgo),
1141
+ isNull(extensions.archivedAt),
1101
1142
  isNull(extensions.hiddenAt),
1102
1143
  ),
1103
1144
  )
@@ -1146,7 +1187,7 @@ export async function updateExtension(
1146
1187
  .from(extensions)
1147
1188
  .where(eq(extensions.id, id));
1148
1189
  const existing = existingRows[0] as ExtensionRow | undefined;
1149
- if (!existing) return null;
1190
+ if (!existing || existing.archivedAt) return null;
1150
1191
  await ensureExtensionHistoryBaseline(existing);
1151
1192
  await db.update(extensions).set(updates).where(eq(extensions.id, id));
1152
1193
  const rows = await db.select().from(extensions).where(eq(extensions.id, id));
@@ -1200,7 +1241,9 @@ export async function updateExtensionContent(
1200
1241
  .select()
1201
1242
  .from(extensions)
1202
1243
  .where(eq(extensions.id, id));
1203
- if (!existingRows[0]) return null;
1244
+ if (!existingRows[0] || (existingRows[0] as ExtensionRow).archivedAt) {
1245
+ return null;
1246
+ }
1204
1247
  const existing = existingRows[0] as ExtensionRow;
1205
1248
  const existingContent = existing.content;
1206
1249
  await ensureExtensionHistoryBaseline(existing);
@@ -1234,20 +1277,13 @@ export async function deleteExtension(id: string): Promise<boolean> {
1234
1277
  const rows = await db.select().from(extensions).where(eq(extensions.id, id));
1235
1278
  const row = rows[0] as ExtensionRow | undefined;
1236
1279
  if (!row) return false;
1280
+ if (row.archivedAt) return true;
1237
1281
  const targets = await extensionChangeTargetsForRow(row);
1238
- await db.delete(extensionShares).where(eq(extensionShares.resourceId, id));
1239
- await db.delete(extensionHides).where(eq(extensionHides.extensionId, id));
1240
- await getDbExec().execute({
1241
- sql: `DELETE FROM tool_data WHERE tool_id = ?`,
1242
- args: [id],
1243
- });
1244
- await getDbExec().execute({
1245
- sql: `DELETE FROM tool_history WHERE tool_id = ?`,
1246
- args: [id],
1247
- });
1248
- const { cascadeDeleteExtensionSlots } = await import("./slots/store.js");
1249
- await cascadeDeleteExtensionSlots(id);
1250
- await db.delete(extensions).where(eq(extensions.id, id));
1282
+ const archivedAt = new Date().toISOString();
1283
+ await db
1284
+ .update(extensions)
1285
+ .set({ archivedAt, updatedAt: archivedAt })
1286
+ .where(eq(extensions.id, id));
1251
1287
  await notifyExtensionChanged(targets);
1252
1288
  return true;
1253
1289
  }
@@ -92,7 +92,7 @@ export function getThemeVars(_isDark?: boolean): string {
92
92
  --muted-foreground: 240 5% 64.9%;
93
93
  --accent: 240 3.7% 15.9%;
94
94
  --accent-foreground: 0 0% 98%;
95
- --destructive: 0 62.8% 30.6%;
95
+ --destructive: 0 84% 60%;
96
96
  --destructive-foreground: 0 0% 98%;
97
97
  --border: 240 3.7% 15.9%;
98
98
  --input: 240 3.7% 15.9%;
@@ -69,6 +69,15 @@ export async function getActiveFileUploadProviderForRequest(): Promise<FileUploa
69
69
  if (builderFileUploadProvider.isConfigured()) {
70
70
  return builderFileUploadProvider;
71
71
  }
72
+ try {
73
+ const { resolveHasBuilderPrivateKey } =
74
+ await import("../server/credential-provider.js");
75
+ if (await resolveHasBuilderPrivateKey()) {
76
+ return builderFileUploadProvider;
77
+ }
78
+ } catch {
79
+ // Treat failed scoped credential lookups as unavailable.
80
+ }
72
81
  return null;
73
82
  }
74
83
 
@@ -100,6 +100,11 @@ export {
100
100
  type ActionMcpAppResourceConfig,
101
101
  type ActionMcpAppResourceMeta,
102
102
  } from "./action.js";
103
+ export {
104
+ normalizeUserProfileName,
105
+ USER_PROFILE_SETTING_KEY,
106
+ type UserProfile,
107
+ } from "./user-profile/index.js";
103
108
  export {
104
109
  ACTION_CHAT_UI_DATA_CHART_RENDERER,
105
110
  ACTION_CHAT_UI_DATA_INSIGHTS_RENDERER,
@@ -41,6 +41,7 @@ export {
41
41
  type ActionMcpAppResourceConfig,
42
42
  type ActionMcpAppResourceMeta,
43
43
  } from "./action.js";
44
+ export * from "./user-profile/index.js";
44
45
  export {
45
46
  embedApp,
46
47
  MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,
@@ -32,6 +32,23 @@ const messages = {
32
32
  openTeamSettings: "Open team settings",
33
33
  openResourceSettings: "Open resource settings",
34
34
  backHome: "Back to home",
35
+ profileTitle: "Account",
36
+ profileDescription: "Your name, profile photo, and signed-in identity.",
37
+ profileLoading: "Loading...",
38
+ profileSignedOut: "Signed out",
39
+ profilePhotoUpdated: "Photo updated",
40
+ profilePhotoError: "Could not update photo",
41
+ profileUploading: "Uploading...",
42
+ profileChangePhoto: "Change photo",
43
+ profileNameLabel: "Name",
44
+ profileNamePlaceholder: "Your name",
45
+ profileNameDescription:
46
+ "This name is used when referring to you across Agent-Native apps.",
47
+ profileSave: "Save changes",
48
+ profileSaving: "Saving...",
49
+ profileSaved: "Profile updated",
50
+ profileSaveError: "Could not update profile",
51
+ profileMenuItem: "Profile",
35
52
  },
36
53
  agentResources: {
37
54
  openDocs: "Open {{section}} documentation",
@@ -634,23 +651,23 @@ const messages = {
634
651
  hideEveryone: "Hide from everyone",
635
652
  localFileDescription:
636
653
  "This extension is backed by {{entryPath}}. Edit or remove it from the workspace.",
637
- deleteQuestion: "Delete {{name}}?",
654
+ deleteQuestion: "Archive {{name}}?",
638
655
  removeQuestion: "Remove {{name}}?",
639
656
  hideForYouDescription:
640
657
  "This hides it from your Extensions list without deleting it for anyone else.",
641
- removeEverywhereDescription: "This removes it everywhere it is shared.",
658
+ removeEverywhereDescription: "This archives it everywhere it is shared.",
642
659
  cancel: "Cancel",
643
660
  remove: "Remove",
644
661
  removing: "Removing...",
645
- delete: "Delete",
646
- deleting: "Deleting...",
662
+ delete: "Archive",
663
+ deleting: "Archiving...",
647
664
  openFullView: "Open full view",
648
665
  removeFromWidgetArea: "Remove from this widget area",
649
- deleteExtensionEllipsis: "Delete extension...",
666
+ deleteExtensionEllipsis: "Archive extension...",
650
667
  removeFromMyListEllipsis: "Remove from my list...",
651
668
  removeFromWidgetAreaForMe: "Remove from this widget area (for me)",
652
669
  deleteEverywhereConfirmation:
653
- "This removes the extension everywhere, for everyone it's shared with.",
670
+ "This archives the extension everywhere, for everyone it's shared with.",
654
671
  addWidget: "Add widget",
655
672
  loading: "Loading...",
656
673
  noWidgetsAvailable: "No widgets available for this slot yet.",
@@ -658,6 +658,14 @@ export async function mergeCoreSharingActions(
658
658
  "set-localization-preference",
659
659
  () => import("../localization/actions/set-localization-preference.js"),
660
660
  ],
661
+ [
662
+ "get-user-profile",
663
+ () => import("../user-profile/actions/get-user-profile.js"),
664
+ ],
665
+ [
666
+ "update-user-profile",
667
+ () => import("../user-profile/actions/update-user-profile.js"),
668
+ ],
661
669
  [
662
670
  "change-appearance",
663
671
  () => import("../appearance/actions/change-appearance.js"),
@@ -740,8 +740,8 @@ export function getBetterAuthSync(): BetterAuthInstance | undefined {
740
740
  * The subset of Better Auth's internal adapter we use for federated-SSO
741
741
  * JIT account linking. Better Auth owns these writes (id + timestamp +
742
742
  * schema handling), so callers never hand-roll SQL against `user`/`account`.
743
- * Read-only lookups + strictly-additive `linkAccount`/`createUser` only no
744
- * update/delete of existing identity rows.
743
+ * Read-only lookups plus account-linking and profile-update operations used by
744
+ * shared Core surfaces. Better Auth owns the actual identity writes.
745
745
  */
746
746
  export interface BetterAuthInternalAdapter {
747
747
  findUserByEmail: (
@@ -761,6 +761,11 @@ export interface BetterAuthInternalAdapter {
761
761
  name: string;
762
762
  emailVerified?: boolean;
763
763
  }) => Promise<{ id: string }>;
764
+ /** Optional because older/custom adapter shapes may not expose mutations. */
765
+ updateUser?: (
766
+ userId: string,
767
+ data: { name?: string; image?: string | null },
768
+ ) => Promise<unknown>;
764
769
  }
765
770
 
766
771
  /**
@@ -18,6 +18,10 @@
18
18
  * });
19
19
  */
20
20
 
21
+ import { getAppName } from "./app-name.js";
22
+
23
+ export const AGENT_NATIVE_EMAIL_LOGO_CONTENT_ID = "agent-native-logo";
24
+
21
25
  export interface EmailCta {
22
26
  label: string;
23
27
  url: string;
@@ -34,6 +38,8 @@ export interface RenderEmailArgs {
34
38
  cta?: EmailCta;
35
39
  /** Small muted text under the CTA (e.g. expiry note). */
36
40
  footer?: string;
41
+ /** Optional app name shown beside the framework logo. */
42
+ brandName?: string;
37
43
  /**
38
44
  * Optional brand hex color for the CTA button and inline links. Defaults to
39
45
  * a monochrome near-white button with dark text.
@@ -71,6 +77,7 @@ function sanitizeHexColor(input: string | undefined): string | undefined {
71
77
  export function renderEmail(args: RenderEmailArgs): RenderedEmail {
72
78
  const preheader = args.preheader || "";
73
79
  const brand = sanitizeHexColor(args.brandColor);
80
+ const brandName = args.brandName?.trim() || getAppName() || "Agent Native";
74
81
 
75
82
  // Monochrome default: near-white button with dark text. Brand override:
76
83
  // colored button with white text.
@@ -104,6 +111,16 @@ export function renderEmail(args: RenderEmailArgs): RenderedEmail {
104
111
  ? `<p style="margin:28px 0 0 0; font-size:13px; line-height:1.5; color:#71717a;">${escapeHtml(args.footer)}</p>`
105
112
  : "";
106
113
 
114
+ const brandHeaderHtml = `
115
+ <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="margin:0 0 28px 0; padding:0 0 24px 0; border-bottom:1px solid #27272a;">
116
+ <tr>
117
+ <td align="center">
118
+ <img src="cid:${AGENT_NATIVE_EMAIL_LOGO_CONTENT_ID}" alt="${escapeAttr(brandName)}" width="28" height="28" style="display:inline-block; vertical-align:middle; width:28px; height:28px; margin:0 8px 0 0; border:0;" />
119
+ <span style="font-size:18px; line-height:28px; font-weight:600; color:#fafafa; vertical-align:middle;">${escapeHtml(brandName)}</span>
120
+ </td>
121
+ </tr>
122
+ </table>`;
123
+
107
124
  const html = `<!DOCTYPE html>
108
125
  <html lang="en">
109
126
  <head>
@@ -129,6 +146,7 @@ export function renderEmail(args: RenderEmailArgs): RenderedEmail {
129
146
  <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="max-width:560px;">
130
147
  <tr>
131
148
  <td style="background-color:#141417; border:1px solid #27272a; border-radius:16px; padding:36px 36px 32px 36px;">
149
+ ${brandHeaderHtml}
132
150
  <h1 style="margin:0 0 20px 0; font-size:24px; line-height:1.3; font-weight:600; color:#fafafa; letter-spacing:-0.02em;">
133
151
  ${escapeHtml(args.heading)}
134
152
  </h1>
@@ -58,6 +58,7 @@ export function renderInviteEmail(
58
58
  const onApp = appName ? ` on ${appName}` : "";
59
59
 
60
60
  const { html, text } = renderEmail({
61
+ brandName: appName,
61
62
  preheader: `${inviter} invited you to join ${orgName}${onApp}.`,
62
63
  heading: `You're invited to join ${orgName}`,
63
64
  paragraphs: [
@@ -95,6 +96,7 @@ export function renderVerifySignupEmail(
95
96
  const appName = resolveAppName();
96
97
 
97
98
  const { html, text } = renderEmail({
99
+ brandName: appName,
98
100
  preheader: `Confirm ${email} to finish setting up your ${appName} account.`,
99
101
  heading: `Verify your email for ${appName}`,
100
102
  paragraphs: [
@@ -130,6 +132,7 @@ export function renderResetPasswordEmail(
130
132
  const appName = resolveAppName();
131
133
 
132
134
  const { html, text } = renderEmail({
135
+ brandName: appName,
133
136
  preheader: `Reset the password for ${email}. This link expires in 1 hour.`,
134
137
  heading: `Reset your ${appName} password`,
135
138
  paragraphs: [
@@ -10,7 +10,10 @@
10
10
  * so the reset-password flow still works end-to-end for local development.
11
11
  */
12
12
 
13
+ import { readFileSync } from "node:fs";
14
+
13
15
  import { resolveSecret } from "./credential-provider.js";
16
+ import { AGENT_NATIVE_EMAIL_LOGO_CONTENT_ID } from "./email-template.js";
14
17
 
15
18
  export type EmailProvider = "resend" | "sendgrid" | "dev";
16
19
 
@@ -35,6 +38,38 @@ export interface SendEmailArgs {
35
38
  attachments?: EmailAttachment[];
36
39
  }
37
40
 
41
+ let cachedAgentNativeLogo: Buffer | undefined;
42
+
43
+ function getAgentNativeLogoAttachment(): EmailAttachment {
44
+ cachedAgentNativeLogo ??= readFileSync(
45
+ new URL("../../src/assets/branding/favicon.png", import.meta.url),
46
+ );
47
+ return {
48
+ filename: "agent-native-logo.png",
49
+ content: cachedAgentNativeLogo,
50
+ contentType: "image/png",
51
+ contentId: AGENT_NATIVE_EMAIL_LOGO_CONTENT_ID,
52
+ disposition: "inline",
53
+ };
54
+ }
55
+
56
+ function resolveAttachments(
57
+ args: SendEmailArgs,
58
+ ): EmailAttachment[] | undefined {
59
+ if (!args.html.includes(`cid:${AGENT_NATIVE_EMAIL_LOGO_CONTENT_ID}`)) {
60
+ return args.attachments;
61
+ }
62
+ if (
63
+ args.attachments?.some(
64
+ (attachment) =>
65
+ attachment.contentId === AGENT_NATIVE_EMAIL_LOGO_CONTENT_ID,
66
+ )
67
+ ) {
68
+ return args.attachments;
69
+ }
70
+ return [...(args.attachments ?? []), getAgentNativeLogoAttachment()];
71
+ }
72
+
38
73
  interface EmailTransportConfig {
39
74
  provider: EmailProvider;
40
75
  resendApiKey?: string;
@@ -94,6 +129,7 @@ export async function sendEmail(args: SendEmailArgs): Promise<void> {
94
129
  const config = await resolveEmailTransport();
95
130
  const provider = config.provider;
96
131
  const from = getFromAddress(config, args.from);
132
+ const attachments = resolveAttachments(args);
97
133
 
98
134
  if (provider === "resend") {
99
135
  const payload: Record<string, unknown> = {
@@ -105,8 +141,8 @@ export async function sendEmail(args: SendEmailArgs): Promise<void> {
105
141
  };
106
142
  if (args.cc) payload.cc = Array.isArray(args.cc) ? args.cc : [args.cc];
107
143
  if (args.replyTo) payload.reply_to = args.replyTo;
108
- if (args.attachments?.length) {
109
- payload.attachments = args.attachments.map((a) => ({
144
+ if (attachments?.length) {
145
+ payload.attachments = attachments.map((a) => ({
110
146
  filename: a.filename,
111
147
  content:
112
148
  typeof a.content === "string"
@@ -159,8 +195,8 @@ export async function sendEmail(args: SendEmailArgs): Promise<void> {
159
195
  if (args.inReplyTo) sgHeaders["In-Reply-To"] = args.inReplyTo;
160
196
  if (args.references) sgHeaders["References"] = args.references;
161
197
  if (Object.keys(sgHeaders).length) sgPayload.headers = sgHeaders;
162
- if (args.attachments?.length) {
163
- sgPayload.attachments = args.attachments.map((a) => ({
198
+ if (attachments?.length) {
199
+ sgPayload.attachments = attachments.map((a) => ({
164
200
  filename: a.filename,
165
201
  content:
166
202
  typeof a.content === "string"
@@ -299,6 +299,7 @@ export default defineAction({
299
299
  process.env.APP_NAME || process.env.VITE_APP_NAME || "Agent Native";
300
300
  const subject = `${actor} shared "${resourceTitle}" with you on ${appName}`;
301
301
  const { html, text } = renderEmail({
302
+ brandName: appName,
302
303
  preheader: subject,
303
304
  heading: "You've been given access",
304
305
  paragraphs: [
@@ -59,6 +59,12 @@ quick controls and deep links such as:
59
59
  - `/settings/usage`
60
60
  - `/settings/apps/:appId`
61
61
 
62
+ The shared Account section is the canonical profile surface at
63
+ `/settings#account`. It owns the editable display name and existing avatar
64
+ control through the authenticated `get-user-profile` and `update-user-profile`
65
+ actions. Shared workspace chrome such as `OrgSwitcher` should link to this
66
+ surface rather than creating an app-local profile page.
67
+
62
68
  When adding a new API key, OAuth grant, provider connection, model selector, app
63
69
  preference, notification preference, or usage/billing surface, register it as a
64
70
  settings tab or app settings panel first. Only add sidebar UI when it is needed