@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
@@ -10,10 +10,12 @@ export interface RecurringJob {
10
10
  path: string;
11
11
  scope: "personal" | "organization";
12
12
  schedule: string;
13
+ timezone: string;
13
14
  scheduleDescription: string;
14
15
  instructions: string;
15
16
  enabled: boolean;
16
17
  lastRun: string | null;
18
+ lastCheck: string | null;
17
19
  lastStatus: string | null;
18
20
  lastError: string | null;
19
21
  nextRun: string | null;
@@ -30,11 +32,13 @@ export interface Automation {
30
32
  triggerType: "event" | "schedule";
31
33
  event: string | null;
32
34
  schedule: string | null;
35
+ timezone: string | null;
33
36
  scheduleDescription: string | null;
34
37
  condition: string | null;
35
38
  body: string;
36
39
  enabled: boolean;
37
40
  lastRun: string | null;
41
+ lastCheck: string | null;
38
42
  lastStatus: string | null;
39
43
  lastError: string | null;
40
44
  nextRun: string | null;
@@ -54,14 +58,23 @@ export type ManageJobInput = {
54
58
  name: string;
55
59
  scope: "personal" | "organization";
56
60
  enabled?: boolean;
61
+ schedule?: string;
62
+ timezone?: string;
57
63
  };
58
64
 
59
- export type ManageAutomationInput = {
60
- operation: "update" | "delete";
61
- name: string;
62
- scope: "personal" | "organization";
63
- enabled?: boolean;
64
- };
65
+ export type ManageAutomationInput = ManageJobInput;
66
+
67
+ export interface AutomationRun {
68
+ id: string;
69
+ automation: string;
70
+ scope: string | null;
71
+ runId: string | null;
72
+ threadId: string | null;
73
+ status: "running" | "success" | "error" | "interrupted";
74
+ startedAt: number;
75
+ finishedAt: number | null;
76
+ error: string | null;
77
+ }
65
78
 
66
79
  function recurringParams(scope: JobsScope) {
67
80
  return { scope: scope === "org" ? "organization" : "personal" } as const;
@@ -105,8 +118,8 @@ export function useManageRecurringJob(scope: JobsScope) {
105
118
  return current.filter((job) => job.name !== variables.name);
106
119
  }
107
120
  return current.map((job) =>
108
- job.name === variables.name && variables.enabled !== undefined
109
- ? { ...job, enabled: variables.enabled }
121
+ job.name === variables.name
122
+ ? { ...job, ...optimisticPatch(variables) }
110
123
  : job,
111
124
  );
112
125
  });
@@ -141,8 +154,8 @@ export function useManageAutomation(scope: JobsScope) {
141
154
  );
142
155
  }
143
156
  return current.map((automation) =>
144
- automation.name === variables.name && variables.enabled !== undefined
145
- ? { ...automation, enabled: variables.enabled }
157
+ automation.name === variables.name
158
+ ? { ...automation, ...optimisticPatch(variables) }
146
159
  : automation,
147
160
  );
148
161
  });
@@ -156,3 +169,30 @@ export function useManageAutomation(scope: JobsScope) {
156
169
  },
157
170
  });
158
171
  }
172
+
173
+ function optimisticPatch(variables: ManageJobInput) {
174
+ const patch: {
175
+ enabled?: boolean;
176
+ schedule?: string;
177
+ timezone?: string;
178
+ } = {};
179
+ if (variables.enabled !== undefined) patch.enabled = variables.enabled;
180
+ if (variables.schedule !== undefined) patch.schedule = variables.schedule;
181
+ if (variables.timezone !== undefined) patch.timezone = variables.timezone;
182
+ return patch;
183
+ }
184
+
185
+ export function useAutomationRuns(
186
+ scope: JobsScope,
187
+ name: string | null,
188
+ active: boolean,
189
+ ) {
190
+ const params = {
191
+ scope: scope === "org" ? "organization" : "personal",
192
+ name: name || "",
193
+ } as const;
194
+ return useActionQuery<AutomationRun[]>("list-automation-runs", params, {
195
+ staleTime: 5_000,
196
+ enabled: active && Boolean(name),
197
+ });
198
+ }
@@ -83,6 +83,13 @@ export interface OrgSwitcherProps {
83
83
  settingsPath?: string | null;
84
84
  /** Path to navigate to when the user clicks "Profile". Defaults to the shared Account settings section. */
85
85
  profilePath?: string | null;
86
+ /**
87
+ * Path to the Manage agent page. Settings links here too, but the switcher
88
+ * is the only always-visible surface, so omitting it leaves Files,
89
+ * Instructions, Memory, Skills and Automations reachable only from Settings.
90
+ * Pass `null` for apps that do not mount the Agent page.
91
+ */
92
+ agentPath?: string | null;
86
93
  }
