@agent-native/core 0.134.1 → 0.135.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (442) hide show
  1. package/corpus/README.md +3 -3
  2. package/corpus/core/CHANGELOG.md +107 -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/index.ts +5 -0
  48. package/corpus/core/src/sharing/recipients.ts +67 -0
  49. package/corpus/core/src/triggers/actions/list-automations.ts +27 -8
  50. package/corpus/core/src/triggers/actions/manage-automation.ts +17 -6
  51. package/corpus/core/src/triggers/actions.ts +16 -4
  52. package/corpus/core/src/triggers/dispatcher.ts +44 -30
  53. package/corpus/core/src/triggers/routes.ts +19 -6
  54. package/corpus/core/src/vitest-config.ts +68 -0
  55. package/corpus/core/vitest.config.ts +5 -0
  56. package/corpus/templates/analytics/app/pages/Settings.tsx +37 -53
  57. package/corpus/templates/analytics/changelog/2026-08-01-new-error-alerts-now-reach-you-by-email-and-a-scheduled-dash.md +6 -0
  58. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +43 -0
  59. package/corpus/templates/analytics/server/lib/error-capture.ts +5 -1
  60. package/corpus/templates/analytics/vitest.config.ts +16 -12
  61. package/corpus/templates/assets/actions/refresh-generation-run.ts +3 -0
  62. package/corpus/templates/assets/app/components/ui/switch.tsx +1 -0
  63. package/corpus/templates/assets/app/hooks/use-assets-prefs.ts +55 -0
  64. package/corpus/templates/assets/app/i18n-data.ts +30 -0
  65. package/corpus/templates/assets/app/routes/settings.tsx +58 -55
  66. package/corpus/templates/assets/changelog/2026-08-01-get-an-email-when-a-generation-you-started-finishes-or-fails.md +6 -0
  67. package/corpus/templates/assets/server/lib/generation-run-notifications.ts +89 -0
  68. package/corpus/templates/assets/server/lib/video-runs.ts +8 -1
  69. package/corpus/templates/assets/server/routes/_agent-native/assets/user-prefs.get.ts +17 -0
  70. package/corpus/templates/assets/server/routes/_agent-native/assets/user-prefs.put.ts +36 -0
  71. package/corpus/templates/assets/shared/assets-user-prefs.ts +10 -0
  72. package/corpus/templates/assets/vitest.config.ts +16 -12
  73. package/corpus/templates/brain/app/routes/settings.tsx +15 -15
  74. package/corpus/templates/brain/vitest.config.ts +16 -12
  75. package/corpus/templates/calendar/app/pages/Settings.tsx +32 -40
  76. package/corpus/templates/calendar/changelog/2026-08-01-language-and-appearance-now-sit-together-in-one-preferences-.md +6 -0
  77. package/corpus/templates/calendar/vitest.config.ts +16 -12
  78. package/corpus/templates/chat/app/routes/settings.tsx +14 -22
  79. package/corpus/templates/chat/vitest.config.ts +9 -0
  80. package/corpus/templates/clips/.agents/skills/video-editing/SKILL.md +31 -0
  81. package/corpus/templates/clips/AGENTS.md +1 -0
  82. package/corpus/templates/clips/actions/add-comment.ts +12 -1
  83. package/corpus/templates/clips/actions/create-meeting.ts +2 -2
  84. package/corpus/templates/clips/actions/create-recording.ts +2 -2
  85. package/corpus/templates/clips/actions/finalize-recording.ts +42 -6
  86. package/corpus/templates/clips/actions/generate-filmstrip.ts +154 -0
  87. package/corpus/templates/clips/actions/get-recording-player-data.ts +6 -0
  88. package/corpus/templates/clips/actions/import-loom-recording.ts +2 -2
  89. package/corpus/templates/clips/actions/lib/ensure-recording-filmstrip.ts +258 -0
  90. package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +11 -3
  91. package/corpus/templates/clips/actions/react-to-comment.ts +13 -0
  92. package/corpus/templates/clips/actions/react-to-recording.ts +10 -1
  93. package/corpus/templates/clips/actions/reply-to-comment.ts +12 -1
  94. package/corpus/templates/clips/actions/stitch-recordings.ts +2 -2
  95. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +152 -23
  96. package/corpus/templates/clips/app/components/editor/waveform.tsx +237 -75
  97. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +23 -1
  98. package/corpus/templates/clips/app/components/settings/ai-setup-section.tsx +441 -0
  99. package/corpus/templates/clips/app/components/settings/slack-section.tsx +329 -0
  100. package/corpus/templates/clips/app/components/settings/types.ts +14 -0
  101. package/corpus/templates/clips/app/components/settings/video-storage-section.tsx +443 -0
  102. package/corpus/templates/clips/app/hooks/use-secret-status.ts +69 -0
  103. package/corpus/templates/clips/app/i18n/en-US.ts +9 -1
  104. package/corpus/templates/clips/app/lib/video-filmstrip.ts +262 -0
  105. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +165 -1351
  106. package/corpus/templates/clips/changelog/2026-07-27-saved-clips-now-resume-from-the-last-uploaded-byte-after-an-.md +6 -0
  107. package/corpus/templates/clips/changelog/2026-07-31-editor-timeline-now-shows-video-frames-behind-the-waveform-g.md +6 -0
  108. package/corpus/templates/clips/changelog/2026-07-31-email-notifications-now-go-out-when-someone-comments-on-or-r.md +6 -0
  109. package/corpus/templates/clips/changelog/2026-07-31-you-can-now-set-a-default-visibility-for-new-recordings-in-s.md +6 -0
  110. package/corpus/templates/clips/changelog/2026-08-01-email-notifications-for-comments-and-reactions-now-actually-.md +6 -0
  111. package/corpus/templates/clips/changelog/2026-08-03-the-desktop-app-now-opens-directly-beneath-its-tray-icon-on-.md +6 -0
  112. package/corpus/templates/clips/chrome-extension/package.json +1 -0
  113. package/corpus/templates/clips/chrome-extension/vitest.config.ts +9 -0
  114. package/corpus/templates/clips/desktop/package.json +1 -0
  115. package/corpus/templates/clips/desktop/src/app.tsx +17 -1
  116. package/corpus/templates/clips/desktop/src/lib/recorder.ts +331 -36
  117. package/corpus/templates/clips/desktop/src/lib/upload-recovery.ts +129 -0
  118. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +815 -15
  119. package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +61 -11
  120. package/corpus/templates/clips/desktop/vitest.config.ts +9 -0
  121. package/corpus/templates/clips/server/db/schema.ts +17 -0
  122. package/corpus/templates/clips/server/jobs/media-verification.ts +4 -0
  123. package/corpus/templates/clips/server/lib/activity-notifications.ts +185 -0
  124. package/corpus/templates/clips/server/lib/recording-media-cleanup.ts +2 -0
  125. package/corpus/templates/clips/server/lib/recording-upload-state.ts +46 -9
  126. package/corpus/templates/clips/server/lib/recordings.ts +24 -0
  127. package/corpus/templates/clips/server/lib/resumable-session.ts +10 -4
  128. package/corpus/templates/clips/server/lib/transactional-email-templates.ts +109 -0
  129. package/corpus/templates/clips/server/lib/upload-interruption.ts +8 -0
  130. package/corpus/templates/clips/server/lib/upload-lease.ts +50 -4
  131. package/corpus/templates/clips/server/lib/video-filmstrip-sprite.ts +207 -0
  132. package/corpus/templates/clips/server/lib/video-remux.ts +13 -4
  133. package/corpus/templates/clips/server/plugins/db.ts +16 -0
  134. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +4 -0
  135. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +123 -36
  136. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +159 -29
  137. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/interrupt.post.ts +197 -0
  138. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/reset-chunks.post.ts +193 -39
  139. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/resume.get.ts +191 -12
  140. package/corpus/templates/clips/shared/clips-ai-prefs.ts +6 -0
  141. package/corpus/templates/clips/shared/feature-flags.ts +12 -0
  142. package/corpus/templates/clips/shared/recording-core.ts +4 -0
  143. package/corpus/templates/clips/vitest.config.ts +23 -19
  144. package/corpus/templates/content/actions/add-comment.ts +15 -1
  145. package/corpus/templates/content/actions/list-documents.ts +1 -0
  146. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +5 -2
  147. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +50 -1
  148. package/corpus/templates/content/app/components/ui/switch.tsx +1 -0
  149. package/corpus/templates/content/app/hooks/use-content-prefs.ts +55 -0
  150. package/corpus/templates/content/app/i18n-data.ts +40 -0
  151. package/corpus/templates/content/app/routes/_app.settings.tsx +47 -18
  152. package/corpus/templates/content/changelog/2026-07-30-breadcrumb-menus-now-hide-internal-system-pages.md +6 -0
  153. package/corpus/templates/content/changelog/2026-08-01-get-an-email-when-someone-comments-on-replies-in-or-mentions.md +6 -0
  154. package/corpus/templates/content/server/lib/comment-notifications.ts +146 -0
  155. package/corpus/templates/content/server/routes/_agent-native/content/user-prefs.get.ts +17 -0
  156. package/corpus/templates/content/server/routes/_agent-native/content/user-prefs.put.ts +36 -0
  157. package/corpus/templates/content/shared/content-user-prefs.ts +11 -0
  158. package/corpus/templates/content/vitest.config.ts +20 -16
  159. package/corpus/templates/crm/app/routes/settings.tsx +14 -22
  160. package/corpus/templates/crm/vitest.config.ts +8 -4
  161. package/corpus/templates/design/app/routes/settings.tsx +14 -22
  162. package/corpus/templates/design/changelog/2026-08-01-review-comments-replies-and-mentions-now-send-an-email-to-th.md +6 -0
  163. package/corpus/templates/design/vitest.config.ts +18 -12
  164. package/corpus/templates/dispatch/app/routes/settings.tsx +26 -40
  165. package/corpus/templates/dispatch/vitest.config.ts +11 -7
  166. package/corpus/templates/factory/app/routes/settings.tsx +14 -22
  167. package/corpus/templates/factory/vitest.config.ts +9 -0
  168. package/corpus/templates/forms/app/routes/_app.settings.tsx +14 -22
  169. package/corpus/templates/forms/vitest.config.ts +27 -23
  170. package/corpus/templates/macros/app/routes/settings.tsx +14 -22
  171. package/corpus/templates/macros/vitest.config.ts +16 -12
  172. package/corpus/templates/mail/app/pages/SettingsPage.tsx +14 -16
  173. package/corpus/templates/mail/vitest.config.ts +16 -12
  174. package/corpus/templates/plan/app/routes/settings.tsx +30 -44
  175. package/corpus/templates/plan/vitest.config.ts +24 -20
  176. package/corpus/templates/slides/actions/add-slide-comment.ts +12 -1
  177. package/corpus/templates/slides/app/components/ui/switch.tsx +1 -0
  178. package/corpus/templates/slides/app/hooks/use-slides-prefs.ts +55 -0
  179. package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
  180. package/corpus/templates/slides/app/routes/settings.tsx +45 -22
  181. package/corpus/templates/slides/changelog/2026-08-01-get-an-email-when-someone-comments-on-or-replies-in-your-dec.md +6 -0
  182. package/corpus/templates/slides/server/lib/comment-notifications.ts +182 -0
  183. package/corpus/templates/slides/server/routes/_agent-native/slides/user-prefs.get.ts +16 -0
  184. package/corpus/templates/slides/server/routes/_agent-native/slides/user-prefs.put.ts +36 -0
  185. package/corpus/templates/slides/shared/slides-user-prefs.ts +11 -0
  186. package/corpus/templates/slides/vitest.config.ts +17 -13
  187. package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +2 -0
  188. package/corpus/templates/tasks/app/routes/settings.tsx +14 -22
  189. package/corpus/templates/tasks/vitest.config.ts +17 -13
  190. package/corpus/toolkit/CHANGELOG.md +9 -0
  191. package/corpus/toolkit/package.json +1 -1
  192. package/corpus/toolkit/vitest.config.ts +3 -0
  193. package/dist/automations/service.d.ts +2 -0
  194. package/dist/automations/service.d.ts.map +1 -1
  195. package/dist/automations/service.js +29 -4
  196. package/dist/automations/service.js.map +1 -1
  197. package/dist/cli/mcp-config-writers.d.ts.map +1 -1
  198. package/dist/cli/mcp-config-writers.js +24 -23
  199. package/dist/cli/mcp-config-writers.js.map +1 -1
  200. package/dist/client/agent-page/AgentJobsTab.d.ts.map +1 -1
  201. package/dist/client/agent-page/AgentJobsTab.js +86 -29
  202. package/dist/client/agent-page/AgentJobsTab.js.map +1 -1
  203. package/dist/client/agent-page/AutomationDetailsDialog.d.ts +21 -0
  204. package/dist/client/agent-page/AutomationDetailsDialog.d.ts.map +1 -0
  205. package/dist/client/agent-page/AutomationDetailsDialog.js +33 -0
  206. package/dist/client/agent-page/AutomationDetailsDialog.js.map +1 -0
  207. package/dist/client/agent-page/AutomationScheduleDialog.d.ts +15 -0
  208. package/dist/client/agent-page/AutomationScheduleDialog.d.ts.map +1 -0
  209. package/dist/client/agent-page/AutomationScheduleDialog.js +46 -0
  210. package/dist/client/agent-page/AutomationScheduleDialog.js.map +1 -0
  211. package/dist/client/agent-page/TimezoneSelect.d.ts +17 -0
  212. package/dist/client/agent-page/TimezoneSelect.d.ts.map +1 -0
  213. package/dist/client/agent-page/TimezoneSelect.js +107 -0
  214. package/dist/client/agent-page/TimezoneSelect.js.map +1 -0
  215. package/dist/client/agent-page/use-jobs.d.ts +20 -7
  216. package/dist/client/agent-page/use-jobs.d.ts.map +1 -1
  217. package/dist/client/agent-page/use-jobs.js +24 -4
  218. package/dist/client/agent-page/use-jobs.js.map +1 -1
  219. package/dist/client/org/OrgSwitcher.d.ts +8 -1
  220. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  221. package/dist/client/org/OrgSwitcher.js +8 -2
  222. package/dist/client/org/OrgSwitcher.js.map +1 -1
  223. package/dist/client/settings/AccountSettingsCard.d.ts.map +1 -1
  224. package/dist/client/settings/AccountSettingsCard.js +10 -9
  225. package/dist/client/settings/AccountSettingsCard.js.map +1 -1
  226. package/dist/client/settings/SchedulingTimezoneField.d.ts +10 -0
  227. package/dist/client/settings/SchedulingTimezoneField.d.ts.map +1 -0
  228. package/dist/client/settings/SchedulingTimezoneField.js +30 -0
  229. package/dist/client/settings/SchedulingTimezoneField.js.map +1 -0
  230. package/dist/client/settings/SettingsRow.d.ts +36 -0
  231. package/dist/client/settings/SettingsRow.d.ts.map +1 -0
  232. package/dist/client/settings/SettingsRow.js +15 -0
  233. package/dist/client/settings/SettingsRow.js.map +1 -0
  234. package/dist/client/settings/agent-settings-search.d.ts.map +1 -1
  235. package/dist/client/settings/agent-settings-search.js +1 -1
  236. package/dist/client/settings/agent-settings-search.js.map +1 -1
  237. package/dist/client/settings/index.d.ts +1 -0
  238. package/dist/client/settings/index.d.ts.map +1 -1
  239. package/dist/client/settings/index.js +1 -0
  240. package/dist/client/settings/index.js.map +1 -1
  241. package/dist/collab/struct-routes.d.ts +1 -1
  242. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  243. package/dist/integrations/identity.d.ts.map +1 -1
  244. package/dist/integrations/identity.js +2 -11
  245. package/dist/integrations/identity.js.map +1 -1
  246. package/dist/jobs/actions/list-automation-runs.d.ts +8 -0
  247. package/dist/jobs/actions/list-automation-runs.d.ts.map +1 -0
  248. package/dist/jobs/actions/list-automation-runs.js +29 -0
  249. package/dist/jobs/actions/list-automation-runs.js.map +1 -0
  250. package/dist/jobs/actions/list-recurring-jobs.d.ts +2 -0
  251. package/dist/jobs/actions/list-recurring-jobs.d.ts.map +1 -1
  252. package/dist/jobs/actions/list-recurring-jobs.js +20 -7
  253. package/dist/jobs/actions/list-recurring-jobs.js.map +1 -1
  254. package/dist/jobs/actions/manage-recurring-job.d.ts +2 -0
  255. package/dist/jobs/actions/manage-recurring-job.js +30 -9
  256. package/dist/jobs/actions/manage-recurring-job.js.map +1 -1
  257. package/dist/jobs/background-automation-runner.d.ts.map +1 -1
  258. package/dist/jobs/background-automation-runner.js +60 -0
  259. package/dist/jobs/background-automation-runner.js.map +1 -1
  260. package/dist/jobs/cron.d.ts +16 -2
  261. package/dist/jobs/cron.d.ts.map +1 -1
  262. package/dist/jobs/cron.js +43 -6
  263. package/dist/jobs/cron.js.map +1 -1
  264. package/dist/jobs/frontmatter.d.ts +12 -0
  265. package/dist/jobs/frontmatter.d.ts.map +1 -1
  266. package/dist/jobs/frontmatter.js +8 -0
  267. package/dist/jobs/frontmatter.js.map +1 -1
  268. package/dist/jobs/run-history.d.ts +56 -0
  269. package/dist/jobs/run-history.d.ts.map +1 -0
  270. package/dist/jobs/run-history.js +169 -0
  271. package/dist/jobs/run-history.js.map +1 -0
  272. package/dist/jobs/scheduler.d.ts.map +1 -1
  273. package/dist/jobs/scheduler.js +51 -18
  274. package/dist/jobs/scheduler.js.map +1 -1
  275. package/dist/jobs/tools.d.ts.map +1 -1
  276. package/dist/jobs/tools.js +37 -6
  277. package/dist/jobs/tools.js.map +1 -1
  278. package/dist/localization/actions/get-localization-preference.d.ts +1 -2
  279. package/dist/localization/actions/get-localization-preference.d.ts.map +1 -1
  280. package/dist/localization/actions/get-localization-preference.js.map +1 -1
  281. package/dist/localization/actions/set-localization-preference.d.ts +3 -3
  282. package/dist/localization/actions/set-localization-preference.d.ts.map +1 -1
  283. package/dist/localization/actions/set-localization-preference.js +33 -8
  284. package/dist/localization/actions/set-localization-preference.js.map +1 -1
  285. package/dist/localization/default-messages.d.ts +25 -0
  286. package/dist/localization/default-messages.d.ts.map +1 -1
  287. package/dist/localization/default-messages.js +25 -0
  288. package/dist/localization/default-messages.js.map +1 -1
  289. package/dist/localization/shared.d.ts +16 -1
  290. package/dist/localization/shared.d.ts.map +1 -1
  291. package/dist/localization/shared.js +22 -4
  292. package/dist/localization/shared.js.map +1 -1
  293. package/dist/localization/user-timezone.d.ts +11 -0
  294. package/dist/localization/user-timezone.d.ts.map +1 -0
  295. package/dist/localization/user-timezone.js +31 -0
  296. package/dist/localization/user-timezone.js.map +1 -0
  297. package/dist/notifications/routes.d.ts +1 -1
  298. package/dist/observability/routes.d.ts +1 -1
  299. package/dist/org/app-roles-handlers.d.ts.map +1 -1
  300. package/dist/org/app-roles-handlers.js +1 -8
  301. package/dist/org/app-roles-handlers.js.map +1 -1
  302. package/dist/org/index.d.ts +1 -0
  303. package/dist/org/index.d.ts.map +1 -1
  304. package/dist/org/index.js +1 -0
  305. package/dist/org/index.js.map +1 -1
  306. package/dist/org/membership.d.ts +6 -0
  307. package/dist/org/membership.d.ts.map +1 -0
  308. package/dist/org/membership.js +16 -0
  309. package/dist/org/membership.js.map +1 -0
  310. package/dist/provider-api/actions/custom-provider-registration.d.ts +10 -10
  311. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  312. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  313. package/dist/resources/handlers.d.ts +1 -1
  314. package/dist/review/actions/create-review-comment.d.ts +32 -1
  315. package/dist/review/actions/create-review-comment.d.ts.map +1 -1
  316. package/dist/review/actions/create-review-comment.js +3 -1
  317. package/dist/review/actions/create-review-comment.js.map +1 -1
  318. package/dist/review/actions/reply-review-comment.d.ts +32 -1
  319. package/dist/review/actions/reply-review-comment.d.ts.map +1 -1
  320. package/dist/review/actions/reply-review-comment.js +3 -1
  321. package/dist/review/actions/reply-review-comment.js.map +1 -1
  322. package/dist/review/index.d.ts +1 -0
  323. package/dist/review/index.d.ts.map +1 -1
  324. package/dist/review/index.js +1 -0
  325. package/dist/review/index.js.map +1 -1
  326. package/dist/review/notifications.d.ts +24 -0
  327. package/dist/review/notifications.d.ts.map +1 -0
  328. package/dist/review/notifications.js +123 -0
  329. package/dist/review/notifications.js.map +1 -0
  330. package/dist/review/types.d.ts +5 -0
  331. package/dist/review/types.d.ts.map +1 -1
  332. package/dist/review/types.js.map +1 -1
  333. package/dist/server/action-discovery.d.ts.map +1 -1
  334. package/dist/server/action-discovery.js +4 -0
  335. package/dist/server/action-discovery.js.map +1 -1
  336. package/dist/server/activity-notifications.d.ts +61 -0
  337. package/dist/server/activity-notifications.d.ts.map +1 -0
  338. package/dist/server/activity-notifications.js +103 -0
  339. package/dist/server/activity-notifications.js.map +1 -0
  340. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  341. package/dist/server/app-name.d.ts +18 -0
  342. package/dist/server/app-name.d.ts.map +1 -1
  343. package/dist/server/app-name.js +31 -0
  344. package/dist/server/app-name.js.map +1 -1
  345. package/dist/server/better-auth-instance.js +4 -4
  346. package/dist/server/better-auth-instance.js.map +1 -1
  347. package/dist/server/email-templates.d.ts +12 -0
  348. package/dist/server/email-templates.d.ts.map +1 -1
  349. package/dist/server/email-templates.js +57 -14
  350. package/dist/server/email-templates.js.map +1 -1
  351. package/dist/server/email.d.ts +12 -0
  352. package/dist/server/email.d.ts.map +1 -1
  353. package/dist/server/email.js +52 -5
  354. package/dist/server/email.js.map +1 -1
  355. package/dist/server/index.d.ts +1 -0
  356. package/dist/server/index.d.ts.map +1 -1
  357. package/dist/server/index.js +1 -0
  358. package/dist/server/index.js.map +1 -1
  359. package/dist/sharing/index.d.ts +1 -0
  360. package/dist/sharing/index.d.ts.map +1 -1
  361. package/dist/sharing/index.js +1 -0
  362. package/dist/sharing/index.js.map +1 -1
  363. package/dist/sharing/recipients.d.ts +31 -0
  364. package/dist/sharing/recipients.d.ts.map +1 -0
  365. package/dist/sharing/recipients.js +40 -0
  366. package/dist/sharing/recipients.js.map +1 -0
  367. package/dist/templates/chat/app/routes/settings.tsx +14 -22
  368. package/dist/templates/chat/vitest.config.ts +9 -0
  369. package/dist/triggers/actions/list-automations.d.ts +2 -0
  370. package/dist/triggers/actions/list-automations.d.ts.map +1 -1
  371. package/dist/triggers/actions/list-automations.js +19 -8
  372. package/dist/triggers/actions/list-automations.js.map +1 -1
  373. package/dist/triggers/actions/manage-automation.d.ts +6 -0
  374. package/dist/triggers/actions/manage-automation.js +12 -6
  375. package/dist/triggers/actions/manage-automation.js.map +1 -1
  376. package/dist/triggers/actions.d.ts.map +1 -1
  377. package/dist/triggers/actions.js +15 -4
  378. package/dist/triggers/actions.js.map +1 -1
  379. package/dist/triggers/dispatcher.d.ts.map +1 -1
  380. package/dist/triggers/dispatcher.js +19 -17
  381. package/dist/triggers/dispatcher.js.map +1 -1
  382. package/dist/triggers/routes.d.ts.map +1 -1
  383. package/dist/triggers/routes.js +6 -6
  384. package/dist/triggers/routes.js.map +1 -1
  385. package/dist/vitest-config.d.ts +10 -0
  386. package/dist/vitest-config.d.ts.map +1 -0
  387. package/dist/vitest-config.js +55 -0
  388. package/dist/vitest-config.js.map +1 -0
  389. package/package.json +5 -4
  390. package/src/automations/service.ts +41 -4
  391. package/src/cli/mcp-config-writers.ts +27 -21
  392. package/src/client/agent-page/AgentJobsTab.tsx +187 -85
  393. package/src/client/agent-page/AutomationDetailsDialog.tsx +208 -0
  394. package/src/client/agent-page/AutomationScheduleDialog.tsx +180 -0
  395. package/src/client/agent-page/TimezoneSelect.tsx +241 -0
  396. package/src/client/agent-page/use-jobs.ts +50 -10
  397. package/src/client/org/OrgSwitcher.tsx +26 -0
  398. package/src/client/settings/AccountSettingsCard.tsx +35 -31
  399. package/src/client/settings/SchedulingTimezoneField.tsx +71 -0
  400. package/src/client/settings/SettingsRow.tsx +113 -0
  401. package/src/client/settings/agent-settings-search.ts +2 -1
  402. package/src/client/settings/index.ts +6 -0
  403. package/src/integrations/identity.ts +2 -12
  404. package/src/jobs/actions/list-automation-runs.ts +33 -0
  405. package/src/jobs/actions/list-recurring-jobs.ts +27 -6
  406. package/src/jobs/actions/manage-recurring-job.ts +41 -9
  407. package/src/jobs/background-automation-runner.ts +88 -0
  408. package/src/jobs/cron.ts +52 -6
  409. package/src/jobs/frontmatter.ts +20 -0
  410. package/src/jobs/run-history.ts +242 -0
  411. package/src/jobs/scheduler.ts +73 -18
  412. package/src/jobs/tools.ts +54 -6
  413. package/src/localization/actions/get-localization-preference.ts +2 -2
  414. package/src/localization/actions/set-localization-preference.ts +49 -11
  415. package/src/localization/default-messages.ts +27 -0
  416. package/src/localization/shared.ts +39 -6
  417. package/src/localization/user-timezone.ts +36 -0
  418. package/src/org/app-roles-handlers.ts +1 -9
  419. package/src/org/index.ts +2 -0
  420. package/src/org/membership.ts +18 -0
  421. package/src/review/actions/create-review-comment.ts +4 -1
  422. package/src/review/actions/reply-review-comment.ts +4 -1
  423. package/src/review/index.ts +5 -0
  424. package/src/review/notifications.ts +163 -0
  425. package/src/review/types.ts +7 -0
  426. package/src/server/action-discovery.ts +4 -0
  427. package/src/server/activity-notifications.ts +174 -0
  428. package/src/server/app-name.ts +31 -0
  429. package/src/server/better-auth-instance.ts +4 -4
  430. package/src/server/email-templates.ts +70 -14
  431. package/src/server/email.ts +66 -3
  432. package/src/server/index.ts +10 -0
  433. package/src/sharing/index.ts +5 -0
  434. package/src/sharing/recipients.ts +67 -0
  435. package/src/templates/chat/app/routes/settings.tsx +14 -22
  436. package/src/templates/chat/vitest.config.ts +9 -0
  437. package/src/triggers/actions/list-automations.ts +27 -8
  438. package/src/triggers/actions/manage-automation.ts +17 -6
  439. package/src/triggers/actions.ts +16 -4
  440. package/src/triggers/dispatcher.ts +44 -30
  441. package/src/triggers/routes.ts +19 -6
  442. package/src/vitest-config.ts +68 -0
