@agent-native/core 0.134.0 → 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 (493) hide show
  1. package/corpus/README.md +3 -3
  2. package/corpus/core/CHANGELOG.md +113 -0
  3. package/corpus/core/docs/content/template-content-developers.mdx +1 -1
  4. package/corpus/core/package.json +3 -2
  5. package/corpus/core/src/automations/service.ts +41 -4
  6. package/corpus/core/src/cli/mcp-config-writers.ts +27 -21
  7. package/corpus/core/src/client/agent-page/AgentJobsTab.tsx +187 -85
  8. package/corpus/core/src/client/agent-page/AutomationDetailsDialog.tsx +208 -0
  9. package/corpus/core/src/client/agent-page/AutomationScheduleDialog.tsx +180 -0
  10. package/corpus/core/src/client/agent-page/TimezoneSelect.tsx +241 -0
  11. package/corpus/core/src/client/agent-page/use-jobs.ts +50 -10
  12. package/corpus/core/src/client/org/OrgSwitcher.tsx +26 -0
  13. package/corpus/core/src/client/settings/AccountSettingsCard.tsx +35 -31
  14. package/corpus/core/src/client/settings/SchedulingTimezoneField.tsx +71 -0
  15. package/corpus/core/src/client/settings/SettingsRow.tsx +113 -0
  16. package/corpus/core/src/client/settings/agent-settings-search.ts +2 -1
  17. package/corpus/core/src/client/settings/index.ts +6 -0
  18. package/corpus/core/src/integrations/identity.ts +2 -12
  19. package/corpus/core/src/jobs/actions/list-automation-runs.ts +33 -0
  20. package/corpus/core/src/jobs/actions/list-recurring-jobs.ts +27 -6
  21. package/corpus/core/src/jobs/actions/manage-recurring-job.ts +41 -9
  22. package/corpus/core/src/jobs/background-automation-runner.ts +88 -0
  23. package/corpus/core/src/jobs/cron.ts +52 -6
  24. package/corpus/core/src/jobs/frontmatter.ts +20 -0
  25. package/corpus/core/src/jobs/run-history.ts +242 -0
  26. package/corpus/core/src/jobs/scheduler.ts +73 -18
  27. package/corpus/core/src/jobs/tools.ts +54 -6
  28. package/corpus/core/src/localization/actions/get-localization-preference.ts +2 -2
  29. package/corpus/core/src/localization/actions/set-localization-preference.ts +49 -11
  30. package/corpus/core/src/localization/default-messages.ts +27 -0
  31. package/corpus/core/src/localization/shared.ts +39 -6
  32. package/corpus/core/src/localization/user-timezone.ts +36 -0
  33. package/corpus/core/src/org/app-roles-handlers.ts +1 -9
  34. package/corpus/core/src/org/index.ts +2 -0
  35. package/corpus/core/src/org/membership.ts +18 -0
  36. package/corpus/core/src/review/actions/create-review-comment.ts +4 -1
  37. package/corpus/core/src/review/actions/reply-review-comment.ts +4 -1
  38. package/corpus/core/src/review/index.ts +5 -0
  39. package/corpus/core/src/review/notifications.ts +163 -0
  40. package/corpus/core/src/review/types.ts +7 -0
  41. package/corpus/core/src/server/action-discovery.ts +4 -0
  42. package/corpus/core/src/server/activity-notifications.ts +174 -0
  43. package/corpus/core/src/server/app-name.ts +31 -0
  44. package/corpus/core/src/server/better-auth-instance.ts +4 -4
  45. package/corpus/core/src/server/email-templates.ts +70 -14
  46. package/corpus/core/src/server/email.ts +66 -3
  47. package/corpus/core/src/server/index.ts +10 -0
  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-29-meeting-notes-no-longer-transcribe-the-other-side-twice-when.md +6 -0
  109. package/corpus/templates/clips/changelog/2026-07-31-editor-timeline-now-shows-video-frames-behind-the-waveform-g.md +6 -0
  110. package/corpus/templates/clips/changelog/2026-07-31-email-notifications-now-go-out-when-someone-comments-on-or-r.md +6 -0
  111. package/corpus/templates/clips/changelog/2026-07-31-you-can-now-set-a-default-visibility-for-new-recordings-in-s.md +6 -0
  112. package/corpus/templates/clips/changelog/2026-08-01-email-notifications-for-comments-and-reactions-now-actually-.md +6 -0
  113. package/corpus/templates/clips/changelog/2026-08-03-the-desktop-app-now-opens-directly-beneath-its-tray-icon-on-.md +6 -0
  114. package/corpus/templates/clips/chrome-extension/package.json +1 -0
  115. package/corpus/templates/clips/chrome-extension/vitest.config.ts +9 -0
  116. package/corpus/templates/clips/desktop/package.json +1 -0
  117. package/corpus/templates/clips/desktop/src/app.tsx +17 -1
  118. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +37 -48
  119. package/corpus/templates/clips/desktop/src/lib/recorder.ts +331 -36
  120. package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +7 -5
  121. package/corpus/templates/clips/desktop/src/lib/transcription-engine.ts +182 -106
  122. package/corpus/templates/clips/desktop/src/lib/upload-recovery.ts +129 -0
  123. package/corpus/templates/clips/desktop/src/overlays/live-transcript.tsx +43 -14
  124. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +3 -3
  125. package/corpus/templates/clips/desktop/src-tauri/src/echo_guard.rs +443 -0
  126. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +1 -0
  127. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +815 -15
  128. package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +61 -11
  129. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +125 -16
  130. package/corpus/templates/clips/desktop/vitest.config.ts +9 -0
  131. package/corpus/templates/clips/server/db/schema.ts +17 -0
  132. package/corpus/templates/clips/server/jobs/media-verification.ts +4 -0
  133. package/corpus/templates/clips/server/lib/activity-notifications.ts +185 -0
  134. package/corpus/templates/clips/server/lib/recording-media-cleanup.ts +2 -0
  135. package/corpus/templates/clips/server/lib/recording-upload-state.ts +46 -9
  136. package/corpus/templates/clips/server/lib/recordings.ts +24 -0
  137. package/corpus/templates/clips/server/lib/resumable-session.ts +10 -4
  138. package/corpus/templates/clips/server/lib/transactional-email-templates.ts +109 -0
  139. package/corpus/templates/clips/server/lib/upload-interruption.ts +8 -0
  140. package/corpus/templates/clips/server/lib/upload-lease.ts +50 -4
  141. package/corpus/templates/clips/server/lib/video-filmstrip-sprite.ts +207 -0
  142. package/corpus/templates/clips/server/lib/video-remux.ts +13 -4
  143. package/corpus/templates/clips/server/plugins/db.ts +16 -0
  144. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +4 -0
  145. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +123 -36
  146. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +159 -29
  147. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/interrupt.post.ts +197 -0
  148. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/reset-chunks.post.ts +193 -39
  149. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/resume.get.ts +191 -12
  150. package/corpus/templates/clips/shared/clips-ai-prefs.ts +6 -0
  151. package/corpus/templates/clips/shared/feature-flags.ts +12 -0
  152. package/corpus/templates/clips/shared/recording-core.ts +4 -0
  153. package/corpus/templates/clips/vitest.config.ts +23 -19
  154. package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +6 -4
  155. package/corpus/templates/content/actions/_database-membership-lock.ts +25 -0
  156. package/corpus/templates/content/actions/_database-row-batch.ts +6 -2
  157. package/corpus/templates/content/actions/_database-source-utils.ts +289 -129
  158. package/corpus/templates/content/actions/_database-utils.ts +12 -3
  159. package/corpus/templates/content/actions/add-comment.ts +15 -1
  160. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +39 -21
  161. package/corpus/templates/content/actions/attach-content-database-source.ts +4 -1
  162. package/corpus/templates/content/actions/change-content-database-source-role.ts +3 -5
  163. package/corpus/templates/content/actions/duplicate-document-property.ts +59 -46
  164. package/corpus/templates/content/actions/execute-builder-source-execution.ts +77 -71
  165. package/corpus/templates/content/actions/list-documents.ts +1 -0
  166. package/corpus/templates/content/actions/materialize-builder-required-fields.ts +7 -0
  167. package/corpus/templates/content/actions/remove-database-items.ts +183 -0
  168. package/corpus/templates/content/actions/set-document-property.ts +57 -39
  169. package/corpus/templates/content/actions/sync-local-folder-source.ts +7 -0
  170. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +5 -2
  171. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +50 -1
  172. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +471 -329
  173. package/corpus/templates/content/app/components/editor/database/row-access.ts +45 -0
  174. package/corpus/templates/content/app/components/editor/database/shared.tsx +141 -38
  175. package/corpus/templates/content/app/components/ui/switch.tsx +1 -0
  176. package/corpus/templates/content/app/hooks/use-content-database.ts +2 -2
  177. package/corpus/templates/content/app/hooks/use-content-prefs.ts +55 -0
  178. package/corpus/templates/content/app/i18n-data.ts +170 -0
  179. package/corpus/templates/content/app/routes/_app.settings.tsx +47 -18
  180. package/corpus/templates/content/changelog/2026-07-30-breadcrumb-menus-now-hide-internal-system-pages.md +6 -0
  181. package/corpus/templates/content/changelog/2026-07-30-database-rows-can-now-be-removed-without-deleting-their-page.md +6 -0
  182. package/corpus/templates/content/changelog/2026-08-01-get-an-email-when-someone-comments-on-replies-in-or-mentions.md +6 -0
  183. package/corpus/templates/content/parity/eval-scenarios.ts +2 -2
  184. package/corpus/templates/content/parity/matrix.md +1 -1
  185. package/corpus/templates/content/parity/matrix.ts +4 -5
  186. package/corpus/templates/content/server/lib/comment-notifications.ts +146 -0
  187. package/corpus/templates/content/server/routes/_agent-native/content/user-prefs.get.ts +17 -0
  188. package/corpus/templates/content/server/routes/_agent-native/content/user-prefs.put.ts +36 -0
  189. package/corpus/templates/content/shared/api.ts +4 -0
  190. package/corpus/templates/content/shared/content-user-prefs.ts +11 -0
  191. package/corpus/templates/content/vitest.config.ts +20 -16
  192. package/corpus/templates/crm/app/routes/settings.tsx +14 -22
  193. package/corpus/templates/crm/vitest.config.ts +8 -4
  194. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +26 -11
  195. package/corpus/templates/design/actions/take-design-screenshot.ts +7 -0
  196. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +11 -3
  197. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +4 -1
  198. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +54 -17
  199. package/corpus/templates/design/app/components/design/design-canvas/local-runtime.ts +126 -0
  200. package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +2 -0
  201. package/corpus/templates/design/app/pages/Index.tsx +3 -1
  202. package/corpus/templates/design/app/pages/Present.tsx +2 -1
  203. package/corpus/templates/design/app/routes/settings.tsx +14 -22
  204. package/corpus/templates/design/changelog/2026-07-30-a-broken-inline-script-in-a-generated-screen-is-now-caught-o.md +6 -0
  205. package/corpus/templates/design/changelog/2026-07-30-design-html-is-now-validated-with-a-spec-grade-html-parser-i.md +6 -0
  206. package/corpus/templates/design/changelog/2026-07-30-designs-now-load-their-tailwind-and-alpine-runtimes-from-the.md +6 -0
  207. package/corpus/templates/design/changelog/2026-07-30-designs-with-a-broken-alpine-expression-are-now-caught-on-sa.md +6 -0
  208. package/corpus/templates/design/changelog/2026-07-30-editing-a-design-no-longer-strips-its-styling-the-canvas-kep.md +6 -0
  209. package/corpus/templates/design/changelog/2026-08-01-review-comments-replies-and-mentions-now-send-an-email-to-th.md +6 -0
  210. package/corpus/templates/design/package.json +4 -0
  211. package/corpus/templates/design/shared/html-integrity.ts +802 -556
  212. package/corpus/templates/design/vitest.config.ts +18 -12
  213. package/corpus/templates/dispatch/app/routes/settings.tsx +26 -40
  214. package/corpus/templates/dispatch/vitest.config.ts +11 -7
  215. package/corpus/templates/factory/app/routes/settings.tsx +14 -22
  216. package/corpus/templates/factory/vitest.config.ts +9 -0
  217. package/corpus/templates/forms/app/routes/_app.settings.tsx +14 -22
  218. package/corpus/templates/forms/vitest.config.ts +27 -23
  219. package/corpus/templates/macros/app/routes/settings.tsx +14 -22
  220. package/corpus/templates/macros/vitest.config.ts +16 -12
  221. package/corpus/templates/mail/app/pages/SettingsPage.tsx +14 -16
  222. package/corpus/templates/mail/vitest.config.ts +16 -12
  223. package/corpus/templates/plan/app/routes/settings.tsx +30 -44
  224. package/corpus/templates/plan/vitest.config.ts +24 -20
  225. package/corpus/templates/slides/actions/add-slide-comment.ts +12 -1
  226. package/corpus/templates/slides/app/components/ui/switch.tsx +1 -0
  227. package/corpus/templates/slides/app/hooks/use-slides-prefs.ts +55 -0
  228. package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
  229. package/corpus/templates/slides/app/routes/settings.tsx +45 -22
  230. package/corpus/templates/slides/changelog/2026-08-01-get-an-email-when-someone-comments-on-or-replies-in-your-dec.md +6 -0
  231. package/corpus/templates/slides/server/lib/comment-notifications.ts +182 -0
  232. package/corpus/templates/slides/server/routes/_agent-native/slides/user-prefs.get.ts +16 -0
  233. package/corpus/templates/slides/server/routes/_agent-native/slides/user-prefs.put.ts +36 -0
  234. package/corpus/templates/slides/shared/slides-user-prefs.ts +11 -0
  235. package/corpus/templates/slides/vitest.config.ts +17 -13
  236. package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +2 -0
  237. package/corpus/templates/tasks/app/routes/settings.tsx +14 -22
  238. package/corpus/templates/tasks/vitest.config.ts +17 -13
  239. package/corpus/toolkit/CHANGELOG.md +9 -0
  240. package/corpus/toolkit/package.json +1 -1
  241. package/corpus/toolkit/vitest.config.ts +3 -0
  242. package/dist/automations/service.d.ts +2 -0
  243. package/dist/automations/service.d.ts.map +1 -1
  244. package/dist/automations/service.js +29 -4
  245. package/dist/automations/service.js.map +1 -1
  246. package/dist/cli/mcp-config-writers.d.ts.map +1 -1
  247. package/dist/cli/mcp-config-writers.js +24 -23
  248. package/dist/cli/mcp-config-writers.js.map +1 -1
  249. package/dist/client/agent-page/AgentJobsTab.d.ts.map +1 -1
  250. package/dist/client/agent-page/AgentJobsTab.js +86 -29
  251. package/dist/client/agent-page/AgentJobsTab.js.map +1 -1
  252. package/dist/client/agent-page/AutomationDetailsDialog.d.ts +21 -0
  253. package/dist/client/agent-page/AutomationDetailsDialog.d.ts.map +1 -0
  254. package/dist/client/agent-page/AutomationDetailsDialog.js +33 -0
  255. package/dist/client/agent-page/AutomationDetailsDialog.js.map +1 -0
  256. package/dist/client/agent-page/AutomationScheduleDialog.d.ts +15 -0
  257. package/dist/client/agent-page/AutomationScheduleDialog.d.ts.map +1 -0
  258. package/dist/client/agent-page/AutomationScheduleDialog.js +46 -0
  259. package/dist/client/agent-page/AutomationScheduleDialog.js.map +1 -0
  260. package/dist/client/agent-page/TimezoneSelect.d.ts +17 -0
  261. package/dist/client/agent-page/TimezoneSelect.d.ts.map +1 -0
  262. package/dist/client/agent-page/TimezoneSelect.js +107 -0
  263. package/dist/client/agent-page/TimezoneSelect.js.map +1 -0
  264. package/dist/client/agent-page/use-jobs.d.ts +20 -7
  265. package/dist/client/agent-page/use-jobs.d.ts.map +1 -1
  266. package/dist/client/agent-page/use-jobs.js +24 -4
  267. package/dist/client/agent-page/use-jobs.js.map +1 -1
  268. package/dist/client/org/OrgSwitcher.d.ts +8 -1
  269. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  270. package/dist/client/org/OrgSwitcher.js +8 -2
  271. package/dist/client/org/OrgSwitcher.js.map +1 -1
  272. package/dist/client/settings/AccountSettingsCard.d.ts.map +1 -1
  273. package/dist/client/settings/AccountSettingsCard.js +10 -9
  274. package/dist/client/settings/AccountSettingsCard.js.map +1 -1
  275. package/dist/client/settings/SchedulingTimezoneField.d.ts +10 -0
  276. package/dist/client/settings/SchedulingTimezoneField.d.ts.map +1 -0
  277. package/dist/client/settings/SchedulingTimezoneField.js +30 -0
  278. package/dist/client/settings/SchedulingTimezoneField.js.map +1 -0
  279. package/dist/client/settings/SettingsRow.d.ts +36 -0
  280. package/dist/client/settings/SettingsRow.d.ts.map +1 -0
  281. package/dist/client/settings/SettingsRow.js +15 -0
  282. package/dist/client/settings/SettingsRow.js.map +1 -0
  283. package/dist/client/settings/agent-settings-search.d.ts.map +1 -1
  284. package/dist/client/settings/agent-settings-search.js +1 -1
  285. package/dist/client/settings/agent-settings-search.js.map +1 -1
  286. package/dist/client/settings/index.d.ts +1 -0
  287. package/dist/client/settings/index.d.ts.map +1 -1
  288. package/dist/client/settings/index.js +1 -0
  289. package/dist/client/settings/index.js.map +1 -1
  290. package/dist/collab/struct-routes.d.ts +1 -1
  291. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  292. package/dist/integrations/identity.d.ts.map +1 -1
  293. package/dist/integrations/identity.js +2 -11
  294. package/dist/integrations/identity.js.map +1 -1
  295. package/dist/jobs/actions/list-automation-runs.d.ts +8 -0
  296. package/dist/jobs/actions/list-automation-runs.d.ts.map +1 -0
  297. package/dist/jobs/actions/list-automation-runs.js +29 -0
  298. package/dist/jobs/actions/list-automation-runs.js.map +1 -0
  299. package/dist/jobs/actions/list-recurring-jobs.d.ts +2 -0
  300. package/dist/jobs/actions/list-recurring-jobs.d.ts.map +1 -1
  301. package/dist/jobs/actions/list-recurring-jobs.js +20 -7
  302. package/dist/jobs/actions/list-recurring-jobs.js.map +1 -1
  303. package/dist/jobs/actions/manage-recurring-job.d.ts +2 -0
  304. package/dist/jobs/actions/manage-recurring-job.js +30 -9
  305. package/dist/jobs/actions/manage-recurring-job.js.map +1 -1
  306. package/dist/jobs/background-automation-runner.d.ts.map +1 -1
  307. package/dist/jobs/background-automation-runner.js +60 -0
  308. package/dist/jobs/background-automation-runner.js.map +1 -1
  309. package/dist/jobs/cron.d.ts +16 -2
  310. package/dist/jobs/cron.d.ts.map +1 -1
  311. package/dist/jobs/cron.js +43 -6
  312. package/dist/jobs/cron.js.map +1 -1
  313. package/dist/jobs/frontmatter.d.ts +12 -0
  314. package/dist/jobs/frontmatter.d.ts.map +1 -1
  315. package/dist/jobs/frontmatter.js +8 -0
  316. package/dist/jobs/frontmatter.js.map +1 -1
  317. package/dist/jobs/run-history.d.ts +56 -0
  318. package/dist/jobs/run-history.d.ts.map +1 -0
  319. package/dist/jobs/run-history.js +169 -0
  320. package/dist/jobs/run-history.js.map +1 -0
  321. package/dist/jobs/scheduler.d.ts.map +1 -1
  322. package/dist/jobs/scheduler.js +51 -18
  323. package/dist/jobs/scheduler.js.map +1 -1
  324. package/dist/jobs/tools.d.ts.map +1 -1
  325. package/dist/jobs/tools.js +37 -6
  326. package/dist/jobs/tools.js.map +1 -1
  327. package/dist/localization/actions/get-localization-preference.d.ts +1 -2
  328. package/dist/localization/actions/get-localization-preference.d.ts.map +1 -1
  329. package/dist/localization/actions/get-localization-preference.js.map +1 -1
  330. package/dist/localization/actions/set-localization-preference.d.ts +3 -3
  331. package/dist/localization/actions/set-localization-preference.d.ts.map +1 -1
  332. package/dist/localization/actions/set-localization-preference.js +33 -8
  333. package/dist/localization/actions/set-localization-preference.js.map +1 -1
  334. package/dist/localization/default-messages.d.ts +25 -0
  335. package/dist/localization/default-messages.d.ts.map +1 -1
  336. package/dist/localization/default-messages.js +25 -0
  337. package/dist/localization/default-messages.js.map +1 -1
  338. package/dist/localization/shared.d.ts +16 -1
  339. package/dist/localization/shared.d.ts.map +1 -1
  340. package/dist/localization/shared.js +22 -4
  341. package/dist/localization/shared.js.map +1 -1
  342. package/dist/localization/user-timezone.d.ts +11 -0
  343. package/dist/localization/user-timezone.d.ts.map +1 -0
  344. package/dist/localization/user-timezone.js +31 -0
  345. package/dist/localization/user-timezone.js.map +1 -0
  346. package/dist/notifications/routes.d.ts +2 -2
  347. package/dist/observability/routes.d.ts +1 -1
  348. package/dist/org/app-roles-handlers.d.ts.map +1 -1
  349. package/dist/org/app-roles-handlers.js +1 -8
  350. package/dist/org/app-roles-handlers.js.map +1 -1
  351. package/dist/org/index.d.ts +1 -0
  352. package/dist/org/index.d.ts.map +1 -1
  353. package/dist/org/index.js +1 -0
  354. package/dist/org/index.js.map +1 -1
  355. package/dist/org/membership.d.ts +6 -0
  356. package/dist/org/membership.d.ts.map +1 -0
  357. package/dist/org/membership.js +16 -0
  358. package/dist/org/membership.js.map +1 -0
  359. package/dist/provider-api/actions/custom-provider-registration.d.ts +10 -10
  360. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  361. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  362. package/dist/resources/handlers.d.ts +1 -1
  363. package/dist/review/actions/create-review-comment.d.ts +32 -1
  364. package/dist/review/actions/create-review-comment.d.ts.map +1 -1
  365. package/dist/review/actions/create-review-comment.js +3 -1
  366. package/dist/review/actions/create-review-comment.js.map +1 -1
  367. package/dist/review/actions/reply-review-comment.d.ts +32 -1
  368. package/dist/review/actions/reply-review-comment.d.ts.map +1 -1
  369. package/dist/review/actions/reply-review-comment.js +3 -1
  370. package/dist/review/actions/reply-review-comment.js.map +1 -1
  371. package/dist/review/index.d.ts +1 -0
  372. package/dist/review/index.d.ts.map +1 -1
  373. package/dist/review/index.js +1 -0
  374. package/dist/review/index.js.map +1 -1
  375. package/dist/review/notifications.d.ts +24 -0
  376. package/dist/review/notifications.d.ts.map +1 -0
  377. package/dist/review/notifications.js +123 -0
  378. package/dist/review/notifications.js.map +1 -0
  379. package/dist/review/types.d.ts +5 -0
  380. package/dist/review/types.d.ts.map +1 -1
  381. package/dist/review/types.js.map +1 -1
  382. package/dist/server/action-discovery.d.ts.map +1 -1
  383. package/dist/server/action-discovery.js +4 -0
  384. package/dist/server/action-discovery.js.map +1 -1
  385. package/dist/server/activity-notifications.d.ts +61 -0
  386. package/dist/server/activity-notifications.d.ts.map +1 -0
  387. package/dist/server/activity-notifications.js +103 -0
  388. package/dist/server/activity-notifications.js.map +1 -0
  389. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  390. package/dist/server/app-name.d.ts +18 -0
  391. package/dist/server/app-name.d.ts.map +1 -1
  392. package/dist/server/app-name.js +31 -0
  393. package/dist/server/app-name.js.map +1 -1
  394. package/dist/server/better-auth-instance.js +4 -4
  395. package/dist/server/better-auth-instance.js.map +1 -1
  396. package/dist/server/email-templates.d.ts +12 -0
  397. package/dist/server/email-templates.d.ts.map +1 -1
  398. package/dist/server/email-templates.js +57 -14
  399. package/dist/server/email-templates.js.map +1 -1
  400. package/dist/server/email.d.ts +12 -0
  401. package/dist/server/email.d.ts.map +1 -1
  402. package/dist/server/email.js +52 -5
  403. package/dist/server/email.js.map +1 -1
  404. package/dist/server/index.d.ts +1 -0
  405. package/dist/server/index.d.ts.map +1 -1
  406. package/dist/server/index.js +1 -0
  407. package/dist/server/index.js.map +1 -1
  408. package/dist/sharing/index.d.ts +1 -0
  409. package/dist/sharing/index.d.ts.map +1 -1
  410. package/dist/sharing/index.js +1 -0
  411. package/dist/sharing/index.js.map +1 -1
  412. package/dist/sharing/recipients.d.ts +31 -0
  413. package/dist/sharing/recipients.d.ts.map +1 -0
  414. package/dist/sharing/recipients.js +40 -0
  415. package/dist/sharing/recipients.js.map +1 -0
  416. package/dist/templates/chat/app/routes/settings.tsx +14 -22
  417. package/dist/templates/chat/vitest.config.ts +9 -0
  418. package/dist/triggers/actions/list-automations.d.ts +2 -0
  419. package/dist/triggers/actions/list-automations.d.ts.map +1 -1
  420. package/dist/triggers/actions/list-automations.js +19 -8
  421. package/dist/triggers/actions/list-automations.js.map +1 -1
  422. package/dist/triggers/actions/manage-automation.d.ts +6 -0
  423. package/dist/triggers/actions/manage-automation.js +12 -6
  424. package/dist/triggers/actions/manage-automation.js.map +1 -1
  425. package/dist/triggers/actions.d.ts.map +1 -1
  426. package/dist/triggers/actions.js +15 -4
  427. package/dist/triggers/actions.js.map +1 -1
  428. package/dist/triggers/dispatcher.d.ts.map +1 -1
  429. package/dist/triggers/dispatcher.js +19 -17
  430. package/dist/triggers/dispatcher.js.map +1 -1
  431. package/dist/triggers/routes.d.ts.map +1 -1
  432. package/dist/triggers/routes.js +6 -6
  433. package/dist/triggers/routes.js.map +1 -1
  434. package/dist/vitest-config.d.ts +10 -0
  435. package/dist/vitest-config.d.ts.map +1 -0
  436. package/dist/vitest-config.js +55 -0
  437. package/dist/vitest-config.js.map +1 -0
  438. package/docs/content/template-content-developers.mdx +1 -1
  439. package/package.json +5 -4
  440. package/src/automations/service.ts +41 -4
  441. package/src/cli/mcp-config-writers.ts +27 -21
  442. package/src/client/agent-page/AgentJobsTab.tsx +187 -85
  443. package/src/client/agent-page/AutomationDetailsDialog.tsx +208 -0
  444. package/src/client/agent-page/AutomationScheduleDialog.tsx +180 -0
  445. package/src/client/agent-page/TimezoneSelect.tsx +241 -0
  446. package/src/client/agent-page/use-jobs.ts +50 -10
  447. package/src/client/org/OrgSwitcher.tsx +26 -0
  448. package/src/client/settings/AccountSettingsCard.tsx +35 -31
  449. package/src/client/settings/SchedulingTimezoneField.tsx +71 -0
  450. package/src/client/settings/SettingsRow.tsx +113 -0
  451. package/src/client/settings/agent-settings-search.ts +2 -1
  452. package/src/client/settings/index.ts +6 -0
  453. package/src/integrations/identity.ts +2 -12
  454. package/src/jobs/actions/list-automation-runs.ts +33 -0
  455. package/src/jobs/actions/list-recurring-jobs.ts +27 -6
  456. package/src/jobs/actions/manage-recurring-job.ts +41 -9
  457. package/src/jobs/background-automation-runner.ts +88 -0
  458. package/src/jobs/cron.ts +52 -6
  459. package/src/jobs/frontmatter.ts +20 -0
  460. package/src/jobs/run-history.ts +242 -0
  461. package/src/jobs/scheduler.ts +73 -18
  462. package/src/jobs/tools.ts +54 -6
  463. package/src/localization/actions/get-localization-preference.ts +2 -2
  464. package/src/localization/actions/set-localization-preference.ts +49 -11
  465. package/src/localization/default-messages.ts +27 -0
  466. package/src/localization/shared.ts +39 -6
  467. package/src/localization/user-timezone.ts +36 -0
  468. package/src/org/app-roles-handlers.ts +1 -9
  469. package/src/org/index.ts +2 -0
  470. package/src/org/membership.ts +18 -0
  471. package/src/review/actions/create-review-comment.ts +4 -1
  472. package/src/review/actions/reply-review-comment.ts +4 -1
  473. package/src/review/index.ts +5 -0
  474. package/src/review/notifications.ts +163 -0
  475. package/src/review/types.ts +7 -0
  476. package/src/server/action-discovery.ts +4 -0
  477. package/src/server/activity-notifications.ts +174 -0
  478. package/src/server/app-name.ts +31 -0
  479. package/src/server/better-auth-instance.ts +4 -4
  480. package/src/server/email-templates.ts +70 -14
  481. package/src/server/email.ts +66 -3
  482. package/src/server/index.ts +10 -0
  483. package/src/sharing/index.ts +5 -0
  484. package/src/sharing/recipients.ts +67 -0
  485. package/src/templates/chat/app/routes/settings.tsx +14 -22
  486. package/src/templates/chat/vitest.config.ts +9 -0
  487. package/src/triggers/actions/list-automations.ts +27 -8
  488. package/src/triggers/actions/manage-automation.ts +17 -6
  489. package/src/triggers/actions.ts +16 -4
  490. package/src/triggers/dispatcher.ts +44 -30
  491. package/src/triggers/routes.ts +19 -6
  492. package/src/vitest-config.ts +68 -0
  493. package/corpus/templates/content/actions/delete-database-items.ts +0 -89
