@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,11 @@
1
+ /**
2
+ * Per-user Slides preferences, stored under one user-setting key so Settings
3
+ * and the notification senders read and write the same object.
4
+ */
5
+
6
+ export const SLIDES_USER_PREFS_KEY = "slides-user-prefs";
7
+
8
+ export type SlidesUserPrefs = {
9
+ /** Comment and reply emails only — never share invites. */
10
+ emailNotifications?: boolean;
11
+ };
@@ -1,18 +1,22 @@
1
1
  import path from "node:path";
2
2
 
3
+ import baseConfig from "@agent-native/core/vitest-config";
3
4
  import react from "@vitejs/plugin-react-swc";
4
- import { defineConfig } from "vitest/config";
5
+ import { defineConfig, mergeConfig } from "vitest/config";
5
6
 
6
- export default defineConfig({
7
- plugins: [react()],
8
- resolve: {
9
- alias: {
10
- "@": path.resolve(__dirname, "./app"),
11
- "@shared": path.resolve(__dirname, "./shared"),
7
+ export default mergeConfig(
8
+ baseConfig,
9
+ defineConfig({
10
+ plugins: [react()],
11
+ resolve: {
12
+ alias: {
13
+ "@": path.resolve(__dirname, "./app"),
14
+ "@shared": path.resolve(__dirname, "./shared"),
15
+ },
12
16
  },
13
- },
14
- test: {
15
- include: ["**/*.{test,spec}.?(c|m)[jt]s?(x)"],
16
- exclude: ["**/node_modules/**", "**/.git/**", "**/dist/**"],
17
- },
18
- });
17
+ test: {
18
+ include: ["**/*.{test,spec}.?(c|m)[jt]s?(x)"],
19
+ exclude: ["**/node_modules/**", "**/.git/**", "**/dist/**"],
20
+ },
21
+ }),
22
+ );
@@ -263,6 +263,8 @@ export function Sidebar({
263
263
  >
264
264
  <OrgSwitcher
265
265
  reserveSpace
266
+ // Tasks does not mount /agent, so the default link would 404.
267
+ agentPath={null}
266
268
  className={
267
269
  collapsed
268
270
  ? "h-8 justify-center px-0 [&>span]:sr-only [&>svg:last-child]:hidden"
@@ -1,18 +1,12 @@
1
1
  import { LanguagePicker, useT } from "@agent-native/core/client/i18n";
2
2
  import {
3
+ SettingsGroup,
4
+ SettingsRow,
3
5
  SettingsTabsPage,
4
6
  useAgentSettingsTabs,
5
7
  } from "@agent-native/core/client/settings";
6
8
  import { useSetPageTitle } from "@agent-native/toolkit/app-shell";
7
9
 
8
- import {
9
- Card,
10
- CardContent,
11
- CardDescription,
12
- CardHeader,
13
- CardTitle,
14
- } from "@/components/ui/card";
15
- import { Label } from "@/components/ui/label";
16
10
  import { APP_TITLE } from "@/lib/app-config";
17
11
 
18
12
  export function meta() {
@@ -33,20 +27,18 @@ export default function SettingsRoute() {
33
27
  {t("header.pageSettings")}
34
28
  </p>
35
29
 
36
- <Card id="language" className="scroll-mt-16">
37
- <CardHeader>
38
- <CardTitle className="text-base">
39
- {t("settings.languageTitle")}
40
- </CardTitle>
41
- <CardDescription>
42
- {t("settings.languageDescription")}
43
- </CardDescription>
44
- </CardHeader>
45
- <CardContent className="max-w-xs space-y-1.5">
46
- <Label>{t("settings.languageLabel")}</Label>
47
- <LanguagePicker label={t("settings.languageLabel")} />
48
- </CardContent>
49
- </Card>
30
+ <SettingsGroup>
31
+ <SettingsRow
32
+ id="language"
33
+ label={t("settings.languageTitle")}
34
+ description={t("settings.languageDescription")}
35
+ control={
36
+ <div className="w-56">
37
+ <LanguagePicker label={t("settings.languageLabel")} />
38
+ </div>
39
+ }
40
+ />
41
+ </SettingsGroup>
50
42
  </div>
51
43
  }
52
44
  />
@@ -1,17 +1,21 @@
1
1
  import path from "node:path";
2
2
 
3
- import { defineConfig } from "vitest/config";
3
+ import baseConfig from "@agent-native/core/vitest-config";
4
+ import { defineConfig, mergeConfig } from "vitest/config";
4
5
 
5
- export default defineConfig({
6
- resolve: {
7
- alias: {
8
- "@": path.resolve(__dirname, "./app"),
9
- "@shared": path.resolve(__dirname, "./shared"),
6
+ export default mergeConfig(
7
+ baseConfig,
8
+ defineConfig({
9
+ resolve: {
10
+ alias: {
11
+ "@": path.resolve(__dirname, "./app"),
12
+ "@shared": path.resolve(__dirname, "./shared"),
13
+ },
10
14
  },
11
- },
12
- test: {
13
- include: ["**/*.{test,spec}.?(c|m)[jt]s?(x)"],
14
- exclude: ["**/node_modules/**", "**/.git/**", "**/dist/**", "**/e2e/**"],
15
- environment: "node",
16
- },
17
- });
15
+ test: {
16
+ include: ["**/*.{test,spec}.?(c|m)[jt]s?(x)"],
17
+ exclude: ["**/node_modules/**", "**/.git/**", "**/dist/**", "**/e2e/**"],
18
+ environment: "node",
19
+ },
20
+ }),
21
+ );
@@ -1,5 +1,14 @@
1
1
  # @agent-native/toolkit
2
2
 
3
+ ## 0.12.2
4
+
5
+ ### Patch Changes
6
+
7
+ - f499dff: Add `@agent-native/core/vitest-config`, a base vitest config that caps a suite's
8
+ worker pool so concurrent test runs no longer oversubscribe the CPU. Defaults to
9
+ 25% of cores; override with `VITEST_CONCURRENCY`. Every template and package
10
+ config merges it in.
11
+
3
12
  ## 0.12.1
4
13
 
5
14
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/toolkit",
3
- "version": "0.12.1",
3
+ "version": "0.12.2",
4
4
  "description": "Reusable app-building UI and helpers for Agent-Native apps.",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -0,0 +1,3 @@
1
+ import baseConfig from "../../vitest.shared";
2
+
3
+ export default baseConfig;
@@ -29,6 +29,7 @@ export interface DefineAutomationInput {
29
29
  triggerType: "schedule" | "event";
30
30
  body: string;
31
31
  schedule?: string;
32
+ timezone?: string;
32
33
  event?: string;
33
34
  condition?: string;
34
35
  domain?: string;
@@ -46,6 +47,7 @@ export interface UpdateAutomationInput {
46
47
  condition?: string | null;
47
48
  delegatedPolicyId?: string | null;
48
49
  schedule?: string;
50
+ timezone?: string;
49
51
  model?: string | null;
50
52
  mcpTools?: unknown;
51
53
  }
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/automations/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/automations/service.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,8 @@
1
1
  import { getDbExec } from "../db/client.js";
2
- import { isValidCron, nextOccurrence } from "../jobs/cron.js";
2
+ import { isValidCron, isValidTimezone, nextOccurrence } from "../jobs/cron.js";
3
3
  import { buildJobResourceContent, normalizeJobMcpTools, parseJobResource, } from "../jobs/frontmatter.js";
4
+ import { deleteAutomationRuns } from "../jobs/run-history.js";
5
+ import { resolveUserSchedulingTimezone } from "../localization/user-timezone.js";
4
6
  import { organizationIdFromResourceOwner, organizationResourceOwner, resourceDelete, resourceGetByPath, resourceList, resourcePut, } from "../resources/store.js";
5
7
  function httpError(message, statusCode) {
6
8
  return Object.assign(new Error(message), { statusCode });
@@ -177,9 +179,18 @@ export async function defineAutomation(actorInput, input) {
177
179
  if (input.triggerType === "event" && !event) {
178
180
  throw httpError("event is required for event-triggered automations.", 400);
179
181
  }
182
+ if (input.timezone && !isValidTimezone(input.timezone)) {
183
+ throw httpError(`Unknown timezone "${input.timezone}".`, 400);
184
+ }
185
+ // Resolve now and persist it: a schedule whose zone is implicit means
186
+ // something different the moment it is read on a differently-zoned host.
187
+ const timezone = input.triggerType === "schedule"
188
+ ? input.timezone || (await resolveUserSchedulingTimezone(actor.userEmail))
189
+ : undefined;
180
190
  const mcpTools = normalizeJobMcpTools(input.mcpTools);
181
191
  const meta = {
182
192
  schedule: input.triggerType === "schedule" ? schedule : "",
193
+ timezone,
183
194
  enabled: true,
184
195
  triggerType: input.triggerType,
185
196
  event: input.triggerType === "event" ? event : undefined,
@@ -191,7 +202,7 @@ export async function defineAutomation(actorInput, input) {
191
202
  orgId: input.scope === "organization" ? actor.orgId : undefined,
192
203
  runAs: "creator",
193
204
  nextRun: input.triggerType === "schedule"
194
- ? nextOccurrence(schedule).toISOString()
205
+ ? nextOccurrence(schedule, undefined, timezone).toISOString()
195
206
  : undefined,
196
207
  model: input.model?.trim() || undefined,
197
208
  mcpTools: mcpTools?.length ? mcpTools : undefined,
@@ -225,14 +236,25 @@ export async function updateAutomation(actorInput, input) {
225
236
  throw httpError(`Invalid cron expression "${input.schedule}".`, 400);
226
237
  }
227
238
  meta.schedule = input.schedule;
228
- meta.nextRun = nextOccurrence(input.schedule).toISOString();
239
+ }
240
+ if (input.timezone !== undefined) {
241
+ if (!isValidTimezone(input.timezone)) {
242
+ throw httpError(`Unknown timezone "${input.timezone}".`, 400);
243
+ }
244
+ if (meta.triggerType !== "schedule") {
245
+ throw httpError("Event automations do not have a timezone.", 400);
246
+ }
247
+ meta.timezone = input.timezone;
248
+ }
249
+ if (input.schedule !== undefined || input.timezone !== undefined) {
250
+ meta.nextRun = nextOccurrence(meta.schedule, undefined, meta.timezone).toISOString();
229
251
  }
230
252
  if (input.enabled !== undefined) {
231
253
  meta.enabled = input.enabled;
232
254
  if (input.enabled &&
233
255
  meta.triggerType === "schedule" &&
234
256
  isValidCron(meta.schedule)) {
235
- meta.nextRun = nextOccurrence(meta.schedule).toISOString();
257
+ meta.nextRun = nextOccurrence(meta.schedule, undefined, meta.timezone).toISOString();
236
258
  }
237
259
  }
238
260
  if (input.condition !== undefined) {
@@ -264,6 +286,9 @@ export async function deleteAutomation(actorInput, scope, name) {
264
286
  throw httpError("Only the automation's creator or an organization admin can delete it.", 403);
265
287
  }
266
288
  await resourceDelete(definition.resource.id);
289
+ // Names are reusable, so leaving history behind would attach these runs to
290
+ // whatever automation is created under the same name next.
291
+ await deleteAutomationRuns(definition.resource.owner, name);
267
292
  }
268
293
  /**
269
294
  * Resolve the identity used by an explicit automation run.
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/automations/service.ts"],"names":[],"mappings":"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","sourcesContent":["import { getDbExec } from \"../db/client.js\";\nimport { isValidCron, nextOccurrence } from \"../jobs/cron.js\";\nimport {\n buildJobResourceContent,\n normalizeJobMcpTools,\n parseJobResource,\n type JobFrontmatter,\n} from \"../jobs/frontmatter.js\";\nimport {\n organizationIdFromResourceOwner,\n organizationResourceOwner,\n resourceDelete,\n resourceGetByPath,\n resourceList,\n resourcePut,\n type Resource,\n} from \"../resources/store.js\";\n\nexport type AutomationScope = \"personal\" | \"organization\";\n\nexport interface AutomationActor {\n userEmail: string;\n orgId?: string | null;\n}\n\nexport interface AutomationDefinition {\n resource: Resource;\n name: string;\n scope: AutomationScope;\n meta: JobFrontmatter & {\n triggerType: \"schedule\" | \"event\";\n mode: \"agentic\" | \"deterministic\";\n };\n body: string;\n canUpdate: boolean;\n}\n\nexport interface AutomationDelivery {\n originScopeId?: string;\n platform?: string;\n destination?: string;\n threadRef?: string;\n tenantId?: string;\n}\n\nexport interface DefineAutomationInput {\n name: string;\n scope: AutomationScope;\n triggerType: \"schedule\" | \"event\";\n body: string;\n schedule?: string;\n event?: string;\n condition?: string;\n domain?: string;\n delegatedPolicyId?: string;\n model?: string;\n mcpTools?: unknown;\n delivery?: AutomationDelivery;\n}\n\nexport type DefinedAutomation = Omit<AutomationDefinition, \"resource\">;\n\nexport interface UpdateAutomationInput {\n name: string;\n scope: AutomationScope;\n enabled?: boolean;\n body?: string;\n condition?: string | null;\n delegatedPolicyId?: string | null;\n schedule?: string;\n model?: string | null;\n mcpTools?: unknown;\n}\n\ninterface OrganizationMembership {\n role: string;\n}\n\nfunction httpError(message: string, statusCode: number): Error {\n return Object.assign(new Error(message), { statusCode });\n}\n\nfunction normalizeActor(actor: AutomationActor): AutomationActor {\n const userEmail = actor.userEmail.trim().toLowerCase();\n if (!userEmail) throw httpError(\"Not authenticated.\", 401);\n return { userEmail, orgId: actor.orgId?.trim() || null };\n}\n\nfunction automationName(path: string): string {\n return path.replace(/^jobs\\//, \"\").replace(/\\.md$/, \"\");\n}\n\nfunction automationPath(name: string): string {\n const normalized = name\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, \"-\");\n if (!normalized) {\n throw httpError(\"Automation name is required (lowercase, hyphens).\", 400);\n }\n return `jobs/${normalized}.md`;\n}\n\nfunction ownerForScope(actor: AutomationActor, scope: AutomationScope): string {\n if (scope === \"personal\") return actor.userEmail;\n if (!actor.orgId) {\n throw httpError(\n \"An organization is required for organization automations.\",\n 400,\n );\n }\n return organizationResourceOwner(actor.orgId);\n}\n\nasync function readOrganizationMembership(\n orgId: string,\n email: string,\n): Promise<OrganizationMembership | null> {\n const result = await getDbExec().execute({\n sql: \"SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1\",\n args: [orgId, email.toLowerCase()],\n });\n if (!result.rows.length) return null;\n return { role: String(result.rows[0]?.role ?? \"\").toLowerCase() };\n}\n\nasync function requireOrganizationMembership(\n actor: AutomationActor,\n): Promise<OrganizationMembership> {\n if (!actor.orgId) {\n throw httpError(\n \"An organization is required for organization automations.\",\n 400,\n );\n }\n const membership = await readOrganizationMembership(\n actor.orgId,\n actor.userEmail,\n );\n if (!membership) {\n throw httpError(\"You are no longer a member of this organization.\", 403);\n }\n return membership;\n}\n\nfunction isOrganizationAdmin(membership: OrganizationMembership): boolean {\n return membership.role === \"owner\" || membership.role === \"admin\";\n}\n\nasync function mutationAccess(\n actorInput: AutomationActor,\n resource: Resource,\n meta: JobFrontmatter,\n): Promise<{ actor: AutomationActor; canUpdate: boolean }> {\n const actor = normalizeActor(actorInput);\n const resourceOrgId = organizationIdFromResourceOwner(resource.owner);\n if (!resourceOrgId) {\n return {\n actor,\n canUpdate: resource.owner.toLowerCase() === actor.userEmail,\n };\n }\n if (actor.orgId !== resourceOrgId) {\n return { actor, canUpdate: false };\n }\n const membership = await requireOrganizationMembership(actor);\n const isCreator =\n meta.createdBy?.trim().toLowerCase() === actor.userEmail.toLowerCase();\n return {\n actor,\n canUpdate: isCreator || isOrganizationAdmin(membership),\n };\n}\n\n/**\n * Compatibility adapters may expose both explicit automations and legacy\n * scheduled jobs. Keep their mutation authorization on the same boundary as\n * the canonical service without forcing legacy resources through the explicit\n * automation classifier.\n */\nexport async function canUpdateAutomationResource(\n actorInput: AutomationActor,\n resource: Resource,\n): Promise<boolean> {\n const { meta } = parseJobResource(resource.content);\n return (await mutationAccess(actorInput, resource, meta)).canUpdate;\n}\n\nfunction assertExplicitAutomation(\n resource: Resource,\n): Omit<AutomationDefinition, \"name\" | \"scope\" | \"canUpdate\"> {\n const parsed = parseJobResource(resource.content);\n if (parsed.classification.kind !== \"automation\") {\n throw httpError(\n `\"${automationName(resource.path)}\" is a legacy scheduled job. Use manage-jobs for compatibility.`,\n 400,\n );\n }\n return {\n resource,\n meta: {\n ...parsed.meta,\n triggerType: parsed.classification.triggerType,\n mode: parsed.meta.mode ?? \"agentic\",\n },\n body: parsed.body,\n };\n}\n\nasync function readDefinition(\n actorInput: AutomationActor,\n scope: AutomationScope,\n name: string,\n): Promise<AutomationDefinition> {\n const actor = normalizeActor(actorInput);\n if (scope === \"organization\") await requireOrganizationMembership(actor);\n const owner = ownerForScope(actor, scope);\n const path = automationPath(name);\n const resource = await resourceGetByPath(owner, path);\n if (!resource) {\n throw httpError(`Automation \"${automationName(path)}\" not found.`, 404);\n }\n const definition = assertExplicitAutomation(resource);\n const access = await mutationAccess(actor, resource, definition.meta);\n return {\n ...definition,\n name: automationName(resource.path),\n scope,\n canUpdate: access.canUpdate,\n };\n}\n\nexport async function listAutomationDefinitions(\n actorInput: AutomationActor,\n scope: AutomationScope,\n): Promise<AutomationDefinition[]> {\n const actor = normalizeActor(actorInput);\n const membership =\n scope === \"organization\"\n ? await requireOrganizationMembership(actor)\n : undefined;\n const owner = ownerForScope(actor, scope);\n const resources = await resourceList(owner, \"jobs/\");\n const automations: AutomationDefinition[] = [];\n\n for (const resourceMeta of resources) {\n if (\n !resourceMeta.path.endsWith(\".md\") ||\n resourceMeta.path.endsWith(\".keep\")\n ) {\n continue;\n }\n const resource = await resourceGetByPath(owner, resourceMeta.path);\n if (!resource) continue;\n const parsed = parseJobResource(resource.content);\n if (parsed.classification.kind !== \"automation\") continue;\n const isCreator =\n parsed.meta.createdBy?.trim().toLowerCase() === actor.userEmail;\n automations.push({\n resource,\n name: automationName(resource.path),\n scope,\n meta: {\n ...parsed.meta,\n triggerType: parsed.classification.triggerType,\n mode: parsed.meta.mode ?? \"agentic\",\n },\n body: parsed.body,\n canUpdate:\n scope === \"personal\" ||\n isCreator ||\n (membership ? isOrganizationAdmin(membership) : false),\n });\n }\n\n return automations;\n}\n\nexport async function defineAutomation(\n actorInput: AutomationActor,\n input: DefineAutomationInput,\n): Promise<DefinedAutomation> {\n const actor = normalizeActor(actorInput);\n if (input.scope === \"organization\") {\n await requireOrganizationMembership(actor);\n }\n const owner = ownerForScope(actor, input.scope);\n const path = automationPath(input.name);\n if (await resourceGetByPath(owner, path)) {\n throw httpError(\n `An automation named \"${automationName(path)}\" already exists.`,\n 409,\n );\n }\n const body = input.body.trim();\n if (!body) throw httpError(\"body is required.\", 400);\n\n const schedule = input.schedule?.trim() ?? \"\";\n const event = input.event?.trim() ?? \"\";\n if (input.triggerType === \"schedule\" && !isValidCron(schedule)) {\n throw httpError(\n schedule\n ? `invalid cron expression \"${schedule}\".`\n : \"schedule is required for scheduled automations.\",\n 400,\n );\n }\n if (input.triggerType === \"event\" && !event) {\n throw httpError(\"event is required for event-triggered automations.\", 400);\n }\n\n const mcpTools = normalizeJobMcpTools(input.mcpTools);\n const meta: JobFrontmatter = {\n schedule: input.triggerType === \"schedule\" ? schedule : \"\",\n enabled: true,\n triggerType: input.triggerType,\n event: input.triggerType === \"event\" ? event : undefined,\n condition: input.condition?.trim() || undefined,\n mode: \"agentic\",\n domain: input.domain?.trim() || undefined,\n delegatedPolicyId: input.delegatedPolicyId?.trim() || undefined,\n createdBy: actor.userEmail,\n orgId: input.scope === \"organization\" ? actor.orgId! : undefined,\n runAs: \"creator\",\n nextRun:\n input.triggerType === \"schedule\"\n ? nextOccurrence(schedule).toISOString()\n : undefined,\n model: input.model?.trim() || undefined,\n mcpTools: mcpTools?.length ? mcpTools : undefined,\n originScopeId: input.delivery?.originScopeId,\n deliveryPlatform: input.delivery?.platform,\n deliveryDestination: input.delivery?.destination,\n deliveryThreadRef: input.delivery?.threadRef,\n deliveryTenantId: input.delivery?.tenantId,\n };\n const content = buildJobResourceContent(meta, body);\n await resourcePut(owner, path, content);\n return {\n name: automationName(path),\n scope: input.scope,\n meta: { ...meta, triggerType: input.triggerType, mode: \"agentic\" },\n body,\n canUpdate: true,\n };\n}\n\nexport async function updateAutomation(\n actorInput: AutomationActor,\n input: UpdateAutomationInput,\n): Promise<AutomationDefinition> {\n const definition = await readDefinition(actorInput, input.scope, input.name);\n if (!definition.canUpdate) {\n throw httpError(\n \"Only the automation's creator or an organization admin can update it.\",\n 403,\n );\n }\n const { meta } = definition;\n if (input.schedule !== undefined) {\n if (meta.triggerType !== \"schedule\") {\n throw httpError(\"Event automations do not have a cron schedule.\", 400);\n }\n if (!isValidCron(input.schedule)) {\n throw httpError(`Invalid cron expression \"${input.schedule}\".`, 400);\n }\n meta.schedule = input.schedule;\n meta.nextRun = nextOccurrence(input.schedule).toISOString();\n }\n if (input.enabled !== undefined) {\n meta.enabled = input.enabled;\n if (\n input.enabled &&\n meta.triggerType === \"schedule\" &&\n isValidCron(meta.schedule)\n ) {\n meta.nextRun = nextOccurrence(meta.schedule).toISOString();\n }\n }\n if (input.condition !== undefined) {\n meta.condition = input.condition?.trim() || undefined;\n }\n if (input.delegatedPolicyId !== undefined) {\n meta.delegatedPolicyId = input.delegatedPolicyId?.trim() || undefined;\n }\n if (input.model !== undefined) {\n meta.model = input.model?.trim() || undefined;\n }\n if (input.mcpTools !== undefined) {\n const mcpTools = normalizeJobMcpTools(input.mcpTools);\n meta.mcpTools = mcpTools?.length ? mcpTools : undefined;\n }\n if (input.scope === \"organization\") {\n meta.orgId = organizationIdFromResourceOwner(definition.resource.owner)!;\n meta.runAs = \"creator\";\n }\n const body = input.body === undefined ? definition.body : input.body.trim();\n if (!body) throw httpError(\"Automation body is required.\", 400);\n await resourcePut(\n definition.resource.owner,\n definition.resource.path,\n buildJobResourceContent(meta, body),\n );\n return { ...definition, meta, body };\n}\n\nexport async function deleteAutomation(\n actorInput: AutomationActor,\n scope: AutomationScope,\n name: string,\n): Promise<void> {\n const definition = await readDefinition(actorInput, scope, name);\n if (!definition.canUpdate) {\n throw httpError(\n \"Only the automation's creator or an organization admin can delete it.\",\n 403,\n );\n }\n await resourceDelete(definition.resource.id);\n}\n\nexport interface AutomationExecutionIdentity {\n userEmail: string;\n orgId?: string;\n eventOwner: string;\n}\n\nexport type AutomationExecutionIdentityResult =\n | { ok: true; identity: AutomationExecutionIdentity }\n | { ok: false; reason: string };\n\n/**\n * Resolve the identity used by an explicit automation run.\n *\n * Organization automations are visible through their organization owner, but\n * always execute as their immutable creator. Event dispatchers must also\n * require EventMeta.owner to equal `eventOwner`; organization visibility does\n * not make an event organization-wide.\n */\nexport async function resolveAutomationExecutionIdentity(\n resourceOwner: string,\n meta: JobFrontmatter,\n): Promise<AutomationExecutionIdentityResult> {\n const orgId = organizationIdFromResourceOwner(resourceOwner);\n if (!orgId) {\n const userEmail = (meta.createdBy || resourceOwner).trim().toLowerCase();\n if (!userEmail || userEmail !== resourceOwner.trim().toLowerCase()) {\n return {\n ok: false,\n reason: \"Personal automation creator does not match its owner.\",\n };\n }\n return { ok: true, identity: { userEmail, eventOwner: userEmail } };\n }\n\n const userEmail = meta.createdBy?.trim().toLowerCase();\n if (!userEmail) {\n return {\n ok: false,\n reason: \"Organization automation has no creator identity.\",\n };\n }\n if (meta.runAs !== \"creator\") {\n return {\n ok: false,\n reason: \"Organization automations must run as their creator.\",\n };\n }\n if (meta.orgId && meta.orgId !== orgId) {\n return {\n ok: false,\n reason: \"Organization automation metadata does not match its owner.\",\n };\n }\n\n const user = await getDbExec().execute({\n sql: `SELECT 1 FROM \"user\" WHERE LOWER(email) = ? LIMIT 1`,\n args: [userEmail],\n });\n if (!user.rows.length) {\n return {\n ok: false,\n reason: `Automation creator \"${userEmail}\" no longer exists.`,\n };\n }\n if (!(await readOrganizationMembership(orgId, userEmail))) {\n return {\n ok: false,\n reason: `Automation creator \"${userEmail}\" is no longer a member of organization \"${orgId}\".`,\n };\n }\n return {\n ok: true,\n identity: { userEmail, orgId, eventOwner: userEmail },\n };\n}\n\nexport function automationMatchesEventOwner(\n identity: AutomationExecutionIdentity,\n eventOwner: string | undefined,\n): boolean {\n return (\n typeof eventOwner === \"string\" &&\n eventOwner.trim().toLowerCase() === identity.eventOwner\n );\n}\n"]}
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/automations/service.ts"],"names":[],"mappings":"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","sourcesContent":["import { getDbExec } from \"../db/client.js\";\nimport { isValidCron, isValidTimezone, nextOccurrence } from \"../jobs/cron.js\";\nimport {\n buildJobResourceContent,\n normalizeJobMcpTools,\n parseJobResource,\n type JobFrontmatter,\n} from \"../jobs/frontmatter.js\";\nimport { deleteAutomationRuns } from \"../jobs/run-history.js\";\nimport { resolveUserSchedulingTimezone } from \"../localization/user-timezone.js\";\nimport {\n organizationIdFromResourceOwner,\n organizationResourceOwner,\n resourceDelete,\n resourceGetByPath,\n resourceList,\n resourcePut,\n type Resource,\n} from \"../resources/store.js\";\n\nexport type AutomationScope = \"personal\" | \"organization\";\n\nexport interface AutomationActor {\n userEmail: string;\n orgId?: string | null;\n}\n\nexport interface AutomationDefinition {\n resource: Resource;\n name: string;\n scope: AutomationScope;\n meta: JobFrontmatter & {\n triggerType: \"schedule\" | \"event\";\n mode: \"agentic\" | \"deterministic\";\n };\n body: string;\n canUpdate: boolean;\n}\n\nexport interface AutomationDelivery {\n originScopeId?: string;\n platform?: string;\n destination?: string;\n threadRef?: string;\n tenantId?: string;\n}\n\nexport interface DefineAutomationInput {\n name: string;\n scope: AutomationScope;\n triggerType: \"schedule\" | \"event\";\n body: string;\n schedule?: string;\n timezone?: string;\n event?: string;\n condition?: string;\n domain?: string;\n delegatedPolicyId?: string;\n model?: string;\n mcpTools?: unknown;\n delivery?: AutomationDelivery;\n}\n\nexport type DefinedAutomation = Omit<AutomationDefinition, \"resource\">;\n\nexport interface UpdateAutomationInput {\n name: string;\n scope: AutomationScope;\n enabled?: boolean;\n body?: string;\n condition?: string | null;\n delegatedPolicyId?: string | null;\n schedule?: string;\n timezone?: string;\n model?: string | null;\n mcpTools?: unknown;\n}\n\ninterface OrganizationMembership {\n role: string;\n}\n\nfunction httpError(message: string, statusCode: number): Error {\n return Object.assign(new Error(message), { statusCode });\n}\n\nfunction normalizeActor(actor: AutomationActor): AutomationActor {\n const userEmail = actor.userEmail.trim().toLowerCase();\n if (!userEmail) throw httpError(\"Not authenticated.\", 401);\n return { userEmail, orgId: actor.orgId?.trim() || null };\n}\n\nfunction automationName(path: string): string {\n return path.replace(/^jobs\\//, \"\").replace(/\\.md$/, \"\");\n}\n\nfunction automationPath(name: string): string {\n const normalized = name\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, \"-\");\n if (!normalized) {\n throw httpError(\"Automation name is required (lowercase, hyphens).\", 400);\n }\n return `jobs/${normalized}.md`;\n}\n\nfunction ownerForScope(actor: AutomationActor, scope: AutomationScope): string {\n if (scope === \"personal\") return actor.userEmail;\n if (!actor.orgId) {\n throw httpError(\n \"An organization is required for organization automations.\",\n 400,\n );\n }\n return organizationResourceOwner(actor.orgId);\n}\n\nasync function readOrganizationMembership(\n orgId: string,\n email: string,\n): Promise<OrganizationMembership | null> {\n const result = await getDbExec().execute({\n sql: \"SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1\",\n args: [orgId, email.toLowerCase()],\n });\n if (!result.rows.length) return null;\n return { role: String(result.rows[0]?.role ?? \"\").toLowerCase() };\n}\n\nasync function requireOrganizationMembership(\n actor: AutomationActor,\n): Promise<OrganizationMembership> {\n if (!actor.orgId) {\n throw httpError(\n \"An organization is required for organization automations.\",\n 400,\n );\n }\n const membership = await readOrganizationMembership(\n actor.orgId,\n actor.userEmail,\n );\n if (!membership) {\n throw httpError(\"You are no longer a member of this organization.\", 403);\n }\n return membership;\n}\n\nfunction isOrganizationAdmin(membership: OrganizationMembership): boolean {\n return membership.role === \"owner\" || membership.role === \"admin\";\n}\n\nasync function mutationAccess(\n actorInput: AutomationActor,\n resource: Resource,\n meta: JobFrontmatter,\n): Promise<{ actor: AutomationActor; canUpdate: boolean }> {\n const actor = normalizeActor(actorInput);\n const resourceOrgId = organizationIdFromResourceOwner(resource.owner);\n if (!resourceOrgId) {\n return {\n actor,\n canUpdate: resource.owner.toLowerCase() === actor.userEmail,\n };\n }\n if (actor.orgId !== resourceOrgId) {\n return { actor, canUpdate: false };\n }\n const membership = await requireOrganizationMembership(actor);\n const isCreator =\n meta.createdBy?.trim().toLowerCase() === actor.userEmail.toLowerCase();\n return {\n actor,\n canUpdate: isCreator || isOrganizationAdmin(membership),\n };\n}\n\n/**\n * Compatibility adapters may expose both explicit automations and legacy\n * scheduled jobs. Keep their mutation authorization on the same boundary as\n * the canonical service without forcing legacy resources through the explicit\n * automation classifier.\n */\nexport async function canUpdateAutomationResource(\n actorInput: AutomationActor,\n resource: Resource,\n): Promise<boolean> {\n const { meta } = parseJobResource(resource.content);\n return (await mutationAccess(actorInput, resource, meta)).canUpdate;\n}\n\nfunction assertExplicitAutomation(\n resource: Resource,\n): Omit<AutomationDefinition, \"name\" | \"scope\" | \"canUpdate\"> {\n const parsed = parseJobResource(resource.content);\n if (parsed.classification.kind !== \"automation\") {\n throw httpError(\n `\"${automationName(resource.path)}\" is a legacy scheduled job. Use manage-jobs for compatibility.`,\n 400,\n );\n }\n return {\n resource,\n meta: {\n ...parsed.meta,\n triggerType: parsed.classification.triggerType,\n mode: parsed.meta.mode ?? \"agentic\",\n },\n body: parsed.body,\n };\n}\n\nasync function readDefinition(\n actorInput: AutomationActor,\n scope: AutomationScope,\n name: string,\n): Promise<AutomationDefinition> {\n const actor = normalizeActor(actorInput);\n if (scope === \"organization\") await requireOrganizationMembership(actor);\n const owner = ownerForScope(actor, scope);\n const path = automationPath(name);\n const resource = await resourceGetByPath(owner, path);\n if (!resource) {\n throw httpError(`Automation \"${automationName(path)}\" not found.`, 404);\n }\n const definition = assertExplicitAutomation(resource);\n const access = await mutationAccess(actor, resource, definition.meta);\n return {\n ...definition,\n name: automationName(resource.path),\n scope,\n canUpdate: access.canUpdate,\n };\n}\n\nexport async function listAutomationDefinitions(\n actorInput: AutomationActor,\n scope: AutomationScope,\n): Promise<AutomationDefinition[]> {\n const actor = normalizeActor(actorInput);\n const membership =\n scope === \"organization\"\n ? await requireOrganizationMembership(actor)\n : undefined;\n const owner = ownerForScope(actor, scope);\n const resources = await resourceList(owner, \"jobs/\");\n const automations: AutomationDefinition[] = [];\n\n for (const resourceMeta of resources) {\n if (\n !resourceMeta.path.endsWith(\".md\") ||\n resourceMeta.path.endsWith(\".keep\")\n ) {\n continue;\n }\n const resource = await resourceGetByPath(owner, resourceMeta.path);\n if (!resource) continue;\n const parsed = parseJobResource(resource.content);\n if (parsed.classification.kind !== \"automation\") continue;\n const isCreator =\n parsed.meta.createdBy?.trim().toLowerCase() === actor.userEmail;\n automations.push({\n resource,\n name: automationName(resource.path),\n scope,\n meta: {\n ...parsed.meta,\n triggerType: parsed.classification.triggerType,\n mode: parsed.meta.mode ?? \"agentic\",\n },\n body: parsed.body,\n canUpdate:\n scope === \"personal\" ||\n isCreator ||\n (membership ? isOrganizationAdmin(membership) : false),\n });\n }\n\n return automations;\n}\n\nexport async function defineAutomation(\n actorInput: AutomationActor,\n input: DefineAutomationInput,\n): Promise<DefinedAutomation> {\n const actor = normalizeActor(actorInput);\n if (input.scope === \"organization\") {\n await requireOrganizationMembership(actor);\n }\n const owner = ownerForScope(actor, input.scope);\n const path = automationPath(input.name);\n if (await resourceGetByPath(owner, path)) {\n throw httpError(\n `An automation named \"${automationName(path)}\" already exists.`,\n 409,\n );\n }\n const body = input.body.trim();\n if (!body) throw httpError(\"body is required.\", 400);\n\n const schedule = input.schedule?.trim() ?? \"\";\n const event = input.event?.trim() ?? \"\";\n if (input.triggerType === \"schedule\" && !isValidCron(schedule)) {\n throw httpError(\n schedule\n ? `invalid cron expression \"${schedule}\".`\n : \"schedule is required for scheduled automations.\",\n 400,\n );\n }\n if (input.triggerType === \"event\" && !event) {\n throw httpError(\"event is required for event-triggered automations.\", 400);\n }\n\n if (input.timezone && !isValidTimezone(input.timezone)) {\n throw httpError(`Unknown timezone \"${input.timezone}\".`, 400);\n }\n // Resolve now and persist it: a schedule whose zone is implicit means\n // something different the moment it is read on a differently-zoned host.\n const timezone =\n input.triggerType === \"schedule\"\n ? input.timezone || (await resolveUserSchedulingTimezone(actor.userEmail))\n : undefined;\n\n const mcpTools = normalizeJobMcpTools(input.mcpTools);\n const meta: JobFrontmatter = {\n schedule: input.triggerType === \"schedule\" ? schedule : \"\",\n timezone,\n enabled: true,\n triggerType: input.triggerType,\n event: input.triggerType === \"event\" ? event : undefined,\n condition: input.condition?.trim() || undefined,\n mode: \"agentic\",\n domain: input.domain?.trim() || undefined,\n delegatedPolicyId: input.delegatedPolicyId?.trim() || undefined,\n createdBy: actor.userEmail,\n orgId: input.scope === \"organization\" ? actor.orgId! : undefined,\n runAs: \"creator\",\n nextRun:\n input.triggerType === \"schedule\"\n ? nextOccurrence(schedule, undefined, timezone).toISOString()\n : undefined,\n model: input.model?.trim() || undefined,\n mcpTools: mcpTools?.length ? mcpTools : undefined,\n originScopeId: input.delivery?.originScopeId,\n deliveryPlatform: input.delivery?.platform,\n deliveryDestination: input.delivery?.destination,\n deliveryThreadRef: input.delivery?.threadRef,\n deliveryTenantId: input.delivery?.tenantId,\n };\n const content = buildJobResourceContent(meta, body);\n await resourcePut(owner, path, content);\n return {\n name: automationName(path),\n scope: input.scope,\n meta: { ...meta, triggerType: input.triggerType, mode: \"agentic\" },\n body,\n canUpdate: true,\n };\n}\n\nexport async function updateAutomation(\n actorInput: AutomationActor,\n input: UpdateAutomationInput,\n): Promise<AutomationDefinition> {\n const definition = await readDefinition(actorInput, input.scope, input.name);\n if (!definition.canUpdate) {\n throw httpError(\n \"Only the automation's creator or an organization admin can update it.\",\n 403,\n );\n }\n const { meta } = definition;\n if (input.schedule !== undefined) {\n if (meta.triggerType !== \"schedule\") {\n throw httpError(\"Event automations do not have a cron schedule.\", 400);\n }\n if (!isValidCron(input.schedule)) {\n throw httpError(`Invalid cron expression \"${input.schedule}\".`, 400);\n }\n meta.schedule = input.schedule;\n }\n if (input.timezone !== undefined) {\n if (!isValidTimezone(input.timezone)) {\n throw httpError(`Unknown timezone \"${input.timezone}\".`, 400);\n }\n if (meta.triggerType !== \"schedule\") {\n throw httpError(\"Event automations do not have a timezone.\", 400);\n }\n meta.timezone = input.timezone;\n }\n if (input.schedule !== undefined || input.timezone !== undefined) {\n meta.nextRun = nextOccurrence(\n meta.schedule,\n undefined,\n meta.timezone,\n ).toISOString();\n }\n if (input.enabled !== undefined) {\n meta.enabled = input.enabled;\n if (\n input.enabled &&\n meta.triggerType === \"schedule\" &&\n isValidCron(meta.schedule)\n ) {\n meta.nextRun = nextOccurrence(\n meta.schedule,\n undefined,\n meta.timezone,\n ).toISOString();\n }\n }\n if (input.condition !== undefined) {\n meta.condition = input.condition?.trim() || undefined;\n }\n if (input.delegatedPolicyId !== undefined) {\n meta.delegatedPolicyId = input.delegatedPolicyId?.trim() || undefined;\n }\n if (input.model !== undefined) {\n meta.model = input.model?.trim() || undefined;\n }\n if (input.mcpTools !== undefined) {\n const mcpTools = normalizeJobMcpTools(input.mcpTools);\n meta.mcpTools = mcpTools?.length ? mcpTools : undefined;\n }\n if (input.scope === \"organization\") {\n meta.orgId = organizationIdFromResourceOwner(definition.resource.owner)!;\n meta.runAs = \"creator\";\n }\n const body = input.body === undefined ? definition.body : input.body.trim();\n if (!body) throw httpError(\"Automation body is required.\", 400);\n await resourcePut(\n definition.resource.owner,\n definition.resource.path,\n buildJobResourceContent(meta, body),\n );\n return { ...definition, meta, body };\n}\n\nexport async function deleteAutomation(\n actorInput: AutomationActor,\n scope: AutomationScope,\n name: string,\n): Promise<void> {\n const definition = await readDefinition(actorInput, scope, name);\n if (!definition.canUpdate) {\n throw httpError(\n \"Only the automation's creator or an organization admin can delete it.\",\n 403,\n );\n }\n await resourceDelete(definition.resource.id);\n // Names are reusable, so leaving history behind would attach these runs to\n // whatever automation is created under the same name next.\n await deleteAutomationRuns(definition.resource.owner, name);\n}\n\nexport interface AutomationExecutionIdentity {\n userEmail: string;\n orgId?: string;\n eventOwner: string;\n}\n\nexport type AutomationExecutionIdentityResult =\n | { ok: true; identity: AutomationExecutionIdentity }\n | { ok: false; reason: string };\n\n/**\n * Resolve the identity used by an explicit automation run.\n *\n * Organization automations are visible through their organization owner, but\n * always execute as their immutable creator. Event dispatchers must also\n * require EventMeta.owner to equal `eventOwner`; organization visibility does\n * not make an event organization-wide.\n */\nexport async function resolveAutomationExecutionIdentity(\n resourceOwner: string,\n meta: JobFrontmatter,\n): Promise<AutomationExecutionIdentityResult> {\n const orgId = organizationIdFromResourceOwner(resourceOwner);\n if (!orgId) {\n const userEmail = (meta.createdBy || resourceOwner).trim().toLowerCase();\n if (!userEmail || userEmail !== resourceOwner.trim().toLowerCase()) {\n return {\n ok: false,\n reason: \"Personal automation creator does not match its owner.\",\n };\n }\n return { ok: true, identity: { userEmail, eventOwner: userEmail } };\n }\n\n const userEmail = meta.createdBy?.trim().toLowerCase();\n if (!userEmail) {\n return {\n ok: false,\n reason: \"Organization automation has no creator identity.\",\n };\n }\n if (meta.runAs !== \"creator\") {\n return {\n ok: false,\n reason: \"Organization automations must run as their creator.\",\n };\n }\n if (meta.orgId && meta.orgId !== orgId) {\n return {\n ok: false,\n reason: \"Organization automation metadata does not match its owner.\",\n };\n }\n\n const user = await getDbExec().execute({\n sql: `SELECT 1 FROM \"user\" WHERE LOWER(email) = ? LIMIT 1`,\n args: [userEmail],\n });\n if (!user.rows.length) {\n return {\n ok: false,\n reason: `Automation creator \"${userEmail}\" no longer exists.`,\n };\n }\n if (!(await readOrganizationMembership(orgId, userEmail))) {\n return {\n ok: false,\n reason: `Automation creator \"${userEmail}\" is no longer a member of organization \"${orgId}\".`,\n };\n }\n return {\n ok: true,\n identity: { userEmail, orgId, eventOwner: userEmail },\n };\n}\n\nexport function automationMatchesEventOwner(\n identity: AutomationExecutionIdentity,\n eventOwner: string | undefined,\n): boolean {\n return (\n typeof eventOwner === \"string\" &&\n eventOwner.trim().toLowerCase() === identity.eventOwner\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-config-writers.d.ts","sourceRoot":"","sources":["../../src/cli/mcp-config-writers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mcp-config-writers.d.ts","sourceRoot":"","sources":["../../src/cli/mcp-config-writers.ts"],"names":[],"mappings":"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"}
@@ -191,6 +191,23 @@ export function configPathFor(client, baseDir, scope) {
191
191
  // ---------------------------------------------------------------------------
192
192
  // JSON client configs (Claude Code, Claude Code CLI, Cowork)
193
193
  // ---------------------------------------------------------------------------
194
+ /**
195
+ * Read an existing MCP config without conflating missing and unreadable files.
196
+ * Only ENOENT means the config is absent; any other read failure must abort
197
+ * before a caller can overwrite existing user configuration.
198
+ */
199
+ function readExistingConfigFile(file) {
200
+ try {
201
+ return fs.readFileSync(file, "utf-8");
202
+ }
203
+ catch (error) {
204
+ if (error.code === "ENOENT")
205
+ return undefined;
206
+ const detail = error instanceof Error ? ` (${error.message})` : "";
207
+ throw new Error(`Cannot read MCP config file: ${file}\n` +
208
+ `Check that the file is readable and re-run. The file has not been modified.${detail}`);
209
+ }
210
+ }
194
211
  /**
195
212
  * Read and parse a JSON config file.
196
213
  *
@@ -201,14 +218,9 @@ export function configPathFor(client, baseDir, scope) {
201
218
  * file with only the new MCP entry (data-loss hazard).
202
219
  */
203
220
  function readJsonFile(file) {
204
- let raw;
205
- try {
206
- raw = fs.readFileSync(file, "utf-8");
207
- }
208
- catch {
209
- // Missing (ENOENT) or unreadable file — treat as empty.
221
+ const raw = readExistingConfigFile(file);
222
+ if (raw === undefined)
210
223
  return {};
211
- }
212
224
  if (!raw.trim())
213
225
  return {};
214
226
  try {
@@ -480,13 +492,7 @@ export function buildCodexLocalBlock(name, args, env, command = "agent-native")
480
492
  * Identical algorithm to `mcp.ts`'s `writeCodexBlock` so the two never diverge.
481
493
  */
482
494
  export function writeCodexBlock(file, name, block) {
483
- let content = "";
484
- try {
485
- content = fs.readFileSync(file, "utf-8");
486
- }
487
- catch {
488
- content = "";
489
- }
495
+ const content = readExistingConfigFile(file) ?? "";
490
496
  const lines = content.split(/\r?\n/);
491
497
  const out = [];
492
498
  let i = 0;
@@ -520,15 +526,10 @@ export function writeCodexBlock(file, name, block) {
520
526
  writeFileAtomic(file, next);
521
527
  }
522
528
  export function codexHasBlock(file, name) {
523
- try {
524
- const content = fs.readFileSync(file, "utf-8");
525
- return content
526
- .split(/\r?\n/)
527
- .some((line) => codexServerNameOfHeader(line) === name);
528
- }
529
- catch {
530
- return false;
531
- }
529
+ const content = readExistingConfigFile(file);
530
+ return (content
531
+ ?.split(/\r?\n/)
532
+ .some((line) => codexServerNameOfHeader(line) === name) ?? false);
532
533
  }
533
534
  // ---------------------------------------------------------------------------
534
535
  // Unified write helper