@agent-native/core 0.134.1 → 0.135.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 (463) hide show
  1. package/corpus/README.md +3 -3
  2. package/corpus/core/CHANGELOG.md +113 -0
  3. package/corpus/core/package.json +3 -2
  4. package/corpus/core/src/automations/service.ts +41 -4
  5. package/corpus/core/src/cli/mcp-config-writers.ts +27 -21
  6. package/corpus/core/src/client/agent-page/AgentJobsTab.tsx +187 -85
  7. package/corpus/core/src/client/agent-page/AutomationDetailsDialog.tsx +208 -0
  8. package/corpus/core/src/client/agent-page/AutomationScheduleDialog.tsx +180 -0
  9. package/corpus/core/src/client/agent-page/TimezoneSelect.tsx +241 -0
  10. package/corpus/core/src/client/agent-page/use-jobs.ts +50 -10
  11. package/corpus/core/src/client/org/OrgSwitcher.tsx +26 -0
  12. package/corpus/core/src/client/settings/AccountSettingsCard.tsx +35 -31
  13. package/corpus/core/src/client/settings/SchedulingTimezoneField.tsx +71 -0
  14. package/corpus/core/src/client/settings/SettingsRow.tsx +113 -0
  15. package/corpus/core/src/client/settings/agent-settings-search.ts +2 -1
  16. package/corpus/core/src/client/settings/index.ts +6 -0
  17. package/corpus/core/src/integrations/identity.ts +2 -12
  18. package/corpus/core/src/jobs/actions/list-automation-runs.ts +33 -0
  19. package/corpus/core/src/jobs/actions/list-recurring-jobs.ts +27 -6
  20. package/corpus/core/src/jobs/actions/manage-recurring-job.ts +41 -9
  21. package/corpus/core/src/jobs/background-automation-runner.ts +88 -0
  22. package/corpus/core/src/jobs/cron.ts +52 -6
  23. package/corpus/core/src/jobs/frontmatter.ts +20 -0
  24. package/corpus/core/src/jobs/run-history.ts +242 -0
  25. package/corpus/core/src/jobs/scheduler.ts +73 -18
  26. package/corpus/core/src/jobs/tools.ts +54 -6
  27. package/corpus/core/src/localization/actions/get-localization-preference.ts +2 -2
  28. package/corpus/core/src/localization/actions/set-localization-preference.ts +49 -11
  29. package/corpus/core/src/localization/default-messages.ts +27 -0
  30. package/corpus/core/src/localization/shared.ts +39 -6
  31. package/corpus/core/src/localization/user-timezone.ts +36 -0
  32. package/corpus/core/src/org/app-roles-handlers.ts +1 -9
  33. package/corpus/core/src/org/index.ts +2 -0
  34. package/corpus/core/src/org/membership.ts +18 -0
  35. package/corpus/core/src/review/actions/create-review-comment.ts +4 -1
  36. package/corpus/core/src/review/actions/reply-review-comment.ts +4 -1
  37. package/corpus/core/src/review/index.ts +5 -0
  38. package/corpus/core/src/review/notifications.ts +163 -0
  39. package/corpus/core/src/review/types.ts +7 -0
  40. package/corpus/core/src/server/action-discovery.ts +4 -0
  41. package/corpus/core/src/server/activity-notifications.ts +174 -0
  42. package/corpus/core/src/server/app-name.ts +31 -0
  43. package/corpus/core/src/server/better-auth-instance.ts +4 -4
  44. package/corpus/core/src/server/email-templates.ts +70 -14
  45. package/corpus/core/src/server/email.ts +66 -3
  46. package/corpus/core/src/server/index.ts +10 -0
  47. package/corpus/core/src/sharing/access.ts +44 -2
  48. package/corpus/core/src/sharing/index.ts +5 -0
  49. package/corpus/core/src/sharing/recipients.ts +67 -0
  50. package/corpus/core/src/triggers/actions/list-automations.ts +27 -8
  51. package/corpus/core/src/triggers/actions/manage-automation.ts +17 -6
  52. package/corpus/core/src/triggers/actions.ts +16 -4
  53. package/corpus/core/src/triggers/dispatcher.ts +44 -30
  54. package/corpus/core/src/triggers/routes.ts +19 -6
  55. package/corpus/core/src/vitest-config.ts +68 -0
  56. package/corpus/core/vitest.config.ts +5 -0
  57. package/corpus/templates/analytics/app/pages/Settings.tsx +37 -53
  58. package/corpus/templates/analytics/changelog/2026-08-01-new-error-alerts-now-reach-you-by-email-and-a-scheduled-dash.md +6 -0
  59. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +43 -0
  60. package/corpus/templates/analytics/server/lib/error-capture.ts +5 -1
  61. package/corpus/templates/analytics/vitest.config.ts +16 -12
  62. package/corpus/templates/assets/actions/refresh-generation-run.ts +3 -0
  63. package/corpus/templates/assets/app/components/ui/switch.tsx +1 -0
  64. package/corpus/templates/assets/app/hooks/use-assets-prefs.ts +55 -0
  65. package/corpus/templates/assets/app/i18n-data.ts +30 -0
  66. package/corpus/templates/assets/app/routes/settings.tsx +58 -55
  67. package/corpus/templates/assets/changelog/2026-08-01-get-an-email-when-a-generation-you-started-finishes-or-fails.md +6 -0
  68. package/corpus/templates/assets/server/lib/generation-run-notifications.ts +89 -0
  69. package/corpus/templates/assets/server/lib/video-runs.ts +8 -1
  70. package/corpus/templates/assets/server/routes/_agent-native/assets/user-prefs.get.ts +17 -0
  71. package/corpus/templates/assets/server/routes/_agent-native/assets/user-prefs.put.ts +36 -0
  72. package/corpus/templates/assets/shared/assets-user-prefs.ts +10 -0
  73. package/corpus/templates/assets/vitest.config.ts +16 -12
  74. package/corpus/templates/brain/app/routes/settings.tsx +15 -15
  75. package/corpus/templates/brain/vitest.config.ts +16 -12
  76. package/corpus/templates/calendar/app/pages/Settings.tsx +32 -40
  77. package/corpus/templates/calendar/changelog/2026-08-01-language-and-appearance-now-sit-together-in-one-preferences-.md +6 -0
  78. package/corpus/templates/calendar/vitest.config.ts +16 -12
  79. package/corpus/templates/chat/app/routes/settings.tsx +14 -22
  80. package/corpus/templates/chat/vitest.config.ts +9 -0
  81. package/corpus/templates/clips/.agents/skills/video-editing/SKILL.md +31 -0
  82. package/corpus/templates/clips/AGENTS.md +1 -0
  83. package/corpus/templates/clips/actions/add-comment.ts +12 -1
  84. package/corpus/templates/clips/actions/create-meeting.ts +2 -2
  85. package/corpus/templates/clips/actions/create-recording.ts +2 -2
  86. package/corpus/templates/clips/actions/finalize-recording.ts +42 -6
  87. package/corpus/templates/clips/actions/generate-filmstrip.ts +154 -0
  88. package/corpus/templates/clips/actions/get-recording-player-data.ts +6 -0
  89. package/corpus/templates/clips/actions/import-loom-recording.ts +2 -2
  90. package/corpus/templates/clips/actions/lib/ensure-recording-filmstrip.ts +258 -0
  91. package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +11 -3
  92. package/corpus/templates/clips/actions/react-to-comment.ts +13 -0
  93. package/corpus/templates/clips/actions/react-to-recording.ts +10 -1
  94. package/corpus/templates/clips/actions/reply-to-comment.ts +12 -1
  95. package/corpus/templates/clips/actions/stitch-recordings.ts +2 -2
  96. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +152 -23
  97. package/corpus/templates/clips/app/components/editor/waveform.tsx +237 -75
  98. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +23 -1
  99. package/corpus/templates/clips/app/components/settings/ai-setup-section.tsx +441 -0
  100. package/corpus/templates/clips/app/components/settings/slack-section.tsx +329 -0
  101. package/corpus/templates/clips/app/components/settings/types.ts +14 -0
  102. package/corpus/templates/clips/app/components/settings/video-storage-section.tsx +443 -0
  103. package/corpus/templates/clips/app/hooks/use-secret-status.ts +69 -0
  104. package/corpus/templates/clips/app/i18n/en-US.ts +9 -1
  105. package/corpus/templates/clips/app/lib/video-filmstrip.ts +262 -0
  106. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +165 -1351
  107. package/corpus/templates/clips/changelog/2026-07-27-saved-clips-now-resume-from-the-last-uploaded-byte-after-an-.md +6 -0
  108. package/corpus/templates/clips/changelog/2026-07-31-editor-timeline-now-shows-video-frames-behind-the-waveform-g.md +6 -0
  109. package/corpus/templates/clips/changelog/2026-07-31-email-notifications-now-go-out-when-someone-comments-on-or-r.md +6 -0
  110. package/corpus/templates/clips/changelog/2026-07-31-you-can-now-set-a-default-visibility-for-new-recordings-in-s.md +6 -0
  111. package/corpus/templates/clips/changelog/2026-08-01-email-notifications-for-comments-and-reactions-now-actually-.md +6 -0
  112. package/corpus/templates/clips/changelog/2026-08-03-the-desktop-app-now-opens-directly-beneath-its-tray-icon-on-.md +6 -0
  113. package/corpus/templates/clips/chrome-extension/package.json +1 -0
  114. package/corpus/templates/clips/chrome-extension/vitest.config.ts +9 -0
  115. package/corpus/templates/clips/desktop/package.json +1 -0
  116. package/corpus/templates/clips/desktop/src/app.tsx +17 -1
  117. package/corpus/templates/clips/desktop/src/lib/recorder.ts +331 -36
  118. package/corpus/templates/clips/desktop/src/lib/upload-recovery.ts +129 -0
  119. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +815 -15
  120. package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +61 -11
  121. package/corpus/templates/clips/desktop/vitest.config.ts +9 -0
  122. package/corpus/templates/clips/server/db/schema.ts +17 -0
  123. package/corpus/templates/clips/server/jobs/media-verification.ts +4 -0
  124. package/corpus/templates/clips/server/lib/activity-notifications.ts +185 -0
  125. package/corpus/templates/clips/server/lib/recording-media-cleanup.ts +2 -0
  126. package/corpus/templates/clips/server/lib/recording-upload-state.ts +46 -9
  127. package/corpus/templates/clips/server/lib/recordings.ts +24 -0
  128. package/corpus/templates/clips/server/lib/resumable-session.ts +10 -4
  129. package/corpus/templates/clips/server/lib/transactional-email-templates.ts +109 -0
  130. package/corpus/templates/clips/server/lib/upload-interruption.ts +8 -0
  131. package/corpus/templates/clips/server/lib/upload-lease.ts +50 -4
  132. package/corpus/templates/clips/server/lib/video-filmstrip-sprite.ts +207 -0
  133. package/corpus/templates/clips/server/lib/video-remux.ts +13 -4
  134. package/corpus/templates/clips/server/plugins/db.ts +16 -0
  135. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +4 -0
  136. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +123 -36
  137. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +159 -29
  138. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/interrupt.post.ts +197 -0
  139. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/reset-chunks.post.ts +193 -39
  140. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/resume.get.ts +191 -12
  141. package/corpus/templates/clips/shared/clips-ai-prefs.ts +6 -0
  142. package/corpus/templates/clips/shared/feature-flags.ts +12 -0
  143. package/corpus/templates/clips/shared/recording-core.ts +4 -0
  144. package/corpus/templates/clips/vitest.config.ts +23 -19
  145. package/corpus/templates/content/actions/_database-utils.ts +113 -4
  146. package/corpus/templates/content/actions/add-comment.ts +15 -1
  147. package/corpus/templates/content/actions/get-document.ts +84 -3
  148. package/corpus/templates/content/actions/list-documents.ts +1 -0
  149. package/corpus/templates/content/app/components/editor/BuilderBodySyncingNotice.tsx +9 -2
  150. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +34 -15
  151. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +55 -13
  152. package/corpus/templates/content/app/components/editor/body-hydration.ts +12 -6
  153. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +2 -3
  154. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +5 -12
  155. package/corpus/templates/content/app/components/ui/switch.tsx +1 -0
  156. package/corpus/templates/content/app/hooks/use-content-database.ts +16 -27
  157. package/corpus/templates/content/app/hooks/use-content-prefs.ts +55 -0
  158. package/corpus/templates/content/app/hooks/use-create-page.ts +3 -6
  159. package/corpus/templates/content/app/hooks/use-document-properties.ts +9 -16
  160. package/corpus/templates/content/app/hooks/use-document-versions.ts +3 -3
  161. package/corpus/templates/content/app/hooks/use-documents.ts +85 -29
  162. package/corpus/templates/content/app/hooks/use-notion.ts +15 -13
  163. package/corpus/templates/content/app/i18n-data.ts +72 -1
  164. package/corpus/templates/content/app/lib/document-query.ts +36 -0
  165. package/corpus/templates/content/app/routes/_app.settings.tsx +47 -18
  166. package/corpus/templates/content/changelog/2026-07-30-breadcrumb-menus-now-hide-internal-system-pages.md +6 -0
  167. package/corpus/templates/content/changelog/2026-08-01-get-an-email-when-someone-comments-on-replies-in-or-mentions.md +6 -0
  168. package/corpus/templates/content/changelog/2026-08-02-pages-opened-from-a-database-now-keep-that-database-s-fields.md +6 -0
  169. package/corpus/templates/content/server/lib/comment-notifications.ts +146 -0
  170. package/corpus/templates/content/server/lib/document-context.ts +11 -6
  171. package/corpus/templates/content/server/routes/_agent-native/content/user-prefs.get.ts +17 -0
  172. package/corpus/templates/content/server/routes/_agent-native/content/user-prefs.put.ts +36 -0
  173. package/corpus/templates/content/shared/api.ts +8 -0
  174. package/corpus/templates/content/shared/content-user-prefs.ts +11 -0
  175. package/corpus/templates/content/vitest.config.ts +20 -16
  176. package/corpus/templates/crm/app/routes/settings.tsx +14 -22
  177. package/corpus/templates/crm/vitest.config.ts +8 -4
  178. package/corpus/templates/design/app/routes/settings.tsx +14 -22
  179. package/corpus/templates/design/changelog/2026-08-01-review-comments-replies-and-mentions-now-send-an-email-to-th.md +6 -0
  180. package/corpus/templates/design/vitest.config.ts +18 -12
  181. package/corpus/templates/dispatch/app/routes/settings.tsx +26 -40
  182. package/corpus/templates/dispatch/vitest.config.ts +11 -7
  183. package/corpus/templates/factory/app/routes/settings.tsx +14 -22
  184. package/corpus/templates/factory/vitest.config.ts +9 -0
  185. package/corpus/templates/forms/app/routes/_app.settings.tsx +14 -22
  186. package/corpus/templates/forms/vitest.config.ts +27 -23
  187. package/corpus/templates/macros/app/routes/settings.tsx +14 -22
  188. package/corpus/templates/macros/vitest.config.ts +16 -12
  189. package/corpus/templates/mail/app/pages/SettingsPage.tsx +14 -16
  190. package/corpus/templates/mail/vitest.config.ts +16 -12
  191. package/corpus/templates/plan/app/routes/settings.tsx +30 -44
  192. package/corpus/templates/plan/vitest.config.ts +24 -20
  193. package/corpus/templates/slides/actions/add-slide-comment.ts +12 -1
  194. package/corpus/templates/slides/app/components/ui/switch.tsx +1 -0
  195. package/corpus/templates/slides/app/hooks/use-slides-prefs.ts +55 -0
  196. package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
  197. package/corpus/templates/slides/app/routes/settings.tsx +45 -22
  198. package/corpus/templates/slides/changelog/2026-08-01-get-an-email-when-someone-comments-on-or-replies-in-your-dec.md +6 -0
  199. package/corpus/templates/slides/server/lib/comment-notifications.ts +182 -0
  200. package/corpus/templates/slides/server/routes/_agent-native/slides/user-prefs.get.ts +16 -0
  201. package/corpus/templates/slides/server/routes/_agent-native/slides/user-prefs.put.ts +36 -0
  202. package/corpus/templates/slides/shared/slides-user-prefs.ts +11 -0
  203. package/corpus/templates/slides/vitest.config.ts +17 -13
  204. package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +2 -0
  205. package/corpus/templates/tasks/app/routes/settings.tsx +14 -22
  206. package/corpus/templates/tasks/vitest.config.ts +17 -13
  207. package/corpus/toolkit/CHANGELOG.md +9 -0
  208. package/corpus/toolkit/package.json +1 -1
  209. package/corpus/toolkit/vitest.config.ts +3 -0
  210. package/dist/automations/service.d.ts +2 -0
  211. package/dist/automations/service.d.ts.map +1 -1
  212. package/dist/automations/service.js +29 -4
  213. package/dist/automations/service.js.map +1 -1
  214. package/dist/cli/mcp-config-writers.d.ts.map +1 -1
  215. package/dist/cli/mcp-config-writers.js +24 -23
  216. package/dist/cli/mcp-config-writers.js.map +1 -1
  217. package/dist/client/agent-page/AgentJobsTab.d.ts.map +1 -1
  218. package/dist/client/agent-page/AgentJobsTab.js +86 -29
  219. package/dist/client/agent-page/AgentJobsTab.js.map +1 -1
  220. package/dist/client/agent-page/AutomationDetailsDialog.d.ts +21 -0
  221. package/dist/client/agent-page/AutomationDetailsDialog.d.ts.map +1 -0
  222. package/dist/client/agent-page/AutomationDetailsDialog.js +33 -0
  223. package/dist/client/agent-page/AutomationDetailsDialog.js.map +1 -0
  224. package/dist/client/agent-page/AutomationScheduleDialog.d.ts +15 -0
  225. package/dist/client/agent-page/AutomationScheduleDialog.d.ts.map +1 -0
  226. package/dist/client/agent-page/AutomationScheduleDialog.js +46 -0
  227. package/dist/client/agent-page/AutomationScheduleDialog.js.map +1 -0
  228. package/dist/client/agent-page/TimezoneSelect.d.ts +17 -0
  229. package/dist/client/agent-page/TimezoneSelect.d.ts.map +1 -0
  230. package/dist/client/agent-page/TimezoneSelect.js +107 -0
  231. package/dist/client/agent-page/TimezoneSelect.js.map +1 -0
  232. package/dist/client/agent-page/use-jobs.d.ts +20 -7
  233. package/dist/client/agent-page/use-jobs.d.ts.map +1 -1
  234. package/dist/client/agent-page/use-jobs.js +24 -4
  235. package/dist/client/agent-page/use-jobs.js.map +1 -1
  236. package/dist/client/org/OrgSwitcher.d.ts +8 -1
  237. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  238. package/dist/client/org/OrgSwitcher.js +8 -2
  239. package/dist/client/org/OrgSwitcher.js.map +1 -1
  240. package/dist/client/settings/AccountSettingsCard.d.ts.map +1 -1
  241. package/dist/client/settings/AccountSettingsCard.js +10 -9
  242. package/dist/client/settings/AccountSettingsCard.js.map +1 -1
  243. package/dist/client/settings/SchedulingTimezoneField.d.ts +10 -0
  244. package/dist/client/settings/SchedulingTimezoneField.d.ts.map +1 -0
  245. package/dist/client/settings/SchedulingTimezoneField.js +30 -0
  246. package/dist/client/settings/SchedulingTimezoneField.js.map +1 -0
  247. package/dist/client/settings/SettingsRow.d.ts +36 -0
  248. package/dist/client/settings/SettingsRow.d.ts.map +1 -0
  249. package/dist/client/settings/SettingsRow.js +15 -0
  250. package/dist/client/settings/SettingsRow.js.map +1 -0
  251. package/dist/client/settings/agent-settings-search.d.ts.map +1 -1
  252. package/dist/client/settings/agent-settings-search.js +1 -1
  253. package/dist/client/settings/agent-settings-search.js.map +1 -1
  254. package/dist/client/settings/index.d.ts +1 -0
  255. package/dist/client/settings/index.d.ts.map +1 -1
  256. package/dist/client/settings/index.js +1 -0
  257. package/dist/client/settings/index.js.map +1 -1
  258. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  259. package/dist/integrations/identity.d.ts.map +1 -1
  260. package/dist/integrations/identity.js +2 -11
  261. package/dist/integrations/identity.js.map +1 -1
  262. package/dist/jobs/actions/list-automation-runs.d.ts +8 -0
  263. package/dist/jobs/actions/list-automation-runs.d.ts.map +1 -0
  264. package/dist/jobs/actions/list-automation-runs.js +29 -0
  265. package/dist/jobs/actions/list-automation-runs.js.map +1 -0
  266. package/dist/jobs/actions/list-recurring-jobs.d.ts +2 -0
  267. package/dist/jobs/actions/list-recurring-jobs.d.ts.map +1 -1
  268. package/dist/jobs/actions/list-recurring-jobs.js +20 -7
  269. package/dist/jobs/actions/list-recurring-jobs.js.map +1 -1
  270. package/dist/jobs/actions/manage-recurring-job.d.ts +2 -0
  271. package/dist/jobs/actions/manage-recurring-job.js +30 -9
  272. package/dist/jobs/actions/manage-recurring-job.js.map +1 -1
  273. package/dist/jobs/background-automation-runner.d.ts.map +1 -1
  274. package/dist/jobs/background-automation-runner.js +60 -0
  275. package/dist/jobs/background-automation-runner.js.map +1 -1
  276. package/dist/jobs/cron.d.ts +16 -2
  277. package/dist/jobs/cron.d.ts.map +1 -1
  278. package/dist/jobs/cron.js +43 -6
  279. package/dist/jobs/cron.js.map +1 -1
  280. package/dist/jobs/frontmatter.d.ts +12 -0
  281. package/dist/jobs/frontmatter.d.ts.map +1 -1
  282. package/dist/jobs/frontmatter.js +8 -0
  283. package/dist/jobs/frontmatter.js.map +1 -1
  284. package/dist/jobs/run-history.d.ts +56 -0
  285. package/dist/jobs/run-history.d.ts.map +1 -0
  286. package/dist/jobs/run-history.js +169 -0
  287. package/dist/jobs/run-history.js.map +1 -0
  288. package/dist/jobs/scheduler.d.ts.map +1 -1
  289. package/dist/jobs/scheduler.js +51 -18
  290. package/dist/jobs/scheduler.js.map +1 -1
  291. package/dist/jobs/tools.d.ts.map +1 -1
  292. package/dist/jobs/tools.js +37 -6
  293. package/dist/jobs/tools.js.map +1 -1
  294. package/dist/localization/actions/get-localization-preference.d.ts +1 -2
  295. package/dist/localization/actions/get-localization-preference.d.ts.map +1 -1
  296. package/dist/localization/actions/get-localization-preference.js.map +1 -1
  297. package/dist/localization/actions/set-localization-preference.d.ts +3 -3
  298. package/dist/localization/actions/set-localization-preference.d.ts.map +1 -1
  299. package/dist/localization/actions/set-localization-preference.js +33 -8
  300. package/dist/localization/actions/set-localization-preference.js.map +1 -1
  301. package/dist/localization/default-messages.d.ts +25 -0
  302. package/dist/localization/default-messages.d.ts.map +1 -1
  303. package/dist/localization/default-messages.js +25 -0
  304. package/dist/localization/default-messages.js.map +1 -1
  305. package/dist/localization/shared.d.ts +16 -1
  306. package/dist/localization/shared.d.ts.map +1 -1
  307. package/dist/localization/shared.js +22 -4
  308. package/dist/localization/shared.js.map +1 -1
  309. package/dist/localization/user-timezone.d.ts +11 -0
  310. package/dist/localization/user-timezone.d.ts.map +1 -0
  311. package/dist/localization/user-timezone.js +31 -0
  312. package/dist/localization/user-timezone.js.map +1 -0
  313. package/dist/notifications/routes.d.ts +4 -4
  314. package/dist/observability/routes.d.ts +3 -3
  315. package/dist/org/app-roles-handlers.d.ts.map +1 -1
  316. package/dist/org/app-roles-handlers.js +1 -8
  317. package/dist/org/app-roles-handlers.js.map +1 -1
  318. package/dist/org/index.d.ts +1 -0
  319. package/dist/org/index.d.ts.map +1 -1
  320. package/dist/org/index.js +1 -0
  321. package/dist/org/index.js.map +1 -1
  322. package/dist/org/membership.d.ts +6 -0
  323. package/dist/org/membership.d.ts.map +1 -0
  324. package/dist/org/membership.js +16 -0
  325. package/dist/org/membership.js.map +1 -0
  326. package/dist/progress/routes.d.ts +1 -1
  327. package/dist/provider-api/actions/custom-provider-registration.d.ts +13 -13
  328. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  329. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  330. package/dist/review/actions/create-review-comment.d.ts +32 -1
  331. package/dist/review/actions/create-review-comment.d.ts.map +1 -1
  332. package/dist/review/actions/create-review-comment.js +3 -1
  333. package/dist/review/actions/create-review-comment.js.map +1 -1
  334. package/dist/review/actions/reply-review-comment.d.ts +32 -1
  335. package/dist/review/actions/reply-review-comment.d.ts.map +1 -1
  336. package/dist/review/actions/reply-review-comment.js +3 -1
  337. package/dist/review/actions/reply-review-comment.js.map +1 -1
  338. package/dist/review/index.d.ts +1 -0
  339. package/dist/review/index.d.ts.map +1 -1
  340. package/dist/review/index.js +1 -0
  341. package/dist/review/index.js.map +1 -1
  342. package/dist/review/notifications.d.ts +24 -0
  343. package/dist/review/notifications.d.ts.map +1 -0
  344. package/dist/review/notifications.js +123 -0
  345. package/dist/review/notifications.js.map +1 -0
  346. package/dist/review/types.d.ts +5 -0
  347. package/dist/review/types.d.ts.map +1 -1
  348. package/dist/review/types.js.map +1 -1
  349. package/dist/server/action-discovery.d.ts.map +1 -1
  350. package/dist/server/action-discovery.js +4 -0
  351. package/dist/server/action-discovery.js.map +1 -1
  352. package/dist/server/activity-notifications.d.ts +61 -0
  353. package/dist/server/activity-notifications.d.ts.map +1 -0
  354. package/dist/server/activity-notifications.js +103 -0
  355. package/dist/server/activity-notifications.js.map +1 -0
  356. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  357. package/dist/server/app-name.d.ts +18 -0
  358. package/dist/server/app-name.d.ts.map +1 -1
  359. package/dist/server/app-name.js +31 -0
  360. package/dist/server/app-name.js.map +1 -1
  361. package/dist/server/better-auth-instance.js +4 -4
  362. package/dist/server/better-auth-instance.js.map +1 -1
  363. package/dist/server/email-templates.d.ts +12 -0
  364. package/dist/server/email-templates.d.ts.map +1 -1
  365. package/dist/server/email-templates.js +57 -14
  366. package/dist/server/email-templates.js.map +1 -1
  367. package/dist/server/email.d.ts +12 -0
  368. package/dist/server/email.d.ts.map +1 -1
  369. package/dist/server/email.js +52 -5
  370. package/dist/server/email.js.map +1 -1
  371. package/dist/server/index.d.ts +1 -0
  372. package/dist/server/index.d.ts.map +1 -1
  373. package/dist/server/index.js +1 -0
  374. package/dist/server/index.js.map +1 -1
  375. package/dist/server/transcribe-voice.d.ts +1 -1
  376. package/dist/sharing/access.d.ts.map +1 -1
  377. package/dist/sharing/access.js +32 -2
  378. package/dist/sharing/access.js.map +1 -1
  379. package/dist/sharing/index.d.ts +1 -0
  380. package/dist/sharing/index.d.ts.map +1 -1
  381. package/dist/sharing/index.js +1 -0
  382. package/dist/sharing/index.js.map +1 -1
  383. package/dist/sharing/recipients.d.ts +31 -0
  384. package/dist/sharing/recipients.d.ts.map +1 -0
  385. package/dist/sharing/recipients.js +40 -0
  386. package/dist/sharing/recipients.js.map +1 -0
  387. package/dist/templates/chat/app/routes/settings.tsx +14 -22
  388. package/dist/templates/chat/vitest.config.ts +9 -0
  389. package/dist/triggers/actions/list-automations.d.ts +2 -0
  390. package/dist/triggers/actions/list-automations.d.ts.map +1 -1
  391. package/dist/triggers/actions/list-automations.js +19 -8
  392. package/dist/triggers/actions/list-automations.js.map +1 -1
  393. package/dist/triggers/actions/manage-automation.d.ts +6 -0
  394. package/dist/triggers/actions/manage-automation.js +12 -6
  395. package/dist/triggers/actions/manage-automation.js.map +1 -1
  396. package/dist/triggers/actions.d.ts.map +1 -1
  397. package/dist/triggers/actions.js +15 -4
  398. package/dist/triggers/actions.js.map +1 -1
  399. package/dist/triggers/dispatcher.d.ts.map +1 -1
  400. package/dist/triggers/dispatcher.js +19 -17
  401. package/dist/triggers/dispatcher.js.map +1 -1
  402. package/dist/triggers/routes.d.ts.map +1 -1
  403. package/dist/triggers/routes.js +6 -6
  404. package/dist/triggers/routes.js.map +1 -1
  405. package/dist/vitest-config.d.ts +10 -0
  406. package/dist/vitest-config.d.ts.map +1 -0
  407. package/dist/vitest-config.js +55 -0
  408. package/dist/vitest-config.js.map +1 -0
  409. package/package.json +5 -4
  410. package/src/automations/service.ts +41 -4
  411. package/src/cli/mcp-config-writers.ts +27 -21
  412. package/src/client/agent-page/AgentJobsTab.tsx +187 -85
  413. package/src/client/agent-page/AutomationDetailsDialog.tsx +208 -0
  414. package/src/client/agent-page/AutomationScheduleDialog.tsx +180 -0
  415. package/src/client/agent-page/TimezoneSelect.tsx +241 -0
  416. package/src/client/agent-page/use-jobs.ts +50 -10
  417. package/src/client/org/OrgSwitcher.tsx +26 -0
  418. package/src/client/settings/AccountSettingsCard.tsx +35 -31
  419. package/src/client/settings/SchedulingTimezoneField.tsx +71 -0
  420. package/src/client/settings/SettingsRow.tsx +113 -0
  421. package/src/client/settings/agent-settings-search.ts +2 -1
  422. package/src/client/settings/index.ts +6 -0
  423. package/src/integrations/identity.ts +2 -12
  424. package/src/jobs/actions/list-automation-runs.ts +33 -0
  425. package/src/jobs/actions/list-recurring-jobs.ts +27 -6
  426. package/src/jobs/actions/manage-recurring-job.ts +41 -9
  427. package/src/jobs/background-automation-runner.ts +88 -0
  428. package/src/jobs/cron.ts +52 -6
  429. package/src/jobs/frontmatter.ts +20 -0
  430. package/src/jobs/run-history.ts +242 -0
  431. package/src/jobs/scheduler.ts +73 -18
  432. package/src/jobs/tools.ts +54 -6
  433. package/src/localization/actions/get-localization-preference.ts +2 -2
  434. package/src/localization/actions/set-localization-preference.ts +49 -11
  435. package/src/localization/default-messages.ts +27 -0
  436. package/src/localization/shared.ts +39 -6
  437. package/src/localization/user-timezone.ts +36 -0
  438. package/src/org/app-roles-handlers.ts +1 -9
  439. package/src/org/index.ts +2 -0
  440. package/src/org/membership.ts +18 -0
  441. package/src/review/actions/create-review-comment.ts +4 -1
  442. package/src/review/actions/reply-review-comment.ts +4 -1
  443. package/src/review/index.ts +5 -0
  444. package/src/review/notifications.ts +163 -0
  445. package/src/review/types.ts +7 -0
  446. package/src/server/action-discovery.ts +4 -0
  447. package/src/server/activity-notifications.ts +174 -0
  448. package/src/server/app-name.ts +31 -0
  449. package/src/server/better-auth-instance.ts +4 -4
  450. package/src/server/email-templates.ts +70 -14
  451. package/src/server/email.ts +66 -3
  452. package/src/server/index.ts +10 -0
  453. package/src/sharing/access.ts +44 -2
  454. package/src/sharing/index.ts +5 -0
  455. package/src/sharing/recipients.ts +67 -0
  456. package/src/templates/chat/app/routes/settings.tsx +14 -22
  457. package/src/templates/chat/vitest.config.ts +9 -0
  458. package/src/triggers/actions/list-automations.ts +27 -8
  459. package/src/triggers/actions/manage-automation.ts +17 -6
  460. package/src/triggers/actions.ts +16 -4
  461. package/src/triggers/dispatcher.ts +44 -30
  462. package/src/triggers/routes.ts +19 -6
  463. package/src/vitest-config.ts +68 -0