@@ -0,0 +1,180 @@
1
+ import { Button } from "@agent-native/toolkit/ui/button";
2
+ import { Input } from "@agent-native/toolkit/ui/input";
3
+ import { IconLoader2 } from "@tabler/icons-react";
4
+ import { useEffect, useState } from "react";
5
+
6
+ import {
7
+ Dialog,
8
+ DialogContent,
9
+ DialogDescription,
10
+ DialogFooter,
11
+ DialogHeader,
12
+ DialogTitle,
13
+ } from "../components/ui/dialog.js";
14
+ import { useT } from "../i18n.js";
15
+ import { TimezoneSelect, browserTimezone } from "./TimezoneSelect.js";
16
+
17
+ const PRESETS: { label: string; cron: string }[] = [
18
+ { label: "Every hour", cron: "0 * * * *" },
19
+ { label: "Every day at 8:00", cron: "0 8 * * *" },
20
+ { label: "Every weekday at 9:00", cron: "0 9 * * 1-5" },
21
+ { label: "Every Monday at 8:00", cron: "0 8 * * 1" },
22
+ ];
23
+
24
+ const CRON_FIELD_COUNT = 5;
25
+
26
+ function looksLikeCron(value: string): boolean {
27
+ return value.trim().split(/\s+/).length === CRON_FIELD_COUNT;
28
+ }
29
+
30
+ export interface AutomationScheduleDialogProps {
31
+ open: boolean;
32
+ name: string;
33
+ schedule: string;
34
+ timezone: string | null;
35
+ saving: boolean;
36
+ error?: string | null;
37
+ onCancel: () => void;
38
+ onSave: (next: { schedule: string; timezone: string }) => void;
39
+ }
40
+
41
+ export function AutomationScheduleDialog({
42
+ open,
43
+ name,
44
+ schedule,
45
+ timezone,
46
+ saving,
47
+ error,
48
+ onCancel,
49
+ onSave,
50
+ }: AutomationScheduleDialogProps) {
51
+ const t = useT();
52
+ const [value, setValue] = useState(schedule);
53
+ const [zone, setZone] = useState(timezone || browserTimezone());
54
+
55
+ useEffect(() => {
56
+ if (!open) return;
57
+ setValue(schedule);
58
+ setZone(timezone || browserTimezone());
59
+ }, [open, schedule, timezone]);
60
+
61
+ const trimmed = value.trim();
62
+ const valid = looksLikeCron(trimmed);
63
+ const changed =
64
+ trimmed !== schedule.trim() || zone !== (timezone || browserTimezone());
65
+
66
+ return (
67
+ <Dialog
68
+ open={open}
69
+ onOpenChange={(next) => {
70
+ if (!next && !saving) onCancel();
71
+ }}
72
+ >
73
+ <DialogContent>
74
+ <DialogHeader>
75
+ <DialogTitle>
76
+ {t("jobs.editScheduleTitle", {
77
+ defaultValue: "Edit schedule — {{name}}",
78
+ name: name.replace(/-/g, " "),
79
+ })}
80
+ </DialogTitle>
81
+ <DialogDescription>
82
+ {t("jobs.editScheduleDescription", {
83
+ defaultValue:
84
+ "The clock time below is read in the timezone you pick, so 8:00 means 8:00 there.",
85
+ })}
86
+ </DialogDescription>
87
+ </DialogHeader>
88
+
89
+ <div className="space-y-3">
90
+ <div>
91
+ <label
92
+ className="text-xs font-medium text-foreground"
93
+ htmlFor="automation-schedule"
94
+ >
95
+ {t("jobs.cronExpression", { defaultValue: "Cron expression" })}
96
+ </label>
97
+ <Input
98
+ id="automation-schedule"
99
+ className="mt-1 font-mono text-sm"
100
+ value={value}
101
+ spellCheck={false}
102
+ autoComplete="off"
103
+ disabled={saving}
104
+ onChange={(event) => setValue(event.target.value)}
105
+ />
106
+ <p className="mt-1 text-[11px] text-muted-foreground">
107
+ {t("jobs.cronFormatHint", {
108
+ defaultValue: "minute hour day-of-month month day-of-week",
109
+ })}
110
+ </p>
111
+ </div>
112
+
113
+ <div className="flex flex-wrap gap-1.5">
114
+ {PRESETS.map((preset) => (
115
+ <Button
116
+ key={preset.cron}
117
+ type="button"
118
+ variant="outline"
119
+ size="sm"
120
+ className="h-7 cursor-pointer text-[11px]"
121
+ disabled={saving}
122
+ onClick={() => setValue(preset.cron)}
123
+ >
124
+ {preset.label}
125
+ </Button>
126
+ ))}
127
+ </div>
128
+
129
+ <div>
130
+ <label
131
+ className="text-xs font-medium text-foreground"
132
+ htmlFor="automation-timezone"
133
+ >
134
+ {t("jobs.timezone", { defaultValue: "Timezone" })}
135
+ </label>
136
+ <div className="mt-1">
137
+ <TimezoneSelect
138
+ id="automation-timezone"
139
+ value={zone}
140
+ disabled={saving}
141
+ onChange={setZone}
142
+ suggested={[browserTimezone()]}
143
+ />
144
+ </div>
145
+ </div>
146
+
147
+ {trimmed && !valid ? (
148
+ <p className="text-xs text-destructive">
149
+ {t("jobs.cronFieldCount", {
150
+ defaultValue: "A cron expression needs exactly 5 fields.",
151
+ })}
152
+ </p>
153
+ ) : null}
154
+ {error ? <p className="text-xs text-destructive">{error}</p> : null}
155
+ </div>
156
+
157
+ <DialogFooter>
158
+ <Button
159
+ type="button"
160
+ variant="outline"
161
+ className="cursor-pointer"
162
+ disabled={saving}
163
+ onClick={onCancel}
164
+ >
165
+ {t("jobs.cancel", { defaultValue: "Cancel" })}
166
+ </Button>
167
+ <Button
168
+ type="button"
169
+ className="cursor-pointer"
170
+ disabled={saving || !valid || !changed}
171
+ onClick={() => onSave({ schedule: trimmed, timezone: zone })}
172
+ >
173
+ {saving ? <IconLoader2 className="size-4 animate-spin" /> : null}
174
+ {t("jobs.saveSchedule", { defaultValue: "Save schedule" })}
175
+ </Button>
176
+ </DialogFooter>
177
+ </DialogContent>
178
+ </Dialog>
179
+ );
180
+ }
@@ -0,0 +1,241 @@
1
+ import {
2
+ Command,
3
+ CommandEmpty,
4
+ CommandGroup,
5
+ CommandInput,
6
+ CommandItem,
7
+ CommandList,
8
+ CommandSeparator,
9
+ } from "@agent-native/toolkit/ui/command";
10
+ import {
11
+ Popover,
12
+ PopoverContent,
13
+ PopoverTrigger,
14
+ } from "@agent-native/toolkit/ui/popover";
15
+ import { IconCheck, IconChevronDown } from "@tabler/icons-react";
16
+ import { useMemo, useState } from "react";
17
+
18
+ const SYSTEM_VALUE = "system";
19
+
20
+ /** The browser's IANA zone, or UTC when the runtime cannot report one. */
21
+ export function browserTimezone(): string {
22
+ try {
23
+ return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
24
+ } catch {
25
+ return "UTC";
26
+ }
27
+ }
28
+
29
+ function supportedTimezones(): string[] {
30
+ const supported = (
31
+ Intl as unknown as { supportedValuesOf?: (key: string) => string[] }
32
+ ).supportedValuesOf;
33
+ const zones = supported ? supported("timeZone") : [];
34
+ // Older runtimes omit supportedValuesOf; the browser zone plus UTC still
35
+ // covers the common case rather than leaving an empty, unusable menu.
36
+ const base = zones.length ? zones : [browserTimezone()];
37
+ return [...new Set(["UTC", ...base])];
38
+ }
39
+
40
+ interface ZoneOption {
41
+ zone: string;
42
+ /** Minutes east of GMT, used to order the list the way a map reads. */
43
+ offsetMinutes: number;
44
+ offsetLabel: string;
45
+ timeLabel: string;
46
+ placeLabel: string;
47
+ }
48
+
49
+ function describeZone(zone: string, now: Date): ZoneOption | null {
50
+ let parts: Intl.DateTimeFormatPart[];
51
+ try {
52
+ parts = new Intl.DateTimeFormat("en-US", {
53
+ timeZone: zone,
54
+ hour: "numeric",
55
+ minute: "2-digit",
56
+ hour12: true,
57
+ timeZoneName: "longOffset",
58
+ }).formatToParts(now);
59
+ } catch {
60
+ // A zone this runtime cannot resolve would otherwise throw during render.
61
+ return null;
62
+ }
63
+
64
+ const part = (type: Intl.DateTimeFormatPartTypes) =>
65
+ parts.find((p) => p.type === type)?.value ?? "";
66
+
67
+ // `longOffset` collapses to a bare "GMT" at zero rather than "GMT+00:00".
68
+ const raw = part("timeZoneName");
69
+ const offsetLabel = raw === "GMT" ? "GMT+00:00" : raw;
70
+ const match = /^GMT([+-])(\d{2}):(\d{2})$/.exec(offsetLabel);
71
+ const offsetMinutes = match
72
+ ? (match[1] === "-" ? -1 : 1) * (Number(match[2]) * 60 + Number(match[3]))
73
+ : 0;
74
+
75
+ return {
76
+ zone,
77
+ offsetMinutes,
78
+ offsetLabel,
79
+ timeLabel: `${part("hour")}:${part("minute")}${part("dayPeriod").toLowerCase()}`,
80
+ placeLabel: zone.replace(/_/g, " "),
81
+ };
82
+ }
83
+
84
+ function zoneOptions(extra: string[], now: Date): ZoneOption[] {
85
+ const zones = [...new Set([...extra, ...supportedTimezones()])];
86
+ return zones
87
+ .map((zone) => describeZone(zone, now))
88
+ .filter((option): option is ZoneOption => option !== null)
89
+ .sort(
90
+ (a, b) =>
91
+ a.offsetMinutes - b.offsetMinutes ||
92
+ a.placeLabel.localeCompare(b.placeLabel),
93
+ );
94
+ }
95
+
96
+ export interface TimezoneSelectProps {
97
+ value: string;
98
+ disabled?: boolean;
99
+ onChange: (timezone: string) => void;
100
+ /** Zones to surface above the full list, e.g. the currently stored one. */
101
+ suggested?: string[];
102
+ /**
103
+ * Label for a leading `system` choice. Settings offer it so the preference
104
+ * stays revertible; a schedule must name a concrete zone and omits it.
105
+ */
106
+ systemLabel?: string;
107
+ id?: string;
108
+ }
109
+
110
+ export function TimezoneSelect({
111
+ value,
112
+ disabled,
113
+ onChange,
114
+ suggested = [],
115
+ systemLabel,
116
+ id,
117
+ }: TimezoneSelectProps) {
118
+ const [open, setOpen] = useState(false);
119
+ const detected = browserTimezone();
120
+
121
+ // 418 zones each need their own formatter, so only pay for that once the
122
+ // list is actually on screen. Reopening re-reads the clock.
123
+ const options = useMemo(() => {
124
+ if (!open) return [];
125
+ const pinned = [...suggested, value].filter(
126
+ (zone) => zone && zone !== SYSTEM_VALUE,
127
+ );
128
+ return zoneOptions(pinned, new Date());
129
+ }, [open, suggested, value]);
130
+
131
+ const selected = useMemo(
132
+ () => (value === SYSTEM_VALUE ? null : describeZone(value, new Date())),
133
+ [value],
134
+ );
135
+
136
+ const triggerLabel =
137
+ value === SYSTEM_VALUE
138
+ ? (systemLabel ?? SYSTEM_VALUE)
139
+ : selected
140
+ ? `(${selected.offsetLabel}) ${selected.placeLabel}`
141
+ : value;
142
+
143
+ function choose(zone: string) {
144
+ setOpen(false);
145
+ if (zone !== value) onChange(zone);
146
+ }
147
+
148
+ function renderZone(option: ZoneOption, key: string) {
149
+ return (
150
+ <CommandItem
151
+ key={key}
152
+ // Searched text: place and offset both need to match what users type.
153
+ // The key is folded in because the detected zone is listed twice, and
154
+ // cmdk treats two items with the same value as the same item.
155
+ value={`${option.placeLabel} ${option.offsetLabel} ${option.zone} ${key}`}
156
+ onSelect={() => choose(option.zone)}
157
+ className="gap-2"
158
+ >
159
+ <IconCheck
160
+ className={`size-4 shrink-0 ${
161
+ option.zone === value ? "opacity-100" : "opacity-0"
162
+ }`}
163
+ />
164
+ <span className="w-24 shrink-0 tabular-nums text-muted-foreground">
165
+ ({option.offsetLabel})
166
+ </span>
167
+ <span className="truncate">{option.placeLabel}</span>
168
+ <span className="ms-auto shrink-0 tabular-nums text-muted-foreground">
169
+ {option.timeLabel}
170
+ </span>
171
+ </CommandItem>
172
+ );
173
+ }
174
+
175
+ const detectedOption = options.find((option) => option.zone === detected);
176
+
177
+ return (
178
+ <Popover open={open} onOpenChange={setOpen}>
179
+ <PopoverTrigger asChild>
180
+ <button
181
+ id={id}
182
+ type="button"
183
+ role="combobox"
184
+ aria-expanded={open}
185
+ disabled={disabled}
186
+ // Matches the text inputs it sits beside, not a button.
187
+ className="flex h-10 w-full items-center justify-between gap-2 rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
188
+ >
189
+ <span className="truncate">{triggerLabel}</span>
190
+ <IconChevronDown className="size-4 shrink-0 opacity-50" />
191
+ </button>
192
+ </PopoverTrigger>
193
+ <PopoverContent
194
+ align="start"
195
+ className="w-[--radix-popover-trigger-width] p-0"
196
+ >
197
+ <Command
198
+ // cmdk's default scorer matches loose subsequences, so "Perth" would
199
+ // otherwise surface most of the list.
200
+ filter={(itemValue, search) =>
201
+ itemValue.toLowerCase().includes(search.toLowerCase().trim())
202
+ ? 1
203
+ : 0
204
+ }
205
+ >
206
+ <CommandInput placeholder="Search a city or region…" />
207
+ <CommandList className="max-h-72">
208
+ <CommandEmpty>No matching timezone.</CommandEmpty>
209
+ {systemLabel || detectedOption ? (
210
+ <>
211
+ <CommandGroup>
212
+ {systemLabel ? (
213
+ <CommandItem
214
+ value={`${systemLabel} follow browser automatic`}
215
+ onSelect={() => choose(SYSTEM_VALUE)}
216
+ className="gap-2"
217
+ >
218
+ <IconCheck
219
+ className={`size-4 shrink-0 ${
220
+ value === SYSTEM_VALUE ? "opacity-100" : "opacity-0"
221
+ }`}
222
+ />
223
+ <span className="truncate">{systemLabel}</span>
224
+ </CommandItem>
225
+ ) : null}
226
+ {detectedOption
227
+ ? renderZone(detectedOption, "detected")
228
+ : null}
229
+ </CommandGroup>
230
+ <CommandSeparator />
231
+ </>
232
+ ) : null}
233
+ <CommandGroup>
234
+ {options.map((option) => renderZone(option, option.zone))}
235
+ </CommandGroup>
236
+ </CommandList>
237
+ </Command>
238
+ </PopoverContent>
239
+ </Popover>
240
+ );
241
+ }
@@ -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
  );