@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
@@ -3,6 +3,8 @@ import { LanguagePicker, useT } from "@agent-native/core/client/i18n";
3
3
  import { TeamPage } from "@agent-native/core/client/org";
4
4
  import {
5
5
  AccountSettingsCard,
6
+ SettingsGroup,
7
+ SettingsRow,
6
8
  SettingsTabsPage,
7
9
  useAgentSettingsTabs,
8
10
  type SettingsSearchEntry,
@@ -10,14 +12,6 @@ import {
10
12
  import { useSetPageTitle } from "@agent-native/toolkit/app-shell";
11
13
  import { useMemo } from "react";
12
14
 
13
- import {
14
- Card,
15
- CardContent,
16
- CardDescription,
17
- CardHeader,
18
- CardTitle,
19
- } from "@/components/ui/card";
20
- import { Label } from "@/components/ui/label";
21
15
  import { APP_TITLE } from "@/lib/app-config";
22
16
 
23
17
  import changelog from "../../CHANGELOG.md?raw";
@@ -55,20 +49,18 @@ export default function SettingsRoute() {
55
49
  {t("settings.description")}
56
50
  </p>
57
51
 
58
- <Card id="language" className="scroll-mt-16">
59
- <CardHeader>
60
- <CardTitle className="text-base">
61
- {t("settings.languageTitle")}
62
- </CardTitle>
63
- <CardDescription>
64
- {t("settings.languageDescription")}
65
- </CardDescription>
66
- </CardHeader>
67
- <CardContent className="max-w-xs space-y-1.5">
68
- <Label>{t("settings.languageLabel")}</Label>
69
- <LanguagePicker label={t("settings.languageLabel")} />
70
- </CardContent>
71
- </Card>
52
+ <SettingsGroup>
53
+ <SettingsRow
54
+ id="language"
55
+ label={t("settings.languageTitle")}
56
+ description={t("settings.languageDescription")}
57
+ control={
58
+ <div className="w-56">
59
+ <LanguagePicker label={t("settings.languageLabel")} />
60
+ </div>
61
+ }
62
+ />
63
+ </SettingsGroup>
72
64
  </div>
73
65
  }
74
66
  team={
@@ -0,0 +1,9 @@
1
+ import baseConfig from "@agent-native/core/vitest-config";
2
+ import { mergeConfig } from "vitest/config";
3
+
4
+ import viteConfig from "./vite.config";
5
+
6
+ // Kept separate from vite.config.ts so the production config never imports
7
+ // vitest: `agent-native build` loads vite.config.ts in installs where vitest
8
+ // is absent.
9
+ export default mergeConfig(viteConfig, baseConfig);
@@ -5,7 +5,12 @@ import {
5
5
  listAutomationDefinitions,
6
6
  type AutomationScope,
7
7
  } from "../../automations/service.js";
8
- import { describeCron, isValidCron, nextOccurrence } from "../../jobs/cron.js";
8
+ import {
9
+ describeCron,
10
+ effectiveTimezone,
11
+ isValidCron,
12
+ nextOccurrence,
13
+ } from "../../jobs/cron.js";
9
14
 
10
15
  const scopeSchema = z.enum(["personal", "organization"]);
11
16
 
@@ -13,15 +18,23 @@ function nextRun(
13
18
  meta: Awaited<ReturnType<typeof listAutomationDefinitions>>[number]["meta"],
14
19
  ): string | null {
15
20
  if (!meta.enabled) return null;
16
- if (meta.nextRun) return meta.nextRun;
17
- if (
21
+ const scheduled = Boolean(
18
22
  meta.triggerType === "schedule" &&
19
23
  meta.schedule &&
20
- isValidCron(meta.schedule)
21
- ) {
22
- return nextOccurrence(meta.schedule).toISOString();
24
+ isValidCron(meta.schedule),
25
+ );
26
+ // A stored `nextRun` in the past means the dispatcher kept declining to run
27
+ // this automation, not that it is overdue. Report the real next occurrence
28
+ // and let `lastError` carry the reason it keeps being passed over.
29
+ if (meta.nextRun) {
30
+ const stored = new Date(meta.nextRun).getTime();
31
+ if (!Number.isFinite(stored) || stored > Date.now() || !scheduled) {
32
+ return meta.nextRun;
33
+ }
23
34
  }
24
- return null;
35
+ return scheduled
36
+ ? nextOccurrence(meta.schedule!, undefined, meta.timezone).toISOString()
37
+ : null;
25
38
  }
26
39
 
27
40
  export interface AutomationActionItem {
@@ -32,11 +45,13 @@ export interface AutomationActionItem {
32
45
  triggerType: "event" | "schedule";
33
46
  event: string | null;
34
47
  schedule: string | null;
48
+ timezone: string | null;
35
49
  scheduleDescription: string | null;
36
50
  condition: string | null;
37
51
  body: string;
38
52
  enabled: boolean;
39
53
  lastRun: string | null;
54
+ lastCheck: string | null;
40
55
  lastStatus: string | null;
41
56
  lastError: string | null;
42
57
  nextRun: string | null;
@@ -76,11 +91,15 @@ export default defineAction({
76
91
  triggerType: meta.triggerType,
77
92
  event: meta.event ?? null,
78
93
  schedule: meta.schedule || null,
79
- scheduleDescription: meta.schedule ? describeCron(meta.schedule) : null,
94
+ timezone: meta.schedule ? effectiveTimezone(meta.timezone) : null,
95
+ scheduleDescription: meta.schedule
96
+ ? describeCron(meta.schedule, effectiveTimezone(meta.timezone))
97
+ : null,
80
98
  condition: meta.condition ?? null,
81
99
  body,
82
100
  enabled: meta.enabled,
83
101
  lastRun: meta.lastRun ?? null,
102
+ lastCheck: meta.lastCheck ?? null,
84
103
  lastStatus: meta.lastStatus ?? null,
85
104
  lastError: meta.lastError ?? null,
86
105
  nextRun: nextRun(meta),
@@ -16,8 +16,10 @@ export default defineAction({
16
16
  name: z.string().min(1),
17
17
  scope: z.enum(["personal", "organization"]).default("personal"),
18
18
  enabled: z.boolean().optional(),
19
+ schedule: z.string().min(1).optional(),
20
+ timezone: z.string().min(1).optional(),
19
21
  }),
20
- run: async ({ operation, name, scope, enabled }, ctx) => {
22
+ run: async ({ operation, name, scope, enabled, schedule, timezone }, ctx) => {
21
23
  const userEmail = ctx?.userEmail;
22
24
  if (!userEmail) throw new Error("Not authenticated.");
23
25
  const actor = { userEmail, orgId: ctx?.orgId };
@@ -27,20 +29,29 @@ export default defineAction({
27
29
  await refreshEventSubscriptions();
28
30
  return { deleted: true, name };
29
31
  }
30
- if (enabled === undefined) {
31
- throw Object.assign(new Error("enabled is required for update."), {
32
- statusCode: 400,
33
- });
32
+ if (
33
+ enabled === undefined &&
34
+ schedule === undefined &&
35
+ timezone === undefined
36
+ ) {
37
+ throw Object.assign(
38
+ new Error("enabled, schedule, or timezone is required for update."),
39
+ { statusCode: 400 },
40
+ );
34
41
  }
35
42
  const definition = await updateAutomation(actor, {
36
43
  name,
37
44
  scope,
38
- enabled,
45
+ ...(enabled === undefined ? {} : { enabled }),
46
+ ...(schedule === undefined ? {} : { schedule }),
47
+ ...(timezone === undefined ? {} : { timezone }),
39
48
  });
40
49
  await refreshEventSubscriptions();
41
50
  return {
42
51
  name,
43
52
  enabled: definition.meta.enabled,
53
+ schedule: definition.meta.schedule || null,
54
+ timezone: definition.meta.timezone ?? null,
44
55
  nextRun: definition.meta.nextRun ?? null,
45
56
  };
46
57
  },
@@ -18,7 +18,7 @@ import {
18
18
  type AutomationScope,
19
19
  } from "../automations/service.js";
20
20
  import { listEvents } from "../event-bus/index.js";
21
- import { describeCron } from "../jobs/cron.js";
21
+ import { describeCron, effectiveTimezone } from "../jobs/cron.js";
22
22
  import {
23
23
  getIntegrationRequestContext,
24
24
  getRequestOrgId,
@@ -71,7 +71,10 @@ async function handleList(
71
71
  triggerType: meta.triggerType,
72
72
  event: meta.event ?? null,
73
73
  schedule: meta.schedule || null,
74
- scheduleDescription: meta.schedule ? describeCron(meta.schedule) : null,
74
+ timezone: meta.timezone ? effectiveTimezone(meta.timezone) : null,
75
+ scheduleDescription: meta.schedule
76
+ ? describeCron(meta.schedule, effectiveTimezone(meta.timezone))
77
+ : null,
75
78
  condition: meta.condition ?? null,
76
79
  mode: meta.mode,
77
80
  domain: meta.domain ?? null,
@@ -127,6 +130,7 @@ async function handleDefine(
127
130
  triggerType: automationTriggerType(args.trigger_type),
128
131
  body: typeof args.body === "string" ? args.body : "",
129
132
  schedule: typeof args.schedule === "string" ? args.schedule : undefined,
133
+ timezone: typeof args.timezone === "string" ? args.timezone : undefined,
130
134
  event: typeof args.event === "string" ? args.event : undefined,
131
135
  condition:
132
136
  typeof args.condition === "string" ? args.condition : undefined,
@@ -164,6 +168,7 @@ async function handleDefine(
164
168
  triggerType: definition.meta.triggerType,
165
169
  event: definition.meta.event ?? null,
166
170
  schedule: definition.meta.schedule || null,
171
+ timezone: definition.meta.timezone ?? null,
167
172
  nextRun: definition.meta.nextRun ?? null,
168
173
  createdBy: definition.meta.createdBy,
169
174
  runAs: definition.meta.runAs,
@@ -208,6 +213,7 @@ async function handleUpdate(
208
213
  : null,
209
214
  body: typeof args.body === "string" ? args.body : undefined,
210
215
  schedule: typeof args.schedule === "string" ? args.schedule : undefined,
216
+ timezone: typeof args.timezone === "string" ? args.timezone : undefined,
211
217
  model:
212
218
  args.model === undefined
213
219
  ? undefined
@@ -225,6 +231,7 @@ async function handleUpdate(
225
231
  triggerType: definition.meta.triggerType,
226
232
  enabled: definition.meta.enabled,
227
233
  schedule: definition.meta.schedule || null,
234
+ timezone: definition.meta.timezone ?? null,
228
235
  nextRun: definition.meta.nextRun ?? null,
229
236
  createdBy: definition.meta.createdBy,
230
237
  runAs: definition.meta.runAs,
@@ -305,8 +312,8 @@ export function createAutomationToolEntries(
305
312
 
306
313
  - **list-events**: List all registered event types that automations can subscribe to. Returns event names, descriptions, and payload schemas. Call this BEFORE defining an automation to discover available events.
307
314
  - **list**: List all automations (triggers). Shows trigger, status, model, MCP allowlist, and delivery metadata. Optional params: scope, domain, enabled_only.
308
- - **define**: Create a new automation. IMPORTANT: Always confirm with the user before calling — show them a summary of what will be created. Required params: name, trigger_type, body. Optional: scope, event, schedule, condition, mode, domain, delegated_policy_id, model, mcpTools.
309
- - **update**: Update an existing automation's settings without changing its creator (enabled, schedule, condition, body, policy, model, MCP allowlist). Required param: name. Use the same scope it was created in.
315
+ - **define**: Create a new automation. IMPORTANT: Always confirm with the user before calling — show them a summary of what will be created. Required params: name, trigger_type, body. Optional: scope, event, schedule, timezone, condition, mode, domain, delegated_policy_id, model, mcpTools.
316
+ - **update**: Update an existing automation's settings without changing its creator (enabled, schedule, timezone, condition, body, policy, model, MCP allowlist). Required param: name. Use the same scope it was created in.
310
317
  - **delete**: Delete an automation. Always confirm with the user first. Required param: name.
311
318
  - **fire-test**: Fire a test event to validate automations. Emits a test.event.fired event. Optional param: data (JSON string).`,
312
319
  parameters: {
@@ -339,6 +346,11 @@ export function createAutomationToolEntries(
339
346
  description:
340
347
  "For event triggers: the event name to subscribe to. Call with action=list-events first to see available events.",
341
348
  },
349
+ timezone: {
350
+ type: "string",
351
+ description:
352
+ "IANA timezone the cron clock time is read in, e.g. 'America/New_York'. Optional; defaults to the user's saved scheduling timezone, then the caller's browser zone. Always pass this when the user names a time of day.",
353
+ },
342
354
  schedule: {
343
355
  type: "string",
344
356
  description:
@@ -82,6 +82,31 @@ const _eventSubscriptions = new Map<string, string>();
82
82
  const _dispatchingTriggers = new Set<string>();
83
83
  let _deps: TriggerDispatcherDeps | null = null;
84
84
 
85
+ /**
86
+ * Record that a tick evaluated this trigger and declined to dispatch it.
87
+ * `lastRun` stays untouched — nothing ran — and an unchanged outcome is not
88
+ * re-persisted, so a permanently blocked trigger neither reports phantom runs
89
+ * nor rewrites its resource on every matching event.
90
+ */
91
+ async function recordTriggerSkip(
92
+ resource: Resource,
93
+ meta: TriggerFrontmatter,
94
+ body: string,
95
+ status: "skipped" | "error",
96
+ reason: string | undefined,
97
+ ): Promise<void> {
98
+ const unchanged = meta.lastStatus === status && meta.lastError === reason;
99
+ meta.lastCheck = new Date().toISOString();
100
+ meta.lastStatus = status;
101
+ meta.lastError = reason;
102
+ if (unchanged) return;
103
+ await resourcePut(
104
+ resource.owner,
105
+ resource.path,
106
+ buildTriggerContent(meta, body),
107
+ );
108
+ }
109
+
85
110
  /**
86
111
  * Initialize the trigger dispatcher. Call once at server startup.
87
112
  * Loads all event-triggered jobs and subscribes to their events.
@@ -173,25 +198,22 @@ async function handleEvent(
173
198
  meta,
174
199
  );
175
200
  } catch {
176
- meta.lastRun = new Date().toISOString();
177
- meta.lastStatus = "skipped";
178
- meta.lastError =
179
- "Could not verify the automation execution identity.";
180
- await resourcePut(
181
- resource.owner,
182
- resource.path,
183
- buildTriggerContent(meta, body),
201
+ await recordTriggerSkip(
202
+ resource,
203
+ meta,
204
+ body,
205
+ "skipped",
206
+ "Could not verify the automation execution identity.",
184
207
  );
185
208
  continue;
186
209
  }
187
210
  if (!resolved.ok) {
188
- meta.lastRun = new Date().toISOString();
189
- meta.lastStatus = "skipped";
190
- meta.lastError = resolved.reason;
191
- await resourcePut(
192
- resource.owner,
193
- resource.path,
194
- buildTriggerContent(meta, body),
211
+ await recordTriggerSkip(
212
+ resource,
213
+ meta,
214
+ body,
215
+ "skipped",
216
+ resolved.reason,
195
217
  );
196
218
  continue;
197
219
  }
@@ -206,13 +228,12 @@ async function handleEvent(
206
228
  const userApiKey = await getOwnerActiveApiKey(owner);
207
229
  const apiKey = userApiKey || _deps.apiKey;
208
230
  if (!apiKey) {
209
- meta.lastRun = new Date().toISOString();
210
- meta.lastStatus = "error";
211
- meta.lastError = "No API key is available for this automation";
212
- await resourcePut(
213
- resource.owner,
214
- resource.path,
215
- buildTriggerContent(meta, body),
231
+ await recordTriggerSkip(
232
+ resource,
233
+ meta,
234
+ body,
235
+ "error",
236
+ "No API key is available for this automation",
216
237
  );
217
238
  console.warn(`[triggers] ${meta.lastError}: "${resource.path}"`);
218
239
  continue;
@@ -221,14 +242,7 @@ async function handleEvent(
221
242
  // Evaluate condition
222
243
  const matches = await evaluateCondition(meta.condition, payload, apiKey);
223
244
  if (!matches) {
224
- meta.lastRun = new Date().toISOString();
225
- meta.lastStatus = "skipped";
226
- meta.lastError = undefined;
227
- await resourcePut(
228
- resource.owner,
229
- resource.path,
230
- buildTriggerContent(meta, body),
231
- );
245
+ await recordTriggerSkip(resource, meta, body, "skipped", undefined);
232
246
  continue;
233
247
  }
234
248
 
@@ -7,7 +7,12 @@ import {
7
7
 
8
8
  import { canUpdateAutomationResource } from "../automations/service.js";
9
9
  import { getDbExec } from "../db/client.js";
10
- import { nextOccurrence, describeCron, isValidCron } from "../jobs/cron.js";
10
+ import {
11
+ nextOccurrence,
12
+ describeCron,
13
+ effectiveTimezone,
14
+ isValidCron,
15
+ } from "../jobs/cron.js";
11
16
  import {
12
17
  buildJobResourceContent,
13
18
  parseJobResource,
@@ -88,10 +93,10 @@ function normalizeAutomationPath(input: SetAutomationEnabledInput): string {
88
93
  return path;
89
94
  }
90
95
 
91
- function scheduleDescription(schedule: string | undefined): string | undefined {
96
+ function scheduleDescription(schedule?: string, timezone?: string) {
92
97
  if (!schedule) return undefined;
93
98
  try {
94
- return describeCron(schedule);
99
+ return describeCron(schedule, effectiveTimezone(timezone));
95
100
  } catch {
96
101
  return schedule;
97
102
  }
@@ -106,7 +111,11 @@ function nextRunForMeta(meta: TriggerFrontmatter): string | undefined {
106
111
  isValidCron(meta.schedule)
107
112
  ) {
108
113
  try {
109
- return nextOccurrence(meta.schedule).toISOString();
114
+ return nextOccurrence(
115
+ meta.schedule,
116
+ undefined,
117
+ meta.timezone,
118
+ ).toISOString();
110
119
  } catch {
111
120
  return undefined;
112
121
  }
@@ -194,7 +203,7 @@ async function resourceToAutomationItem(
194
203
  triggerType: meta.triggerType,
195
204
  event: meta.event,
196
205
  schedule: meta.schedule || undefined,
197
- scheduleDescription: scheduleDescription(meta.schedule),
206
+ scheduleDescription: scheduleDescription(meta.schedule, meta.timezone),
198
207
  condition: meta.condition,
199
208
  mode: meta.mode,
200
209
  domain: meta.domain,
@@ -292,7 +301,11 @@ export async function setAutomationEnabledForOwner(
292
301
  meta.schedule &&
293
302
  isValidCron(meta.schedule)
294
303
  ) {
295
- parsed.meta.nextRun = nextOccurrence(meta.schedule).toISOString();
304
+ parsed.meta.nextRun = nextOccurrence(
305
+ meta.schedule,
306
+ undefined,
307
+ meta.timezone,
308
+ ).toISOString();
296
309
  }
297
310
 
298
311
  const updatedContent = buildJobResourceContent(parsed.meta, parsed.body);
@@ -0,0 +1,68 @@
1
+ import type { ViteUserConfig } from "vitest/config";
2
+
3
+ /**
4
+ * Base vitest config that caps a suite's worker pool at a share of the machine.
5
+ *
6
+ * Vitest sizes its pool at `cores - 1` with no awareness of peer processes, so
7
+ * several suites running at once — concurrent agent sessions, or a workspace
8
+ * running packages in parallel — each try to claim the whole box. Set
9
+ * `VITEST_CONCURRENCY` to a percentage or a worker count to change the lid; a
10
+ * package that needs its own value sets `test.maxWorkers` in its own config,
11
+ * which wins the merge.
12
+ *
13
+ * This ships from core rather than living at the monorepo root because template
14
+ * directories are scaffolded out verbatim as standalone apps — a config that
15
+ * reaches above the template would resolve to nothing in the generated app.
16
+ *
17
+ * Keep this module free of runtime imports so loading it costs a config file
18
+ * nothing beyond reading the environment.
19
+ */
20
+
21
+ const DEFAULT_MAX_WORKERS = "25%";
22
+ const ENV_KEYS = ["VITEST_CONCURRENCY", "AGENT_NATIVE_VITEST_CONCURRENCY"];
23
+
24
+ /**
25
+ * Resolve the worker lid from the environment, throwing on anything that is
26
+ * neither a percentage nor a worker count. A bad value must not quietly become
27
+ * the default — that reads as "configured" while running at some other size.
28
+ */
29
+ export function resolveMaxWorkers(
30
+ env: NodeJS.ProcessEnv = process.env,
31
+ ): string | number {
32
+ const rawMaxWorkers = env.VITEST_MAX_WORKERS;
33
+ if (rawMaxWorkers?.includes("%")) {
34
+ throw new Error(
35
+ `VITEST_MAX_WORKERS=${rawMaxWorkers} is not a percentage to vitest — it parses as ` +
36
+ `${Number.parseInt(rawMaxWorkers)} workers. Use VITEST_CONCURRENCY for percentages, ` +
37
+ `or an integer for VITEST_MAX_WORKERS.`,
38
+ );
39
+ }
40
+
41
+ const key = ENV_KEYS.find((name) => env[name]);
42
+ if (!key) return DEFAULT_MAX_WORKERS;
43
+
44
+ const value = env[key]!.trim();
45
+ if (/^\d+%$/.test(value)) {
46
+ const percent = Number.parseInt(value);
47
+ if (percent < 1 || percent > 100) {
48
+ throw new Error(`${key}=${value} is out of range — use 1% to 100%.`);
49
+ }
50
+ return value;
51
+ }
52
+
53
+ const count = Number(value);
54
+ if (!Number.isInteger(count) || count < 1) {
55
+ throw new Error(
56
+ `${key}=${value} is not a percentage like "25%" or a worker count like "2".`,
57
+ );
58
+ }
59
+ return count;
60
+ }
61
+
62
+ const vitestBaseConfig: ViteUserConfig = {
63
+ test: {
64
+ maxWorkers: resolveMaxWorkers(),
65
+ },
66
+ };
67
+
68
+ export default vitestBaseConfig;