@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
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base vitest config that caps a suite's worker pool at a share of the machine.
|
|
3
|
+
*
|
|
4
|
+
* Vitest sizes its pool at `cores - 1` with no awareness of peer processes, so
|
|
5
|
+
* several suites running at once — concurrent agent sessions, or a workspace
|
|
6
|
+
* running packages in parallel — each try to claim the whole box. Set
|
|
7
|
+
* `VITEST_CONCURRENCY` to a percentage or a worker count to change the lid; a
|
|
8
|
+
* package that needs its own value sets `test.maxWorkers` in its own config,
|
|
9
|
+
* which wins the merge.
|
|
10
|
+
*
|
|
11
|
+
* This ships from core rather than living at the monorepo root because template
|
|
12
|
+
* directories are scaffolded out verbatim as standalone apps — a config that
|
|
13
|
+
* reaches above the template would resolve to nothing in the generated app.
|
|
14
|
+
*
|
|
15
|
+
* Keep this module free of runtime imports so loading it costs a config file
|
|
16
|
+
* nothing beyond reading the environment.
|
|
17
|
+
*/
|
|
18
|
+
const DEFAULT_MAX_WORKERS = "25%";
|
|
19
|
+
const ENV_KEYS = ["VITEST_CONCURRENCY", "AGENT_NATIVE_VITEST_CONCURRENCY"];
|
|
20
|
+
/**
|
|
21
|
+
* Resolve the worker lid from the environment, throwing on anything that is
|
|
22
|
+
* neither a percentage nor a worker count. A bad value must not quietly become
|
|
23
|
+
* the default — that reads as "configured" while running at some other size.
|
|
24
|
+
*/
|
|
25
|
+
export function resolveMaxWorkers(env = process.env) {
|
|
26
|
+
const rawMaxWorkers = env.VITEST_MAX_WORKERS;
|
|
27
|
+
if (rawMaxWorkers?.includes("%")) {
|
|
28
|
+
throw new Error(`VITEST_MAX_WORKERS=${rawMaxWorkers} is not a percentage to vitest — it parses as ` +
|
|
29
|
+
`${Number.parseInt(rawMaxWorkers)} workers. Use VITEST_CONCURRENCY for percentages, ` +
|
|
30
|
+
`or an integer for VITEST_MAX_WORKERS.`);
|
|
31
|
+
}
|
|
32
|
+
const key = ENV_KEYS.find((name) => env[name]);
|
|
33
|
+
if (!key)
|
|
34
|
+
return DEFAULT_MAX_WORKERS;
|
|
35
|
+
const value = env[key].trim();
|
|
36
|
+
if (/^\d+%$/.test(value)) {
|
|
37
|
+
const percent = Number.parseInt(value);
|
|
38
|
+
if (percent < 1 || percent > 100) {
|
|
39
|
+
throw new Error(`${key}=${value} is out of range — use 1% to 100%.`);
|
|
40
|
+
}
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
const count = Number(value);
|
|
44
|
+
if (!Number.isInteger(count) || count < 1) {
|
|
45
|
+
throw new Error(`${key}=${value} is not a percentage like "25%" or a worker count like "2".`);
|
|
46
|
+
}
|
|
47
|
+
return count;
|
|
48
|
+
}
|
|
49
|
+
const vitestBaseConfig = {
|
|
50
|
+
test: {
|
|
51
|
+
maxWorkers: resolveMaxWorkers(),
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
export default vitestBaseConfig;
|
|
55
|
+
//# sourceMappingURL=vitest-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest-config.js","sourceRoot":"","sources":["../src/vitest-config.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,mBAAmB,GAAG,KAAK,CAAC;AAClC,MAAM,QAAQ,GAAG,CAAC,oBAAoB,EAAE,iCAAiC,CAAC,CAAC;AAE3E;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,GAAG,GAAsB,OAAO,CAAC,GAAG;IAEpC,MAAM,aAAa,GAAG,GAAG,CAAC,kBAAkB,CAAC;IAC7C,IAAI,aAAa,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,sBAAsB,aAAa,gDAAgD;YACjF,GAAG,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,oDAAoD;YACrF,uCAAuC,CAC1C,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/C,IAAI,CAAC,GAAG;QAAE,OAAO,mBAAmB,CAAC;IAErC,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAE,CAAC,IAAI,EAAE,CAAC;IAC/B,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,GAAG,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,IAAI,KAAK,oCAAoC,CAAC,CAAC;QACvE,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CACb,GAAG,GAAG,IAAI,KAAK,6DAA6D,CAC7E,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,gBAAgB,GAAmB;IACvC,IAAI,EAAE;QACJ,UAAU,EAAE,iBAAiB,EAAE;KAChC;CACF,CAAC;AAEF,eAAe,gBAAgB,CAAC","sourcesContent":["import type { ViteUserConfig } from \"vitest/config\";\n\n/**\n * Base vitest config that caps a suite's worker pool at a share of the machine.\n *\n * Vitest sizes its pool at `cores - 1` with no awareness of peer processes, so\n * several suites running at once — concurrent agent sessions, or a workspace\n * running packages in parallel — each try to claim the whole box. Set\n * `VITEST_CONCURRENCY` to a percentage or a worker count to change the lid; a\n * package that needs its own value sets `test.maxWorkers` in its own config,\n * which wins the merge.\n *\n * This ships from core rather than living at the monorepo root because template\n * directories are scaffolded out verbatim as standalone apps — a config that\n * reaches above the template would resolve to nothing in the generated app.\n *\n * Keep this module free of runtime imports so loading it costs a config file\n * nothing beyond reading the environment.\n */\n\nconst DEFAULT_MAX_WORKERS = \"25%\";\nconst ENV_KEYS = [\"VITEST_CONCURRENCY\", \"AGENT_NATIVE_VITEST_CONCURRENCY\"];\n\n/**\n * Resolve the worker lid from the environment, throwing on anything that is\n * neither a percentage nor a worker count. A bad value must not quietly become\n * the default — that reads as \"configured\" while running at some other size.\n */\nexport function resolveMaxWorkers(\n env: NodeJS.ProcessEnv = process.env,\n): string | number {\n const rawMaxWorkers = env.VITEST_MAX_WORKERS;\n if (rawMaxWorkers?.includes(\"%\")) {\n throw new Error(\n `VITEST_MAX_WORKERS=${rawMaxWorkers} is not a percentage to vitest — it parses as ` +\n `${Number.parseInt(rawMaxWorkers)} workers. Use VITEST_CONCURRENCY for percentages, ` +\n `or an integer for VITEST_MAX_WORKERS.`,\n );\n }\n\n const key = ENV_KEYS.find((name) => env[name]);\n if (!key) return DEFAULT_MAX_WORKERS;\n\n const value = env[key]!.trim();\n if (/^\\d+%$/.test(value)) {\n const percent = Number.parseInt(value);\n if (percent < 1 || percent > 100) {\n throw new Error(`${key}=${value} is out of range — use 1% to 100%.`);\n }\n return value;\n }\n\n const count = Number(value);\n if (!Number.isInteger(count) || count < 1) {\n throw new Error(\n `${key}=${value} is not a percentage like \"25%\" or a worker count like \"2\".`,\n );\n }\n return count;\n}\n\nconst vitestBaseConfig: ViteUserConfig = {\n test: {\n maxWorkers: resolveMaxWorkers(),\n },\n};\n\nexport default vitestBaseConfig;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.135.1",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"default": "./dist/index.js"
|
|
62
62
|
},
|
|
63
63
|
"./vite": "./dist/vite/index.js",
|
|
64
|
+
"./vitest-config": "./dist/vitest-config.js",
|
|
64
65
|
"./server": "./dist/server/index.js",
|
|
65
66
|
"./server/edge": "./dist/server/edge.js",
|
|
66
67
|
"./server/entry-server": "./dist/server/entry-server.js",
|
|
@@ -395,8 +396,8 @@
|
|
|
395
396
|
"y-protocols": "^1.0.7",
|
|
396
397
|
"yjs": "^13.6.31",
|
|
397
398
|
"zod": "^4.3.6",
|
|
398
|
-
"@agent-native/recap-cli": "0.5.
|
|
399
|
-
"@agent-native/toolkit": "^0.12.
|
|
399
|
+
"@agent-native/recap-cli": "0.5.2",
|
|
400
|
+
"@agent-native/toolkit": "^0.12.2"
|
|
400
401
|
},
|
|
401
402
|
"devDependencies": {
|
|
402
403
|
"@ai-sdk/anthropic": "^3.0.71",
|
|
@@ -586,6 +587,6 @@
|
|
|
586
587
|
"build": "tsc && tsc -p tsconfig.cli.json && node scripts/finalize-build.mjs && node scripts/check-dist-imports.mjs",
|
|
587
588
|
"dev": "tsc --watch",
|
|
588
589
|
"typecheck": "tsc --noEmit",
|
|
589
|
-
"test": "vitest --run --dir src
|
|
590
|
+
"test": "vitest --run --dir src"
|
|
590
591
|
}
|
|
591
592
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { getDbExec } from "../db/client.js";
|
|
2
|
-
import { isValidCron, nextOccurrence } from "../jobs/cron.js";
|
|
2
|
+
import { isValidCron, isValidTimezone, nextOccurrence } from "../jobs/cron.js";
|
|
3
3
|
import {
|
|
4
4
|
buildJobResourceContent,
|
|
5
5
|
normalizeJobMcpTools,
|
|
6
6
|
parseJobResource,
|
|
7
7
|
type JobFrontmatter,
|
|
8
8
|
} from "../jobs/frontmatter.js";
|
|
9
|
+
import { deleteAutomationRuns } from "../jobs/run-history.js";
|
|
10
|
+
import { resolveUserSchedulingTimezone } from "../localization/user-timezone.js";
|
|
9
11
|
import {
|
|
10
12
|
organizationIdFromResourceOwner,
|
|
11
13
|
organizationResourceOwner,
|
|
@@ -49,6 +51,7 @@ export interface DefineAutomationInput {
|
|
|
49
51
|
triggerType: "schedule" | "event";
|
|
50
52
|
body: string;
|
|
51
53
|
schedule?: string;
|
|
54
|
+
timezone?: string;
|
|
52
55
|
event?: string;
|
|
53
56
|
condition?: string;
|
|
54
57
|
domain?: string;
|
|
@@ -68,6 +71,7 @@ export interface UpdateAutomationInput {
|
|
|
68
71
|
condition?: string | null;
|
|
69
72
|
delegatedPolicyId?: string | null;
|
|
70
73
|
schedule?: string;
|
|
74
|
+
timezone?: string;
|
|
71
75
|
model?: string | null;
|
|
72
76
|
mcpTools?: unknown;
|
|
73
77
|
}
|
|
@@ -309,9 +313,20 @@ export async function defineAutomation(
|
|
|
309
313
|
throw httpError("event is required for event-triggered automations.", 400);
|
|
310
314
|
}
|
|
311
315
|
|
|
316
|
+
if (input.timezone && !isValidTimezone(input.timezone)) {
|
|
317
|
+
throw httpError(`Unknown timezone "${input.timezone}".`, 400);
|
|
318
|
+
}
|
|
319
|
+
// Resolve now and persist it: a schedule whose zone is implicit means
|
|
320
|
+
// something different the moment it is read on a differently-zoned host.
|
|
321
|
+
const timezone =
|
|
322
|
+
input.triggerType === "schedule"
|
|
323
|
+
? input.timezone || (await resolveUserSchedulingTimezone(actor.userEmail))
|
|
324
|
+
: undefined;
|
|
325
|
+
|
|
312
326
|
const mcpTools = normalizeJobMcpTools(input.mcpTools);
|
|
313
327
|
const meta: JobFrontmatter = {
|
|
314
328
|
schedule: input.triggerType === "schedule" ? schedule : "",
|
|
329
|
+
timezone,
|
|
315
330
|
enabled: true,
|
|
316
331
|
triggerType: input.triggerType,
|
|
317
332
|
event: input.triggerType === "event" ? event : undefined,
|
|
@@ -324,7 +339,7 @@ export async function defineAutomation(
|
|
|
324
339
|
runAs: "creator",
|
|
325
340
|
nextRun:
|
|
326
341
|
input.triggerType === "schedule"
|
|
327
|
-
? nextOccurrence(schedule).toISOString()
|
|
342
|
+
? nextOccurrence(schedule, undefined, timezone).toISOString()
|
|
328
343
|
: undefined,
|
|
329
344
|
model: input.model?.trim() || undefined,
|
|
330
345
|
mcpTools: mcpTools?.length ? mcpTools : undefined,
|
|
@@ -365,7 +380,22 @@ export async function updateAutomation(
|
|
|
365
380
|
throw httpError(`Invalid cron expression "${input.schedule}".`, 400);
|
|
366
381
|
}
|
|
367
382
|
meta.schedule = input.schedule;
|
|
368
|
-
|
|
383
|
+
}
|
|
384
|
+
if (input.timezone !== undefined) {
|
|
385
|
+
if (!isValidTimezone(input.timezone)) {
|
|
386
|
+
throw httpError(`Unknown timezone "${input.timezone}".`, 400);
|
|
387
|
+
}
|
|
388
|
+
if (meta.triggerType !== "schedule") {
|
|
389
|
+
throw httpError("Event automations do not have a timezone.", 400);
|
|
390
|
+
}
|
|
391
|
+
meta.timezone = input.timezone;
|
|
392
|
+
}
|
|
393
|
+
if (input.schedule !== undefined || input.timezone !== undefined) {
|
|
394
|
+
meta.nextRun = nextOccurrence(
|
|
395
|
+
meta.schedule,
|
|
396
|
+
undefined,
|
|
397
|
+
meta.timezone,
|
|
398
|
+
).toISOString();
|
|
369
399
|
}
|
|
370
400
|
if (input.enabled !== undefined) {
|
|
371
401
|
meta.enabled = input.enabled;
|
|
@@ -374,7 +404,11 @@ export async function updateAutomation(
|
|
|
374
404
|
meta.triggerType === "schedule" &&
|
|
375
405
|
isValidCron(meta.schedule)
|
|
376
406
|
) {
|
|
377
|
-
meta.nextRun = nextOccurrence(
|
|
407
|
+
meta.nextRun = nextOccurrence(
|
|
408
|
+
meta.schedule,
|
|
409
|
+
undefined,
|
|
410
|
+
meta.timezone,
|
|
411
|
+
).toISOString();
|
|
378
412
|
}
|
|
379
413
|
}
|
|
380
414
|
if (input.condition !== undefined) {
|
|
@@ -417,6 +451,9 @@ export async function deleteAutomation(
|
|
|
417
451
|
);
|
|
418
452
|
}
|
|
419
453
|
await resourceDelete(definition.resource.id);
|
|
454
|
+
// Names are reusable, so leaving history behind would attach these runs to
|
|
455
|
+
// whatever automation is created under the same name next.
|
|
456
|
+
await deleteAutomationRuns(definition.resource.owner, name);
|
|
420
457
|
}
|
|
421
458
|
|
|
422
459
|
export interface AutomationExecutionIdentity {
|
|
@@ -259,6 +259,24 @@ export function configPathFor(
|
|
|
259
259
|
// JSON client configs (Claude Code, Claude Code CLI, Cowork)
|
|
260
260
|
// ---------------------------------------------------------------------------
|
|
261
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Read an existing MCP config without conflating missing and unreadable files.
|
|
264
|
+
* Only ENOENT means the config is absent; any other read failure must abort
|
|
265
|
+
* before a caller can overwrite existing user configuration.
|
|
266
|
+
*/
|
|
267
|
+
function readExistingConfigFile(file: string): string | undefined {
|
|
268
|
+
try {
|
|
269
|
+
return fs.readFileSync(file, "utf-8");
|
|
270
|
+
} catch (error) {
|
|
271
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return undefined;
|
|
272
|
+
const detail = error instanceof Error ? ` (${error.message})` : "";
|
|
273
|
+
throw new Error(
|
|
274
|
+
`Cannot read MCP config file: ${file}\n` +
|
|
275
|
+
`Check that the file is readable and re-run. The file has not been modified.${detail}`,
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
262
280
|
/**
|
|
263
281
|
* Read and parse a JSON config file.
|
|
264
282
|
*
|
|
@@ -269,13 +287,8 @@ export function configPathFor(
|
|
|
269
287
|
* file with only the new MCP entry (data-loss hazard).
|
|
270
288
|
*/
|
|
271
289
|
function readJsonFile(file: string): Record<string, any> {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
raw = fs.readFileSync(file, "utf-8");
|
|
275
|
-
} catch {
|
|
276
|
-
// Missing (ENOENT) or unreadable file — treat as empty.
|
|
277
|
-
return {};
|
|
278
|
-
}
|
|
290
|
+
const raw = readExistingConfigFile(file);
|
|
291
|
+
if (raw === undefined) return {};
|
|
279
292
|
if (!raw.trim()) return {};
|
|
280
293
|
try {
|
|
281
294
|
const parsed = JSON.parse(raw);
|
|
@@ -576,12 +589,7 @@ export function writeCodexBlock(
|
|
|
576
589
|
name: string,
|
|
577
590
|
block: string | null,
|
|
578
591
|
): void {
|
|
579
|
-
|
|
580
|
-
try {
|
|
581
|
-
content = fs.readFileSync(file, "utf-8");
|
|
582
|
-
} catch {
|
|
583
|
-
content = "";
|
|
584
|
-
}
|
|
592
|
+
const content = readExistingConfigFile(file) ?? "";
|
|
585
593
|
|
|
586
594
|
const lines = content.split(/\r?\n/);
|
|
587
595
|
const out: string[] = [];
|
|
@@ -616,14 +624,12 @@ export function writeCodexBlock(
|
|
|
616
624
|
}
|
|
617
625
|
|
|
618
626
|
export function codexHasBlock(file: string, name: string): boolean {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
.some((line) => codexServerNameOfHeader(line) === name)
|
|
624
|
-
|
|
625
|
-
return false;
|
|
626
|
-
}
|
|
627
|
+
const content = readExistingConfigFile(file);
|
|
628
|
+
return (
|
|
629
|
+
content
|
|
630
|
+
?.split(/\r?\n/)
|
|
631
|
+
.some((line) => codexServerNameOfHeader(line) === name) ?? false
|
|
632
|
+
);
|
|
627
633
|
}
|
|
628
634
|
|
|
629
635
|
// ---------------------------------------------------------------------------
|
|
@@ -3,8 +3,10 @@ import {
|
|
|
3
3
|
IconBolt,
|
|
4
4
|
IconCalendarEvent,
|
|
5
5
|
IconClock,
|
|
6
|
+
IconAlertTriangle,
|
|
6
7
|
IconEye,
|
|
7
8
|
IconLoader2,
|
|
9
|
+
IconPencil,
|
|
8
10
|
IconPlayerPause,
|
|
9
11
|
IconPlayerPlay,
|
|
10
12
|
IconTrash,
|
|
@@ -24,6 +26,11 @@ import { useFormatters, useT } from "../i18n.js";
|
|
|
24
26
|
import { automationCreationContext } from "../settings/AutomationsSection.js";
|
|
25
27
|
import { AgentEmptyState } from "./AgentEmptyState.js";
|
|
26
28
|
import { AgentTabFrame } from "./AgentTabFrame.js";
|
|
29
|
+
import {
|
|
30
|
+
AutomationDetailsDialog,
|
|
31
|
+
type AutomationDetailsField,
|
|
32
|
+
} from "./AutomationDetailsDialog.js";
|
|
33
|
+
import { AutomationScheduleDialog } from "./AutomationScheduleDialog.js";
|
|
27
34
|
import type { AgentPageTabProps } from "./types.js";
|
|
28
35
|
import {
|
|
29
36
|
useAutomations,
|
|
@@ -62,6 +69,101 @@ function listAutomations(automations: Automation[]): ListedAutomation[] {
|
|
|
62
69
|
}));
|
|
63
70
|
}
|
|
64
71
|
|
|
72
|
+
type Translate = ReturnType<typeof useT>;
|
|
73
|
+
|
|
74
|
+
function describeTrigger(entry: ListedAutomation, t: Translate): string {
|
|
75
|
+
if (entry.kind === "automation" && entry.triggerType === "event") {
|
|
76
|
+
return t("jobs.automationEventDetails", {
|
|
77
|
+
defaultValue: "Runs when {{event}}.",
|
|
78
|
+
event: entry.resource.event ?? "an event fires",
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return (
|
|
82
|
+
entry.resource.scheduleDescription ||
|
|
83
|
+
entry.resource.schedule ||
|
|
84
|
+
t("jobs.scheduledTrigger", { defaultValue: "Scheduled" })
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function detailsFields(
|
|
89
|
+
entry: ListedAutomation,
|
|
90
|
+
t: Translate,
|
|
91
|
+
formatDateTime: (value: string | null) => string | null,
|
|
92
|
+
): AutomationDetailsField[] {
|
|
93
|
+
const resource = entry.resource;
|
|
94
|
+
const unset = t("jobs.notSet", { defaultValue: "—" });
|
|
95
|
+
const fields: AutomationDetailsField[] = [
|
|
96
|
+
{
|
|
97
|
+
label: t("jobs.status", { defaultValue: "Status" }),
|
|
98
|
+
value: resource.enabled
|
|
99
|
+
? t("jobs.enabled", { defaultValue: "Enabled" })
|
|
100
|
+
: t("jobs.paused", { defaultValue: "Paused" }),
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
label: t("jobs.trigger", { defaultValue: "Trigger" }),
|
|
104
|
+
value:
|
|
105
|
+
entry.triggerType === "event"
|
|
106
|
+
? t("jobs.eventTrigger", { defaultValue: "Event-triggered" })
|
|
107
|
+
: t("jobs.scheduledTrigger", { defaultValue: "Scheduled" }),
|
|
108
|
+
},
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
if (entry.triggerType === "schedule") {
|
|
112
|
+
fields.push(
|
|
113
|
+
{
|
|
114
|
+
label: t("jobs.cronExpression", { defaultValue: "Cron expression" }),
|
|
115
|
+
value: resource.schedule || unset,
|
|
116
|
+
mono: true,
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
label: t("jobs.timezone", { defaultValue: "Timezone" }),
|
|
120
|
+
value: resource.timezone || unset,
|
|
121
|
+
},
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
fields.push(
|
|
126
|
+
{
|
|
127
|
+
label: t("jobs.nextRun", { defaultValue: "Next run" }),
|
|
128
|
+
value: formatDateTime(resource.nextRun) ?? unset,
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
label: t("jobs.lastRun", { defaultValue: "Last run" }),
|
|
132
|
+
value:
|
|
133
|
+
formatDateTime(resource.lastRun) ??
|
|
134
|
+
t("jobs.neverRan", { defaultValue: "Never" }),
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
label: t("jobs.lastChecked", { defaultValue: "Last checked" }),
|
|
138
|
+
value: formatDateTime(resource.lastCheck) ?? unset,
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
label: t("jobs.lastStatus", { defaultValue: "Last status" }),
|
|
142
|
+
value: resource.lastStatus || unset,
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
label: t("jobs.scope", { defaultValue: "Scope" }),
|
|
146
|
+
value:
|
|
147
|
+
resource.scope === "organization"
|
|
148
|
+
? t("jobs.organization", { defaultValue: "Organization" })
|
|
149
|
+
: t("jobs.personal", { defaultValue: "Personal" }),
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
label: t("jobs.createdBy", { defaultValue: "Created by" }),
|
|
153
|
+
value: resource.createdBy || unset,
|
|
154
|
+
},
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
if (entry.kind === "automation") {
|
|
158
|
+
fields.push({
|
|
159
|
+
label: t("jobs.model", { defaultValue: "Model" }),
|
|
160
|
+
value: entry.resource.model || unset,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return fields;
|
|
165
|
+
}
|
|
166
|
+
|
|
65
167
|
export function organizationAutomationCreationContext(): string {
|
|
66
168
|
return "The user wants to create a new organization automation. Use manage-automations with action=define and scope=organization to create it. Ask clarifying questions if needed about whether it runs on a schedule or event, any conditions, and what actions to take.";
|
|
67
169
|
}
|
|
@@ -83,6 +185,9 @@ export function AgentJobsTab({ canManageOrg = false }: AgentPageTabProps) {
|
|
|
83
185
|
const [detailsTarget, setDetailsTarget] = useState<ListedAutomation | null>(
|
|
84
186
|
null,
|
|
85
187
|
);
|
|
188
|
+
const [scheduleTarget, setScheduleTarget] = useState<ListedAutomation | null>(
|
|
189
|
+
null,
|
|
190
|
+
);
|
|
86
191
|
|
|
87
192
|
const formatDateTime = (value: string | null) => {
|
|
88
193
|
if (!value || Number.isNaN(new Date(value).getTime())) return null;
|
|
@@ -111,14 +216,14 @@ export function AgentJobsTab({ canManageOrg = false }: AgentPageTabProps) {
|
|
|
111
216
|
const mutateEntry = (
|
|
112
217
|
entry: ListedAutomation,
|
|
113
218
|
operation: "update" | "delete",
|
|
114
|
-
enabled?: boolean,
|
|
219
|
+
patch?: { enabled?: boolean; schedule?: string },
|
|
115
220
|
onSuccess?: () => void,
|
|
116
221
|
) => {
|
|
117
222
|
const input = {
|
|
118
223
|
operation,
|
|
119
224
|
name: entry.resource.name,
|
|
120
225
|
scope: entry.resource.scope,
|
|
121
|
-
...
|
|
226
|
+
...patch,
|
|
122
227
|
};
|
|
123
228
|
const options = onSuccess ? { onSuccess } : undefined;
|
|
124
229
|
|
|
@@ -243,6 +348,7 @@ export function AgentJobsTab({ canManageOrg = false }: AgentPageTabProps) {
|
|
|
243
348
|
{entries.map((entry) => {
|
|
244
349
|
const resource = entry.resource;
|
|
245
350
|
const lastRun = formatDateTime(resource.lastRun);
|
|
351
|
+
const lastCheck = formatDateTime(resource.lastCheck);
|
|
246
352
|
const nextRun = formatDateTime(resource.nextRun);
|
|
247
353
|
const triggerDescription =
|
|
248
354
|
entry.kind === "automation" && entry.triggerType === "event"
|
|
@@ -310,7 +416,7 @@ export function AgentJobsTab({ canManageOrg = false }: AgentPageTabProps) {
|
|
|
310
416
|
<p className="mt-1 line-clamp-2 text-xs text-muted-foreground/80">
|
|
311
417
|
{instructions}
|
|
312
418
|
</p>
|
|
313
|
-
{lastRun || nextRun ? (
|
|
419
|
+
{lastRun || nextRun || lastCheck ? (
|
|
314
420
|
<div className="mt-2 flex flex-wrap gap-x-4 gap-y-1 text-[11px] text-muted-foreground">
|
|
315
421
|
{nextRun ? (
|
|
316
422
|
<span>
|
|
@@ -318,14 +424,29 @@ export function AgentJobsTab({ canManageOrg = false }: AgentPageTabProps) {
|
|
|
318
424
|
{nextRun}
|
|
319
425
|
</span>
|
|
320
426
|
) : null}
|
|
321
|
-
|
|
427
|
+
<span>
|
|
428
|
+
{t("jobs.lastRun", { defaultValue: "Last run" })}:{" "}
|
|
429
|
+
{lastRun ??
|
|
430
|
+
t("jobs.neverRan", { defaultValue: "Never" })}
|
|
431
|
+
</span>
|
|
432
|
+
{!lastRun && lastCheck ? (
|
|
322
433
|
<span>
|
|
323
|
-
{t("jobs.
|
|
324
|
-
|
|
434
|
+
{t("jobs.lastChecked", {
|
|
435
|
+
defaultValue: "Last checked",
|
|
436
|
+
})}
|
|
437
|
+
: {lastCheck}
|
|
325
438
|
</span>
|
|
326
439
|
) : null}
|
|
327
440
|
</div>
|
|
328
441
|
) : null}
|
|
442
|
+
{resource.lastError ? (
|
|
443
|
+
<p className="mt-2 flex items-start gap-1.5 text-[11px] text-destructive">
|
|
444
|
+
<IconAlertTriangle className="mt-px size-3 shrink-0" />
|
|
445
|
+
<span className="min-w-0 break-words">
|
|
446
|
+
{resource.lastError}
|
|
447
|
+
</span>
|
|
448
|
+
</p>
|
|
449
|
+
) : null}
|
|
329
450
|
</div>
|
|
330
451
|
<div className="flex shrink-0 items-center gap-1">
|
|
331
452
|
<Button
|
|
@@ -340,6 +461,19 @@ export function AgentJobsTab({ canManageOrg = false }: AgentPageTabProps) {
|
|
|
340
461
|
</Button>
|
|
341
462
|
{resource.canUpdate ? (
|
|
342
463
|
<>
|
|
464
|
+
{entry.triggerType === "schedule" ? (
|
|
465
|
+
<Button
|
|
466
|
+
type="button"
|
|
467
|
+
variant="ghost"
|
|
468
|
+
size="sm"
|
|
469
|
+
className="cursor-pointer px-2 text-xs"
|
|
470
|
+
disabled={mutationPending}
|
|
471
|
+
onClick={() => setScheduleTarget(entry)}
|
|
472
|
+
>
|
|
473
|
+
<IconPencil className="size-3.5" />
|
|
474
|
+
{t("jobs.edit", { defaultValue: "Edit" })}
|
|
475
|
+
</Button>
|
|
476
|
+
) : null}
|
|
343
477
|
<Button
|
|
344
478
|
type="button"
|
|
345
479
|
variant="ghost"
|
|
@@ -347,7 +481,9 @@ export function AgentJobsTab({ canManageOrg = false }: AgentPageTabProps) {
|
|
|
347
481
|
className="cursor-pointer px-2 text-xs"
|
|
348
482
|
disabled={mutationPending}
|
|
349
483
|
onClick={() =>
|
|
350
|
-
mutateEntry(entry, "update",
|
|
484
|
+
mutateEntry(entry, "update", {
|
|
485
|
+
enabled: !resource.enabled,
|
|
486
|
+
})
|
|
351
487
|
}
|
|
352
488
|
>
|
|
353
489
|
{resource.enabled ? (
|
|
@@ -505,84 +641,50 @@ export function AgentJobsTab({ canManageOrg = false }: AgentPageTabProps) {
|
|
|
505
641
|
</DialogContent>
|
|
506
642
|
</Dialog>
|
|
507
643
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
{
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
) : null}
|
|
553
|
-
<div>
|
|
554
|
-
<p className="text-xs font-medium text-foreground">
|
|
555
|
-
{t("jobs.instructions", { defaultValue: "Instructions" })}
|
|
556
|
-
</p>
|
|
557
|
-
<p className="mt-1 whitespace-pre-wrap text-sm text-muted-foreground">
|
|
558
|
-
{detailsTarget.kind === "automation"
|
|
559
|
-
? detailsTarget.resource.body
|
|
560
|
-
: detailsTarget.resource.instructions}
|
|
561
|
-
</p>
|
|
562
|
-
</div>
|
|
563
|
-
{(detailsTarget.resource.mcpTools ?? []).length > 0 ? (
|
|
564
|
-
<div>
|
|
565
|
-
<p className="text-xs font-medium text-foreground">
|
|
566
|
-
{t("jobs.mcpTools", {
|
|
567
|
-
defaultValue: "Connected MCP tools",
|
|
568
|
-
})}
|
|
569
|
-
</p>
|
|
570
|
-
<div className="mt-1 flex flex-wrap gap-1.5">
|
|
571
|
-
{(detailsTarget.resource.mcpTools ?? []).map((toolName) => (
|
|
572
|
-
<code
|
|
573
|
-
key={toolName}
|
|
574
|
-
className="rounded bg-muted px-1.5 py-0.5 text-[11px] text-muted-foreground"
|
|
575
|
-
>
|
|
576
|
-
{toolName}
|
|
577
|
-
</code>
|
|
578
|
-
))}
|
|
579
|
-
</div>
|
|
580
|
-
</div>
|
|
581
|
-
) : null}
|
|
582
|
-
</div>
|
|
583
|
-
) : null}
|
|
584
|
-
</DialogContent>
|
|
585
|
-
</Dialog>
|
|
644
|
+
{detailsTarget ? (
|
|
645
|
+
<AutomationDetailsDialog
|
|
646
|
+
open
|
|
647
|
+
name={detailsTarget.resource.name}
|
|
648
|
+
scope={
|
|
649
|
+
detailsTarget.resource.scope === "organization" ? "org" : "user"
|
|
650
|
+
}
|
|
651
|
+
triggerSummary={describeTrigger(detailsTarget, t)}
|
|
652
|
+
fields={detailsFields(detailsTarget, t, formatDateTime)}
|
|
653
|
+
condition={
|
|
654
|
+
detailsTarget.kind === "automation"
|
|
655
|
+
? detailsTarget.resource.condition
|
|
656
|
+
: null
|
|
657
|
+
}
|
|
658
|
+
instructions={
|
|
659
|
+
detailsTarget.kind === "automation"
|
|
660
|
+
? detailsTarget.resource.body
|
|
661
|
+
: detailsTarget.resource.instructions
|
|
662
|
+
}
|
|
663
|
+
mcpTools={detailsTarget.resource.mcpTools ?? []}
|
|
664
|
+
lastError={detailsTarget.resource.lastError}
|
|
665
|
+
formatTimestamp={(value) =>
|
|
666
|
+
formatDateTime(new Date(value).toISOString()) ?? String(value)
|
|
667
|
+
}
|
|
668
|
+
onClose={() => setDetailsTarget(null)}
|
|
669
|
+
/>
|
|
670
|
+
) : null}
|
|
671
|
+
|
|
672
|
+
{scheduleTarget ? (
|
|
673
|
+
<AutomationScheduleDialog
|
|
674
|
+
open
|
|
675
|
+
name={scheduleTarget.resource.name}
|
|
676
|
+
schedule={scheduleTarget.resource.schedule ?? ""}
|
|
677
|
+
timezone={scheduleTarget.resource.timezone ?? null}
|
|
678
|
+
saving={mutationPending}
|
|
679
|
+
error={mutationError ? mutationError.message : null}
|
|
680
|
+
onCancel={() => setScheduleTarget(null)}
|
|
681
|
+
onSave={(next) =>
|
|
682
|
+
mutateEntry(scheduleTarget, "update", next, () =>
|
|
683
|
+
setScheduleTarget(null),
|
|
684
|
+
)
|
|
685
|
+
}
|
|
686
|
+
/>
|
|
687
|
+
) : null}
|
|
586
688
|
</AgentTabFrame>
|
|
587
689
|
);
|
|
588
690
|
}
|