@@ -1,23 +1,27 @@
1
1
  import path from "node:path";
2
2
 
3
- import { defineConfig } from "vitest/config";
3
+ import baseConfig from "@agent-native/core/vitest-config";
4
+ import { defineConfig, mergeConfig } from "vitest/config";
4
5
 
5
- export default defineConfig({
6
- resolve: {
7
- alias: {
8
- "@": path.resolve(__dirname, "./app"),
9
- "@shared": path.resolve(__dirname, "./shared"),
6
+ export default mergeConfig(
7
+ baseConfig,
8
+ defineConfig({
9
+ resolve: {
10
+ alias: {
11
+ "@": path.resolve(__dirname, "./app"),
12
+ "@shared": path.resolve(__dirname, "./shared"),
13
+ },
10
14
  },
11
- },
12
- test: {
13
- include: ["**/*.{test,spec}.?(c|m)[jt]s?(x)"],
14
- exclude: [
15
- "**/node_modules/**",
16
- "**/.git/**",
17
- "**/dist/**",
18
- "**/.output/**",
19
- "**/.react-router/**",
20
- "**/e2e/**",
21
- ],
22
- },
23
- });
15
+ test: {
16
+ include: ["**/*.{test,spec}.?(c|m)[jt]s?(x)"],
17
+ exclude: [
18
+ "**/node_modules/**",
19
+ "**/.git/**",
20
+ "**/dist/**",
21
+ "**/.output/**",
22
+ "**/.react-router/**",
23
+ "**/e2e/**",
24
+ ],
25
+ },
26
+ }),
27
+ );
@@ -1234,10 +1234,15 @@ export async function getDatabaseByDocumentId(
1234
1234
 
1235
1235
  export async function getDatabaseItemByDocumentId(
1236
1236
  documentId: string,
1237
- options: { includeDeleted?: boolean } = {},
1237
+ options: { includeDeleted?: boolean; databaseId?: string } = {},
1238
1238
  db = getDb(),
1239
1239
  ) {
1240
1240
  const clauses = [eq(schema.contentDatabaseItems.documentId, documentId)];
1241
+ if (options.databaseId) {
1242
+ clauses.push(
1243
+ eq(schema.contentDatabaseItems.databaseId, options.databaseId),
1244
+ );
1245
+ }
1241
1246
  if (!options.includeDeleted) {
1242
1247
  clauses.push(isNull(schema.contentDatabases.deletedAt));
1243
1248
  }
@@ -1262,13 +1267,33 @@ export async function getDatabaseItemByDocumentId(
1262
1267
  )
1263
1268
  .leftJoin(
1264
1269
  schema.contentDatabaseBodyHydrationQueue,
1265
- eq(
1266
- schema.contentDatabaseBodyHydrationQueue.databaseItemId,
1267
- schema.contentDatabaseItems.id,
1270
+ and(
1271
+ eq(
1272
+ schema.contentDatabaseBodyHydrationQueue.databaseItemId,
1273
+ schema.contentDatabaseItems.id,
1274
+ ),
1275
+ eq(
1276
+ schema.contentDatabaseBodyHydrationQueue.sourceId,
1277
+ schema.contentDatabaseSourceRows.sourceId,
1278
+ ),
1279
+ eq(
1280
+ schema.contentDatabaseBodyHydrationQueue.sourceRowId,
1281
+ schema.contentDatabaseSourceRows.sourceRowId,
1282
+ ),
1268
1283
  ),
1269
1284
  )
1270
1285
  .where(and(...clauses))
1271
1286
  .orderBy(
1287
+ sql`CASE
1288
+ WHEN ${schema.contentDatabaseSourceRows.sourceId} IS NOT NULL
1289
+ AND (
1290
+ ${schema.contentDatabaseItems.bodyHydrationStatus} IN ('pending', 'hydrating')
1291
+ OR ${schema.contentDatabaseBodyHydrationQueue.id} IS NOT NULL
1292
+ ) THEN 0
1293
+ WHEN ${schema.contentDatabaseSourceRows.sourceId} IS NOT NULL
1294
+ AND ${schema.contentDatabaseItems.bodyHydrationStatus} = 'error' THEN 1
1295
+ ELSE 2
1296
+ END`,
1272
1297
  sql`CASE WHEN ${schema.contentDatabaseSourceRows.sourceId} IS NOT NULL THEN 0 ELSE 1 END`,
1273
1298
  sql`CASE WHEN ${schema.contentDatabases.systemRole} IS NULL THEN 0 ELSE 1 END`,
1274
1299
  sql`CASE WHEN ${schema.contentDatabases.systemRole} = 'files' THEN 0 ELSE 1 END`,
@@ -1277,6 +1302,90 @@ export async function getDatabaseItemByDocumentId(
1277
1302
  return row ?? null;
1278
1303
  }
1279
1304
 
1305
+ export async function getBuilderBodyHydrationMembershipByDocumentId(
1306
+ documentId: string,
1307
+ db = getDb(),
1308
+ ) {
1309
+ const rows = await db
1310
+ .select({
1311
+ item: schema.contentDatabaseItems,
1312
+ database: schema.contentDatabases,
1313
+ sourceId: schema.contentDatabaseSourceRows.sourceId,
1314
+ sourceRowId: schema.contentDatabaseSourceRows.sourceRowId,
1315
+ bodyHydrationQueueId: schema.contentDatabaseBodyHydrationQueue.id,
1316
+ queueSourceId: schema.contentDatabaseBodyHydrationQueue.sourceId,
1317
+ queueSourceRowId: schema.contentDatabaseBodyHydrationQueue.sourceRowId,
1318
+ })
1319
+ .from(schema.contentDatabaseSourceRows)
1320
+ .innerJoin(
1321
+ schema.contentDatabaseSources,
1322
+ eq(
1323
+ schema.contentDatabaseSources.id,
1324
+ schema.contentDatabaseSourceRows.sourceId,
1325
+ ),
1326
+ )
1327
+ .innerJoin(
1328
+ schema.contentDatabaseItems,
1329
+ eq(
1330
+ schema.contentDatabaseItems.id,
1331
+ schema.contentDatabaseSourceRows.databaseItemId,
1332
+ ),
1333
+ )
1334
+ .innerJoin(
1335
+ schema.contentDatabases,
1336
+ eq(schema.contentDatabases.id, schema.contentDatabaseItems.databaseId),
1337
+ )
1338
+ .leftJoin(
1339
+ schema.contentDatabaseBodyHydrationQueue,
1340
+ eq(
1341
+ schema.contentDatabaseBodyHydrationQueue.databaseItemId,
1342
+ schema.contentDatabaseItems.id,
1343
+ ),
1344
+ )
1345
+ .where(
1346
+ and(
1347
+ eq(schema.contentDatabaseSourceRows.documentId, documentId),
1348
+ eq(schema.contentDatabaseItems.documentId, documentId),
1349
+ eq(schema.contentDatabaseSources.sourceType, "builder-cms"),
1350
+ isNull(schema.contentDatabases.deletedAt),
1351
+ ),
1352
+ );
1353
+
1354
+ const boundRows = rows.filter(
1355
+ (row) =>
1356
+ !row.bodyHydrationQueueId ||
1357
+ (row.queueSourceId === row.sourceId &&
1358
+ row.queueSourceRowId === row.sourceRowId),
1359
+ );
1360
+ if (boundRows.length === 0) return null;
1361
+
1362
+ const priority = (row: (typeof boundRows)[number]) => {
1363
+ if (
1364
+ row.bodyHydrationQueueId ||
1365
+ row.item.bodyHydrationStatus === "pending" ||
1366
+ row.item.bodyHydrationStatus === "hydrating"
1367
+ ) {
1368
+ return 0;
1369
+ }
1370
+ if (row.item.bodyHydrationStatus === "error") return 1;
1371
+ return 2;
1372
+ };
1373
+ const topPriority = Math.min(...boundRows.map(priority));
1374
+ const candidates = boundRows
1375
+ .filter((row) => priority(row) === topPriority)
1376
+ .sort((left, right) =>
1377
+ `${left.database.id}:${left.sourceId}:${left.sourceRowId}`.localeCompare(
1378
+ `${right.database.id}:${right.sourceId}:${right.sourceRowId}`,
1379
+ ),
1380
+ );
1381
+ const sourceIds = new Set(candidates.map((row) => row.sourceId));
1382
+
1383
+ return {
1384
+ membership: candidates[0]!,
1385
+ hydrationSourceId: sourceIds.size === 1 ? candidates[0]!.sourceId : null,
1386
+ };
1387
+ }
1388
+
1280
1389
  export async function deleteDatabaseDataForDocument(
1281
1390
  documentId: string,
1282
1391
  ownerEmail: string,
@@ -4,6 +4,7 @@ import { assertAccess } from "@agent-native/core/sharing";
4
4
  import { z } from "zod";
5
5
 
6
6
  import { getDb, schema } from "../server/db/index.js";
7
+ import { notifyDocumentComment } from "../server/lib/comment-notifications.js";
7
8
 
8
9
  type Mention = { email: string; name: string };
9
10
 
@@ -115,6 +116,19 @@ export default defineAction({
115
116
  authorName: name,
116
117
  });
117
118
 
118
- return { id, threadId };
119
+ const notified = await notifyDocumentComment({
120
+ documentId,
121
+ documentTitle: (access.resource.title as string | null) ?? "",
122
+ orgId: (access.resource.orgId as string | null) ?? null,
123
+ threadId,
124
+ ownerEmail,
125
+ authorEmail: email,
126
+ authorName: name,
127
+ content,
128
+ mentions,
129
+ isReply: Boolean(parentId ?? args.threadId),
130
+ });
131
+
132
+ return { id, threadId, notified };
119
133
  },
120
134
  });
@@ -11,6 +11,7 @@ import { favoriteDocumentIds } from "./_content-favorites.js";
11
11
  import { resolveContentSpaceAccess } from "./_content-space-access.js";
12
12
  import {
13
13
  getDatabaseByDocumentId,
14
+ getBuilderBodyHydrationMembershipByDocumentId,
14
15
  getDocumentContextPath,
15
16
  getDatabaseItemByDocumentId,
16
17
  isSoftDeletedDatabaseDocument,
@@ -18,7 +19,9 @@ import {
18
19
  } from "./_database-utils.js";
19
20
  import { serializeDocumentSource } from "./_document-source.js";
20
21
  import {
22
+ getDatabaseById,
21
23
  listPropertiesForDocument,
24
+ resolvePropertyDatabaseForDocument,
22
25
  serializeDatabase,
23
26
  } from "./_property-utils.js";
24
27
 
@@ -54,6 +57,14 @@ export default defineAction({
54
57
  description: "Get a single document by ID with full content.",
55
58
  schema: z.object({
56
59
  id: z.string().optional().describe("Document ID (required)"),
60
+ databaseId: z
61
+ .string()
62
+ .optional()
63
+ .describe("Exact Database context for membership-local data"),
64
+ databaseDocumentId: z
65
+ .string()
66
+ .optional()
67
+ .describe("Backing document ID for the exact Database context"),
57
68
  }),
58
69
  http: { method: "GET" },
59
70
  readOnly: true,
@@ -79,8 +90,54 @@ export default defineAction({
79
90
  });
80
91
  }
81
92
  const doc = access.resource;
93
+ if (args.databaseDocumentId && !args.databaseId) {
94
+ throw Object.assign(new Error("databaseDocumentId requires databaseId"), {
95
+ statusCode: 404,
96
+ });
97
+ }
98
+
82
99
  const database = await getDatabaseByDocumentId(doc.id);
83
- const databaseMembership = await getDatabaseItemByDocumentId(doc.id);
100
+ const databaseMembership = args.databaseId
101
+ ? await getDatabaseItemByDocumentId(doc.id, {
102
+ databaseId: args.databaseId,
103
+ })
104
+ : await getDatabaseItemByDocumentId(doc.id);
105
+ const propertyDatabase = args.databaseId
106
+ ? await getDatabaseById(args.databaseId)
107
+ : await resolvePropertyDatabaseForDocument(doc);
108
+ const propertyDatabaseAccess =
109
+ args.databaseId && propertyDatabase
110
+ ? await resolveDocumentAccess(propertyDatabase.documentId)
111
+ : null;
112
+ if (
113
+ args.databaseId &&
114
+ (!propertyDatabase ||
115
+ !propertyDatabaseAccess ||
116
+ (propertyDatabase.documentId !== doc.id && !databaseMembership))
117
+ ) {
118
+ throw Object.assign(new Error("Database context not found"), {
119
+ statusCode: 404,
120
+ });
121
+ }
122
+ if (
123
+ args.databaseDocumentId &&
124
+ propertyDatabase?.documentId !== args.databaseDocumentId
125
+ ) {
126
+ throw Object.assign(new Error("Database context not found"), {
127
+ statusCode: 404,
128
+ });
129
+ }
130
+ const bodyHydrationTarget =
131
+ await getBuilderBodyHydrationMembershipByDocumentId(doc.id);
132
+ const bodyHydrationMembership = bodyHydrationTarget?.membership;
133
+ const bodyHydrationAccess = bodyHydrationTarget?.hydrationSourceId
134
+ ? await resolveDocumentAccess(
135
+ bodyHydrationMembership!.database.documentId,
136
+ )
137
+ : null;
138
+ const bodyHydration = bodyHydrationMembership
139
+ ? serializeDatabaseMembership(bodyHydrationMembership).bodyHydration
140
+ : null;
84
141
  const userEmail = getRequestUserEmail();
85
142
  const favoriteIds = userEmail
86
143
  ? await favoriteDocumentIds(getDb(), userEmail, [doc.id])
@@ -112,10 +169,34 @@ export default defineAction({
112
169
  databaseMembership: databaseMembership
113
170
  ? serializeDatabaseMembership(databaseMembership)
114
171
  : undefined,
172
+ bodyHydration: bodyHydrationMembership
173
+ ? {
174
+ hydration: bodyHydrationAccess
175
+ ? bodyHydration!
176
+ : {
177
+ status: bodyHydration!.status,
178
+ attemptedAt: null,
179
+ error: null,
180
+ version: null,
181
+ },
182
+ ...(bodyHydrationAccess &&
183
+ canEditRole(bodyHydrationAccess.role) &&
184
+ bodyHydrationTarget?.hydrationSourceId
185
+ ? {
186
+ provider: "builder" as const,
187
+ sourceId: bodyHydrationTarget.hydrationSourceId,
188
+ databaseDocumentId:
189
+ bodyHydrationMembership.database.documentId,
190
+ }
191
+ : {}),
192
+ }
193
+ : undefined,
115
194
  createdAt: doc.createdAt,
116
195
  updatedAt: doc.updatedAt,
117
- properties: await listPropertiesForDocument(doc),
118
- contextPath: await getDocumentContextPath(doc),
196
+ properties: await listPropertiesForDocument(doc, args.databaseId),
197
+ contextPath: await getDocumentContextPath(doc, {
198
+ databaseId: args.databaseId,
199
+ }),
119
200
  };
120
201
  },
121
202
  link: ({ result }) => {
@@ -337,6 +337,7 @@ export default defineAction({
337
337
  id: database.id,
338
338
  documentId: database.documentId,
339
339
  title: database.title,
340
+ systemRole: database.systemRole,
340
341
  description: d.description,
341
342
  viewConfig: parseDatabaseViewConfig(database.viewConfigJson),
342
343
  createdAt: database.createdAt,
@@ -8,9 +8,16 @@ export function BuilderBodySyncingNotice({
8
8
  description: string;
9
9
  }) {
10
10
  return (
11
- <div className="rounded-lg border border-dashed border-border bg-muted/35 px-4 py-5 text-sm">
11
+ <div
12
+ className="rounded-lg border border-dashed border-border bg-muted/35 px-4 py-5 text-sm"
13
+ role="status"
14
+ aria-live="polite"
15
+ >
12
16
  <div className="flex items-center gap-2 font-medium text-foreground">
13
- <IconLoader2 className="size-4 animate-spin text-muted-foreground" />
17
+ <IconLoader2
18
+ className="size-4 animate-spin text-muted-foreground"
19
+ aria-hidden="true"
20
+ />
14
21
  {title}
15
22
  </div>
16
23
  <p className="mt-2 max-w-2xl leading-6 text-muted-foreground">
@@ -62,8 +62,10 @@ import {
62
62
  type ContentSpaceSummary,
63
63
  } from "@/hooks/use-content-spaces";
64
64
  import {
65
+ mergeDocumentIntoDocumentCache,
65
66
  isDocumentUpdateConflict,
66
67
  patchDocumentCaches,
68
+ documentQueryFilter,
67
69
  useDocument,
68
70
  useDeleteDocument,
69
71
  useDocuments,
@@ -247,7 +249,10 @@ export function DocumentEditor({
247
249
  databaseId,
248
250
  databaseDocumentId,
249
251
  }: DocumentEditorProps) {
250
- const documentQuery = useDocument(documentId);
252
+ const documentQuery = useDocument(documentId, {
253
+ databaseId,
254
+ databaseDocumentId,
255
+ });
251
256
  const {
252
257
  data: queriedDocument,
253
258
  isError,
@@ -445,6 +450,7 @@ export function documentEditorBreadcrumbNavigationItems(
445
450
  | "title"
446
451
  | "icon"
447
452
  | "position"
453
+ | "database"
448
454
  | "databaseMembership"
449
455
  | "source"
450
456
  >[], // i18n-ignore type expression
@@ -457,6 +463,9 @@ export function documentEditorBreadcrumbNavigationItems(
457
463
  workspacesTitle: string;
458
464
  },
459
465
  ): ToolbarBreadcrumbItem[] {
466
+ const peerDocuments = documents.filter(
467
+ (item) => !item.database?.systemRole && item.source?.kind !== "folder",
468
+ );
460
469
  const documentById = new Map(documents.map((item) => [item.id, item]));
461
470
  const workspaceDocumentIds = new Set(
462
471
  spaces.map((space) => space.filesDocumentId),
@@ -480,9 +489,8 @@ export function documentEditorBreadcrumbNavigationItems(
480
489
  if (!current) return item;
481
490
  const membershipDocumentId =
482
491
  current.databaseMembership?.databaseDocumentId ?? null;
483
- const siblings = documents
492
+ const siblings = peerDocuments
484
493
  .filter((candidate) => {
485
- if (candidate.source?.kind === "folder") return false;
486
494
  if (candidate.parentId !== current.parentId) return false;
487
495
  if (current.parentId) return true;
488
496
  return (
@@ -536,7 +544,7 @@ function DocumentEditorBody({
536
544
  const deleteDocument = useDeleteDocument();
537
545
  const queryClient = useQueryClient();
538
546
  const processBuilderBodies = useProcessBuilderBodyHydration(
539
- document.databaseMembership?.databaseDocumentId ?? documentId,
547
+ document.bodyHydration?.databaseDocumentId ?? documentId,
540
548
  );
541
549
  const canEdit = document.canEdit ?? true;
542
550
  const canEditRef = useRef(canEdit);
@@ -661,24 +669,30 @@ function DocumentEditorBody({
661
669
  );
662
670
 
663
671
  useEffect(() => {
664
- const membership = document.databaseMembership;
665
- const hydration = membership?.bodyHydration;
672
+ const hydrationContext = document.bodyHydration;
673
+ const hydration = hydrationContext?.hydration;
666
674
  if (
667
- !membership?.sourceId ||
675
+ !canEdit ||
676
+ !hydrationContext?.sourceId ||
668
677
  !hydration ||
669
678
  (hydration.status !== "pending" && hydration.status !== "error")
670
679
  ) {
671
680
  return;
672
681
  }
673
- const promotionKey = `${membership.sourceId}:${documentId}:${hydration.status}:${hydration.version ?? ""}`;
682
+ const promotionKey = `${hydrationContext.sourceId}:${documentId}:${hydration.status}:${hydration.version ?? ""}`;
674
683
  if (promotedBuilderBodyRef.current === promotionKey) return;
675
684
  promotedBuilderBodyRef.current = promotionKey;
676
685
  processBuilderBodies.mutate({
677
- sourceId: membership.sourceId,
686
+ sourceId: hydrationContext.sourceId,
678
687
  documentId,
679
688
  limit: 1,
680
689
  });
681
- }, [document.databaseMembership, documentId, processBuilderBodies.mutate]);
690
+ }, [
691
+ canEdit,
692
+ document.bodyHydration,
693
+ documentId,
694
+ processBuilderBodies.mutate,
695
+ ]);
682
696
  const titleFocusedRef = useRef(false);
683
697
  const scrollContainerRef = useRef<HTMLDivElement>(null);
684
698
  const titleInputRef = useRef<HTMLTextAreaElement>(null);
@@ -973,9 +987,8 @@ function DocumentEditorBody({
973
987
  description:
974
988
  error instanceof Error ? error.message : t("empty.genericError"),
975
989
  });
976
- queryClient.setQueryData(
977
- ["action", "get-document", { id: documentId }],
978
- fileFirstDocument,
990
+ queryClient.setQueriesData(documentQueryFilter(documentId), (old) =>
991
+ mergeDocumentIntoDocumentCache(old, fileFirstDocument),
979
992
  );
980
993
  queryClient.invalidateQueries({
981
994
  queryKey: ["action", "list-documents"],
@@ -1887,9 +1900,15 @@ function DocumentEditorBody({
1887
1900
  if (bodyHydrationPending) {
1888
1901
  return (
1889
1902
  <BuilderBodySyncingNotice
1890
- title={t("editor.builderBodySyncing")}
1903
+ title={t(
1904
+ document.bodyHydration?.provider === "builder"
1905
+ ? "editor.builderBodySyncing"
1906
+ : "editor.pageBodySyncing",
1907
+ )}
1891
1908
  description={t(
1892
- "editor.builderBodySyncingDescription",
1909
+ document.bodyHydration?.provider === "builder"
1910
+ ? "editor.builderBodySyncingDescription"
1911
+ : "editor.pageBodySyncingDescription",
1893
1912
  )}
1894
1913
  />
1895
1914
  );
@@ -90,6 +90,7 @@ import {
90
90
  useSearchNotionPages,
91
91
  useCreateAndLinkNotionPage,
92
92
  } from "@/hooks/use-notion";
93
+ import { documentQueryFilter } from "@/lib/document-query";
93
94
  import {
94
95
  localSourceAbsolutePath,
95
96
  revealLinkedLocalSourceFile,
@@ -318,6 +319,15 @@ export function compactToolbarBreadcrumbItems(
318
319
  ];
319
320
  }
320
321
 
322
+ export function firstSelectableBreadcrumbMenuItemId(
323
+ menuItems: ToolbarBreadcrumbItem["menuItems"],
324
+ currentDocumentId: string,
325
+ ): string | null {
326
+ return (
327
+ menuItems?.find((menuItem) => menuItem.id !== currentDocumentId)?.id ?? null
328
+ );
329
+ }
330
+
321
331
  function ToolbarBreadcrumbMenu({
322
332
  item,
323
333
  label,
@@ -337,6 +347,12 @@ function ToolbarBreadcrumbMenu({
337
347
  }) {
338
348
  const [open, setOpen] = useState(false);
339
349
  const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
350
+ const openedWithKeyboardRef = useRef(false);
351
+ const firstSelectableItemRef = useRef<HTMLDivElement | null>(null);
352
+ const firstSelectableItemId = firstSelectableBreadcrumbMenuItemId(
353
+ item.menuItems,
354
+ currentDocumentId,
355
+ );
340
356
 
341
357
  function cancelClose() {
342
358
  if (!closeTimerRef.current) return;
@@ -349,8 +365,25 @@ function ToolbarBreadcrumbMenu({
349
365
  closeTimerRef.current = setTimeout(() => setOpen(false), 140);
350
366
  }
351
367
 
368
+ useEffect(() => {
369
+ if (!open || !openedWithKeyboardRef.current) return;
370
+ openedWithKeyboardRef.current = false;
371
+ const frame = requestAnimationFrame(() => {
372
+ firstSelectableItemRef.current?.focus();
373
+ });
374
+ return () => cancelAnimationFrame(frame);
375
+ }, [open]);
376
+
352
377
  return (
353
- <DropdownMenu modal={false} open={open} onOpenChange={setOpen}>
378
+ <DropdownMenu
379
+ modal={false}
380
+ open={open}
381
+ onOpenChange={(nextOpen) => {
382
+ if (nextOpen) cancelClose();
383
+ else openedWithKeyboardRef.current = false;
384
+ setOpen(nextOpen);
385
+ }}
386
+ >
354
387
  <DropdownMenuTrigger asChild>
355
388
  <button
356
389
  type="button"
@@ -364,6 +397,16 @@ function ToolbarBreadcrumbMenu({
364
397
  setOpen(true);
365
398
  }}
366
399
  onPointerLeave={scheduleClose}
400
+ onKeyDown={(event) => {
401
+ if (
402
+ event.key === "Enter" ||
403
+ event.key === " " ||
404
+ event.key === "ArrowDown"
405
+ ) {
406
+ openedWithKeyboardRef.current = true;
407
+ cancelClose();
408
+ }
409
+ }}
367
410
  >
368
411
  {children}
369
412
  </button>
@@ -371,6 +414,7 @@ function ToolbarBreadcrumbMenu({
371
414
  <DropdownMenuContent
372
415
  align="start"
373
416
  className="w-64"
417
+ onKeyDown={cancelClose}
374
418
  onPointerEnter={cancelClose}
375
419
  onPointerLeave={scheduleClose}
376
420
  >
@@ -379,7 +423,13 @@ function ToolbarBreadcrumbMenu({
379
423
  return (
380
424
  <DropdownMenuItem
381
425
  key={menuItem.id}
426
+ ref={
427
+ menuItem.id === firstSelectableItemId
428
+ ? firstSelectableItemRef
429
+ : undefined
430
+ }
382
431
  className="gap-2"
432
+ disabled={menuItem.id === currentDocumentId}
383
433
  onSelect={() => onOpen(menuItem.id)}
384
434
  >
385
435
  <span className="flex size-4 shrink-0 items-center justify-center">
@@ -523,12 +573,8 @@ export function DocumentToolbar({
523
573
  const previous = hideFromSearch;
524
574
  setPendingHideFromSearch(next);
525
575
 
526
- queryClient.setQueryData(
527
- ["action", "get-document", { id: documentId }],
528
- (old: any) =>
529
- old && typeof old === "object"
530
- ? { ...old, hideFromSearch: next }
531
- : old,
576
+ queryClient.setQueriesData(documentQueryFilter(documentId), (old: any) =>
577
+ old && typeof old === "object" ? { ...old, hideFromSearch: next } : old,
532
578
  );
533
579
  queryClient.setQueryData(
534
580
  ["action", "list-documents", undefined],
@@ -552,9 +598,7 @@ export function DocumentToolbar({
552
598
  });
553
599
  } catch (err) {
554
600
  setPendingHideFromSearch(previous);
555
- queryClient.invalidateQueries({
556
- queryKey: ["action", "get-document", { id: documentId }],
557
- });
601
+ queryClient.invalidateQueries(documentQueryFilter(documentId));
558
602
  queryClient.invalidateQueries({
559
603
  queryKey: ["action", "list-documents"],
560
604
  });
@@ -565,9 +609,7 @@ export function DocumentToolbar({
565
609
  throw err;
566
610
  } finally {
567
611
  setPendingHideFromSearch(null);
568
- queryClient.invalidateQueries({
569
- queryKey: ["action", "get-document", { id: documentId }],
570
- });
612
+ queryClient.invalidateQueries(documentQueryFilter(documentId));
571
613
  queryClient.invalidateQueries({
572
614
  queryKey: ["action", "list-documents"],
573
615
  });
@@ -54,12 +54,12 @@ export function databaseItemBodyHydrationIsPending(
54
54
  }
55
55
 
56
56
  export function documentBodyHydrationIsPending(
57
- document: Pick<Document, "content" | "databaseMembership">,
57
+ document: Pick<Document, "content" | "bodyHydration">,
58
58
  ) {
59
- const hydration = document.databaseMembership?.bodyHydration;
59
+ const hydration = document.bodyHydration?.hydration;
60
60
  if (
61
61
  sourceBackedEmptyBodyNeedsHydration({
62
- sourceId: document.databaseMembership?.sourceId,
62
+ sourceId: document.bodyHydration ? "source-backed" : undefined,
63
63
  content: document.content,
64
64
  hydration,
65
65
  })
@@ -81,7 +81,10 @@ export function newDocumentPageChoiceIsDisabled(args: {
81
81
 
82
82
  export function previewBodyHydrationIsPending(args: {
83
83
  item: Pick<ContentDatabaseItem, "bodyHydration" | "document">;
84
- document: Pick<Document, "content" | "databaseMembership"> | null | undefined;
84
+ document:
85
+ | Pick<Document, "content" | "databaseMembership" | "bodyHydration">
86
+ | null
87
+ | undefined;
85
88
  }) {
86
89
  const membership =
87
90
  args.document?.databaseMembership ?? args.item.document.databaseMembership;
@@ -128,11 +131,14 @@ export function previewDraftConflictsWithHydratedBody(args: {
128
131
 
129
132
  export function previewBodyHydrationIsTerminalError(args: {
130
133
  item: Pick<ContentDatabaseItem, "bodyHydration" | "document">;
131
- document: Pick<Document, "databaseMembership"> | null | undefined;
134
+ document:
135
+ | Pick<Document, "databaseMembership" | "bodyHydration">
136
+ | null
137
+ | undefined;
132
138
  }) {
133
139
  return (
134
140
  builderBodyHydrationIsTerminalError(
135
- args.document?.databaseMembership?.bodyHydration,
141
+ args.document?.bodyHydration?.hydration,
136
142
  ) ||
137
143
  builderBodyHydrationIsTerminalError(
138
144
  args.item.bodyHydration ??