@agent-native/core 0.134.1 → 0.135.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +3 -3
- package/corpus/core/CHANGELOG.md +107 -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/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/add-comment.ts +15 -1
- package/corpus/templates/content/actions/list-documents.ts +1 -0
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +5 -2
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +50 -1
- package/corpus/templates/content/app/components/ui/switch.tsx +1 -0
- package/corpus/templates/content/app/hooks/use-content-prefs.ts +55 -0
- package/corpus/templates/content/app/i18n-data.ts +40 -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/server/lib/comment-notifications.ts +146 -0
- 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/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/collab/struct-routes.d.ts +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 +1 -1
- package/dist/observability/routes.d.ts +1 -1
- 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/provider-api/actions/custom-provider-registration.d.ts +10 -10
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- 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/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/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
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import baseConfig from "@agent-native/core/vitest-config";
|
|
4
|
+
import { defineConfig, mergeConfig } from "vitest/config";
|
|
4
5
|
|
|
5
|
-
export default
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
export default mergeConfig(
|
|
7
|
+
baseConfig,
|
|
8
|
+
defineConfig({
|
|
9
|
+
resolve: {
|
|
10
|
+
alias: {
|
|
11
|
+
"@": path.resolve(__dirname, "./app"),
|
|
12
|
+
"@shared": path.resolve(__dirname, "./shared"),
|
|
13
|
+
},
|
|
10
14
|
},
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
},
|
|
23
|
-
|
|
15
|
+
test: {
|
|
16
|
+
include: ["**/*.{test,spec}.?(c|m)[jt]s?(x)"],
|
|
17
|
+
exclude: [
|
|
18
|
+
"**/node_modules/**",
|
|
19
|
+
"**/.git/**",
|
|
20
|
+
"**/dist/**",
|
|
21
|
+
"**/.output/**",
|
|
22
|
+
"**/.react-router/**",
|
|
23
|
+
"**/e2e/**",
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
}),
|
|
27
|
+
);
|
|
@@ -4,6 +4,7 @@ import { assertAccess } from "@agent-native/core/sharing";
|
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
|
|
6
6
|
import { getDb, schema } from "../server/db/index.js";
|
|
7
|
+
import { notifyDocumentComment } from "../server/lib/comment-notifications.js";
|
|
7
8
|
|
|
8
9
|
type Mention = { email: string; name: string };
|
|
9
10
|
|
|
@@ -115,6 +116,19 @@ export default defineAction({
|
|
|
115
116
|
authorName: name,
|
|
116
117
|
});
|
|
117
118
|
|
|
118
|
-
|
|
119
|
+
const notified = await notifyDocumentComment({
|
|
120
|
+
documentId,
|
|
121
|
+
documentTitle: (access.resource.title as string | null) ?? "",
|
|
122
|
+
orgId: (access.resource.orgId as string | null) ?? null,
|
|
123
|
+
threadId,
|
|
124
|
+
ownerEmail,
|
|
125
|
+
authorEmail: email,
|
|
126
|
+
authorName: name,
|
|
127
|
+
content,
|
|
128
|
+
mentions,
|
|
129
|
+
isReply: Boolean(parentId ?? args.threadId),
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
return { id, threadId, notified };
|
|
119
133
|
},
|
|
120
134
|
});
|
|
@@ -337,6 +337,7 @@ export default defineAction({
|
|
|
337
337
|
id: database.id,
|
|
338
338
|
documentId: database.documentId,
|
|
339
339
|
title: database.title,
|
|
340
|
+
systemRole: database.systemRole,
|
|
340
341
|
description: d.description,
|
|
341
342
|
viewConfig: parseDatabaseViewConfig(database.viewConfigJson),
|
|
342
343
|
createdAt: database.createdAt,
|
|
@@ -445,6 +445,7 @@ export function documentEditorBreadcrumbNavigationItems(
|
|
|
445
445
|
| "title"
|
|
446
446
|
| "icon"
|
|
447
447
|
| "position"
|
|
448
|
+
| "database"
|
|
448
449
|
| "databaseMembership"
|
|
449
450
|
| "source"
|
|
450
451
|
>[], // i18n-ignore type expression
|
|
@@ -457,6 +458,9 @@ export function documentEditorBreadcrumbNavigationItems(
|
|
|
457
458
|
workspacesTitle: string;
|
|
458
459
|
},
|
|
459
460
|
): ToolbarBreadcrumbItem[] {
|
|
461
|
+
const peerDocuments = documents.filter(
|
|
462
|
+
(item) => !item.database?.systemRole && item.source?.kind !== "folder",
|
|
463
|
+
);
|
|
460
464
|
const documentById = new Map(documents.map((item) => [item.id, item]));
|
|
461
465
|
const workspaceDocumentIds = new Set(
|
|
462
466
|
spaces.map((space) => space.filesDocumentId),
|
|
@@ -480,9 +484,8 @@ export function documentEditorBreadcrumbNavigationItems(
|
|
|
480
484
|
if (!current) return item;
|
|
481
485
|
const membershipDocumentId =
|
|
482
486
|
current.databaseMembership?.databaseDocumentId ?? null;
|
|
483
|
-
const siblings =
|
|
487
|
+
const siblings = peerDocuments
|
|
484
488
|
.filter((candidate) => {
|
|
485
|
-
if (candidate.source?.kind === "folder") return false;
|
|
486
489
|
if (candidate.parentId !== current.parentId) return false;
|
|
487
490
|
if (current.parentId) return true;
|
|
488
491
|
return (
|
|
@@ -318,6 +318,15 @@ export function compactToolbarBreadcrumbItems(
|
|
|
318
318
|
];
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
+
export function firstSelectableBreadcrumbMenuItemId(
|
|
322
|
+
menuItems: ToolbarBreadcrumbItem["menuItems"],
|
|
323
|
+
currentDocumentId: string,
|
|
324
|
+
): string | null {
|
|
325
|
+
return (
|
|
326
|
+
menuItems?.find((menuItem) => menuItem.id !== currentDocumentId)?.id ?? null
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
|
|
321
330
|
function ToolbarBreadcrumbMenu({
|
|
322
331
|
item,
|
|
323
332
|
label,
|
|
@@ -337,6 +346,12 @@ function ToolbarBreadcrumbMenu({
|
|
|
337
346
|
}) {
|
|
338
347
|
const [open, setOpen] = useState(false);
|
|
339
348
|
const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
349
|
+
const openedWithKeyboardRef = useRef(false);
|
|
350
|
+
const firstSelectableItemRef = useRef<HTMLDivElement | null>(null);
|
|
351
|
+
const firstSelectableItemId = firstSelectableBreadcrumbMenuItemId(
|
|
352
|
+
item.menuItems,
|
|
353
|
+
currentDocumentId,
|
|
354
|
+
);
|
|
340
355
|
|
|
341
356
|
function cancelClose() {
|
|
342
357
|
if (!closeTimerRef.current) return;
|
|
@@ -349,8 +364,25 @@ function ToolbarBreadcrumbMenu({
|
|
|
349
364
|
closeTimerRef.current = setTimeout(() => setOpen(false), 140);
|
|
350
365
|
}
|
|
351
366
|
|
|
367
|
+
useEffect(() => {
|
|
368
|
+
if (!open || !openedWithKeyboardRef.current) return;
|
|
369
|
+
openedWithKeyboardRef.current = false;
|
|
370
|
+
const frame = requestAnimationFrame(() => {
|
|
371
|
+
firstSelectableItemRef.current?.focus();
|
|
372
|
+
});
|
|
373
|
+
return () => cancelAnimationFrame(frame);
|
|
374
|
+
}, [open]);
|
|
375
|
+
|
|
352
376
|
return (
|
|
353
|
-
<DropdownMenu
|
|
377
|
+
<DropdownMenu
|
|
378
|
+
modal={false}
|
|
379
|
+
open={open}
|
|
380
|
+
onOpenChange={(nextOpen) => {
|
|
381
|
+
if (nextOpen) cancelClose();
|
|
382
|
+
else openedWithKeyboardRef.current = false;
|
|
383
|
+
setOpen(nextOpen);
|
|
384
|
+
}}
|
|
385
|
+
>
|
|
354
386
|
<DropdownMenuTrigger asChild>
|
|
355
387
|
<button
|
|
356
388
|
type="button"
|
|
@@ -364,6 +396,16 @@ function ToolbarBreadcrumbMenu({
|
|
|
364
396
|
setOpen(true);
|
|
365
397
|
}}
|
|
366
398
|
onPointerLeave={scheduleClose}
|
|
399
|
+
onKeyDown={(event) => {
|
|
400
|
+
if (
|
|
401
|
+
event.key === "Enter" ||
|
|
402
|
+
event.key === " " ||
|
|
403
|
+
event.key === "ArrowDown"
|
|
404
|
+
) {
|
|
405
|
+
openedWithKeyboardRef.current = true;
|
|
406
|
+
cancelClose();
|
|
407
|
+
}
|
|
408
|
+
}}
|
|
367
409
|
>
|
|
368
410
|
{children}
|
|
369
411
|
</button>
|
|
@@ -371,6 +413,7 @@ function ToolbarBreadcrumbMenu({
|
|
|
371
413
|
<DropdownMenuContent
|
|
372
414
|
align="start"
|
|
373
415
|
className="w-64"
|
|
416
|
+
onKeyDown={cancelClose}
|
|
374
417
|
onPointerEnter={cancelClose}
|
|
375
418
|
onPointerLeave={scheduleClose}
|
|
376
419
|
>
|
|
@@ -379,7 +422,13 @@ function ToolbarBreadcrumbMenu({
|
|
|
379
422
|
return (
|
|
380
423
|
<DropdownMenuItem
|
|
381
424
|
key={menuItem.id}
|
|
425
|
+
ref={
|
|
426
|
+
menuItem.id === firstSelectableItemId
|
|
427
|
+
? firstSelectableItemRef
|
|
428
|
+
: undefined
|
|
429
|
+
}
|
|
382
430
|
className="gap-2"
|
|
431
|
+
disabled={menuItem.id === currentDocumentId}
|
|
383
432
|
onSelect={() => onOpen(menuItem.id)}
|
|
384
433
|
>
|
|
385
434
|
<span className="flex size-4 shrink-0 items-center justify-center">
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "@agent-native/toolkit/ui/switch";
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { agentNativePath } from "@agent-native/core/client/api-path";
|
|
2
|
+
import type { ContentUserPrefs } from "@shared/content-user-prefs";
|
|
3
|
+
import { useCallback, useEffect, useState } from "react";
|
|
4
|
+
|
|
5
|
+
const PREFS_PATH = "/_agent-native/content/user-prefs";
|
|
6
|
+
|
|
7
|
+
export interface ContentPrefsState {
|
|
8
|
+
prefs: ContentUserPrefs;
|
|
9
|
+
loading: boolean;
|
|
10
|
+
/** Applies the patch optimistically and rolls back if the write fails. */
|
|
11
|
+
save: (patch: ContentUserPrefs) => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function useContentPrefs(): ContentPrefsState {
|
|
15
|
+
const [prefs, setPrefs] = useState<ContentUserPrefs>({});
|
|
16
|
+
const [loading, setLoading] = useState(true);
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
let cancelled = false;
|
|
20
|
+
void (async () => {
|
|
21
|
+
try {
|
|
22
|
+
const res = await fetch(agentNativePath(PREFS_PATH));
|
|
23
|
+
const json = res.ok ? await res.json() : null;
|
|
24
|
+
if (cancelled) return;
|
|
25
|
+
if (json && typeof json === "object" && !("error" in json)) {
|
|
26
|
+
setPrefs(json as ContentUserPrefs);
|
|
27
|
+
}
|
|
28
|
+
} finally {
|
|
29
|
+
if (!cancelled) setLoading(false);
|
|
30
|
+
}
|
|
31
|
+
})();
|
|
32
|
+
return () => {
|
|
33
|
+
cancelled = true;
|
|
34
|
+
};
|
|
35
|
+
}, []);
|
|
36
|
+
|
|
37
|
+
const save = useCallback(
|
|
38
|
+
async (patch: ContentUserPrefs) => {
|
|
39
|
+
const previous = prefs;
|
|
40
|
+
setPrefs((current) => ({ ...current, ...patch }));
|
|
41
|
+
const res = await fetch(agentNativePath(PREFS_PATH), {
|
|
42
|
+
method: "PUT",
|
|
43
|
+
headers: { "Content-Type": "application/json" },
|
|
44
|
+
body: JSON.stringify(patch),
|
|
45
|
+
});
|
|
46
|
+
if (!res.ok) {
|
|
47
|
+
setPrefs(previous);
|
|
48
|
+
throw new Error(`Save failed (${res.status})`);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
[prefs],
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
return { prefs, loading, save };
|
|
55
|
+
}
|
|
@@ -3055,6 +3055,10 @@ const enUS = {
|
|
|
3055
3055
|
metaTitle: "Settings - Content",
|
|
3056
3056
|
title: "Settings",
|
|
3057
3057
|
description: "Language and workspace preferences for Content.",
|
|
3058
|
+
emailNotifications: "Email notifications",
|
|
3059
|
+
emailNotificationsDescription:
|
|
3060
|
+
"Get an email when someone comments on, replies in, or mentions you on your document.",
|
|
3061
|
+
saveFailed: "Failed to save",
|
|
3058
3062
|
languageTitle: "Language",
|
|
3059
3063
|
languageDescription:
|
|
3060
3064
|
"Choose the interface language. This preference is saved for your account.",
|
|
@@ -9133,6 +9137,10 @@ export const messagesByLocale = {
|
|
|
9133
9137
|
settings: {
|
|
9134
9138
|
title: "设置",
|
|
9135
9139
|
description: "Content 的语言和工作区偏好设置。",
|
|
9140
|
+
emailNotifications: "邮件通知",
|
|
9141
|
+
emailNotificationsDescription:
|
|
9142
|
+
"当有人评论你的文档、在讨论串中回复或提到你时,收到邮件通知。",
|
|
9143
|
+
saveFailed: "保存失败",
|
|
9136
9144
|
languageTitle: "语言",
|
|
9137
9145
|
languageDescription: "选择界面语言。此偏好会保存到你的账户。",
|
|
9138
9146
|
languageLabel: "界面语言",
|
|
@@ -9325,6 +9333,10 @@ export const messagesByLocale = {
|
|
|
9325
9333
|
settings: {
|
|
9326
9334
|
title: "Ajustes",
|
|
9327
9335
|
description: "Preferencias de idioma y espacio de trabajo para Content.",
|
|
9336
|
+
emailNotifications: "Notificaciones por correo",
|
|
9337
|
+
emailNotificationsDescription:
|
|
9338
|
+
"Recibe un correo cuando alguien comente, responda o te mencione en tu documento.",
|
|
9339
|
+
saveFailed: "No se pudo guardar",
|
|
9328
9340
|
languageTitle: "Idioma",
|
|
9329
9341
|
languageDescription:
|
|
9330
9342
|
"Elige el idioma de la interfaz. Esta preferencia se guarda en tu cuenta.",
|
|
@@ -9524,6 +9536,10 @@ export const messagesByLocale = {
|
|
|
9524
9536
|
settings: {
|
|
9525
9537
|
title: "Paramètres",
|
|
9526
9538
|
description: "Préférences de langue et d’espace de travail pour Content.",
|
|
9539
|
+
emailNotifications: "Notifications par e-mail",
|
|
9540
|
+
emailNotificationsDescription:
|
|
9541
|
+
"Recevez un e-mail lorsqu’une personne commente, répond ou vous mentionne dans votre document.",
|
|
9542
|
+
saveFailed: "Échec de l’enregistrement",
|
|
9527
9543
|
languageTitle: "Langue",
|
|
9528
9544
|
languageDescription:
|
|
9529
9545
|
"Choisissez la langue de l’interface. Cette préférence est enregistrée dans votre compte.",
|
|
@@ -9721,6 +9737,10 @@ export const messagesByLocale = {
|
|
|
9721
9737
|
settings: {
|
|
9722
9738
|
title: "Einstellungen",
|
|
9723
9739
|
description: "Sprach- und Arbeitsbereichseinstellungen für Content.",
|
|
9740
|
+
emailNotifications: "E-Mail-Benachrichtigungen",
|
|
9741
|
+
emailNotificationsDescription:
|
|
9742
|
+
"Erhalte eine E-Mail, wenn jemand dein Dokument kommentiert, antwortet oder dich erwähnt.",
|
|
9743
|
+
saveFailed: "Speichern fehlgeschlagen",
|
|
9724
9744
|
languageTitle: "Sprache",
|
|
9725
9745
|
languageDescription:
|
|
9726
9746
|
"Wähle die Sprache der Oberfläche. Diese Einstellung wird in deinem Konto gespeichert.",
|
|
@@ -9917,6 +9937,10 @@ export const messagesByLocale = {
|
|
|
9917
9937
|
settings: {
|
|
9918
9938
|
title: "設定",
|
|
9919
9939
|
description: "Content の言語とワークスペース設定。",
|
|
9940
|
+
emailNotifications: "メール通知",
|
|
9941
|
+
emailNotificationsDescription:
|
|
9942
|
+
"誰かがあなたのドキュメントにコメント、返信、またはあなたにメンションしたときにメールを受け取ります。",
|
|
9943
|
+
saveFailed: "保存に失敗しました",
|
|
9920
9944
|
languageTitle: "言語",
|
|
9921
9945
|
languageDescription:
|
|
9922
9946
|
"インターフェース言語を選択します。この設定はアカウントに保存されます。",
|
|
@@ -10105,6 +10129,10 @@ export const messagesByLocale = {
|
|
|
10105
10129
|
settings: {
|
|
10106
10130
|
title: "설정",
|
|
10107
10131
|
description: "Content의 언어 및 워크스페이스 환경설정입니다.",
|
|
10132
|
+
emailNotifications: "이메일 알림",
|
|
10133
|
+
emailNotificationsDescription:
|
|
10134
|
+
"누군가 내 문서에 댓글을 달거나 답글을 남기거나 나를 멘션하면 이메일을 받습니다.",
|
|
10135
|
+
saveFailed: "저장 실패",
|
|
10108
10136
|
languageTitle: "언어",
|
|
10109
10137
|
languageDescription:
|
|
10110
10138
|
"인터페이스 언어를 선택하세요. 이 기본 설정은 계정에 저장됩니다.",
|
|
@@ -10299,6 +10327,10 @@ export const messagesByLocale = {
|
|
|
10299
10327
|
settings: {
|
|
10300
10328
|
title: "Configurações",
|
|
10301
10329
|
description: "Preferências de idioma e espaço de trabalho do Content.",
|
|
10330
|
+
emailNotifications: "Notificações por e-mail",
|
|
10331
|
+
emailNotificationsDescription:
|
|
10332
|
+
"Receba um e-mail quando alguém comentar, responder ou mencionar você no seu documento.",
|
|
10333
|
+
saveFailed: "Falha ao salvar",
|
|
10302
10334
|
languageTitle: "Idioma",
|
|
10303
10335
|
languageDescription:
|
|
10304
10336
|
"Escolha o idioma da interface. Essa preferência é salva na sua conta.",
|
|
@@ -10486,6 +10518,10 @@ export const messagesByLocale = {
|
|
|
10486
10518
|
settings: {
|
|
10487
10519
|
title: "सेटिंग्स",
|
|
10488
10520
|
description: "Content के लिए भाषा और कार्यस्थान प्राथमिकताएं।",
|
|
10521
|
+
emailNotifications: "ईमेल सूचनाएँ",
|
|
10522
|
+
emailNotificationsDescription:
|
|
10523
|
+
"जब कोई आपके दस्तावेज़ पर टिप्पणी करे, जवाब दे या आपका उल्लेख करे तो ईमेल पाएँ।",
|
|
10524
|
+
saveFailed: "सहेजने में विफल",
|
|
10489
10525
|
languageTitle: "भाषा",
|
|
10490
10526
|
languageDescription: "इंटरफ़ेस भाषा चुनें। यह पसंद आपके खाते में सहेजी जाती है।",
|
|
10491
10527
|
languageLabel: "इंटरफ़ेस भाषा",
|
|
@@ -10672,6 +10708,10 @@ export const messagesByLocale = {
|
|
|
10672
10708
|
settings: {
|
|
10673
10709
|
title: "الإعدادات",
|
|
10674
10710
|
description: "تفضيلات اللغة ومساحة العمل في Content.",
|
|
10711
|
+
emailNotifications: "إشعارات البريد الإلكتروني",
|
|
10712
|
+
emailNotificationsDescription:
|
|
10713
|
+
"احصل على بريد إلكتروني عندما يعلّق شخص على مستندك أو يرد أو يذكرك.",
|
|
10714
|
+
saveFailed: "فشل الحفظ",
|
|
10675
10715
|
languageTitle: "اللغة",
|
|
10676
10716
|
languageDescription: "اختر لغة الواجهة. يتم حفظ هذا التفضيل في حسابك.",
|
|
10677
10717
|
languageLabel: "لغة الواجهة",
|
|
@@ -3,6 +3,8 @@ import { LanguagePicker, useT } from "@agent-native/core/client/i18n";
|
|
|
3
3
|
import { TeamPage } from "@agent-native/core/client/org";
|
|
4
4
|
import {
|
|
5
5
|
AccountSettingsCard,
|
|
6
|
+
SettingsGroup,
|
|
7
|
+
SettingsRow,
|
|
6
8
|
SettingsTabsPage,
|
|
7
9
|
useAgentSettingsTabs,
|
|
8
10
|
type SettingsSearchEntry,
|
|
@@ -10,8 +12,10 @@ import {
|
|
|
10
12
|
import { CreativeContextSettingsLink } from "@agent-native/creative-context/client";
|
|
11
13
|
import { useSetPageTitle } from "@agent-native/toolkit/app-shell";
|
|
12
14
|
import { useMemo } from "react";
|
|
15
|
+
import { toast } from "sonner";
|
|
13
16
|
|
|
14
|
-
import {
|
|
17
|
+
import { Switch } from "@/components/ui/switch";
|
|
18
|
+
import { useContentPrefs } from "@/hooks/use-content-prefs";
|
|
15
19
|
import { messagesByLocale } from "@/i18n-data";
|
|
16
20
|
|
|
17
21
|
import changelog from "../../CHANGELOG.md?raw";
|
|
@@ -24,6 +28,7 @@ export default function SettingsRoute() {
|
|
|
24
28
|
const t = useT();
|
|
25
29
|
const agentSettingsTabs = useAgentSettingsTabs();
|
|
26
30
|
useSetPageTitle(t("settings.title"));
|
|
31
|
+
const { prefs, loading: prefsLoading, save: savePrefs } = useContentPrefs();
|
|
27
32
|
|
|
28
33
|
const generalSearchEntries = useMemo<SettingsSearchEntry[]>(
|
|
29
34
|
() => [
|
|
@@ -33,6 +38,12 @@ export default function SettingsRoute() {
|
|
|
33
38
|
keywords: "language locale translation i18n",
|
|
34
39
|
hash: "language",
|
|
35
40
|
},
|
|
41
|
+
{
|
|
42
|
+
id: "content-notifications",
|
|
43
|
+
label: t("settings.emailNotifications"),
|
|
44
|
+
keywords: "email notifications comments replies mentions alerts",
|
|
45
|
+
hash: "notifications",
|
|
46
|
+
},
|
|
36
47
|
],
|
|
37
48
|
[t],
|
|
38
49
|
);
|
|
@@ -52,23 +63,41 @@ export default function SettingsRoute() {
|
|
|
52
63
|
|
|
53
64
|
<CreativeContextSettingsLink />
|
|
54
65
|
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
<SettingsGroup>
|
|
67
|
+
<SettingsRow
|
|
68
|
+
id="language"
|
|
69
|
+
label={t("settings.languageTitle")}
|
|
70
|
+
description={t("settings.languageDescription")}
|
|
71
|
+
control={
|
|
72
|
+
<div className="w-56">
|
|
73
|
+
<LanguagePicker label={t("settings.languageLabel")} />
|
|
74
|
+
</div>
|
|
75
|
+
}
|
|
76
|
+
/>
|
|
77
|
+
<SettingsRow
|
|
78
|
+
id="notifications"
|
|
79
|
+
label={t("settings.emailNotifications")}
|
|
80
|
+
description={t("settings.emailNotificationsDescription")}
|
|
81
|
+
control={
|
|
82
|
+
<Switch
|
|
83
|
+
aria-label={t("settings.emailNotifications")}
|
|
84
|
+
checked={prefs.emailNotifications !== false}
|
|
85
|
+
disabled={prefsLoading}
|
|
86
|
+
onCheckedChange={(checked) => {
|
|
87
|
+
savePrefs({ emailNotifications: checked }).catch(
|
|
88
|
+
(err) => {
|
|
89
|
+
toast.error(
|
|
90
|
+
err instanceof Error
|
|
91
|
+
? err.message
|
|
92
|
+
: t("settings.saveFailed"),
|
|
93
|
+
);
|
|
94
|
+
},
|
|
95
|
+
);
|
|
96
|
+
}}
|
|
97
|
+
/>
|
|
98
|
+
}
|
|
99
|
+
/>
|
|
100
|
+
</SettingsGroup>
|
|
72
101
|
</main>
|
|
73
102
|
}
|
|
74
103
|
team={
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email notifications for document comments, replies, and mentions.
|
|
3
|
+
*
|
|
4
|
+
* Recipient resolution, preference filtering, and delivery reporting come from
|
|
5
|
+
* `@agent-native/core/server`; this module owns only the Documents rows and the
|
|
6
|
+
* email copy. Share invites are not routed through the `emailNotifications`
|
|
7
|
+
* preference — they have their own delivery path.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
emailStrong,
|
|
12
|
+
getAppProductionUrl,
|
|
13
|
+
notifyActivity,
|
|
14
|
+
renderEmail,
|
|
15
|
+
runActivityNotification,
|
|
16
|
+
sendEmail,
|
|
17
|
+
type ActivityNotificationResult,
|
|
18
|
+
} from "@agent-native/core/server";
|
|
19
|
+
import { filterRecipientsByResourceAccess } from "@agent-native/core/sharing";
|
|
20
|
+
import { and, eq } from "drizzle-orm";
|
|
21
|
+
|
|
22
|
+
import { CONTENT_USER_PREFS_KEY } from "../../shared/content-user-prefs.js";
|
|
23
|
+
import { getDb, schema } from "../db/index.js";
|
|
24
|
+
|
|
25
|
+
export type DocumentCommentNotificationResult = ActivityNotificationResult;
|
|
26
|
+
|
|
27
|
+
const LOG_LABEL = "[content] comment notification";
|
|
28
|
+
const EXCERPT_LIMIT = 240;
|
|
29
|
+
|
|
30
|
+
function excerpt(content: string): string {
|
|
31
|
+
const collapsed = content.replace(/\s+/g, " ").trim();
|
|
32
|
+
return collapsed.length > EXCERPT_LIMIT
|
|
33
|
+
? `${collapsed.slice(0, EXCERPT_LIMIT - 1)}…`
|
|
34
|
+
: collapsed;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function documentUrl(documentId: string): string {
|
|
38
|
+
const base = getAppProductionUrl().replace(/\/+$/, "");
|
|
39
|
+
return `${base}/page/${encodeURIComponent(documentId)}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function threadParticipants(
|
|
43
|
+
documentId: string,
|
|
44
|
+
threadId: string,
|
|
45
|
+
): Promise<string[]> {
|
|
46
|
+
const rows = await getDb()
|
|
47
|
+
.select({ authorEmail: schema.documentComments.authorEmail })
|
|
48
|
+
.from(schema.documentComments)
|
|
49
|
+
.where(
|
|
50
|
+
and(
|
|
51
|
+
eq(schema.documentComments.documentId, documentId),
|
|
52
|
+
eq(schema.documentComments.threadId, threadId),
|
|
53
|
+
),
|
|
54
|
+
);
|
|
55
|
+
return rows.map((row) => row.authorEmail);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface DocumentCommentNotificationInput {
|
|
59
|
+
documentId: string;
|
|
60
|
+
/** Read from the access-checked resource by the caller, never re-queried. */
|
|
61
|
+
documentTitle: string;
|
|
62
|
+
/** The document's org, so `org` visibility resolves for its members. */
|
|
63
|
+
orgId?: string | null;
|
|
64
|
+
threadId: string;
|
|
65
|
+
ownerEmail: string;
|
|
66
|
+
authorEmail: string;
|
|
67
|
+
authorName?: string | null;
|
|
68
|
+
content: string;
|
|
69
|
+
mentions: { email: string; name: string }[];
|
|
70
|
+
isReply: boolean;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function notifyDocumentComment(
|
|
74
|
+
input: DocumentCommentNotificationInput,
|
|
75
|
+
): Promise<DocumentCommentNotificationResult> {
|
|
76
|
+
return runActivityNotification(LOG_LABEL, () =>
|
|
77
|
+
deliverDocumentCommentEmails(input),
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function deliverDocumentCommentEmails(
|
|
82
|
+
input: DocumentCommentNotificationInput,
|
|
83
|
+
): Promise<DocumentCommentNotificationResult> {
|
|
84
|
+
const title = input.documentTitle.trim() || "Untitled";
|
|
85
|
+
const mentioned = new Set(
|
|
86
|
+
input.mentions.map((mention) => mention.email.trim().toLowerCase()),
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const candidates = [input.ownerEmail, ...mentioned];
|
|
90
|
+
if (input.isReply) {
|
|
91
|
+
candidates.push(
|
|
92
|
+
...(await threadParticipants(input.documentId, input.threadId)),
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Mentions are caller-supplied and thread rows are historical; re-check both
|
|
97
|
+
// against the document's live ACL before mailing anyone its contents.
|
|
98
|
+
const allowed = await filterRecipientsByResourceAccess({
|
|
99
|
+
resourceType: "document",
|
|
100
|
+
resourceId: input.documentId,
|
|
101
|
+
emails: candidates,
|
|
102
|
+
orgId: input.orgId,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const actor = input.authorName?.trim() || input.authorEmail;
|
|
106
|
+
const url = documentUrl(input.documentId);
|
|
107
|
+
|
|
108
|
+
return notifyActivity({
|
|
109
|
+
candidates: allowed,
|
|
110
|
+
actorEmail: input.authorEmail,
|
|
111
|
+
preferenceKey: CONTENT_USER_PREFS_KEY,
|
|
112
|
+
logLabel: LOG_LABEL,
|
|
113
|
+
send: async (to) => {
|
|
114
|
+
const wasMentioned = mentioned.has(to);
|
|
115
|
+
const lead = wasMentioned
|
|
116
|
+
? `${emailStrong(actor)} mentioned you in a comment on ${emailStrong(title)}.`
|
|
117
|
+
: input.isReply
|
|
118
|
+
? `${emailStrong(actor)} replied in a comment thread on ${emailStrong(title)}.`
|
|
119
|
+
: `${emailStrong(actor)} commented on ${emailStrong(title)}.`;
|
|
120
|
+
|
|
121
|
+
const { html, text } = renderEmail({
|
|
122
|
+
preheader: `${actor} commented on ${title}.`,
|
|
123
|
+
heading: wasMentioned
|
|
124
|
+
? "You were mentioned"
|
|
125
|
+
: input.isReply
|
|
126
|
+
? "New reply on your document"
|
|
127
|
+
: "New comment",
|
|
128
|
+
paragraphs: [lead, `"${excerpt(input.content)}"`],
|
|
129
|
+
cta: { label: "Open document", url },
|
|
130
|
+
footer:
|
|
131
|
+
"You received this because you own, were mentioned in, or participated in this thread. Turn these off in Documents settings.",
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
await sendEmail({
|
|
135
|
+
to,
|
|
136
|
+
subject: wasMentioned
|
|
137
|
+
? `${actor} mentioned you on "${title}"`
|
|
138
|
+
: input.isReply
|
|
139
|
+
? `${actor} replied to a comment on "${title}"`
|
|
140
|
+
: `${actor} commented on "${title}"`,
|
|
141
|
+
html,
|
|
142
|
+
text,
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { getSession } from "@agent-native/core/server";
|
|
2
|
+
import { getUserSetting } from "@agent-native/core/settings";
|
|
3
|
+
import { defineEventHandler, setResponseStatus } from "h3";
|
|
4
|
+
|
|
5
|
+
import { CONTENT_USER_PREFS_KEY } from "../../../../shared/content-user-prefs.js";
|
|
6
|
+
|
|
7
|
+
export default defineEventHandler(async (event) => {
|
|
8
|
+
const session = await getSession(event);
|
|
9
|
+
if (!session?.email) {
|
|
10
|
+
setResponseStatus(event, 401);
|
|
11
|
+
return { error: "unauthorized" };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const stored = await getUserSetting(session.email, CONTENT_USER_PREFS_KEY);
|
|
15
|
+
// coercion-ok: a null read means this user has no preferences yet, which is a real state.
|
|
16
|
+
return stored ?? {};
|
|
17
|
+
});
|