@@ -4,5 +4,6 @@ export { SettingsTabsPage, } from "./SettingsTabsPage.js";
4
4
  export { AccountSettingsCard, AccountSettingsForm, } from "./AccountSettingsCard.js";
5
5
  export { openBuilderConnectPopup, useBuilderConnectFlow, useBuilderStatus, withBuilderConnectTrackingParams, } from "./useBuilderStatus.js";
6
6
  export { SecretsSection } from "./SecretsSection.js";
7
+ export { SettingsGroup, SettingsRow, } from "./SettingsRow.js";
7
8
  export { normalizeSettingsSection, settingsSectionDomId, useSettingsPanelController, } from "./useSettingsPanelController.js";
8
9
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/settings/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,aAAa,EACb,oBAAoB,GAGrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,0BAA0B,GAE3B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,gBAAgB,GAIjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GAGpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,gBAAgB,EAChB,gCAAgC,GAMjC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,cAAc,EAA4B,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,0BAA0B,GAG3B,MAAM,iCAAiC,CAAC","sourcesContent":["export {\n AgentSettingsContent,\n areExtensionSettingsEnabled,\n SettingsPanel,\n useAgentSettingsTabs,\n type AgentSettingsTabsOptions,\n type SettingsPanelProps,\n} from \"./SettingsPanel.js\";\nexport {\n getAgentSettingsSearchTabs,\n type AgentSettingsSearchTab,\n} from \"./agent-settings-search.js\";\nexport {\n SettingsTabsPage,\n type SettingsSearchEntry,\n type SettingsTabItem,\n type SettingsTabsPageProps,\n} from \"./SettingsTabsPage.js\";\nexport {\n AccountSettingsCard,\n AccountSettingsForm,\n type AccountSettingsCardProps,\n type AccountSettingsFormProps,\n} from \"./AccountSettingsCard.js\";\nexport {\n openBuilderConnectPopup,\n useBuilderConnectFlow,\n useBuilderStatus,\n withBuilderConnectTrackingParams,\n type BuilderConnectFlow,\n type BuilderConnectFlowOptions,\n type BuilderConnectStartOptions,\n type BuilderStatus,\n type OpenBuilderConnectPopupOptions,\n} from \"./useBuilderStatus.js\";\nexport { SecretsSection, type SecretsSectionProps } from \"./SecretsSection.js\";\nexport {\n normalizeSettingsSection,\n settingsSectionDomId,\n useSettingsPanelController,\n type SettingsPanelController,\n type SettingsPanelControllerOptions,\n} from \"./useSettingsPanelController.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/settings/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,aAAa,EACb,oBAAoB,GAGrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,0BAA0B,GAE3B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,gBAAgB,GAIjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GAGpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,gBAAgB,EAChB,gCAAgC,GAMjC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,cAAc,EAA4B,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EACL,aAAa,EACb,WAAW,GAGZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,0BAA0B,GAG3B,MAAM,iCAAiC,CAAC","sourcesContent":["export {\n AgentSettingsContent,\n areExtensionSettingsEnabled,\n SettingsPanel,\n useAgentSettingsTabs,\n type AgentSettingsTabsOptions,\n type SettingsPanelProps,\n} from \"./SettingsPanel.js\";\nexport {\n getAgentSettingsSearchTabs,\n type AgentSettingsSearchTab,\n} from \"./agent-settings-search.js\";\nexport {\n SettingsTabsPage,\n type SettingsSearchEntry,\n type SettingsTabItem,\n type SettingsTabsPageProps,\n} from \"./SettingsTabsPage.js\";\nexport {\n AccountSettingsCard,\n AccountSettingsForm,\n type AccountSettingsCardProps,\n type AccountSettingsFormProps,\n} from \"./AccountSettingsCard.js\";\nexport {\n openBuilderConnectPopup,\n useBuilderConnectFlow,\n useBuilderStatus,\n withBuilderConnectTrackingParams,\n type BuilderConnectFlow,\n type BuilderConnectFlowOptions,\n type BuilderConnectStartOptions,\n type BuilderStatus,\n type OpenBuilderConnectPopupOptions,\n} from \"./useBuilderStatus.js\";\nexport { SecretsSection, type SecretsSectionProps } from \"./SecretsSection.js\";\nexport {\n SettingsGroup,\n SettingsRow,\n type SettingsGroupProps,\n type SettingsRowProps,\n} from \"./SettingsRow.js\";\nexport {\n normalizeSettingsSection,\n settingsSectionDomId,\n useSettingsPanelController,\n type SettingsPanelController,\n type SettingsPanelControllerOptions,\n} from \"./useSettingsPanelController.js\";\n"]}
@@ -13,8 +13,8 @@
13
13
  * Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