87
94
 
88
95
  function personalLabelFromEmail(email: string | null | undefined): string {
@@ -119,6 +126,7 @@ const COMPACT_SWITCHER_BUTTON_CLASS =
119
126
 
120
127
  const DEFAULT_ORGANIZATION_SETTINGS_PATH = "/settings#organization";
121
128
  const DEFAULT_PROFILE_PATH = "/settings#account";
129
+ const DEFAULT_AGENT_PATH = "/agent";
122
130
 
123
131
  const APP_ICON_MAP: Record<string, typeof IconApps> = {
124
132
  Mail: IconMail,
@@ -311,6 +319,7 @@ export function OrgSwitcher({
311
319
  compact,
312
320
  settingsPath = DEFAULT_ORGANIZATION_SETTINGS_PATH,
313
321
  profilePath = DEFAULT_PROFILE_PATH,
322
+ agentPath = DEFAULT_AGENT_PATH,
314
323
  }: OrgSwitcherProps) {
315
324
  const { data: org, isLoading } = useOrg();
316
325
  const { session } = useSession();
@@ -607,6 +616,23 @@ export function OrgSwitcher({
607
616
  </span>
608
617
  </button>
609
618
  )}
619
+ {agentPath && (
620
+ <button
621
+ type="button"
622
+ onClick={() => {
623
+ setOpen(false);
624
+ navigate(agentPath);
625
+ }}
626
+ className={`${ITEM_CLASS} cursor-pointer`}
627
+ >
628
+ <IconBrain className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
629
+ <span className="flex-1 text-start">
630
+ {t("settings.manageAgentMenuItem", {
631
+ defaultValue: "Manage agent",
632
+ })}
633
+ </span>
634
+ </button>
635
+ )}
610
636
  {inOrg && (
611
637
  <button
612
638
  type="button"
@@ -13,6 +13,7 @@ import { useActionMutation, useActionQuery } from "../use-action.js";
13
13
  import { uploadAvatar, useAvatarUrl } from "../use-avatar.js";
14
14
  import { useSession } from "../use-session.js";
15
15
  import { cn } from "../utils.js";
16
+ import { SchedulingTimezoneField } from "./SchedulingTimezoneField.js";
16
17
 
17
18
  function profileInitials(name: string): string {
18
19
  return (
@@ -157,38 +158,41 @@ export function AccountSettingsForm({
157
158
  description={t("settings.profileNameDescription")}
158
159
  disabled={!email || profileQuery.isLoading || updateProfile.isPending}
159
160
  />
160
- <div className="flex items-center justify-between gap-3">
161
- <div className="min-h-4 text-xs">
162
- {updateProfile.isSuccess && (
163
- <p className="text-green-600 dark:text-green-400">
164
- {t("settings.profileSaved")}
165
- </p>
166
- )}
167
- {updateProfile.error && (
168
- <p className="text-destructive">
169
- {t("settings.profileSaveError")}
170
- </p>
171
- )}
172
- </div>
173
- <ActionButton
174
- type="button"
175
- intent="primary"
176
- emphasis="solid"
177
- size="compact"
178
- pending={updateProfile.isPending}
179
- disabled={
180
- !email ||
181
- profileQuery.isLoading ||
182
- updateProfile.isPending ||
183
- !name.trim()
184
- }
185
- onPress={handleProfileSave}
186
- >
187
- {updateProfile.isPending
188
- ? t("settings.profileSaving")
189
- : t("settings.profileSave")}
190
- </ActionButton>
161
+ </div>
162
+
163
+ <div className="border-t border-border/60 pt-3">
164
+ <SchedulingTimezoneField />
165
+ </div>
166
+
167
+ <div className="flex items-center justify-between gap-3 border-t border-border/60 pt-3">
168
+ <div className="min-h-4 text-xs">
169
+ {updateProfile.isSuccess && (
170
+ <p className="text-green-600 dark:text-green-400">
171
+ {t("settings.profileSaved")}
172
+ </p>
173
+ )}
174
+ {updateProfile.error && (
175
+ <p className="text-destructive">{t("settings.profileSaveError")}</p>
176
+ )}
191
177
  </div>
178
+ <ActionButton
179
+ type="button"
180
+ intent="primary"
181
+ emphasis="solid"
182
+ size="compact"
183
+ pending={updateProfile.isPending}
184
+ disabled={
185
+ !email ||
186
+ profileQuery.isLoading ||
187
+ updateProfile.isPending ||
188
+ !name.trim()
189
+ }
190
+ onPress={handleProfileSave}
191
+ >
192
+ {updateProfile.isPending
193
+ ? t("settings.profileSaving")
194
+ : t("settings.profileSave")}
195
+ </ActionButton>
192
196
  </div>
193
197
  </div>
194
198
  );
@@ -0,0 +1,71 @@
1
+ import {
2
+ TimezoneSelect,
3
+ browserTimezone,
4
+ } from "../agent-page/TimezoneSelect.js";
5
+ import { useT } from "../i18n.js";
6
+ import { useActionMutation, useActionQuery } from "../use-action.js";
7
+
8
+ interface LocalizationPreferenceResult {
9
+ locale: string;
10
+ timezone: string;
11
+ }
12
+
13
+ const SYSTEM = "system";
14
+
15
+ /**
16
+ * Timezone used when the agent schedules work for this user.
17
+ *
18
+ * This is deliberately a stored preference rather than a per-request read of
19
+ * the browser zone: automations are created and run by callers that have no
20
+ * browser at all (cron ticks, chat integrations, A2A), and those callers would
21
+ * otherwise fall back to the host zone and schedule the user's 8am job in UTC.
22
+ */
23
+ export function SchedulingTimezoneField() {
24
+ const t = useT();
25
+ const detected = browserTimezone();
26
+ const preference = useActionQuery<LocalizationPreferenceResult>(
27
+ "get-localization-preference",
28
+ );
29
+ const save = useActionMutation<
30
+ LocalizationPreferenceResult,
31
+ { timezone: string }
32
+ >("set-localization-preference");
33
+
34
+ // Selecting a zone commits it, matching the language picker beside it.
35
+ const stored = preference.data?.timezone ?? SYSTEM;
36
+ const pending = save.isPending ? save.variables?.timezone : undefined;
37
+ const value = pending ?? stored;
38
+
39
+ return (
40
+ <div className="space-y-2">
41
+ <label
42
+ className="text-sm font-medium"
43
+ htmlFor="agent-native-scheduling-timezone"
44
+ >
45
+ {t("settings.timezoneLabel", { defaultValue: "Timezone" })}
46
+ </label>
47
+
48
+ <TimezoneSelect
49
+ id="agent-native-scheduling-timezone"
50
+ value={value}
51
+ disabled={preference.isLoading || save.isPending}
52
+ suggested={[detected]}
53
+ systemLabel={t("settings.timezoneSystem", {
54
+ defaultValue: "Follow this browser ({{zone}})",
55
+ zone: detected,
56
+ })}
57
+ onChange={(timezone) => save.mutate({ timezone })}
58
+ />
59
+
60
+ <p className="min-h-4 text-xs text-muted-foreground">
61
+ {save.error ? (
62
+ <span className="text-destructive">{save.error.message}</span>
63
+ ) : (
64
+ t("settings.timezoneHint", {
65
+ defaultValue: "Used for timestamps and scheduled automations.",
66
+ })
67
+ )}
68
+ </p>
69
+ </div>
70
+ );
71
+ }
@@ -0,0 +1,113 @@
1
+ import type { ReactNode } from "react";
2
+
3
+ import { cn } from "../utils.js";
4
+
5
+ export interface SettingsGroupProps {
6
+ /** Anchor target so a settings search hit can scroll the whole group. */
7
+ id?: string;
8
+ title?: string;
9
+ description?: string;
10
+ className?: string;
11
+ children: ReactNode;
12
+ }
13
+
14
+ /**
15
+ * A bordered card holding several one-line settings instead of one card per
16
+ * control. Copy is passed in already translated — core components do not
17
+ * resolve an app's i18n keys.
18
+ */
19
+ export function SettingsGroup({
20
+ id,
21
+ title,
22
+ description,
23
+ className,
24
+ children,
25
+ }: SettingsGroupProps) {
26
+ return (
27
+ <section
28
+ id={id}
29
+ className={cn(
30
+ "scroll-mt-16 overflow-hidden rounded-lg border border-border bg-card text-card-foreground shadow-sm",
31
+ className,
32
+ )}
33
+ >
34
+ {(title || description) && (
35
+ <header className="border-b border-border/60 px-5 py-4 sm:px-6">
36
+ {title && (
37
+ <h2 className="text-base font-semibold leading-none tracking-tight">
38
+ {title}
39
+ </h2>
40
+ )}
41
+ {description && (
42
+ <p className="mt-1.5 text-sm leading-snug text-muted-foreground">
43
+ {description}
44
+ </p>
45
+ )}
46
+ </header>
47
+ )}
48
+ <div className="divide-y divide-border/60">{children}</div>
49
+ </section>
50
+ );
51
+ }
52
+
53
+ export interface SettingsRowProps {
54
+ /**
55
+ * Anchor target. Rows keep the ids their former standalone cards used, so
56
+ * existing settings-search hashes still resolve after a card collapses into
57
+ * a row.
58
+ */
59
+ id?: string;
60
+ label: ReactNode;
61
+ description?: ReactNode;
62
+ icon?: ReactNode;
63
+ /** Badge or pill rendered beside the label. */
64
+ status?: ReactNode;
65
+ /** The input itself: switch, select, button, link. */
66
+ control?: ReactNode;
67
+ /** Extra content below the row, e.g. a disclosure panel. */
68
+ children?: ReactNode;
69
+ className?: string;
70
+ }
71
+
72
+ /** One setting: label and description on the start side, control on the end. */
73
+ export function SettingsRow({
74
+ id,
75
+ label,
76
+ description,
77
+ icon,
78
+ status,
79
+ control,
80
+ children,
81
+ className,
82
+ }: SettingsRowProps) {
83
+ return (
84
+ <div id={id} className={cn("scroll-mt-16 px-5 py-4 sm:px-6", className)}>
85
+ <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
86
+ <div className="flex min-w-0 gap-3">
87
+ {icon && (
88
+ <span className="mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-md border border-border bg-background text-muted-foreground [&>svg]:size-[18px]">
89
+ {icon}
90
+ </span>
91
+ )}
92
+ <div className="min-w-0">
93
+ <div className="flex flex-wrap items-center gap-2">
94
+ <span className="text-sm font-medium text-foreground">
95
+ {label}
96
+ </span>
97
+ {status}
98
+ </div>
99
+ {description && (
100
+ <p className="mt-1 max-w-xl text-sm leading-6 text-muted-foreground">
101
+ {description}
102
+ </p>
103
+ )}
104
+ </div>
105
+ </div>
106
+ {control && (
107
+ <div className="shrink-0 sm:ms-4 sm:text-end">{control}</div>
108
+ )}
109
+ </div>
110
+ {children && <div className="mt-4">{children}</div>}
111
+ </div>
112
+ );
113
+ }
@@ -93,7 +93,8 @@ const SETTINGS_SECTION_SEARCH_META: Record<
93
93
  > = {
94
94
  account: {
95
95
  label: "Account",
96
- keywords: "profile photo avatar identity signed in email name",
96
+ keywords:
97
+ "profile photo avatar identity signed in email name timezone time zone schedule scheduling clock",
97
98
  },
98
99
  llm: {
99
100
  label: "LLM",
@@ -34,6 +34,12 @@ export {
34
34
  type OpenBuilderConnectPopupOptions,
35
35
  } from "./useBuilderStatus.js";
36
36
  export { SecretsSection, type SecretsSectionProps } from "./SecretsSection.js";
37
+ export {
38
+ SettingsGroup,
39
+ SettingsRow,
40
+ type SettingsGroupProps,
41
+ type SettingsRowProps,
42
+ } from "./SettingsRow.js";
37
43
  export {
38
44
  normalizeSettingsSection,
39
45
  settingsSectionDomId,
@@ -1,4 +1,4 @@
1
- import { getDbExec } from "../db/client.js";
1
+ import { isOrgMember as isMemberOfOrg } from "../org/membership.js";
2
2
  import { upsertVerifiedIntegrationIdentity } from "./identity-links-store.js";
3
3
  import {
4
4
  getActiveIntegrationInstallationByKey,
@@ -74,16 +74,6 @@ async function resolveSlackInstallation(incoming: IncomingMessage) {
74
74
  : null;
75
75
  }
76
76
 
77
- async function isMemberOfOrg(email: string, orgId: string): Promise<boolean> {
78
- const { rows } = await getDbExec().execute({
79
- sql: `SELECT 1 FROM org_members
80
- WHERE org_id = ? AND LOWER(email) = ?
81
- LIMIT 1`,
82
- args: [orgId, email],
83
- });
84
- return rows.length > 0;
85
- }
86
-
87
77
  /**
88
78
  * Resolve the default integration principal.
89
79
  *
@@ -150,7 +140,7 @@ export async function resolveDefaultIntegrationExecutionContext(
150
140
  incoming.tenantId
151
141
  ) {
152
142
  try {
153
- isOrgMember = await isMemberOfOrg(email, installation.orgId);
143
+ isOrgMember = await isMemberOfOrg(installation.orgId, email);
154
144
  } catch {
155
145
  // A membership-store outage is not evidence that the sender is merely
156
146
  // unlinked. Fail closed instead of widening them to org-wide access.
@@ -0,0 +1,33 @@
1
+ import { z } from "zod";
2
+
3
+ import { defineAction } from "../../action.js";
4
+ import { organizationResourceOwner } from "../../resources/store.js";
5
+ import { listAutomationRuns, type AutomationRun } from "../run-history.js";
6
+
7
+ const scopeSchema = z.enum(["personal", "organization"]);
8
+
9
+ export default defineAction({
10
+ description:
11
+ "List past execution records for one automation or recurring job in the selected scope.",
12
+ agentTool: false,
13
+ schema: z.object({
14
+ name: z.string().min(1),
15
+ scope: scopeSchema.default("personal"),
16
+ limit: z.number().int().min(1).max(100).optional(),
17
+ }),
18
+ http: { method: "GET" },
19
+ readOnly: true,
20
+ parallelSafe: true,
21
+ run: async ({ name, scope, limit }, ctx): Promise<AutomationRun[]> => {
22
+ const userEmail = ctx?.userEmail;
23
+ if (!userEmail) throw new Error("Not authenticated.");
24
+ if (scope === "organization" && !ctx?.orgId) return [];
25
+
26
+ const owner =
27
+ scope === "organization"
28
+ ? organizationResourceOwner(ctx.orgId as string)
29
+ : userEmail;
30
+
31
+ return listAutomationRuns({ owners: [owner], automation: name, limit });
32
+ },
33
+ });
@@ -6,7 +6,12 @@ import {
6
6
  resourceGetByPath,
7
7
  resourceList,
8
8
  } from "../../resources/store.js";
9
- import { describeCron, isValidCron, nextOccurrence } from "../cron.js";
9
+ import {
10
+ describeCron,
11
+ effectiveTimezone,
12
+ isValidCron,
13
+ nextOccurrence,
14
+ } from "../cron.js";
10
15
  import { classifyJobResource } from "../frontmatter.js";
11
16
  import { parseJobFrontmatter } from "../scheduler.js";
12
17
  import { authorizeJobMutation } from "../tools.js";
@@ -17,15 +22,25 @@ function jobName(path: string): string {
17
22
  return path.replace(/^jobs\//, "").replace(/\.md$/, "");
18
23
  }
19
24
 
25
+ /**
26
+ * A stored `nextRun` in the past means the scheduler kept declining to run the
27
+ * job, not that it is due two days ago. Report the real next occurrence and
28
+ * let `lastError` carry the reason it keeps being passed over.
29
+ */
20
30
  function nextRun(
21
31
  meta: ReturnType<typeof parseJobFrontmatter>["meta"],
22
32
  ): string | null {
23
33
  if (!meta.enabled) return null;
24
- if (meta.nextRun) return meta.nextRun;
25
- if (meta.schedule && isValidCron(meta.schedule)) {
26
- return nextOccurrence(meta.schedule).toISOString();
34
+ const scheduled = Boolean(meta.schedule && isValidCron(meta.schedule));
35
+ if (meta.nextRun) {
36
+ const stored = new Date(meta.nextRun).getTime();
37
+ if (!Number.isFinite(stored) || stored > Date.now() || !scheduled) {
38
+ return meta.nextRun;
39
+ }
27
40
  }
28
- return null;
41
+ return scheduled
42
+ ? nextOccurrence(meta.schedule, undefined, meta.timezone).toISOString()
43
+ : null;
29
44
  }
30
45
 
31
46
  export interface RecurringJobActionItem {
@@ -34,10 +49,12 @@ export interface RecurringJobActionItem {
34
49
  path: string;
35
50
  scope: "personal" | "organization";
36
51
  schedule: string;
52
+ timezone: string;
37
53
  scheduleDescription: string;
38
54
  instructions: string;
39
55
  enabled: boolean;
40
56
  lastRun: string | null;
57
+ lastCheck: string | null;
41
58
  lastStatus: string | null;
42
59
  lastError: string | null;
43
60
  nextRun: string | null;
@@ -87,10 +104,14 @@ export default defineAction({
87
104
  path: full.path,
88
105
  scope,
89
106
  schedule: meta.schedule,
90
- scheduleDescription: meta.schedule ? describeCron(meta.schedule) : "",
107
+ timezone: effectiveTimezone(meta.timezone),
108
+ scheduleDescription: meta.schedule
109
+ ? describeCron(meta.schedule, effectiveTimezone(meta.timezone))
110
+ : "",
91
111
  instructions: body,
92
112
  enabled: meta.enabled,
93
113
  lastRun: meta.lastRun ?? null,
114
+ lastCheck: meta.lastCheck ?? null,
94
115
  lastStatus: meta.lastStatus ?? null,
95
116
  lastError: meta.lastError ?? null,
96
117
  nextRun: nextRun(meta),
@@ -7,8 +7,9 @@ import {
7
7
  resourceGetByPath,
8
8
  resourcePut,
9
9
  } from "../../resources/store.js";
10
- import { isValidCron, nextOccurrence } from "../cron.js";
10
+ import { isValidCron, isValidTimezone, nextOccurrence } from "../cron.js";
11
11
  import { classifyJobResource } from "../frontmatter.js";
12
+ import { deleteAutomationRuns } from "../run-history.js";
12
13
  import { buildJobContent, parseJobFrontmatter } from "../scheduler.js";
13
14
  import { authorizeJobMutation } from "../tools.js";
14
15
 
@@ -23,8 +24,10 @@ export default defineAction({
23
24
  name: z.string().min(1),
24
25
  scope: scopeSchema.default("personal"),
25
26
  enabled: z.boolean().optional(),
27
+ schedule: z.string().min(1).optional(),
28
+ timezone: z.string().min(1).optional(),
26
29
  }),
27
- run: async ({ operation, name, scope, enabled }, ctx) => {
30
+ run: async ({ operation, name, scope, enabled, schedule, timezone }, ctx) => {
28
31
  const userEmail = ctx?.userEmail;
29
32
  if (!userEmail) throw new Error("Not authenticated.");
30
33
  if (scope === "organization" && !ctx?.orgId) {
@@ -54,17 +57,46 @@ export default defineAction({
54
57
 
55
58
  if (operation === "delete") {
56
59
  await resourceDelete(resource.id);
60
+ // Names are reusable; history left behind would surface as the run
61
+ // history of whatever job is next created under this name.
62
+ await deleteAutomationRuns(resource.owner, name);
57
63
  return { deleted: true, name };
58
64
  }
59
65
 
60
- if (enabled === undefined) {
61
- throw Object.assign(new Error("enabled is required for update."), {
62
- statusCode: 400,
63
- });
66
+ if (timezone !== undefined) {
67
+ if (!isValidTimezone(timezone)) {
68
+ throw Object.assign(new Error(`Unknown timezone "${timezone}".`), {
69
+ statusCode: 400,
70
+ });
71
+ }
72
+ meta.timezone = timezone;
73
+ }
74
+ if (
75
+ enabled === undefined &&
76
+ schedule === undefined &&
77
+ timezone === undefined
78
+ ) {
79
+ throw Object.assign(
80
+ new Error("enabled, schedule, or timezone is required for update."),
81
+ { statusCode: 400 },
82
+ );
83
+ }
84
+ if (schedule !== undefined) {
85
+ if (!isValidCron(schedule)) {
86
+ throw Object.assign(
87
+ new Error(`Invalid cron expression "${schedule}".`),
88
+ { statusCode: 400 },
89
+ );
90
+ }
91
+ meta.schedule = schedule;
64
92
  }
65
- meta.enabled = enabled;
66
- if (enabled && meta.schedule && isValidCron(meta.schedule)) {
67
- meta.nextRun = nextOccurrence(meta.schedule).toISOString();
93
+ if (enabled !== undefined) meta.enabled = enabled;
94
+ if (meta.enabled && meta.schedule && isValidCron(meta.schedule)) {
95
+ meta.nextRun = nextOccurrence(
96
+ meta.schedule,
97
+ undefined,
98
+ meta.timezone,
99
+ ).toISOString();
68
100
  }
69
101
  await resourcePut(
70
102
  resource.owner,