@agent-native/core 0.134.1 → 0.135.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +3 -3
- package/corpus/core/CHANGELOG.md +113 -0
- package/corpus/core/package.json +3 -2
- package/corpus/core/src/automations/service.ts +41 -4
- package/corpus/core/src/cli/mcp-config-writers.ts +27 -21
- package/corpus/core/src/client/agent-page/AgentJobsTab.tsx +187 -85
- package/corpus/core/src/client/agent-page/AutomationDetailsDialog.tsx +208 -0
- package/corpus/core/src/client/agent-page/AutomationScheduleDialog.tsx +180 -0
- package/corpus/core/src/client/agent-page/TimezoneSelect.tsx +241 -0
- package/corpus/core/src/client/agent-page/use-jobs.ts +50 -10
- package/corpus/core/src/client/org/OrgSwitcher.tsx +26 -0
- package/corpus/core/src/client/settings/AccountSettingsCard.tsx +35 -31
- package/corpus/core/src/client/settings/SchedulingTimezoneField.tsx +71 -0
- package/corpus/core/src/client/settings/SettingsRow.tsx +113 -0
- package/corpus/core/src/client/settings/agent-settings-search.ts +2 -1
- package/corpus/core/src/client/settings/index.ts +6 -0
- package/corpus/core/src/integrations/identity.ts +2 -12
- package/corpus/core/src/jobs/actions/list-automation-runs.ts +33 -0
- package/corpus/core/src/jobs/actions/list-recurring-jobs.ts +27 -6
- package/corpus/core/src/jobs/actions/manage-recurring-job.ts +41 -9
- package/corpus/core/src/jobs/background-automation-runner.ts +88 -0
- package/corpus/core/src/jobs/cron.ts +52 -6
- package/corpus/core/src/jobs/frontmatter.ts +20 -0
- package/corpus/core/src/jobs/run-history.ts +242 -0
- package/corpus/core/src/jobs/scheduler.ts +73 -18
- package/corpus/core/src/jobs/tools.ts +54 -6
- package/corpus/core/src/localization/actions/get-localization-preference.ts +2 -2
- package/corpus/core/src/localization/actions/set-localization-preference.ts +49 -11
- package/corpus/core/src/localization/default-messages.ts +27 -0
- package/corpus/core/src/localization/shared.ts +39 -6
- package/corpus/core/src/localization/user-timezone.ts +36 -0
- package/corpus/core/src/org/app-roles-handlers.ts +1 -9
- package/corpus/core/src/org/index.ts +2 -0
- package/corpus/core/src/org/membership.ts +18 -0
- package/corpus/core/src/review/actions/create-review-comment.ts +4 -1
- package/corpus/core/src/review/actions/reply-review-comment.ts +4 -1
- package/corpus/core/src/review/index.ts +5 -0
- package/corpus/core/src/review/notifications.ts +163 -0
- package/corpus/core/src/review/types.ts +7 -0
- package/corpus/core/src/server/action-discovery.ts +4 -0
- package/corpus/core/src/server/activity-notifications.ts +174 -0
- package/corpus/core/src/server/app-name.ts +31 -0
- package/corpus/core/src/server/better-auth-instance.ts +4 -4
- package/corpus/core/src/server/email-templates.ts +70 -14
- package/corpus/core/src/server/email.ts +66 -3
- package/corpus/core/src/server/index.ts +10 -0
- package/corpus/core/src/sharing/access.ts +44 -2
- package/corpus/core/src/sharing/index.ts +5 -0
- package/corpus/core/src/sharing/recipients.ts +67 -0
- package/corpus/core/src/triggers/actions/list-automations.ts +27 -8
- package/corpus/core/src/triggers/actions/manage-automation.ts +17 -6
- package/corpus/core/src/triggers/actions.ts +16 -4
- package/corpus/core/src/triggers/dispatcher.ts +44 -30
- package/corpus/core/src/triggers/routes.ts +19 -6
- package/corpus/core/src/vitest-config.ts +68 -0
- package/corpus/core/vitest.config.ts +5 -0
- package/corpus/templates/analytics/app/pages/Settings.tsx +37 -53
- package/corpus/templates/analytics/changelog/2026-08-01-new-error-alerts-now-reach-you-by-email-and-a-scheduled-dash.md +6 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +43 -0
- package/corpus/templates/analytics/server/lib/error-capture.ts +5 -1
- package/corpus/templates/analytics/vitest.config.ts +16 -12
- package/corpus/templates/assets/actions/refresh-generation-run.ts +3 -0
- package/corpus/templates/assets/app/components/ui/switch.tsx +1 -0
- package/corpus/templates/assets/app/hooks/use-assets-prefs.ts +55 -0
- package/corpus/templates/assets/app/i18n-data.ts +30 -0
- package/corpus/templates/assets/app/routes/settings.tsx +58 -55
- package/corpus/templates/assets/changelog/2026-08-01-get-an-email-when-a-generation-you-started-finishes-or-fails.md +6 -0
- package/corpus/templates/assets/server/lib/generation-run-notifications.ts +89 -0
- package/corpus/templates/assets/server/lib/video-runs.ts +8 -1
- package/corpus/templates/assets/server/routes/_agent-native/assets/user-prefs.get.ts +17 -0
- package/corpus/templates/assets/server/routes/_agent-native/assets/user-prefs.put.ts +36 -0
- package/corpus/templates/assets/shared/assets-user-prefs.ts +10 -0
- package/corpus/templates/assets/vitest.config.ts +16 -12
- package/corpus/templates/brain/app/routes/settings.tsx +15 -15
- package/corpus/templates/brain/vitest.config.ts +16 -12
- package/corpus/templates/calendar/app/pages/Settings.tsx +32 -40
- package/corpus/templates/calendar/changelog/2026-08-01-language-and-appearance-now-sit-together-in-one-preferences-.md +6 -0
- package/corpus/templates/calendar/vitest.config.ts +16 -12
- package/corpus/templates/chat/app/routes/settings.tsx +14 -22
- package/corpus/templates/chat/vitest.config.ts +9 -0
- package/corpus/templates/clips/.agents/skills/video-editing/SKILL.md +31 -0
- package/corpus/templates/clips/AGENTS.md +1 -0
- package/corpus/templates/clips/actions/add-comment.ts +12 -1
- package/corpus/templates/clips/actions/create-meeting.ts +2 -2
- package/corpus/templates/clips/actions/create-recording.ts +2 -2
- package/corpus/templates/clips/actions/finalize-recording.ts +42 -6
- package/corpus/templates/clips/actions/generate-filmstrip.ts +154 -0
- package/corpus/templates/clips/actions/get-recording-player-data.ts +6 -0
- package/corpus/templates/clips/actions/import-loom-recording.ts +2 -2
- package/corpus/templates/clips/actions/lib/ensure-recording-filmstrip.ts +258 -0
- package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +11 -3
- package/corpus/templates/clips/actions/react-to-comment.ts +13 -0
- package/corpus/templates/clips/actions/react-to-recording.ts +10 -1
- package/corpus/templates/clips/actions/reply-to-comment.ts +12 -1
- package/corpus/templates/clips/actions/stitch-recordings.ts +2 -2
- package/corpus/templates/clips/app/components/editor/editor-layout.tsx +152 -23
- package/corpus/templates/clips/app/components/editor/waveform.tsx +237 -75
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +23 -1
- package/corpus/templates/clips/app/components/settings/ai-setup-section.tsx +441 -0
- package/corpus/templates/clips/app/components/settings/slack-section.tsx +329 -0
- package/corpus/templates/clips/app/components/settings/types.ts +14 -0
- package/corpus/templates/clips/app/components/settings/video-storage-section.tsx +443 -0
- package/corpus/templates/clips/app/hooks/use-secret-status.ts +69 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +9 -1
- package/corpus/templates/clips/app/lib/video-filmstrip.ts +262 -0
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +165 -1351
- package/corpus/templates/clips/changelog/2026-07-27-saved-clips-now-resume-from-the-last-uploaded-byte-after-an-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-31-editor-timeline-now-shows-video-frames-behind-the-waveform-g.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-31-email-notifications-now-go-out-when-someone-comments-on-or-r.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-31-you-can-now-set-a-default-visibility-for-new-recordings-in-s.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-01-email-notifications-for-comments-and-reactions-now-actually-.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-03-the-desktop-app-now-opens-directly-beneath-its-tray-icon-on-.md +6 -0
- package/corpus/templates/clips/chrome-extension/package.json +1 -0
- package/corpus/templates/clips/chrome-extension/vitest.config.ts +9 -0
- package/corpus/templates/clips/desktop/package.json +1 -0
- package/corpus/templates/clips/desktop/src/app.tsx +17 -1
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +331 -36
- package/corpus/templates/clips/desktop/src/lib/upload-recovery.ts +129 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +815 -15
- package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +61 -11
- package/corpus/templates/clips/desktop/vitest.config.ts +9 -0
- package/corpus/templates/clips/server/db/schema.ts +17 -0
- package/corpus/templates/clips/server/jobs/media-verification.ts +4 -0
- package/corpus/templates/clips/server/lib/activity-notifications.ts +185 -0
- package/corpus/templates/clips/server/lib/recording-media-cleanup.ts +2 -0
- package/corpus/templates/clips/server/lib/recording-upload-state.ts +46 -9
- package/corpus/templates/clips/server/lib/recordings.ts +24 -0
- package/corpus/templates/clips/server/lib/resumable-session.ts +10 -4
- package/corpus/templates/clips/server/lib/transactional-email-templates.ts +109 -0
- package/corpus/templates/clips/server/lib/upload-interruption.ts +8 -0
- package/corpus/templates/clips/server/lib/upload-lease.ts +50 -4
- package/corpus/templates/clips/server/lib/video-filmstrip-sprite.ts +207 -0
- package/corpus/templates/clips/server/lib/video-remux.ts +13 -4
- package/corpus/templates/clips/server/plugins/db.ts +16 -0
- package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +4 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +123 -36
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +159 -29
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/interrupt.post.ts +197 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/reset-chunks.post.ts +193 -39
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/resume.get.ts +191 -12
- package/corpus/templates/clips/shared/clips-ai-prefs.ts +6 -0
- package/corpus/templates/clips/shared/feature-flags.ts +12 -0
- package/corpus/templates/clips/shared/recording-core.ts +4 -0
- package/corpus/templates/clips/vitest.config.ts +23 -19
- package/corpus/templates/content/actions/_database-utils.ts +113 -4
- package/corpus/templates/content/actions/add-comment.ts +15 -1
- package/corpus/templates/content/actions/get-document.ts +84 -3
- package/corpus/templates/content/actions/list-documents.ts +1 -0
- package/corpus/templates/content/app/components/editor/BuilderBodySyncingNotice.tsx +9 -2
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +34 -15
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +55 -13
- package/corpus/templates/content/app/components/editor/body-hydration.ts +12 -6
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +2 -3
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +5 -12
- package/corpus/templates/content/app/components/ui/switch.tsx +1 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +16 -27
- package/corpus/templates/content/app/hooks/use-content-prefs.ts +55 -0
- package/corpus/templates/content/app/hooks/use-create-page.ts +3 -6
- package/corpus/templates/content/app/hooks/use-document-properties.ts +9 -16
- package/corpus/templates/content/app/hooks/use-document-versions.ts +3 -3
- package/corpus/templates/content/app/hooks/use-documents.ts +85 -29
- package/corpus/templates/content/app/hooks/use-notion.ts +15 -13
- package/corpus/templates/content/app/i18n-data.ts +72 -1
- package/corpus/templates/content/app/lib/document-query.ts +36 -0
- package/corpus/templates/content/app/routes/_app.settings.tsx +47 -18
- package/corpus/templates/content/changelog/2026-07-30-breadcrumb-menus-now-hide-internal-system-pages.md +6 -0
- package/corpus/templates/content/changelog/2026-08-01-get-an-email-when-someone-comments-on-replies-in-or-mentions.md +6 -0
- package/corpus/templates/content/changelog/2026-08-02-pages-opened-from-a-database-now-keep-that-database-s-fields.md +6 -0
- package/corpus/templates/content/server/lib/comment-notifications.ts +146 -0
- package/corpus/templates/content/server/lib/document-context.ts +11 -6
- package/corpus/templates/content/server/routes/_agent-native/content/user-prefs.get.ts +17 -0
- package/corpus/templates/content/server/routes/_agent-native/content/user-prefs.put.ts +36 -0
- package/corpus/templates/content/shared/api.ts +8 -0
- package/corpus/templates/content/shared/content-user-prefs.ts +11 -0
- package/corpus/templates/content/vitest.config.ts +20 -16
- package/corpus/templates/crm/app/routes/settings.tsx +14 -22
- package/corpus/templates/crm/vitest.config.ts +8 -4
- package/corpus/templates/design/app/routes/settings.tsx +14 -22
- package/corpus/templates/design/changelog/2026-08-01-review-comments-replies-and-mentions-now-send-an-email-to-th.md +6 -0
- package/corpus/templates/design/vitest.config.ts +18 -12
- package/corpus/templates/dispatch/app/routes/settings.tsx +26 -40
- package/corpus/templates/dispatch/vitest.config.ts +11 -7
- package/corpus/templates/factory/app/routes/settings.tsx +14 -22
- package/corpus/templates/factory/vitest.config.ts +9 -0
- package/corpus/templates/forms/app/routes/_app.settings.tsx +14 -22
- package/corpus/templates/forms/vitest.config.ts +27 -23
- package/corpus/templates/macros/app/routes/settings.tsx +14 -22
- package/corpus/templates/macros/vitest.config.ts +16 -12
- package/corpus/templates/mail/app/pages/SettingsPage.tsx +14 -16
- package/corpus/templates/mail/vitest.config.ts +16 -12
- package/corpus/templates/plan/app/routes/settings.tsx +30 -44
- package/corpus/templates/plan/vitest.config.ts +24 -20
- package/corpus/templates/slides/actions/add-slide-comment.ts +12 -1
- package/corpus/templates/slides/app/components/ui/switch.tsx +1 -0
- package/corpus/templates/slides/app/hooks/use-slides-prefs.ts +55 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
- package/corpus/templates/slides/app/routes/settings.tsx +45 -22
- package/corpus/templates/slides/changelog/2026-08-01-get-an-email-when-someone-comments-on-or-replies-in-your-dec.md +6 -0
- package/corpus/templates/slides/server/lib/comment-notifications.ts +182 -0
- package/corpus/templates/slides/server/routes/_agent-native/slides/user-prefs.get.ts +16 -0
- package/corpus/templates/slides/server/routes/_agent-native/slides/user-prefs.put.ts +36 -0
- package/corpus/templates/slides/shared/slides-user-prefs.ts +11 -0
- package/corpus/templates/slides/vitest.config.ts +17 -13
- package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +2 -0
- package/corpus/templates/tasks/app/routes/settings.tsx +14 -22
- package/corpus/templates/tasks/vitest.config.ts +17 -13
- package/corpus/toolkit/CHANGELOG.md +9 -0
- package/corpus/toolkit/package.json +1 -1
- package/corpus/toolkit/vitest.config.ts +3 -0
- package/dist/automations/service.d.ts +2 -0
- package/dist/automations/service.d.ts.map +1 -1
- package/dist/automations/service.js +29 -4
- package/dist/automations/service.js.map +1 -1
- package/dist/cli/mcp-config-writers.d.ts.map +1 -1
- package/dist/cli/mcp-config-writers.js +24 -23
- package/dist/cli/mcp-config-writers.js.map +1 -1
- package/dist/client/agent-page/AgentJobsTab.d.ts.map +1 -1
- package/dist/client/agent-page/AgentJobsTab.js +86 -29
- package/dist/client/agent-page/AgentJobsTab.js.map +1 -1
- package/dist/client/agent-page/AutomationDetailsDialog.d.ts +21 -0
- package/dist/client/agent-page/AutomationDetailsDialog.d.ts.map +1 -0
- package/dist/client/agent-page/AutomationDetailsDialog.js +33 -0
- package/dist/client/agent-page/AutomationDetailsDialog.js.map +1 -0
- package/dist/client/agent-page/AutomationScheduleDialog.d.ts +15 -0
- package/dist/client/agent-page/AutomationScheduleDialog.d.ts.map +1 -0
- package/dist/client/agent-page/AutomationScheduleDialog.js +46 -0
- package/dist/client/agent-page/AutomationScheduleDialog.js.map +1 -0
- package/dist/client/agent-page/TimezoneSelect.d.ts +17 -0
- package/dist/client/agent-page/TimezoneSelect.d.ts.map +1 -0
- package/dist/client/agent-page/TimezoneSelect.js +107 -0
- package/dist/client/agent-page/TimezoneSelect.js.map +1 -0
- package/dist/client/agent-page/use-jobs.d.ts +20 -7
- package/dist/client/agent-page/use-jobs.d.ts.map +1 -1
- package/dist/client/agent-page/use-jobs.js +24 -4
- package/dist/client/agent-page/use-jobs.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts +8 -1
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +8 -2
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/settings/AccountSettingsCard.d.ts.map +1 -1
- package/dist/client/settings/AccountSettingsCard.js +10 -9
- package/dist/client/settings/AccountSettingsCard.js.map +1 -1
- package/dist/client/settings/SchedulingTimezoneField.d.ts +10 -0
- package/dist/client/settings/SchedulingTimezoneField.d.ts.map +1 -0
- package/dist/client/settings/SchedulingTimezoneField.js +30 -0
- package/dist/client/settings/SchedulingTimezoneField.js.map +1 -0
- package/dist/client/settings/SettingsRow.d.ts +36 -0
- package/dist/client/settings/SettingsRow.d.ts.map +1 -0
- package/dist/client/settings/SettingsRow.js +15 -0
- package/dist/client/settings/SettingsRow.js.map +1 -0
- package/dist/client/settings/agent-settings-search.d.ts.map +1 -1
- package/dist/client/settings/agent-settings-search.js +1 -1
- package/dist/client/settings/agent-settings-search.js.map +1 -1
- package/dist/client/settings/index.d.ts +1 -0
- package/dist/client/settings/index.d.ts.map +1 -1
- package/dist/client/settings/index.js +1 -0
- package/dist/client/settings/index.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/integrations/identity.d.ts.map +1 -1
- package/dist/integrations/identity.js +2 -11
- package/dist/integrations/identity.js.map +1 -1
- package/dist/jobs/actions/list-automation-runs.d.ts +8 -0
- package/dist/jobs/actions/list-automation-runs.d.ts.map +1 -0
- package/dist/jobs/actions/list-automation-runs.js +29 -0
- package/dist/jobs/actions/list-automation-runs.js.map +1 -0
- package/dist/jobs/actions/list-recurring-jobs.d.ts +2 -0
- package/dist/jobs/actions/list-recurring-jobs.d.ts.map +1 -1
- package/dist/jobs/actions/list-recurring-jobs.js +20 -7
- package/dist/jobs/actions/list-recurring-jobs.js.map +1 -1
- package/dist/jobs/actions/manage-recurring-job.d.ts +2 -0
- package/dist/jobs/actions/manage-recurring-job.js +30 -9
- package/dist/jobs/actions/manage-recurring-job.js.map +1 -1
- package/dist/jobs/background-automation-runner.d.ts.map +1 -1
- package/dist/jobs/background-automation-runner.js +60 -0
- package/dist/jobs/background-automation-runner.js.map +1 -1
- package/dist/jobs/cron.d.ts +16 -2
- package/dist/jobs/cron.d.ts.map +1 -1
- package/dist/jobs/cron.js +43 -6
- package/dist/jobs/cron.js.map +1 -1
- package/dist/jobs/frontmatter.d.ts +12 -0
- package/dist/jobs/frontmatter.d.ts.map +1 -1
- package/dist/jobs/frontmatter.js +8 -0
- package/dist/jobs/frontmatter.js.map +1 -1
- package/dist/jobs/run-history.d.ts +56 -0
- package/dist/jobs/run-history.d.ts.map +1 -0
- package/dist/jobs/run-history.js +169 -0
- package/dist/jobs/run-history.js.map +1 -0
- package/dist/jobs/scheduler.d.ts.map +1 -1
- package/dist/jobs/scheduler.js +51 -18
- package/dist/jobs/scheduler.js.map +1 -1
- package/dist/jobs/tools.d.ts.map +1 -1
- package/dist/jobs/tools.js +37 -6
- package/dist/jobs/tools.js.map +1 -1
- package/dist/localization/actions/get-localization-preference.d.ts +1 -2
- package/dist/localization/actions/get-localization-preference.d.ts.map +1 -1
- package/dist/localization/actions/get-localization-preference.js.map +1 -1
- package/dist/localization/actions/set-localization-preference.d.ts +3 -3
- package/dist/localization/actions/set-localization-preference.d.ts.map +1 -1
- package/dist/localization/actions/set-localization-preference.js +33 -8
- package/dist/localization/actions/set-localization-preference.js.map +1 -1
- package/dist/localization/default-messages.d.ts +25 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +25 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/localization/shared.d.ts +16 -1
- package/dist/localization/shared.d.ts.map +1 -1
- package/dist/localization/shared.js +22 -4
- package/dist/localization/shared.js.map +1 -1
- package/dist/localization/user-timezone.d.ts +11 -0
- package/dist/localization/user-timezone.d.ts.map +1 -0
- package/dist/localization/user-timezone.js +31 -0
- package/dist/localization/user-timezone.js.map +1 -0
- package/dist/notifications/routes.d.ts +4 -4
- package/dist/observability/routes.d.ts +3 -3
- package/dist/org/app-roles-handlers.d.ts.map +1 -1
- package/dist/org/app-roles-handlers.js +1 -8
- package/dist/org/app-roles-handlers.js.map +1 -1
- package/dist/org/index.d.ts +1 -0
- package/dist/org/index.d.ts.map +1 -1
- package/dist/org/index.js +1 -0
- package/dist/org/index.js.map +1 -1
- package/dist/org/membership.d.ts +6 -0
- package/dist/org/membership.d.ts.map +1 -0
- package/dist/org/membership.js +16 -0
- package/dist/org/membership.js.map +1 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +13 -13
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/review/actions/create-review-comment.d.ts +32 -1
- package/dist/review/actions/create-review-comment.d.ts.map +1 -1
- package/dist/review/actions/create-review-comment.js +3 -1
- package/dist/review/actions/create-review-comment.js.map +1 -1
- package/dist/review/actions/reply-review-comment.d.ts +32 -1
- package/dist/review/actions/reply-review-comment.d.ts.map +1 -1
- package/dist/review/actions/reply-review-comment.js +3 -1
- package/dist/review/actions/reply-review-comment.js.map +1 -1
- package/dist/review/index.d.ts +1 -0
- package/dist/review/index.d.ts.map +1 -1
- package/dist/review/index.js +1 -0
- package/dist/review/index.js.map +1 -1
- package/dist/review/notifications.d.ts +24 -0
- package/dist/review/notifications.d.ts.map +1 -0
- package/dist/review/notifications.js +123 -0
- package/dist/review/notifications.js.map +1 -0
- package/dist/review/types.d.ts +5 -0
- package/dist/review/types.d.ts.map +1 -1
- package/dist/review/types.js.map +1 -1
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +4 -0
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/activity-notifications.d.ts +61 -0
- package/dist/server/activity-notifications.d.ts.map +1 -0
- package/dist/server/activity-notifications.js +103 -0
- package/dist/server/activity-notifications.js.map +1 -0
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/app-name.d.ts +18 -0
- package/dist/server/app-name.d.ts.map +1 -1
- package/dist/server/app-name.js +31 -0
- package/dist/server/app-name.js.map +1 -1
- package/dist/server/better-auth-instance.js +4 -4
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/email-templates.d.ts +12 -0
- package/dist/server/email-templates.d.ts.map +1 -1
- package/dist/server/email-templates.js +57 -14
- package/dist/server/email-templates.js.map +1 -1
- package/dist/server/email.d.ts +12 -0
- package/dist/server/email.d.ts.map +1 -1
- package/dist/server/email.js +52 -5
- package/dist/server/email.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/sharing/access.d.ts.map +1 -1
- package/dist/sharing/access.js +32 -2
- package/dist/sharing/access.js.map +1 -1
- package/dist/sharing/index.d.ts +1 -0
- package/dist/sharing/index.d.ts.map +1 -1
- package/dist/sharing/index.js +1 -0
- package/dist/sharing/index.js.map +1 -1
- package/dist/sharing/recipients.d.ts +31 -0
- package/dist/sharing/recipients.d.ts.map +1 -0
- package/dist/sharing/recipients.js +40 -0
- package/dist/sharing/recipients.js.map +1 -0
- package/dist/templates/chat/app/routes/settings.tsx +14 -22
- package/dist/templates/chat/vitest.config.ts +9 -0
- package/dist/triggers/actions/list-automations.d.ts +2 -0
- package/dist/triggers/actions/list-automations.d.ts.map +1 -1
- package/dist/triggers/actions/list-automations.js +19 -8
- package/dist/triggers/actions/list-automations.js.map +1 -1
- package/dist/triggers/actions/manage-automation.d.ts +6 -0
- package/dist/triggers/actions/manage-automation.js +12 -6
- package/dist/triggers/actions/manage-automation.js.map +1 -1
- package/dist/triggers/actions.d.ts.map +1 -1
- package/dist/triggers/actions.js +15 -4
- package/dist/triggers/actions.js.map +1 -1
- package/dist/triggers/dispatcher.d.ts.map +1 -1
- package/dist/triggers/dispatcher.js +19 -17
- package/dist/triggers/dispatcher.js.map +1 -1
- package/dist/triggers/routes.d.ts.map +1 -1
- package/dist/triggers/routes.js +6 -6
- package/dist/triggers/routes.js.map +1 -1
- package/dist/vitest-config.d.ts +10 -0
- package/dist/vitest-config.d.ts.map +1 -0
- package/dist/vitest-config.js +55 -0
- package/dist/vitest-config.js.map +1 -0
- package/package.json +5 -4
- package/src/automations/service.ts +41 -4
- package/src/cli/mcp-config-writers.ts +27 -21
- package/src/client/agent-page/AgentJobsTab.tsx +187 -85
- package/src/client/agent-page/AutomationDetailsDialog.tsx +208 -0
- package/src/client/agent-page/AutomationScheduleDialog.tsx +180 -0
- package/src/client/agent-page/TimezoneSelect.tsx +241 -0
- package/src/client/agent-page/use-jobs.ts +50 -10
- package/src/client/org/OrgSwitcher.tsx +26 -0
- package/src/client/settings/AccountSettingsCard.tsx +35 -31
- package/src/client/settings/SchedulingTimezoneField.tsx +71 -0
- package/src/client/settings/SettingsRow.tsx +113 -0
- package/src/client/settings/agent-settings-search.ts +2 -1
- package/src/client/settings/index.ts +6 -0
- package/src/integrations/identity.ts +2 -12
- package/src/jobs/actions/list-automation-runs.ts +33 -0
- package/src/jobs/actions/list-recurring-jobs.ts +27 -6
- package/src/jobs/actions/manage-recurring-job.ts +41 -9
- package/src/jobs/background-automation-runner.ts +88 -0
- package/src/jobs/cron.ts +52 -6
- package/src/jobs/frontmatter.ts +20 -0
- package/src/jobs/run-history.ts +242 -0
- package/src/jobs/scheduler.ts +73 -18
- package/src/jobs/tools.ts +54 -6
- package/src/localization/actions/get-localization-preference.ts +2 -2
- package/src/localization/actions/set-localization-preference.ts +49 -11
- package/src/localization/default-messages.ts +27 -0
- package/src/localization/shared.ts +39 -6
- package/src/localization/user-timezone.ts +36 -0
- package/src/org/app-roles-handlers.ts +1 -9
- package/src/org/index.ts +2 -0
- package/src/org/membership.ts +18 -0
- package/src/review/actions/create-review-comment.ts +4 -1
- package/src/review/actions/reply-review-comment.ts +4 -1
- package/src/review/index.ts +5 -0
- package/src/review/notifications.ts +163 -0
- package/src/review/types.ts +7 -0
- package/src/server/action-discovery.ts +4 -0
- package/src/server/activity-notifications.ts +174 -0
- package/src/server/app-name.ts +31 -0
- package/src/server/better-auth-instance.ts +4 -4
- package/src/server/email-templates.ts +70 -14
- package/src/server/email.ts +66 -3
- package/src/server/index.ts +10 -0
- package/src/sharing/access.ts +44 -2
- package/src/sharing/index.ts +5 -0
- package/src/sharing/recipients.ts +67 -0
- package/src/templates/chat/app/routes/settings.tsx +14 -22
- package/src/templates/chat/vitest.config.ts +9 -0
- package/src/triggers/actions/list-automations.ts +27 -8
- package/src/triggers/actions/manage-automation.ts +17 -6
- package/src/triggers/actions.ts +16 -4
- package/src/triggers/dispatcher.ts +44 -30
- package/src/triggers/routes.ts +19 -6
- package/src/vitest-config.ts +68 -0
|
@@ -10,10 +10,12 @@ export interface RecurringJob {
|
|
|
10
10
|
path: string;
|
|
11
11
|
scope: "personal" | "organization";
|
|
12
12
|
schedule: string;
|
|
13
|
+
timezone: string;
|
|
13
14
|
scheduleDescription: string;
|
|
14
15
|
instructions: string;
|
|
15
16
|
enabled: boolean;
|
|
16
17
|
lastRun: string | null;
|
|
18
|
+
lastCheck: string | null;
|
|
17
19
|
lastStatus: string | null;
|
|
18
20
|
lastError: string | null;
|
|
19
21
|
nextRun: string | null;
|
|
@@ -30,11 +32,13 @@ export interface Automation {
|
|
|
30
32
|
triggerType: "event" | "schedule";
|
|
31
33
|
event: string | null;
|
|
32
34
|
schedule: string | null;
|
|
35
|
+
timezone: string | null;
|
|
33
36
|
scheduleDescription: string | null;
|
|
34
37
|
condition: string | null;
|
|
35
38
|
body: string;
|
|
36
39
|
enabled: boolean;
|
|
37
40
|
lastRun: string | null;
|
|
41
|
+
lastCheck: string | null;
|
|
38
42
|
lastStatus: string | null;
|
|
39
43
|
lastError: string | null;
|
|
40
44
|
nextRun: string | null;
|
|
@@ -54,14 +58,23 @@ export type ManageJobInput = {
|
|
|
54
58
|
name: string;
|
|
55
59
|
scope: "personal" | "organization";
|
|
56
60
|
enabled?: boolean;
|
|
61
|
+
schedule?: string;
|
|
62
|
+
timezone?: string;
|
|
57
63
|
};
|
|
58
64
|
|
|
59
|
-
export type ManageAutomationInput =
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
export type ManageAutomationInput = ManageJobInput;
|
|
66
|
+
|
|
67
|
+
export interface AutomationRun {
|
|
68
|
+
id: string;
|
|
69
|
+
automation: string;
|
|
70
|
+
scope: string | null;
|
|
71
|
+
runId: string | null;
|
|
72
|
+
threadId: string | null;
|
|
73
|
+
status: "running" | "success" | "error" | "interrupted";
|
|
74
|
+
startedAt: number;
|
|
75
|
+
finishedAt: number | null;
|
|
76
|
+
error: string | null;
|
|
77
|
+
}
|
|
65
78
|
|
|
66
79
|
function recurringParams(scope: JobsScope) {
|
|
67
80
|
return { scope: scope === "org" ? "organization" : "personal" } as const;
|
|
@@ -105,8 +118,8 @@ export function useManageRecurringJob(scope: JobsScope) {
|
|
|
105
118
|
return current.filter((job) => job.name !== variables.name);
|
|
106
119
|
}
|
|
107
120
|
return current.map((job) =>
|
|
108
|
-
job.name === variables.name
|
|
109
|
-
? { ...job,
|
|
121
|
+
job.name === variables.name
|
|
122
|
+
? { ...job, ...optimisticPatch(variables) }
|
|
110
123
|
: job,
|
|
111
124
|
);
|
|
112
125
|
});
|
|
@@ -141,8 +154,8 @@ export function useManageAutomation(scope: JobsScope) {
|
|
|
141
154
|
);
|
|
142
155
|
}
|
|
143
156
|
return current.map((automation) =>
|
|
144
|
-
automation.name === variables.name
|
|
145
|
-
? { ...automation,
|
|
157
|
+
automation.name === variables.name
|
|
158
|
+
? { ...automation, ...optimisticPatch(variables) }
|
|
146
159
|
: automation,
|
|
147
160
|
);
|
|
148
161
|
});
|
|
@@ -156,3 +169,30 @@ export function useManageAutomation(scope: JobsScope) {
|
|
|
156
169
|
},
|
|
157
170
|
});
|
|
158
171
|
}
|
|
172
|
+
|
|
173
|
+
function optimisticPatch(variables: ManageJobInput) {
|
|
174
|
+
const patch: {
|
|
175
|
+
enabled?: boolean;
|
|
176
|
+
schedule?: string;
|
|
177
|
+
timezone?: string;
|
|
178
|
+
} = {};
|
|
179
|
+
if (variables.enabled !== undefined) patch.enabled = variables.enabled;
|
|
180
|
+
if (variables.schedule !== undefined) patch.schedule = variables.schedule;
|
|
181
|
+
if (variables.timezone !== undefined) patch.timezone = variables.timezone;
|
|
182
|
+
return patch;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function useAutomationRuns(
|
|
186
|
+
scope: JobsScope,
|
|
187
|
+
name: string | null,
|
|
188
|
+
active: boolean,
|
|
189
|
+
) {
|
|
190
|
+
const params = {
|
|
191
|
+
scope: scope === "org" ? "organization" : "personal",
|
|
192
|
+
name: name || "",
|
|
193
|
+
} as const;
|
|
194
|
+
return useActionQuery<AutomationRun[]>("list-automation-runs", params, {
|
|
195
|
+
staleTime: 5_000,
|
|
196
|
+
enabled: active && Boolean(name),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
@@ -83,6 +83,13 @@ export interface OrgSwitcherProps {
|
|
|
83
83
|
settingsPath?: string | null;
|
|
84
84
|
/** Path to navigate to when the user clicks "Profile". Defaults to the shared Account settings section. */
|
|
85
85
|
profilePath?: string | null;
|
|
86
|
+
/**
|
|
87
|
+
* Path to the Manage agent page. Settings links here too, but the switcher
|
|
88
|
+
* is the only always-visible surface, so omitting it leaves Files,
|
|
89
|
+
* Instructions, Memory, Skills and Automations reachable only from Settings.
|
|
90
|
+
* Pass `null` for apps that do not mount the Agent page.
|
|
91
|
+
*/
|
|
92
|
+
agentPath?: string | null;
|
|
86
93
|
}
|
|
87
94
|
|
|
88
95
|
function personalLabelFromEmail(email: string | null | undefined): string {
|
|
@@ -119,6 +126,7 @@ const COMPACT_SWITCHER_BUTTON_CLASS =
|
|
|
119
126
|
|
|
120
127
|
const DEFAULT_ORGANIZATION_SETTINGS_PATH = "/settings#organization";
|
|
121
128
|
const DEFAULT_PROFILE_PATH = "/settings#account";
|
|
129
|
+
const DEFAULT_AGENT_PATH = "/agent";
|
|
122
130
|
|
|
123
131
|
const APP_ICON_MAP: Record<string, typeof IconApps> = {
|
|
124
132
|
Mail: IconMail,
|
|
@@ -311,6 +319,7 @@ export function OrgSwitcher({
|
|
|
311
319
|
compact,
|
|
312
320
|
settingsPath = DEFAULT_ORGANIZATION_SETTINGS_PATH,
|
|
313
321
|
profilePath = DEFAULT_PROFILE_PATH,
|
|
322
|
+
agentPath = DEFAULT_AGENT_PATH,
|
|
314
323
|
}: OrgSwitcherProps) {
|
|
315
324
|
const { data: org, isLoading } = useOrg();
|
|
316
325
|
const { session } = useSession();
|
|
@@ -607,6 +616,23 @@ export function OrgSwitcher({
|
|
|
607
616
|
</span>
|
|
608
617
|
</button>
|
|
609
618
|
)}
|
|
619
|
+
{agentPath && (
|
|
620
|
+
<button
|
|
621
|
+
type="button"
|
|
622
|
+
onClick={() => {
|
|
623
|
+
setOpen(false);
|
|
624
|
+
navigate(agentPath);
|
|
625
|
+
}}
|
|
626
|
+
className={`${ITEM_CLASS} cursor-pointer`}
|
|
627
|
+
>
|
|
628
|
+
<IconBrain className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
|
|
629
|
+
<span className="flex-1 text-start">
|
|
630
|
+
{t("settings.manageAgentMenuItem", {
|
|
631
|
+
defaultValue: "Manage agent",
|
|
632
|
+
})}
|
|
633
|
+
</span>
|
|
634
|
+
</button>
|
|
635
|
+
)}
|
|
610
636
|
{inOrg && (
|
|
611
637
|
<button
|
|
612
638
|
type="button"
|
|
@@ -13,6 +13,7 @@ import { useActionMutation, useActionQuery } from "../use-action.js";
|
|
|
13
13
|
import { uploadAvatar, useAvatarUrl } from "../use-avatar.js";
|
|
14
14
|
import { useSession } from "../use-session.js";
|
|
15
15
|
import { cn } from "../utils.js";
|
|
16
|
+
import { SchedulingTimezoneField } from "./SchedulingTimezoneField.js";
|
|
16
17
|
|
|
17
18
|
function profileInitials(name: string): string {
|
|
18
19
|
return (
|
|
@@ -157,38 +158,41 @@ export function AccountSettingsForm({
|
|
|
157
158
|
description={t("settings.profileNameDescription")}
|
|
158
159
|
disabled={!email || profileQuery.isLoading || updateProfile.isPending}
|
|
159
160
|
/>
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
emphasis="solid"
|
|
177
|
-
size="compact"
|
|
178
|
-
pending={updateProfile.isPending}
|
|
179
|
-
disabled={
|
|
180
|
-
!email ||
|
|
181
|
-
profileQuery.isLoading ||
|
|
182
|
-
updateProfile.isPending ||
|
|
183
|
-
!name.trim()
|
|
184
|
-
}
|
|
185
|
-
onPress={handleProfileSave}
|
|
186
|
-
>
|
|
187
|
-
{updateProfile.isPending
|
|
188
|
-
? t("settings.profileSaving")
|
|
189
|
-
: t("settings.profileSave")}
|
|
190
|
-
</ActionButton>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<div className="border-t border-border/60 pt-3">
|
|
164
|
+
<SchedulingTimezoneField />
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
<div className="flex items-center justify-between gap-3 border-t border-border/60 pt-3">
|
|
168
|
+
<div className="min-h-4 text-xs">
|
|
169
|
+
{updateProfile.isSuccess && (
|
|
170
|
+
<p className="text-green-600 dark:text-green-400">
|
|
171
|
+
{t("settings.profileSaved")}
|
|
172
|
+
</p>
|
|
173
|
+
)}
|
|
174
|
+
{updateProfile.error && (
|
|
175
|
+
<p className="text-destructive">{t("settings.profileSaveError")}</p>
|
|
176
|
+
)}
|
|
191
177
|
</div>
|
|
178
|
+
<ActionButton
|
|
179
|
+
type="button"
|
|
180
|
+
intent="primary"
|
|
181
|
+
emphasis="solid"
|
|
182
|
+
size="compact"
|
|
183
|
+
pending={updateProfile.isPending}
|
|
184
|
+
disabled={
|
|
185
|
+
!email ||
|
|
186
|
+
profileQuery.isLoading ||
|
|
187
|
+
updateProfile.isPending ||
|
|
188
|
+
!name.trim()
|
|
189
|
+
}
|
|
190
|
+
onPress={handleProfileSave}
|
|
191
|
+
>
|
|
192
|
+
{updateProfile.isPending
|
|
193
|
+
? t("settings.profileSaving")
|
|
194
|
+
: t("settings.profileSave")}
|
|
195
|
+
</ActionButton>
|
|
192
196
|
</div>
|
|
193
197
|
</div>
|
|
194
198
|
);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TimezoneSelect,
|
|
3
|
+
browserTimezone,
|
|
4
|
+
} from "../agent-page/TimezoneSelect.js";
|
|
5
|
+
import { useT } from "../i18n.js";
|
|
6
|
+
import { useActionMutation, useActionQuery } from "../use-action.js";
|
|
7
|
+
|
|
8
|
+
interface LocalizationPreferenceResult {
|
|
9
|
+
locale: string;
|
|
10
|
+
timezone: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const SYSTEM = "system";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Timezone used when the agent schedules work for this user.
|
|
17
|
+
*
|
|
18
|
+
* This is deliberately a stored preference rather than a per-request read of
|
|
19
|
+
* the browser zone: automations are created and run by callers that have no
|
|
20
|
+
* browser at all (cron ticks, chat integrations, A2A), and those callers would
|
|
21
|
+
* otherwise fall back to the host zone and schedule the user's 8am job in UTC.
|
|
22
|
+
*/
|
|
23
|
+
export function SchedulingTimezoneField() {
|
|
24
|
+
const t = useT();
|
|
25
|
+
const detected = browserTimezone();
|
|
26
|
+
const preference = useActionQuery<LocalizationPreferenceResult>(
|
|
27
|
+
"get-localization-preference",
|
|
28
|
+
);
|
|
29
|
+
const save = useActionMutation<
|
|
30
|
+
LocalizationPreferenceResult,
|
|
31
|
+
{ timezone: string }
|
|
32
|
+
>("set-localization-preference");
|
|
33
|
+
|
|
34
|
+
// Selecting a zone commits it, matching the language picker beside it.
|
|
35
|
+
const stored = preference.data?.timezone ?? SYSTEM;
|
|
36
|
+
const pending = save.isPending ? save.variables?.timezone : undefined;
|
|
37
|
+
const value = pending ?? stored;
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div className="space-y-2">
|
|
41
|
+
<label
|
|
42
|
+
className="text-sm font-medium"
|
|
43
|
+
htmlFor="agent-native-scheduling-timezone"
|
|
44
|
+
>
|
|
45
|
+
{t("settings.timezoneLabel", { defaultValue: "Timezone" })}
|
|
46
|
+
</label>
|
|
47
|
+
|
|
48
|
+
<TimezoneSelect
|
|
49
|
+
id="agent-native-scheduling-timezone"
|
|
50
|
+
value={value}
|
|
51
|
+
disabled={preference.isLoading || save.isPending}
|
|
52
|
+
suggested={[detected]}
|
|
53
|
+
systemLabel={t("settings.timezoneSystem", {
|
|
54
|
+
defaultValue: "Follow this browser ({{zone}})",
|
|
55
|
+
zone: detected,
|
|
56
|
+
})}
|
|
57
|
+
onChange={(timezone) => save.mutate({ timezone })}
|
|
58
|
+
/>
|
|
59
|
+
|
|
60
|
+
<p className="min-h-4 text-xs text-muted-foreground">
|
|
61
|
+
{save.error ? (
|
|
62
|
+
<span className="text-destructive">{save.error.message}</span>
|
|
63
|
+
) : (
|
|
64
|
+
t("settings.timezoneHint", {
|
|
65
|
+
defaultValue: "Used for timestamps and scheduled automations.",
|
|
66
|
+
})
|
|
67
|
+
)}
|
|
68
|
+
</p>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../utils.js";
|
|
4
|
+
|
|
5
|
+
export interface SettingsGroupProps {
|
|
6
|
+
/** Anchor target so a settings search hit can scroll the whole group. */
|
|
7
|
+
id?: string;
|
|
8
|
+
title?: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
className?: string;
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A bordered card holding several one-line settings instead of one card per
|
|
16
|
+
* control. Copy is passed in already translated — core components do not
|
|
17
|
+
* resolve an app's i18n keys.
|
|
18
|
+
*/
|
|
19
|
+
export function SettingsGroup({
|
|
20
|
+
id,
|
|
21
|
+
title,
|
|
22
|
+
description,
|
|
23
|
+
className,
|
|
24
|
+
children,
|
|
25
|
+
}: SettingsGroupProps) {
|
|
26
|
+
return (
|
|
27
|
+
<section
|
|
28
|
+
id={id}
|
|
29
|
+
className={cn(
|
|
30
|
+
"scroll-mt-16 overflow-hidden rounded-lg border border-border bg-card text-card-foreground shadow-sm",
|
|
31
|
+
className,
|
|
32
|
+
)}
|
|
33
|
+
>
|
|
34
|
+
{(title || description) && (
|
|
35
|
+
<header className="border-b border-border/60 px-5 py-4 sm:px-6">
|
|
36
|
+
{title && (
|
|
37
|
+
<h2 className="text-base font-semibold leading-none tracking-tight">
|
|
38
|
+
{title}
|
|
39
|
+
</h2>
|
|
40
|
+
)}
|
|
41
|
+
{description && (
|
|
42
|
+
<p className="mt-1.5 text-sm leading-snug text-muted-foreground">
|
|
43
|
+
{description}
|
|
44
|
+
</p>
|
|
45
|
+
)}
|
|
46
|
+
</header>
|
|
47
|
+
)}
|
|
48
|
+
<div className="divide-y divide-border/60">{children}</div>
|
|
49
|
+
</section>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface SettingsRowProps {
|
|
54
|
+
/**
|
|
55
|
+
* Anchor target. Rows keep the ids their former standalone cards used, so
|
|
56
|
+
* existing settings-search hashes still resolve after a card collapses into
|
|
57
|
+
* a row.
|
|
58
|
+
*/
|
|
59
|
+
id?: string;
|
|
60
|
+
label: ReactNode;
|
|
61
|
+
description?: ReactNode;
|
|
62
|
+
icon?: ReactNode;
|
|
63
|
+
/** Badge or pill rendered beside the label. */
|
|
64
|
+
status?: ReactNode;
|
|
65
|
+
/** The input itself: switch, select, button, link. */
|
|
66
|
+
control?: ReactNode;
|
|
67
|
+
/** Extra content below the row, e.g. a disclosure panel. */
|
|
68
|
+
children?: ReactNode;
|
|
69
|
+
className?: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** One setting: label and description on the start side, control on the end. */
|
|
73
|
+
export function SettingsRow({
|
|
74
|
+
id,
|
|
75
|
+
label,
|
|
76
|
+
description,
|
|
77
|
+
icon,
|
|
78
|
+
status,
|
|
79
|
+
control,
|
|
80
|
+
children,
|
|
81
|
+
className,
|
|
82
|
+
}: SettingsRowProps) {
|
|
83
|
+
return (
|
|
84
|
+
<div id={id} className={cn("scroll-mt-16 px-5 py-4 sm:px-6", className)}>
|
|
85
|
+
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
|
86
|
+
<div className="flex min-w-0 gap-3">
|
|
87
|
+
{icon && (
|
|
88
|
+
<span className="mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-md border border-border bg-background text-muted-foreground [&>svg]:size-[18px]">
|
|
89
|
+
{icon}
|
|
90
|
+
</span>
|
|
91
|
+
)}
|
|
92
|
+
<div className="min-w-0">
|
|
93
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
94
|
+
<span className="text-sm font-medium text-foreground">
|
|
95
|
+
{label}
|
|
96
|
+
</span>
|
|
97
|
+
{status}
|
|
98
|
+
</div>
|
|
99
|
+
{description && (
|
|
100
|
+
<p className="mt-1 max-w-xl text-sm leading-6 text-muted-foreground">
|
|
101
|
+
{description}
|
|
102
|
+
</p>
|
|
103
|
+
)}
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
{control && (
|
|
107
|
+
<div className="shrink-0 sm:ms-4 sm:text-end">{control}</div>
|
|
108
|
+
)}
|
|
109
|
+
</div>
|
|
110
|
+
{children && <div className="mt-4">{children}</div>}
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
@@ -93,7 +93,8 @@ const SETTINGS_SECTION_SEARCH_META: Record<
|
|
|
93
93
|
> = {
|
|
94
94
|
account: {
|
|
95
95
|
label: "Account",
|
|
96
|
-
keywords:
|
|
96
|
+
keywords:
|
|
97
|
+
"profile photo avatar identity signed in email name timezone time zone schedule scheduling clock",
|
|
97
98
|
},
|
|
98
99
|
llm: {
|
|
99
100
|
label: "LLM",
|
|
@@ -34,6 +34,12 @@ export {
|
|
|
34
34
|
type OpenBuilderConnectPopupOptions,
|
|
35
35
|
} from "./useBuilderStatus.js";
|
|
36
36
|
export { SecretsSection, type SecretsSectionProps } from "./SecretsSection.js";
|
|
37
|
+
export {
|
|
38
|
+
SettingsGroup,
|
|
39
|
+
SettingsRow,
|
|
40
|
+
type SettingsGroupProps,
|
|
41
|
+
type SettingsRowProps,
|
|
42
|
+
} from "./SettingsRow.js";
|
|
37
43
|
export {
|
|
38
44
|
normalizeSettingsSection,
|
|
39
45
|
settingsSectionDomId,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isOrgMember as isMemberOfOrg } from "../org/membership.js";
|
|
2
2
|
import { upsertVerifiedIntegrationIdentity } from "./identity-links-store.js";
|
|
3
3
|
import {
|
|
4
4
|
getActiveIntegrationInstallationByKey,
|
|
@@ -74,16 +74,6 @@ async function resolveSlackInstallation(incoming: IncomingMessage) {
|
|
|
74
74
|
: null;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
async function isMemberOfOrg(email: string, orgId: string): Promise<boolean> {
|
|
78
|
-
const { rows } = await getDbExec().execute({
|
|
79
|
-
sql: `SELECT 1 FROM org_members
|
|
80
|
-
WHERE org_id = ? AND LOWER(email) = ?
|
|
81
|
-
LIMIT 1`,
|
|
82
|
-
args: [orgId, email],
|
|
83
|
-
});
|
|
84
|
-
return rows.length > 0;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
77
|
/**
|
|
88
78
|
* Resolve the default integration principal.
|
|
89
79
|
*
|
|
@@ -150,7 +140,7 @@ export async function resolveDefaultIntegrationExecutionContext(
|
|
|
150
140
|
incoming.tenantId
|
|
151
141
|
) {
|
|
152
142
|
try {
|
|
153
|
-
isOrgMember = await isMemberOfOrg(
|
|
143
|
+
isOrgMember = await isMemberOfOrg(installation.orgId, email);
|
|
154
144
|
} catch {
|
|
155
145
|
// A membership-store outage is not evidence that the sender is merely
|
|
156
146
|
// unlinked. Fail closed instead of widening them to org-wide access.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import { defineAction } from "../../action.js";
|
|
4
|
+
import { organizationResourceOwner } from "../../resources/store.js";
|
|
5
|
+
import { listAutomationRuns, type AutomationRun } from "../run-history.js";
|
|
6
|
+
|
|
7
|
+
const scopeSchema = z.enum(["personal", "organization"]);
|
|
8
|
+
|
|
9
|
+
export default defineAction({
|
|
10
|
+
description:
|
|
11
|
+
"List past execution records for one automation or recurring job in the selected scope.",
|
|
12
|
+
agentTool: false,
|
|
13
|
+
schema: z.object({
|
|
14
|
+
name: z.string().min(1),
|
|
15
|
+
scope: scopeSchema.default("personal"),
|
|
16
|
+
limit: z.number().int().min(1).max(100).optional(),
|
|
17
|
+
}),
|
|
18
|
+
http: { method: "GET" },
|
|
19
|
+
readOnly: true,
|
|
20
|
+
parallelSafe: true,
|
|
21
|
+
run: async ({ name, scope, limit }, ctx): Promise<AutomationRun[]> => {
|
|
22
|
+
const userEmail = ctx?.userEmail;
|
|
23
|
+
if (!userEmail) throw new Error("Not authenticated.");
|
|
24
|
+
if (scope === "organization" && !ctx?.orgId) return [];
|
|
25
|
+
|
|
26
|
+
const owner =
|
|
27
|
+
scope === "organization"
|
|
28
|
+
? organizationResourceOwner(ctx.orgId as string)
|
|
29
|
+
: userEmail;
|
|
30
|
+
|
|
31
|
+
return listAutomationRuns({ owners: [owner], automation: name, limit });
|
|
32
|
+
},
|
|
33
|
+
});
|
|
@@ -6,7 +6,12 @@ import {
|
|
|
6
6
|
resourceGetByPath,
|
|
7
7
|
resourceList,
|
|
8
8
|
} from "../../resources/store.js";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
describeCron,
|
|
11
|
+
effectiveTimezone,
|
|
12
|
+
isValidCron,
|
|
13
|
+
nextOccurrence,
|
|
14
|
+
} from "../cron.js";
|
|
10
15
|
import { classifyJobResource } from "../frontmatter.js";
|
|
11
16
|
import { parseJobFrontmatter } from "../scheduler.js";
|
|
12
17
|
import { authorizeJobMutation } from "../tools.js";
|
|
@@ -17,15 +22,25 @@ function jobName(path: string): string {
|
|
|
17
22
|
return path.replace(/^jobs\//, "").replace(/\.md$/, "");
|
|
18
23
|
}
|
|
19
24
|
|
|
25
|
+
/**
|
|
26
|
+
* A stored `nextRun` in the past means the scheduler kept declining to run the
|
|
27
|
+
* job, not that it is due two days ago. Report the real next occurrence and
|
|
28
|
+
* let `lastError` carry the reason it keeps being passed over.
|
|
29
|
+
*/
|
|
20
30
|
function nextRun(
|
|
21
31
|
meta: ReturnType<typeof parseJobFrontmatter>["meta"],
|
|
22
32
|
): string | null {
|
|
23
33
|
if (!meta.enabled) return null;
|
|
24
|
-
|
|
25
|
-
if (meta.
|
|
26
|
-
|
|
34
|
+
const scheduled = Boolean(meta.schedule && isValidCron(meta.schedule));
|
|
35
|
+
if (meta.nextRun) {
|
|
36
|
+
const stored = new Date(meta.nextRun).getTime();
|
|
37
|
+
if (!Number.isFinite(stored) || stored > Date.now() || !scheduled) {
|
|
38
|
+
return meta.nextRun;
|
|
39
|
+
}
|
|
27
40
|
}
|
|
28
|
-
return
|
|
41
|
+
return scheduled
|
|
42
|
+
? nextOccurrence(meta.schedule, undefined, meta.timezone).toISOString()
|
|
43
|
+
: null;
|
|
29
44
|
}
|
|
30
45
|
|
|
31
46
|
export interface RecurringJobActionItem {
|
|
@@ -34,10 +49,12 @@ export interface RecurringJobActionItem {
|
|
|
34
49
|
path: string;
|
|
35
50
|
scope: "personal" | "organization";
|
|
36
51
|
schedule: string;
|
|
52
|
+
timezone: string;
|
|
37
53
|
scheduleDescription: string;
|
|
38
54
|
instructions: string;
|
|
39
55
|
enabled: boolean;
|
|
40
56
|
lastRun: string | null;
|
|
57
|
+
lastCheck: string | null;
|
|
41
58
|
lastStatus: string | null;
|
|
42
59
|
lastError: string | null;
|
|
43
60
|
nextRun: string | null;
|
|
@@ -87,10 +104,14 @@ export default defineAction({
|
|
|
87
104
|
path: full.path,
|
|
88
105
|
scope,
|
|
89
106
|
schedule: meta.schedule,
|
|
90
|
-
|
|
107
|
+
timezone: effectiveTimezone(meta.timezone),
|
|
108
|
+
scheduleDescription: meta.schedule
|
|
109
|
+
? describeCron(meta.schedule, effectiveTimezone(meta.timezone))
|
|
110
|
+
: "",
|
|
91
111
|
instructions: body,
|
|
92
112
|
enabled: meta.enabled,
|
|
93
113
|
lastRun: meta.lastRun ?? null,
|
|
114
|
+
lastCheck: meta.lastCheck ?? null,
|
|
94
115
|
lastStatus: meta.lastStatus ?? null,
|
|
95
116
|
lastError: meta.lastError ?? null,
|
|
96
117
|
nextRun: nextRun(meta),
|
|
@@ -7,8 +7,9 @@ import {
|
|
|
7
7
|
resourceGetByPath,
|
|
8
8
|
resourcePut,
|
|
9
9
|
} from "../../resources/store.js";
|
|
10
|
-
import { isValidCron, nextOccurrence } from "../cron.js";
|
|
10
|
+
import { isValidCron, isValidTimezone, nextOccurrence } from "../cron.js";
|
|
11
11
|
import { classifyJobResource } from "../frontmatter.js";
|
|
12
|
+
import { deleteAutomationRuns } from "../run-history.js";
|
|
12
13
|
import { buildJobContent, parseJobFrontmatter } from "../scheduler.js";
|
|
13
14
|
import { authorizeJobMutation } from "../tools.js";
|
|
14
15
|
|
|
@@ -23,8 +24,10 @@ export default defineAction({
|
|
|
23
24
|
name: z.string().min(1),
|
|
24
25
|
scope: scopeSchema.default("personal"),
|
|
25
26
|
enabled: z.boolean().optional(),
|
|
27
|
+
schedule: z.string().min(1).optional(),
|
|
28
|
+
timezone: z.string().min(1).optional(),
|
|
26
29
|
}),
|
|
27
|
-
run: async ({ operation, name, scope, enabled }, ctx) => {
|
|
30
|
+
run: async ({ operation, name, scope, enabled, schedule, timezone }, ctx) => {
|
|
28
31
|
const userEmail = ctx?.userEmail;
|
|
29
32
|
if (!userEmail) throw new Error("Not authenticated.");
|
|
30
33
|
if (scope === "organization" && !ctx?.orgId) {
|
|
@@ -54,17 +57,46 @@ export default defineAction({
|
|
|
54
57
|
|
|
55
58
|
if (operation === "delete") {
|
|
56
59
|
await resourceDelete(resource.id);
|
|
60
|
+
// Names are reusable; history left behind would surface as the run
|
|
61
|
+
// history of whatever job is next created under this name.
|
|
62
|
+
await deleteAutomationRuns(resource.owner, name);
|
|
57
63
|
return { deleted: true, name };
|
|
58
64
|
}
|
|
59
65
|
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
if (timezone !== undefined) {
|
|
67
|
+
if (!isValidTimezone(timezone)) {
|
|
68
|
+
throw Object.assign(new Error(`Unknown timezone "${timezone}".`), {
|
|
69
|
+
statusCode: 400,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
meta.timezone = timezone;
|
|
73
|
+
}
|
|
74
|
+
if (
|
|
75
|
+
enabled === undefined &&
|
|
76
|
+
schedule === undefined &&
|
|
77
|
+
timezone === undefined
|
|
78
|
+
) {
|
|
79
|
+
throw Object.assign(
|
|
80
|
+
new Error("enabled, schedule, or timezone is required for update."),
|
|
81
|
+
{ statusCode: 400 },
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
if (schedule !== undefined) {
|
|
85
|
+
if (!isValidCron(schedule)) {
|
|
86
|
+
throw Object.assign(
|
|
87
|
+
new Error(`Invalid cron expression "${schedule}".`),
|
|
88
|
+
{ statusCode: 400 },
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
meta.schedule = schedule;
|
|
64
92
|
}
|
|
65
|
-
meta.enabled = enabled;
|
|
66
|
-
if (enabled && meta.schedule && isValidCron(meta.schedule)) {
|
|
67
|
-
meta.nextRun = nextOccurrence(
|
|
93
|
+
if (enabled !== undefined) meta.enabled = enabled;
|
|
94
|
+
if (meta.enabled && meta.schedule && isValidCron(meta.schedule)) {
|
|
95
|
+
meta.nextRun = nextOccurrence(
|
|
96
|
+
meta.schedule,
|
|
97
|
+
undefined,
|
|
98
|
+
meta.timezone,
|
|
99
|
+
).toISOString();
|
|
68
100
|
}
|
|
69
101
|
await resourcePut(
|
|
70
102
|
resource.owner,
|