14
14
  */
15
15
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
16
- ok?: undefined;
17
16
  error: string;
17
+ ok?: undefined;
18
18
  } | {
19
19
  error?: undefined;
20
20
  ok: boolean;
@@ -17,12 +17,12 @@ declare const _default: import("../../action.js").ActionDefinition<{
17
17
  id?: undefined;
18
18
  provider?: undefined;
19
19
  } | {
20
+ error?: undefined;
20
21
  configured?: undefined;
21
22
  connectPath?: undefined;
22
23
  url: string;
23
24
  id: string;
24
25
  provider: string;
25
- error?: undefined;
26
26
  }>;
27
27
  export default _default;
28
28
  //# sourceMappingURL=upload-image.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/integrations/identity.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAE/E,MAAM,MAAM,gCAAgC,GACxC,YAAY,GACZ,OAAO,GACP,oBAAoB,GACpB,yBAAyB,CAAC;AAE9B;;;;;GAKG;AACH,qBAAa,gCAAiC,SAAQ,KAAK;IACzD,QAAQ,CAAC,MAAM,EAAE,gCAAgC,CAAC;IAClD,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAEnC,YACE,MAAM,EAAE,gCAAgC,EACxC,OAAO,EAAE,MAAM,EACf,iBAAiB,EAAE,MAAM,EAM1B;CACF;AAmDD;;;;;;;;;;;;GAYG;AACH,wBAAsB,yCAAyC,CAC7D,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,2BAA2B,CAAC,CA8FtC"}
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/integrations/identity.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAE/E,MAAM,MAAM,gCAAgC,GACxC,YAAY,GACZ,OAAO,GACP,oBAAoB,GACpB,yBAAyB,CAAC;AAE9B;;;;;GAKG;AACH,qBAAa,gCAAiC,SAAQ,KAAK;IACzD,QAAQ,CAAC,MAAM,EAAE,gCAAgC,CAAC;IAClD,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAEnC,YACE,MAAM,EAAE,gCAAgC,EACxC,OAAO,EAAE,MAAM,EACf,iBAAiB,EAAE,MAAM,EAM1B;CACF;AAyCD;;;;;;;;;;;;GAYG;AACH,wBAAsB,yCAAyC,CAC7D,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,2BAA2B,CAAC,CA8FtC"}
@@ -1,4 +1,4 @@
1
- import { getDbExec } from "../db/client.js";
1
+ import { isOrgMember as isMemberOfOrg } from "../org/membership.js";
2
2
  import { upsertVerifiedIntegrationIdentity } from "./identity-links-store.js";
3
3
  import { getActiveIntegrationInstallationByKey, getActiveIntegrationInstallationForTenant, } from "./installations-store.js";
4
4
  import { slackInstallationKey } from "./slack-oauth.js";
@@ -48,15 +48,6 @@ async function resolveSlackInstallation(incoming) {
48
48
  ? getActiveIntegrationInstallationForTenant("slack", teamId ?? enterpriseId)
49
49
  : null;
50
50
  }
51
- async function isMemberOfOrg(email, orgId) {
52
- const { rows } = await getDbExec().execute({
53
- sql: `SELECT 1 FROM org_members
54
- WHERE org_id = ? AND LOWER(email) = ?
55
- LIMIT 1`,
56
- args: [orgId, email],
57
- });
58
- return rows.length > 0;
59
- }
60
51
  /**
61
52
  * Resolve the default integration principal.
62
53
  *
@@ -101,7 +92,7 @@ export async function resolveDefaultIntegrationExecutionContext(incoming) {
101
92
  incoming.senderId &&
102
93
  incoming.tenantId) {
103
94
  try {
104
- isOrgMember = await isMemberOfOrg(email, installation.orgId);
95
+ isOrgMember = await isMemberOfOrg(installation.orgId, email);
105
96
  }
106
97
  catch {
107
98
  // A membership-store outage is not evidence that the sender is merely
@@ -1 +1 @@
1
- {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/integrations/identity.ts"],"names":[],"mappings":"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","sourcesContent":["import { getDbExec } from \"../db/client.js\";\nimport { upsertVerifiedIntegrationIdentity } from \"./identity-links-store.js\";\nimport {\n getActiveIntegrationInstallationByKey,\n getActiveIntegrationInstallationForTenant,\n} from \"./installations-store.js\";\nimport { slackInstallationKey } from \"./slack-oauth.js\";\nimport type { IncomingMessage, IntegrationExecutionContext } from \"./types.js\";\n\nexport type IntegrationIdentityDeclineReason =\n | \"unverified\"\n | \"guest\"\n | \"unlinked-workspace\"\n | \"membership-check-failed\";\n\n/**\n * Thrown when the default Slack DM identity ladder declines to run a message.\n * `reason` is a stable machine-readable discriminator (used e.g. to dedupe\n * decline replies); `userFacingMessage` is safe to send back to the sender as\n * a polite reply; `message` stays log-only.\n */\nexport class IntegrationIdentityDeclinedError extends Error {\n readonly reason: IntegrationIdentityDeclineReason;\n readonly userFacingMessage: string;\n\n constructor(\n reason: IntegrationIdentityDeclineReason,\n message: string,\n userFacingMessage: string,\n ) {\n super(message);\n this.name = \"IntegrationIdentityDeclinedError\";\n this.reason = reason;\n this.userFacingMessage = userFacingMessage;\n }\n}\n\nfunction serviceOwner(platform: string): string {\n return `integration@${platform}`;\n}\n\nfunction normalizedEmail(value: unknown): string | null {\n if (typeof value !== \"string\") return null;\n const email = value.trim().toLowerCase();\n if (!email || email.length > 320 || !email.includes(\"@\")) return null;\n return email;\n}\n\nasync function resolveSlackInstallation(incoming: IncomingMessage) {\n const teamId =\n typeof incoming.platformContext.teamId === \"string\"\n ? incoming.platformContext.teamId\n : incoming.tenantId;\n const enterpriseId =\n typeof incoming.platformContext.enterpriseId === \"string\"\n ? incoming.platformContext.enterpriseId\n : undefined;\n const apiAppId =\n typeof incoming.platformContext.apiAppId === \"string\"\n ? incoming.platformContext.apiAppId\n : undefined;\n if (apiAppId && (teamId || enterpriseId)) {\n const byKey = await getActiveIntegrationInstallationByKey(\n \"slack\",\n slackInstallationKey({ teamId, enterpriseId, apiAppId }),\n );\n if (byKey) return byKey;\n }\n return teamId || enterpriseId\n ? getActiveIntegrationInstallationForTenant(\n \"slack\",\n teamId ?? enterpriseId!,\n )\n : null;\n}\n\nasync function isMemberOfOrg(email: string, orgId: string): Promise<boolean> {\n const { rows } = await getDbExec().execute({\n sql: `SELECT 1 FROM org_members\n WHERE org_id = ? AND LOWER(email) = ?\n LIMIT 1`,\n args: [orgId, email],\n });\n return rows.length > 0;\n}\n\n/**\n * Resolve the default integration principal.\n *\n * Slack DMs become a user principal only after the adapter has verified the\n * sender email and the email is already a member of the managed installation's\n * Agent Native organization. Hydrated full workspace members whose email is\n * missing, unverified, or not an organization member run as an anonymous\n * org-scoped service principal instead — the same visibility shared channels\n * get. Hydration failures, guests/external members, and workspaces without a\n * connected organization are declined with a user-facing message. Shared\n * channels deliberately stay service-scoped so a channel message cannot borrow\n * one participant's private permissions.\n */\nexport async function resolveDefaultIntegrationExecutionContext(\n incoming: IncomingMessage,\n): Promise<IntegrationExecutionContext> {\n const installation =\n incoming.platform === \"slack\"\n ? await resolveSlackInstallation(incoming)\n : null;\n\n if (incoming.platform !== \"slack\" || incoming.conversationType !== \"dm\") {\n return {\n ownerEmail: serviceOwner(incoming.platform),\n orgId: installation?.orgId ?? null,\n principalType: \"service\",\n ...(installation?.id ? { installationId: installation.id } : {}),\n };\n }\n\n // Hydration check first: a transient users.info failure must land on the\n // retry decline here, never on the anonymous org-scoped tier below.\n if (incoming.actorTrust?.verified !== true) {\n throw new IntegrationIdentityDeclinedError(\n \"unverified\",\n \"Slack DM sender identity could not be hydrated; declining instead of guessing a principal.\",\n \"I couldn't verify your Slack identity just now, so I can't run this request. Please try again in a moment.\",\n );\n }\n if (\n incoming.actorTrust.memberType === \"guest\" ||\n incoming.actorTrust.memberType === \"external\"\n ) {\n throw new IntegrationIdentityDeclinedError(\n \"guest\",\n \"External or guest Slack members cannot use this integration.\",\n \"This assistant is only available to members of this workspace's organization.\",\n );\n }\n if (!installation?.orgId) {\n throw new IntegrationIdentityDeclinedError(\n \"unlinked-workspace\",\n \"Slack workspace is not connected to an Agent Native organization.\",\n \"This Slack workspace isn't connected to an organization yet.\",\n );\n }\n\n const email = normalizedEmail(incoming.senderEmail);\n let isOrgMember = false;\n if (\n email &&\n incoming.senderVerified === true &&\n incoming.senderId &&\n incoming.tenantId\n ) {\n try {\n isOrgMember = await isMemberOfOrg(email, installation.orgId);\n } catch {\n // A membership-store outage is not evidence that the sender is merely\n // unlinked. Fail closed instead of widening them to org-wide access.\n throw new IntegrationIdentityDeclinedError(\n \"membership-check-failed\",\n \"Slack DM organization membership could not be verified.\",\n \"I couldn't verify your organization membership just now, so I can't run this request. Please try again in a moment.\",\n );\n }\n }\n if (isOrgMember && email && incoming.senderId && incoming.tenantId) {\n const link = await upsertVerifiedIntegrationIdentity({\n platform: incoming.platform,\n tenantId: incoming.tenantId,\n externalUserId: incoming.senderId,\n userEmail: email,\n orgId: installation.orgId,\n });\n return {\n ownerEmail: link.userEmail,\n orgId: link.orgId,\n principalType: \"user\",\n installationId: installation.id,\n };\n }\n\n // Hydrated full workspace member (member/admin/owner) whose email is\n // unverified, missing (legacy install without users:read.email), or not an\n // organization member: run with the anonymous org-scoped service principal —\n // the same visibility shared channels get. Nothing user-private is\n // accessible. One structured line keeps 100%-anonymous workspaces (legacy\n // scope missing) visible in logs.\n console.warn(\n `[integrations] anonymous org-scoped principal used: platform=${incoming.platform} teamId=${incoming.tenantId ?? \"unknown\"} emailPresent=${Boolean(email)} memberType=${incoming.actorTrust.memberType}`,\n );\n return {\n ownerEmail: serviceOwner(incoming.platform),\n orgId: installation.orgId,\n principalType: \"service\",\n installationId: installation.id,\n anonymousMember: true,\n };\n}\n"]}
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/integrations/identity.ts"],"names":[],"mappings":"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","sourcesContent":["import { isOrgMember as isMemberOfOrg } from \"../org/membership.js\";\nimport { upsertVerifiedIntegrationIdentity } from \"./identity-links-store.js\";\nimport {\n getActiveIntegrationInstallationByKey,\n getActiveIntegrationInstallationForTenant,\n} from \"./installations-store.js\";\nimport { slackInstallationKey } from \"./slack-oauth.js\";\nimport type { IncomingMessage, IntegrationExecutionContext } from \"./types.js\";\n\nexport type IntegrationIdentityDeclineReason =\n | \"unverified\"\n | \"guest\"\n | \"unlinked-workspace\"\n | \"membership-check-failed\";\n\n/**\n * Thrown when the default Slack DM identity ladder declines to run a message.\n * `reason` is a stable machine-readable discriminator (used e.g. to dedupe\n * decline replies); `userFacingMessage` is safe to send back to the sender as\n * a polite reply; `message` stays log-only.\n */\nexport class IntegrationIdentityDeclinedError extends Error {\n readonly reason: IntegrationIdentityDeclineReason;\n readonly userFacingMessage: string;\n\n constructor(\n reason: IntegrationIdentityDeclineReason,\n message: string,\n userFacingMessage: string,\n ) {\n super(message);\n this.name = \"IntegrationIdentityDeclinedError\";\n this.reason = reason;\n this.userFacingMessage = userFacingMessage;\n }\n}\n\nfunction serviceOwner(platform: string): string {\n return `integration@${platform}`;\n}\n\nfunction normalizedEmail(value: unknown): string | null {\n if (typeof value !== \"string\") return null;\n const email = value.trim().toLowerCase();\n if (!email || email.length > 320 || !email.includes(\"@\")) return null;\n return email;\n}\n\nasync function resolveSlackInstallation(incoming: IncomingMessage) {\n const teamId =\n typeof incoming.platformContext.teamId === \"string\"\n ? incoming.platformContext.teamId\n : incoming.tenantId;\n const enterpriseId =\n typeof incoming.platformContext.enterpriseId === \"string\"\n ? incoming.platformContext.enterpriseId\n : undefined;\n const apiAppId =\n typeof incoming.platformContext.apiAppId === \"string\"\n ? incoming.platformContext.apiAppId\n : undefined;\n if (apiAppId && (teamId || enterpriseId)) {\n const byKey = await getActiveIntegrationInstallationByKey(\n \"slack\",\n slackInstallationKey({ teamId, enterpriseId, apiAppId }),\n );\n if (byKey) return byKey;\n }\n return teamId || enterpriseId\n ? getActiveIntegrationInstallationForTenant(\n \"slack\",\n teamId ?? enterpriseId!,\n )\n : null;\n}\n\n/**\n * Resolve the default integration principal.\n *\n * Slack DMs become a user principal only after the adapter has verified the\n * sender email and the email is already a member of the managed installation's\n * Agent Native organization. Hydrated full workspace members whose email is\n * missing, unverified, or not an organization member run as an anonymous\n * org-scoped service principal instead — the same visibility shared channels\n * get. Hydration failures, guests/external members, and workspaces without a\n * connected organization are declined with a user-facing message. Shared\n * channels deliberately stay service-scoped so a channel message cannot borrow\n * one participant's private permissions.\n */\nexport async function resolveDefaultIntegrationExecutionContext(\n incoming: IncomingMessage,\n): Promise<IntegrationExecutionContext> {\n const installation =\n incoming.platform === \"slack\"\n ? await resolveSlackInstallation(incoming)\n : null;\n\n if (incoming.platform !== \"slack\" || incoming.conversationType !== \"dm\") {\n return {\n ownerEmail: serviceOwner(incoming.platform),\n orgId: installation?.orgId ?? null,\n principalType: \"service\",\n ...(installation?.id ? { installationId: installation.id } : {}),\n };\n }\n\n // Hydration check first: a transient users.info failure must land on the\n // retry decline here, never on the anonymous org-scoped tier below.\n if (incoming.actorTrust?.verified !== true) {\n throw new IntegrationIdentityDeclinedError(\n \"unverified\",\n \"Slack DM sender identity could not be hydrated; declining instead of guessing a principal.\",\n \"I couldn't verify your Slack identity just now, so I can't run this request. Please try again in a moment.\",\n );\n }\n if (\n incoming.actorTrust.memberType === \"guest\" ||\n incoming.actorTrust.memberType === \"external\"\n ) {\n throw new IntegrationIdentityDeclinedError(\n \"guest\",\n \"External or guest Slack members cannot use this integration.\",\n \"This assistant is only available to members of this workspace's organization.\",\n );\n }\n if (!installation?.orgId) {\n throw new IntegrationIdentityDeclinedError(\n \"unlinked-workspace\",\n \"Slack workspace is not connected to an Agent Native organization.\",\n \"This Slack workspace isn't connected to an organization yet.\",\n );\n }\n\n const email = normalizedEmail(incoming.senderEmail);\n let isOrgMember = false;\n if (\n email &&\n incoming.senderVerified === true &&\n incoming.senderId &&\n incoming.tenantId\n ) {\n try {\n isOrgMember = await isMemberOfOrg(installation.orgId, email);\n } catch {\n // A membership-store outage is not evidence that the sender is merely\n // unlinked. Fail closed instead of widening them to org-wide access.\n throw new IntegrationIdentityDeclinedError(\n \"membership-check-failed\",\n \"Slack DM organization membership could not be verified.\",\n \"I couldn't verify your organization membership just now, so I can't run this request. Please try again in a moment.\",\n );\n }\n }\n if (isOrgMember && email && incoming.senderId && incoming.tenantId) {\n const link = await upsertVerifiedIntegrationIdentity({\n platform: incoming.platform,\n tenantId: incoming.tenantId,\n externalUserId: incoming.senderId,\n userEmail: email,\n orgId: installation.orgId,\n });\n return {\n ownerEmail: link.userEmail,\n orgId: link.orgId,\n principalType: \"user\",\n installationId: installation.id,\n };\n }\n\n // Hydrated full workspace member (member/admin/owner) whose email is\n // unverified, missing (legacy install without users:read.email), or not an\n // organization member: run with the anonymous org-scoped service principal —\n // the same visibility shared channels get. Nothing user-private is\n // accessible. One structured line keeps 100%-anonymous workspaces (legacy\n // scope missing) visible in logs.\n console.warn(\n `[integrations] anonymous org-scoped principal used: platform=${incoming.platform} teamId=${incoming.tenantId ?? \"unknown\"} emailPresent=${Boolean(email)} memberType=${incoming.actorTrust.memberType}`,\n );\n return {\n ownerEmail: serviceOwner(incoming.platform),\n orgId: installation.orgId,\n principalType: \"service\",\n installationId: installation.id,\n anonymousMember: true,\n };\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import { type AutomationRun } from "../run-history.js";
2
+ declare const _default: import("../../action.js").ActionDefinition<{
3
+ name: string;
4
+ scope?: "organization" | "personal";
5
+ limit?: number;
6
+ }, AutomationRun[]>;
7
+ export default _default;
8
+ //# sourceMappingURL=list-automation-runs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-automation-runs.d.ts","sourceRoot":"","sources":["../../../src/jobs/actions/list-automation-runs.ts"],"names":[],"mappings":"AAIA,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ import { defineAction } from "../../action.js";
3
+ import { organizationResourceOwner } from "../../resources/store.js";
4
+ import { listAutomationRuns } from "../run-history.js";
5
+ const scopeSchema = z.enum(["personal", "organization"]);
6
+ export default defineAction({
7
+ description: "List past execution records for one automation or recurring job in the selected scope.",
8
+ agentTool: false,
9
+ schema: z.object({
10
+ name: z.string().min(1),
11
+ scope: scopeSchema.default("personal"),
12
+ limit: z.number().int().min(1).max(100).optional(),
13
+ }),
14
+ http: { method: "GET" },
15
+ readOnly: true,
16
+ parallelSafe: true,
17
+ run: async ({ name, scope, limit }, ctx) => {
18
+ const userEmail = ctx?.userEmail;
19
+ if (!userEmail)
20
+ throw new Error("Not authenticated.");
21
+ if (scope === "organization" && !ctx?.orgId)
22
+ return [];
23
+ const owner = scope === "organization"
24
+ ? organizationResourceOwner(ctx.orgId)
25
+ : userEmail;
26
+ return listAutomationRuns({ owners: [owner], automation: name, limit });
27
+ },
28
+ });
29
+ //# sourceMappingURL=list-automation-runs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-automation-runs.js","sourceRoot":"","sources":["../../../src/jobs/actions/list-automation-runs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAsB,MAAM,mBAAmB,CAAC;AAE3E,MAAM,WAAW,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC;AAEzD,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,wFAAwF;IAC1F,SAAS,EAAE,KAAK;IAChB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACvB,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC;QACtC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;KACnD,CAAC;IACF,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;IACvB,QAAQ,EAAE,IAAI;IACd,YAAY,EAAE,IAAI;IAClB,GAAG,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,GAAG,EAA4B,EAAE;QACnE,MAAM,SAAS,GAAG,GAAG,EAAE,SAAS,CAAC;QACjC,IAAI,CAAC,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACtD,IAAI,KAAK,KAAK,cAAc,IAAI,CAAC,GAAG,EAAE,KAAK;YAAE,OAAO,EAAE,CAAC;QAEvD,MAAM,KAAK,GACT,KAAK,KAAK,cAAc;YACtB,CAAC,CAAC,yBAAyB,CAAC,GAAG,CAAC,KAAe,CAAC;YAChD,CAAC,CAAC,SAAS,CAAC;QAEhB,OAAO,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1E,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { z } from \"zod\";\n\nimport { defineAction } from \"../../action.js\";\nimport { organizationResourceOwner } from \"../../resources/store.js\";\nimport { listAutomationRuns, type AutomationRun } from \"../run-history.js\";\n\nconst scopeSchema = z.enum([\"personal\", \"organization\"]);\n\nexport default defineAction({\n description:\n \"List past execution records for one automation or recurring job in the selected scope.\",\n agentTool: false,\n schema: z.object({\n name: z.string().min(1),\n scope: scopeSchema.default(\"personal\"),\n limit: z.number().int().min(1).max(100).optional(),\n }),\n http: { method: \"GET\" },\n readOnly: true,\n parallelSafe: true,\n run: async ({ name, scope, limit }, ctx): Promise<AutomationRun[]> => {\n const userEmail = ctx?.userEmail;\n if (!userEmail) throw new Error(\"Not authenticated.\");\n if (scope === \"organization\" && !ctx?.orgId) return [];\n\n const owner =\n scope === \"organization\"\n ? organizationResourceOwner(ctx.orgId as string)\n : userEmail;\n\n return listAutomationRuns({ owners: [owner], automation: name, limit });\n },\n});\n"]}
@@ -4,10 +4,12 @@ export interface RecurringJobActionItem {
4
4
  path: string;
5
5
  scope: "personal" | "organization";
6
6
  schedule: string;
7
+ timezone: string;
7
8
  scheduleDescription: string;
8
9
  instructions: string;
9
10
  enabled: boolean;
10
11
  lastRun: string | null;
12
+ lastCheck: string | null;
11
13
  lastStatus: string | null;
12
14
  lastError: string | null;
13
15
  nextRun: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"list-recurring-jobs.d.ts","sourceRoot":"","sources":["../../../src/jobs/actions/list-recurring-jobs.ts"],"names":[],"mappings":"AA8BA,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,UAAU,GAAG,cAAc,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;CACpB"}
1
+ {"version":3,"file":"list-recurring-jobs.d.ts","sourceRoot":"","sources":["../../../src/jobs/actions/list-recurring-jobs.ts"],"names":[],"mappings":"AA6CA,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,UAAU,GAAG,cAAc,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;CACpB"}
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { defineAction } from "../../action.js";
3
3
  import { organizationResourceOwner, resourceGetByPath, resourceList, } from "../../resources/store.js";
4
- import { describeCron, isValidCron, nextOccurrence } from "../cron.js";
4
+ import { describeCron, effectiveTimezone, isValidCron, nextOccurrence, } from "../cron.js";
5
5
  import { classifyJobResource } from "../frontmatter.js";
6
6
  import { parseJobFrontmatter } from "../scheduler.js";
7
7
  import { authorizeJobMutation } from "../tools.js";
@@ -9,15 +9,24 @@ const scopeSchema = z.enum(["personal", "organization"]);
9
9
  function jobName(path) {
10
10
  return path.replace(/^jobs\//, "").replace(/\.md$/, "");
11
11
  }
12
+ /**
13
+ * A stored `nextRun` in the past means the scheduler kept declining to run the
14
+ * job, not that it is due two days ago. Report the real next occurrence and
15
+ * let `lastError` carry the reason it keeps being passed over.
16
+ */
12
17
  function nextRun(meta) {
13
18
  if (!meta.enabled)
14
19
  return null;
15
- if (meta.nextRun)
16
- return meta.nextRun;
17
- if (meta.schedule && isValidCron(meta.schedule)) {
18
- return nextOccurrence(meta.schedule).toISOString();
20
+ const scheduled = Boolean(meta.schedule && isValidCron(meta.schedule));
21
+ if (meta.nextRun) {
22
+ const stored = new Date(meta.nextRun).getTime();
23
+ if (!Number.isFinite(stored) || stored > Date.now() || !scheduled) {
24
+ return meta.nextRun;
25
+ }
19
26
  }
20
- return null;
27
+ return scheduled
28
+ ? nextOccurrence(meta.schedule, undefined, meta.timezone).toISOString()
29
+ : null;
21
30
  }
22
31
  export default defineAction({
23
32
  description: "List legacy recurring cron jobs visible in the selected personal or organization scope. This compatibility read surface is used by the Agent Automations page.",
@@ -55,10 +64,14 @@ export default defineAction({
55
64
  path: full.path,
56
65
  scope,
57
66
  schedule: meta.schedule,
58
- scheduleDescription: meta.schedule ? describeCron(meta.schedule) : "",
67
+ timezone: effectiveTimezone(meta.timezone),
68
+ scheduleDescription: meta.schedule
69
+ ? describeCron(meta.schedule, effectiveTimezone(meta.timezone))
70
+ : "",
59
71
  instructions: body,
60
72
  enabled: meta.enabled,
61
73
  lastRun: meta.lastRun ?? null,
74
+ lastCheck: meta.lastCheck ?? null,
62
75
  lastStatus: meta.lastStatus ?? null,
63
76
  lastError: meta.lastError ?? null,
64
77
  nextRun: nextRun(meta),
@@ -1 +1 @@
1
- {"version":3,"file":"list-recurring-jobs.js","sourceRoot":"","sources":["../../../src/jobs/actions/list-recurring-jobs.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\n\nimport { defineAction } from \"../../action.js\";\nimport {\n organizationResourceOwner,\n resourceGetByPath,\n resourceList,\n} from \"../../resources/store.js\";\nimport { describeCron, isValidCron, nextOccurrence } from \"../cron.js\";\nimport { classifyJobResource } from \"../frontmatter.js\";\nimport { parseJobFrontmatter } from \"../scheduler.js\";\nimport { authorizeJobMutation } from \"../tools.js\";\n\nconst scopeSchema = z.enum([\"personal\", \"organization\"]);\n\nfunction jobName(path: string): string {\n return path.replace(/^jobs\\//, \"\").replace(/\\.md$/, \"\");\n}\n\nfunction nextRun(\n meta: ReturnType<typeof parseJobFrontmatter>[\"meta\"],\n): string | null {\n if (!meta.enabled) return null;\n if (meta.nextRun) return meta.nextRun;\n if (meta.schedule && isValidCron(meta.schedule)) {\n return nextOccurrence(meta.schedule).toISOString();\n }\n return null;\n}\n\nexport interface RecurringJobActionItem {\n id: string;\n name: string;\n path: string;\n scope: \"personal\" | \"organization\";\n schedule: string;\n scheduleDescription: string;\n instructions: string;\n enabled: boolean;\n lastRun: string | null;\n lastStatus: string | null;\n lastError: string | null;\n nextRun: string | null;\n createdBy: string | null;\n mcpTools: string[];\n canUpdate: boolean;\n}\n\nexport default defineAction({\n description:\n \"List legacy recurring cron jobs visible in the selected personal or organization scope. This compatibility read surface is used by the Agent Automations page.\",\n agentTool: false,\n schema: z.object({\n scope: scopeSchema.default(\"personal\"),\n }),\n http: { method: \"GET\" },\n readOnly: true,\n parallelSafe: true,\n run: async ({ scope }, ctx): Promise<RecurringJobActionItem[]> => {\n const userEmail = ctx?.userEmail;\n if (!userEmail) throw new Error(\"Not authenticated.\");\n\n if (scope === \"organization\" && !ctx?.orgId) return [];\n\n const owner =\n scope === \"organization\"\n ? organizationResourceOwner(ctx.orgId as string)\n : userEmail;\n const resources = await resourceList(owner, \"jobs/\");\n const jobs: RecurringJobActionItem[] = [];\n\n for (const resource of resources) {\n if (!resource.path.endsWith(\".md\") || resource.path.endsWith(\".keep\")) {\n continue;\n }\n const full = await resourceGetByPath(owner, resource.path);\n if (!full || classifyJobResource(full.content).kind === \"automation\") {\n continue;\n }\n\n const { meta, body } = parseJobFrontmatter(full.content);\n const canUpdate =\n scope === \"personal\" || !(await authorizeJobMutation(owner, meta));\n jobs.push({\n id: full.id,\n name: jobName(full.path),\n path: full.path,\n scope,\n schedule: meta.schedule,\n scheduleDescription: meta.schedule ? describeCron(meta.schedule) : \"\",\n instructions: body,\n enabled: meta.enabled,\n lastRun: meta.lastRun ?? null,\n lastStatus: meta.lastStatus ?? null,\n lastError: meta.lastError ?? null,\n nextRun: nextRun(meta),\n createdBy: meta.createdBy ?? null,\n mcpTools: meta.mcpTools ?? [],\n canUpdate,\n });\n }\n\n return jobs;\n },\n});\n"]}
1
+ {"version":3,"file":"list-recurring-jobs.js","sourceRoot":"","sources":["../../../src/jobs/actions/list-recurring-jobs.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\n\nimport { defineAction } from \"../../action.js\";\nimport {\n organizationResourceOwner,\n resourceGetByPath,\n resourceList,\n} from \"../../resources/store.js\";\nimport {\n describeCron,\n effectiveTimezone,\n isValidCron,\n nextOccurrence,\n} from \"../cron.js\";\nimport { classifyJobResource } from \"../frontmatter.js\";\nimport { parseJobFrontmatter } from \"../scheduler.js\";\nimport { authorizeJobMutation } from \"../tools.js\";\n\nconst scopeSchema = z.enum([\"personal\", \"organization\"]);\n\nfunction jobName(path: string): string {\n return path.replace(/^jobs\\//, \"\").replace(/\\.md$/, \"\");\n}\n\n/**\n * A stored `nextRun` in the past means the scheduler kept declining to run the\n * job, not that it is due two days ago. Report the real next occurrence and\n * let `lastError` carry the reason it keeps being passed over.\n */\nfunction nextRun(\n meta: ReturnType<typeof parseJobFrontmatter>[\"meta\"],\n): string | null {\n if (!meta.enabled) return null;\n const scheduled = Boolean(meta.schedule && isValidCron(meta.schedule));\n if (meta.nextRun) {\n const stored = new Date(meta.nextRun).getTime();\n if (!Number.isFinite(stored) || stored > Date.now() || !scheduled) {\n return meta.nextRun;\n }\n }\n return scheduled\n ? nextOccurrence(meta.schedule, undefined, meta.timezone).toISOString()\n : null;\n}\n\nexport interface RecurringJobActionItem {\n id: string;\n name: string;\n path: string;\n scope: \"personal\" | \"organization\";\n schedule: string;\n timezone: string;\n scheduleDescription: string;\n instructions: string;\n enabled: boolean;\n lastRun: string | null;\n lastCheck: string | null;\n lastStatus: string | null;\n lastError: string | null;\n nextRun: string | null;\n createdBy: string | null;\n mcpTools: string[];\n canUpdate: boolean;\n}\n\nexport default defineAction({\n description:\n \"List legacy recurring cron jobs visible in the selected personal or organization scope. This compatibility read surface is used by the Agent Automations page.\",\n agentTool: false,\n schema: z.object({\n scope: scopeSchema.default(\"personal\"),\n }),\n http: { method: \"GET\" },\n readOnly: true,\n parallelSafe: true,\n run: async ({ scope }, ctx): Promise<RecurringJobActionItem[]> => {\n const userEmail = ctx?.userEmail;\n if (!userEmail) throw new Error(\"Not authenticated.\");\n\n if (scope === \"organization\" && !ctx?.orgId) return [];\n\n const owner =\n scope === \"organization\"\n ? organizationResourceOwner(ctx.orgId as string)\n : userEmail;\n const resources = await resourceList(owner, \"jobs/\");\n const jobs: RecurringJobActionItem[] = [];\n\n for (const resource of resources) {\n if (!resource.path.endsWith(\".md\") || resource.path.endsWith(\".keep\")) {\n continue;\n }\n const full = await resourceGetByPath(owner, resource.path);\n if (!full || classifyJobResource(full.content).kind === \"automation\") {\n continue;\n }\n\n const { meta, body } = parseJobFrontmatter(full.content);\n const canUpdate =\n scope === \"personal\" || !(await authorizeJobMutation(owner, meta));\n jobs.push({\n id: full.id,\n name: jobName(full.path),\n path: full.path,\n scope,\n schedule: meta.schedule,\n timezone: effectiveTimezone(meta.timezone),\n scheduleDescription: meta.schedule\n ? describeCron(meta.schedule, effectiveTimezone(meta.timezone))\n : \"\",\n instructions: body,\n enabled: meta.enabled,\n lastRun: meta.lastRun ?? null,\n lastCheck: meta.lastCheck ?? null,\n lastStatus: meta.lastStatus ?? null,\n lastError: meta.lastError ?? null,\n nextRun: nextRun(meta),\n createdBy: meta.createdBy ?? null,\n mcpTools: meta.mcpTools ?? [],\n canUpdate,\n });\n }\n\n return jobs;\n },\n});\n"]}
@@ -3,6 +3,8 @@ declare const _default: import("../../action.js").ActionDefinition<{
3
3
  name: string;
4
4
  scope?: "organization" | "personal";
5
5
  enabled?: boolean;
6
+ schedule?: string;
7
+ timezone?: string;
6
8
  }, {
7
9
  deleted: boolean;
8
10
  name: string;
@@ -1,8 +1,9 @@
1
1
  import { z } from "zod";
2
2
  import { defineAction } from "../../action.js";
3
3
  import { organizationResourceOwner, resourceDelete, resourceGetByPath, resourcePut, } from "../../resources/store.js";
4
- import { isValidCron, nextOccurrence } from "../cron.js";
4
+ import { isValidCron, isValidTimezone, nextOccurrence } from "../cron.js";
5
5
  import { classifyJobResource } from "../frontmatter.js";
6
+ import { deleteAutomationRuns } from "../run-history.js";
6
7
  import { buildJobContent, parseJobFrontmatter } from "../scheduler.js";
7
8
  import { authorizeJobMutation } from "../tools.js";
8
9
  const scopeSchema = z.enum(["personal", "organization"]);
@@ -14,8 +15,10 @@ export default defineAction({
14
15
  name: z.string().min(1),
15
16
  scope: scopeSchema.default("personal"),
16
17
  enabled: z.boolean().optional(),
18
+ schedule: z.string().min(1).optional(),
19
+ timezone: z.string().min(1).optional(),
17
20
  }),
18
- run: async ({ operation, name, scope, enabled }, ctx) => {
21
+ run: async ({ operation, name, scope, enabled, schedule, timezone }, ctx) => {
19
22
  const userEmail = ctx?.userEmail;
20
23
  if (!userEmail)
21
24
  throw new Error("Not authenticated.");
@@ -43,16 +46,34 @@ export default defineAction({
43
46
  throw Object.assign(new Error(denied), { statusCode: 403 });
44
47
  if (operation === "delete") {
45
48
  await resourceDelete(resource.id);
49
+ // Names are reusable; history left behind would surface as the run
50
+ // history of whatever job is next created under this name.
51
+ await deleteAutomationRuns(resource.owner, name);
46
52
  return { deleted: true, name };
47
53
  }
48
- if (enabled === undefined) {
49
- throw Object.assign(new Error("enabled is required for update."), {
50
- statusCode: 400,
51
- });
54
+ if (timezone !== undefined) {
55
+ if (!isValidTimezone(timezone)) {
56
+ throw Object.assign(new Error(`Unknown timezone "${timezone}".`), {
57
+ statusCode: 400,
58
+ });
59
+ }
60
+ meta.timezone = timezone;
61
+ }
62
+ if (enabled === undefined &&
63
+ schedule === undefined &&
64
+ timezone === undefined) {
65
+ throw Object.assign(new Error("enabled, schedule, or timezone is required for update."), { statusCode: 400 });
66
+ }
67
+ if (schedule !== undefined) {
68
+ if (!isValidCron(schedule)) {
69
+ throw Object.assign(new Error(`Invalid cron expression "${schedule}".`), { statusCode: 400 });
70
+ }
71
+ meta.schedule = schedule;
52
72
  }
53
- meta.enabled = enabled;
54
- if (enabled && meta.schedule && isValidCron(meta.schedule)) {
55
- meta.nextRun = nextOccurrence(meta.schedule).toISOString();
73
+ if (enabled !== undefined)
74
+ meta.enabled = enabled;
75
+ if (meta.enabled && meta.schedule && isValidCron(meta.schedule)) {
76
+ meta.nextRun = nextOccurrence(meta.schedule, undefined, meta.timezone).toISOString();
56
77
  }
57
78
  await resourcePut(resource.owner, resource.path, buildJobContent(meta, body));
58
79
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"manage-recurring-job.js","sourceRoot":"","sources":["../../../src/jobs/actions/manage-recurring-job.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\n\nimport { defineAction } from \"../../action.js\";\nimport {\n organizationResourceOwner,\n resourceDelete,\n resourceGetByPath,\n resourcePut,\n} from \"../../resources/store.js\";\nimport { isValidCron, nextOccurrence } from \"../cron.js\";\nimport { classifyJobResource } from \"../frontmatter.js\";\nimport { buildJobContent, parseJobFrontmatter } from \"../scheduler.js\";\nimport { authorizeJobMutation } from \"../tools.js\";\n\nconst scopeSchema = z.enum([\"personal\", \"organization\"]);\n\nexport default defineAction({\n description:\n \"Enable, pause, or delete one legacy recurring cron job from the Agent Automations page.\",\n agentTool: false,\n schema: z.object({\n operation: z.enum([\"update\", \"delete\"]),\n name: z.string().min(1),\n scope: scopeSchema.default(\"personal\"),\n enabled: z.boolean().optional(),\n }),\n run: async ({ operation, name, scope, enabled }, ctx) => {\n const userEmail = ctx?.userEmail;\n if (!userEmail) throw new Error(\"Not authenticated.\");\n if (scope === \"organization\" && !ctx?.orgId) {\n throw new Error(\"An organization is required for organization jobs.\");\n }\n\n const owner =\n scope === \"organization\"\n ? organizationResourceOwner(ctx.orgId as string)\n : userEmail;\n const path = `jobs/${name}.md`;\n const resource = await resourceGetByPath(owner, path);\n if (!resource) {\n throw Object.assign(new Error(`Job \"${name}\" not found.`), {\n statusCode: 404,\n });\n }\n\n const { meta, body } = parseJobFrontmatter(resource.content);\n if (classifyJobResource(resource.content).kind === \"automation\") {\n throw Object.assign(new Error(`Job \"${name}\" is an automation.`), {\n statusCode: 400,\n });\n }\n const denied = await authorizeJobMutation(resource.owner, meta);\n if (denied) throw Object.assign(new Error(denied), { statusCode: 403 });\n\n if (operation === \"delete\") {\n await resourceDelete(resource.id);\n return { deleted: true, name };\n }\n\n if (enabled === undefined) {\n throw Object.assign(new Error(\"enabled is required for update.\"), {\n statusCode: 400,\n });\n }\n meta.enabled = enabled;\n if (enabled && meta.schedule && isValidCron(meta.schedule)) {\n meta.nextRun = nextOccurrence(meta.schedule).toISOString();\n }\n await resourcePut(\n resource.owner,\n resource.path,\n buildJobContent(meta, body),\n );\n\n return {\n name,\n enabled: meta.enabled,\n nextRun: meta.nextRun ?? null,\n };\n },\n});\n"]}
1
+ {"version":3,"file":"manage-recurring-job.js","sourceRoot":"","sources":["../../../src/jobs/actions/manage-recurring-job.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\n\nimport { defineAction } from \"../../action.js\";\nimport {\n organizationResourceOwner,\n resourceDelete,\n resourceGetByPath,\n resourcePut,\n} from \"../../resources/store.js\";\nimport { isValidCron, isValidTimezone, nextOccurrence } from \"../cron.js\";\nimport { classifyJobResource } from \"../frontmatter.js\";\nimport { deleteAutomationRuns } from \"../run-history.js\";\nimport { buildJobContent, parseJobFrontmatter } from \"../scheduler.js\";\nimport { authorizeJobMutation } from \"../tools.js\";\n\nconst scopeSchema = z.enum([\"personal\", \"organization\"]);\n\nexport default defineAction({\n description:\n \"Enable, pause, or delete one legacy recurring cron job from the Agent Automations page.\",\n agentTool: false,\n schema: z.object({\n operation: z.enum([\"update\", \"delete\"]),\n name: z.string().min(1),\n scope: scopeSchema.default(\"personal\"),\n enabled: z.boolean().optional(),\n schedule: z.string().min(1).optional(),\n timezone: z.string().min(1).optional(),\n }),\n run: async ({ operation, name, scope, enabled, schedule, timezone }, ctx) => {\n const userEmail = ctx?.userEmail;\n if (!userEmail) throw new Error(\"Not authenticated.\");\n if (scope === \"organization\" && !ctx?.orgId) {\n throw new Error(\"An organization is required for organization jobs.\");\n }\n\n const owner =\n scope === \"organization\"\n ? organizationResourceOwner(ctx.orgId as string)\n : userEmail;\n const path = `jobs/${name}.md`;\n const resource = await resourceGetByPath(owner, path);\n if (!resource) {\n throw Object.assign(new Error(`Job \"${name}\" not found.`), {\n statusCode: 404,\n });\n }\n\n const { meta, body } = parseJobFrontmatter(resource.content);\n if (classifyJobResource(resource.content).kind === \"automation\") {\n throw Object.assign(new Error(`Job \"${name}\" is an automation.`), {\n statusCode: 400,\n });\n }\n const denied = await authorizeJobMutation(resource.owner, meta);\n if (denied) throw Object.assign(new Error(denied), { statusCode: 403 });\n\n if (operation === \"delete\") {\n await resourceDelete(resource.id);\n // Names are reusable; history left behind would surface as the run\n // history of whatever job is next created under this name.\n await deleteAutomationRuns(resource.owner, name);\n return { deleted: true, name };\n }\n\n if (timezone !== undefined) {\n if (!isValidTimezone(timezone)) {\n throw Object.assign(new Error(`Unknown timezone \"${timezone}\".`), {\n statusCode: 400,\n });\n }\n meta.timezone = timezone;\n }\n if (\n enabled === undefined &&\n schedule === undefined &&\n timezone === undefined\n ) {\n throw Object.assign(\n new Error(\"enabled, schedule, or timezone is required for update.\"),\n { statusCode: 400 },\n );\n }\n if (schedule !== undefined) {\n if (!isValidCron(schedule)) {\n throw Object.assign(\n new Error(`Invalid cron expression \"${schedule}\".`),\n { statusCode: 400 },\n );\n }\n meta.schedule = schedule;\n }\n if (enabled !== undefined) meta.enabled = enabled;\n if (meta.enabled && meta.schedule && isValidCron(meta.schedule)) {\n meta.nextRun = nextOccurrence(\n meta.schedule,\n undefined,\n meta.timezone,\n ).toISOString();\n }\n await resourcePut(\n resource.owner,\n resource.path,\n buildJobContent(meta, body),\n );\n\n return {\n name,\n enabled: meta.enabled,\n nextRun: meta.nextRun ?? null,\n };\n },\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"background-automation-runner.d.ts","sourceRoot":"","sources":["../../src/jobs/background-automation-runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"background-automation-runner.d.ts","sourceRoot":"","sources":["../../src/jobs/background-automation-runner.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,7 @@ import { createThread } from "../chat-threads/store.js";
10
10
  import { queryOrgMembers } from "../org/context.js";
11
11
  import { organizationIdFromResourceOwner, } from "../resources/store.js";
12
12
  import { runWithRequestContext, } from "../server/request-context.js";
13
+ import { attachAutomationRunThread, finishAutomationRun, startAutomationRun, } from "./run-history.js";
13
14
  const BACKGROUND_RUN_STUCK_MS = 10 * 60_000;
14
15
  const BACKGROUND_RUN_HARD_TIMEOUT_MS = 5 * 60_000;
15
16
  /**
@@ -146,6 +147,64 @@ function createRunId(prefix) {
146
147
  return `${safePrefix}-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
147
148
  }
148
149
  export async function runBackgroundAutomation(options, deps) {
150
+ const { automation } = options;
151
+ // Bookkeeping, so it must not gate the work it describes: a history table
152
+ // that cannot be written should cost us the record, not the automation.
153
+ // Everything downstream tolerates a null id by skipping its own write.
154
+ let historyId = null;
155
+ try {
156
+ historyId = await startAutomationRun({
157
+ owner: automation.resource.owner,
158
+ automation: automation.name,
159
+ path: automation.resource.path,
160
+ scope: organizationIdFromResourceOwner(automation.resource.owner)
161
+ ? "organization"
162
+ : "personal",
163
+ orgId: options.orgId ?? null,
164
+ });
165
+ }
166
+ catch (err) {
167
+ console.error(`[automations] Could not open a history record for "${automation.name}"; running anyway:`, err);
168
+ }
169
+ let result;
170
+ try {
171
+ result = await executeBackgroundAutomation(options, deps, historyId);
172
+ }
173
+ catch (err) {
174
+ await recordRunOutcome(historyId, "error", err instanceof Error ? err.message : String(err));
175
+ throw err;
176
+ }
177
+ // Outside the try: history is bookkeeping about the run, so a failure to
178
+ // write it must not turn a completed automation into a reported failure.
179
+ await recordRunOutcome(historyId, "success");
180
+ return result;
181
+ }
182
+ /**
183
+ * Link the run to its agent thread. Bookkeeping again: the automation is
184
+ * already executing by this point, so a failed write costs the cross-reference
185
+ * in the history view, not the run.
186
+ */
187
+ async function recordRunThread(historyId, threadId, runId) {
188
+ if (!historyId)
189
+ return;
190
+ try {
191
+ await attachAutomationRunThread(historyId, threadId, runId);
192
+ }
193
+ catch (err) {
194
+ console.error(`[automations] Could not attach thread ${threadId} to run ${historyId}:`, err);
195
+ }
196
+ }
197
+ async function recordRunOutcome(historyId, status, error) {
198
+ if (!historyId)
199
+ return;
200
+ try {
201
+ await finishAutomationRun(historyId, status, error);
202
+ }
203
+ catch (err) {
204
+ console.error(`[automations] Could not record run ${historyId} as ${status}:`, err);
205
+ }
206
+ }
207
+ async function executeBackgroundAutomation(options, deps, historyId) {
149
208
  const { automation, ownerEmail, orgId, prompt, threadTitle, usageLabel } = options;
150
209
  return runWithRequestContext({
151
210
  ...options.requestContext,
@@ -180,6 +239,7 @@ export async function runBackgroundAutomation(options, deps) {
180
239
  const systemPrompt = await deps.getSystemPrompt(ownerEmail);
181
240
  const thread = await createThread(ownerEmail, { title: threadTitle });
182
241
  const runId = createRunId(options.runIdPrefix);
242
+ await recordRunThread(historyId, thread.id, runId);
183
243
  // Scheduled work is background work: it has no synchronous serverless
184
244
  // caller waiting on it, so it must not inherit the interactive clamp
185
245
  // (40s soft timeout, a 30s no-progress backstop at 0.75x that, and 6