@agent-native/core 0.134.0 → 0.135.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +3 -3
- package/corpus/core/CHANGELOG.md +113 -0
- package/corpus/core/docs/content/template-content-developers.mdx +1 -1
- 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-29-meeting-notes-no-longer-transcribe-the-other-side-twice-when.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/hooks/useMeetingTranscription.ts +37 -48
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +331 -36
- package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +7 -5
- package/corpus/templates/clips/desktop/src/lib/transcription-engine.ts +182 -106
- package/corpus/templates/clips/desktop/src/lib/upload-recovery.ts +129 -0
- package/corpus/templates/clips/desktop/src/overlays/live-transcript.tsx +43 -14
- package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +3 -3
- package/corpus/templates/clips/desktop/src-tauri/src/echo_guard.rs +443 -0
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +1 -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/src-tauri/src/whisper_speech.rs +125 -16
- 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/.agents/skills/document-editing/references/databases.md +6 -4
- package/corpus/templates/content/actions/_database-membership-lock.ts +25 -0
- package/corpus/templates/content/actions/_database-row-batch.ts +6 -2
- package/corpus/templates/content/actions/_database-source-utils.ts +289 -129
- package/corpus/templates/content/actions/_database-utils.ts +12 -3
- package/corpus/templates/content/actions/add-comment.ts +15 -1
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +39 -21
- package/corpus/templates/content/actions/attach-content-database-source.ts +4 -1
- package/corpus/templates/content/actions/change-content-database-source-role.ts +3 -5
- package/corpus/templates/content/actions/duplicate-document-property.ts +59 -46
- package/corpus/templates/content/actions/execute-builder-source-execution.ts +77 -71
- package/corpus/templates/content/actions/list-documents.ts +1 -0
- package/corpus/templates/content/actions/materialize-builder-required-fields.ts +7 -0
- package/corpus/templates/content/actions/remove-database-items.ts +183 -0
- package/corpus/templates/content/actions/set-document-property.ts +57 -39
- package/corpus/templates/content/actions/sync-local-folder-source.ts +7 -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/editor/database/DatabaseView.tsx +471 -329
- package/corpus/templates/content/app/components/editor/database/row-access.ts +45 -0
- package/corpus/templates/content/app/components/editor/database/shared.tsx +141 -38
- package/corpus/templates/content/app/components/ui/switch.tsx +1 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +2 -2
- package/corpus/templates/content/app/hooks/use-content-prefs.ts +55 -0
- package/corpus/templates/content/app/i18n-data.ts +170 -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-07-30-database-rows-can-now-be-removed-without-deleting-their-page.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/parity/eval-scenarios.ts +2 -2
- package/corpus/templates/content/parity/matrix.md +1 -1
- package/corpus/templates/content/parity/matrix.ts +4 -5
- 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/api.ts +4 -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/.generated/bridge/editor-chrome.generated.ts +26 -11
- package/corpus/templates/design/actions/take-design-screenshot.ts +7 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +11 -3
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +4 -1
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +54 -17
- package/corpus/templates/design/app/components/design/design-canvas/local-runtime.ts +126 -0
- package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +2 -0
- package/corpus/templates/design/app/pages/Index.tsx +3 -1
- package/corpus/templates/design/app/pages/Present.tsx +2 -1
- package/corpus/templates/design/app/routes/settings.tsx +14 -22
- package/corpus/templates/design/changelog/2026-07-30-a-broken-inline-script-in-a-generated-screen-is-now-caught-o.md +6 -0
- package/corpus/templates/design/changelog/2026-07-30-design-html-is-now-validated-with-a-spec-grade-html-parser-i.md +6 -0
- package/corpus/templates/design/changelog/2026-07-30-designs-now-load-their-tailwind-and-alpine-runtimes-from-the.md +6 -0
- package/corpus/templates/design/changelog/2026-07-30-designs-with-a-broken-alpine-expression-are-now-caught-on-sa.md +6 -0
- package/corpus/templates/design/changelog/2026-07-30-editing-a-design-no-longer-strips-its-styling-the-canvas-kep.md +6 -0
- 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/package.json +4 -0
- package/corpus/templates/design/shared/html-integrity.ts +802 -556
- 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 +2 -2
- 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/docs/content/template-content-developers.mdx +1 -1
- 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
- package/corpus/templates/content/actions/delete-database-items.ts +0 -89
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { getDbExec } from "../db/client.js";
|
|
2
|
-
import { isValidCron, nextOccurrence } from "../jobs/cron.js";
|
|
2
|
+
import { isValidCron, isValidTimezone, nextOccurrence } from "../jobs/cron.js";
|
|
3
3
|
import { buildJobResourceContent, normalizeJobMcpTools, parseJobResource, } from "../jobs/frontmatter.js";
|
|
4
|
+
import { deleteAutomationRuns } from "../jobs/run-history.js";
|
|
5
|
+
import { resolveUserSchedulingTimezone } from "../localization/user-timezone.js";
|
|
4
6
|
import { organizationIdFromResourceOwner, organizationResourceOwner, resourceDelete, resourceGetByPath, resourceList, resourcePut, } from "../resources/store.js";
|
|
5
7
|
function httpError(message, statusCode) {
|
|
6
8
|
return Object.assign(new Error(message), { statusCode });
|
|
@@ -177,9 +179,18 @@ export async function defineAutomation(actorInput, input) {
|
|
|
177
179
|
if (input.triggerType === "event" && !event) {
|
|
178
180
|
throw httpError("event is required for event-triggered automations.", 400);
|
|
179
181
|
}
|
|
182
|
+
if (input.timezone && !isValidTimezone(input.timezone)) {
|
|
183
|
+
throw httpError(`Unknown timezone "${input.timezone}".`, 400);
|
|
184
|
+
}
|
|
185
|
+
// Resolve now and persist it: a schedule whose zone is implicit means
|
|
186
|
+
// something different the moment it is read on a differently-zoned host.
|
|
187
|
+
const timezone = input.triggerType === "schedule"
|
|
188
|
+
? input.timezone || (await resolveUserSchedulingTimezone(actor.userEmail))
|
|
189
|
+
: undefined;
|
|
180
190
|
const mcpTools = normalizeJobMcpTools(input.mcpTools);
|
|
181
191
|
const meta = {
|
|
182
192
|
schedule: input.triggerType === "schedule" ? schedule : "",
|
|
193
|
+
timezone,
|
|
183
194
|
enabled: true,
|
|
184
195
|
triggerType: input.triggerType,
|
|
185
196
|
event: input.triggerType === "event" ? event : undefined,
|
|
@@ -191,7 +202,7 @@ export async function defineAutomation(actorInput, input) {
|
|
|
191
202
|
orgId: input.scope === "organization" ? actor.orgId : undefined,
|
|
192
203
|
runAs: "creator",
|
|
193
204
|
nextRun: input.triggerType === "schedule"
|
|
194
|
-
? nextOccurrence(schedule).toISOString()
|
|
205
|
+
? nextOccurrence(schedule, undefined, timezone).toISOString()
|
|
195
206
|
: undefined,
|
|
196
207
|
model: input.model?.trim() || undefined,
|
|
197
208
|
mcpTools: mcpTools?.length ? mcpTools : undefined,
|
|
@@ -225,14 +236,25 @@ export async function updateAutomation(actorInput, input) {
|
|
|
225
236
|
throw httpError(`Invalid cron expression "${input.schedule}".`, 400);
|
|
226
237
|
}
|
|
227
238
|
meta.schedule = input.schedule;
|
|
228
|
-
|
|
239
|
+
}
|
|
240
|
+
if (input.timezone !== undefined) {
|
|
241
|
+
if (!isValidTimezone(input.timezone)) {
|
|
242
|
+
throw httpError(`Unknown timezone "${input.timezone}".`, 400);
|
|
243
|
+
}
|
|
244
|
+
if (meta.triggerType !== "schedule") {
|
|
245
|
+
throw httpError("Event automations do not have a timezone.", 400);
|
|
246
|
+
}
|
|
247
|
+
meta.timezone = input.timezone;
|
|
248
|
+
}
|
|
249
|
+
if (input.schedule !== undefined || input.timezone !== undefined) {
|
|
250
|
+
meta.nextRun = nextOccurrence(meta.schedule, undefined, meta.timezone).toISOString();
|
|
229
251
|
}
|
|
230
252
|
if (input.enabled !== undefined) {
|
|
231
253
|
meta.enabled = input.enabled;
|
|
232
254
|
if (input.enabled &&
|
|
233
255
|
meta.triggerType === "schedule" &&
|
|
234
256
|
isValidCron(meta.schedule)) {
|
|
235
|
-
meta.nextRun = nextOccurrence(meta.schedule).toISOString();
|
|
257
|
+
meta.nextRun = nextOccurrence(meta.schedule, undefined, meta.timezone).toISOString();
|
|
236
258
|
}
|
|
237
259
|
}
|
|
238
260
|
if (input.condition !== undefined) {
|
|
@@ -264,6 +286,9 @@ export async function deleteAutomation(actorInput, scope, name) {
|
|
|
264
286
|
throw httpError("Only the automation's creator or an organization admin can delete it.", 403);
|
|
265
287
|
}
|
|
266
288
|
await resourceDelete(definition.resource.id);
|
|
289
|
+
// Names are reusable, so leaving history behind would attach these runs to
|
|
290
|
+
// whatever automation is created under the same name next.
|
|
291
|
+
await deleteAutomationRuns(definition.resource.owner, name);
|
|
267
292
|
}
|
|
268
293
|
/**
|
|
269
294
|
* Resolve the identity used by an explicit automation run.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/automations/service.ts"],"names":[],"mappings":"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","sourcesContent":["import { getDbExec } from \"../db/client.js\";\nimport { isValidCron, nextOccurrence } from \"../jobs/cron.js\";\nimport {\n buildJobResourceContent,\n normalizeJobMcpTools,\n parseJobResource,\n type JobFrontmatter,\n} from \"../jobs/frontmatter.js\";\nimport {\n organizationIdFromResourceOwner,\n organizationResourceOwner,\n resourceDelete,\n resourceGetByPath,\n resourceList,\n resourcePut,\n type Resource,\n} from \"../resources/store.js\";\n\nexport type AutomationScope = \"personal\" | \"organization\";\n\nexport interface AutomationActor {\n userEmail: string;\n orgId?: string | null;\n}\n\nexport interface AutomationDefinition {\n resource: Resource;\n name: string;\n scope: AutomationScope;\n meta: JobFrontmatter & {\n triggerType: \"schedule\" | \"event\";\n mode: \"agentic\" | \"deterministic\";\n };\n body: string;\n canUpdate: boolean;\n}\n\nexport interface AutomationDelivery {\n originScopeId?: string;\n platform?: string;\n destination?: string;\n threadRef?: string;\n tenantId?: string;\n}\n\nexport interface DefineAutomationInput {\n name: string;\n scope: AutomationScope;\n triggerType: \"schedule\" | \"event\";\n body: string;\n schedule?: string;\n event?: string;\n condition?: string;\n domain?: string;\n delegatedPolicyId?: string;\n model?: string;\n mcpTools?: unknown;\n delivery?: AutomationDelivery;\n}\n\nexport type DefinedAutomation = Omit<AutomationDefinition, \"resource\">;\n\nexport interface UpdateAutomationInput {\n name: string;\n scope: AutomationScope;\n enabled?: boolean;\n body?: string;\n condition?: string | null;\n delegatedPolicyId?: string | null;\n schedule?: string;\n model?: string | null;\n mcpTools?: unknown;\n}\n\ninterface OrganizationMembership {\n role: string;\n}\n\nfunction httpError(message: string, statusCode: number): Error {\n return Object.assign(new Error(message), { statusCode });\n}\n\nfunction normalizeActor(actor: AutomationActor): AutomationActor {\n const userEmail = actor.userEmail.trim().toLowerCase();\n if (!userEmail) throw httpError(\"Not authenticated.\", 401);\n return { userEmail, orgId: actor.orgId?.trim() || null };\n}\n\nfunction automationName(path: string): string {\n return path.replace(/^jobs\\//, \"\").replace(/\\.md$/, \"\");\n}\n\nfunction automationPath(name: string): string {\n const normalized = name\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, \"-\");\n if (!normalized) {\n throw httpError(\"Automation name is required (lowercase, hyphens).\", 400);\n }\n return `jobs/${normalized}.md`;\n}\n\nfunction ownerForScope(actor: AutomationActor, scope: AutomationScope): string {\n if (scope === \"personal\") return actor.userEmail;\n if (!actor.orgId) {\n throw httpError(\n \"An organization is required for organization automations.\",\n 400,\n );\n }\n return organizationResourceOwner(actor.orgId);\n}\n\nasync function readOrganizationMembership(\n orgId: string,\n email: string,\n): Promise<OrganizationMembership | null> {\n const result = await getDbExec().execute({\n sql: \"SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1\",\n args: [orgId, email.toLowerCase()],\n });\n if (!result.rows.length) return null;\n return { role: String(result.rows[0]?.role ?? \"\").toLowerCase() };\n}\n\nasync function requireOrganizationMembership(\n actor: AutomationActor,\n): Promise<OrganizationMembership> {\n if (!actor.orgId) {\n throw httpError(\n \"An organization is required for organization automations.\",\n 400,\n );\n }\n const membership = await readOrganizationMembership(\n actor.orgId,\n actor.userEmail,\n );\n if (!membership) {\n throw httpError(\"You are no longer a member of this organization.\", 403);\n }\n return membership;\n}\n\nfunction isOrganizationAdmin(membership: OrganizationMembership): boolean {\n return membership.role === \"owner\" || membership.role === \"admin\";\n}\n\nasync function mutationAccess(\n actorInput: AutomationActor,\n resource: Resource,\n meta: JobFrontmatter,\n): Promise<{ actor: AutomationActor; canUpdate: boolean }> {\n const actor = normalizeActor(actorInput);\n const resourceOrgId = organizationIdFromResourceOwner(resource.owner);\n if (!resourceOrgId) {\n return {\n actor,\n canUpdate: resource.owner.toLowerCase() === actor.userEmail,\n };\n }\n if (actor.orgId !== resourceOrgId) {\n return { actor, canUpdate: false };\n }\n const membership = await requireOrganizationMembership(actor);\n const isCreator =\n meta.createdBy?.trim().toLowerCase() === actor.userEmail.toLowerCase();\n return {\n actor,\n canUpdate: isCreator || isOrganizationAdmin(membership),\n };\n}\n\n/**\n * Compatibility adapters may expose both explicit automations and legacy\n * scheduled jobs. Keep their mutation authorization on the same boundary as\n * the canonical service without forcing legacy resources through the explicit\n * automation classifier.\n */\nexport async function canUpdateAutomationResource(\n actorInput: AutomationActor,\n resource: Resource,\n): Promise<boolean> {\n const { meta } = parseJobResource(resource.content);\n return (await mutationAccess(actorInput, resource, meta)).canUpdate;\n}\n\nfunction assertExplicitAutomation(\n resource: Resource,\n): Omit<AutomationDefinition, \"name\" | \"scope\" | \"canUpdate\"> {\n const parsed = parseJobResource(resource.content);\n if (parsed.classification.kind !== \"automation\") {\n throw httpError(\n `\"${automationName(resource.path)}\" is a legacy scheduled job. Use manage-jobs for compatibility.`,\n 400,\n );\n }\n return {\n resource,\n meta: {\n ...parsed.meta,\n triggerType: parsed.classification.triggerType,\n mode: parsed.meta.mode ?? \"agentic\",\n },\n body: parsed.body,\n };\n}\n\nasync function readDefinition(\n actorInput: AutomationActor,\n scope: AutomationScope,\n name: string,\n): Promise<AutomationDefinition> {\n const actor = normalizeActor(actorInput);\n if (scope === \"organization\") await requireOrganizationMembership(actor);\n const owner = ownerForScope(actor, scope);\n const path = automationPath(name);\n const resource = await resourceGetByPath(owner, path);\n if (!resource) {\n throw httpError(`Automation \"${automationName(path)}\" not found.`, 404);\n }\n const definition = assertExplicitAutomation(resource);\n const access = await mutationAccess(actor, resource, definition.meta);\n return {\n ...definition,\n name: automationName(resource.path),\n scope,\n canUpdate: access.canUpdate,\n };\n}\n\nexport async function listAutomationDefinitions(\n actorInput: AutomationActor,\n scope: AutomationScope,\n): Promise<AutomationDefinition[]> {\n const actor = normalizeActor(actorInput);\n const membership =\n scope === \"organization\"\n ? await requireOrganizationMembership(actor)\n : undefined;\n const owner = ownerForScope(actor, scope);\n const resources = await resourceList(owner, \"jobs/\");\n const automations: AutomationDefinition[] = [];\n\n for (const resourceMeta of resources) {\n if (\n !resourceMeta.path.endsWith(\".md\") ||\n resourceMeta.path.endsWith(\".keep\")\n ) {\n continue;\n }\n const resource = await resourceGetByPath(owner, resourceMeta.path);\n if (!resource) continue;\n const parsed = parseJobResource(resource.content);\n if (parsed.classification.kind !== \"automation\") continue;\n const isCreator =\n parsed.meta.createdBy?.trim().toLowerCase() === actor.userEmail;\n automations.push({\n resource,\n name: automationName(resource.path),\n scope,\n meta: {\n ...parsed.meta,\n triggerType: parsed.classification.triggerType,\n mode: parsed.meta.mode ?? \"agentic\",\n },\n body: parsed.body,\n canUpdate:\n scope === \"personal\" ||\n isCreator ||\n (membership ? isOrganizationAdmin(membership) : false),\n });\n }\n\n return automations;\n}\n\nexport async function defineAutomation(\n actorInput: AutomationActor,\n input: DefineAutomationInput,\n): Promise<DefinedAutomation> {\n const actor = normalizeActor(actorInput);\n if (input.scope === \"organization\") {\n await requireOrganizationMembership(actor);\n }\n const owner = ownerForScope(actor, input.scope);\n const path = automationPath(input.name);\n if (await resourceGetByPath(owner, path)) {\n throw httpError(\n `An automation named \"${automationName(path)}\" already exists.`,\n 409,\n );\n }\n const body = input.body.trim();\n if (!body) throw httpError(\"body is required.\", 400);\n\n const schedule = input.schedule?.trim() ?? \"\";\n const event = input.event?.trim() ?? \"\";\n if (input.triggerType === \"schedule\" && !isValidCron(schedule)) {\n throw httpError(\n schedule\n ? `invalid cron expression \"${schedule}\".`\n : \"schedule is required for scheduled automations.\",\n 400,\n );\n }\n if (input.triggerType === \"event\" && !event) {\n throw httpError(\"event is required for event-triggered automations.\", 400);\n }\n\n const mcpTools = normalizeJobMcpTools(input.mcpTools);\n const meta: JobFrontmatter = {\n schedule: input.triggerType === \"schedule\" ? schedule : \"\",\n enabled: true,\n triggerType: input.triggerType,\n event: input.triggerType === \"event\" ? event : undefined,\n condition: input.condition?.trim() || undefined,\n mode: \"agentic\",\n domain: input.domain?.trim() || undefined,\n delegatedPolicyId: input.delegatedPolicyId?.trim() || undefined,\n createdBy: actor.userEmail,\n orgId: input.scope === \"organization\" ? actor.orgId! : undefined,\n runAs: \"creator\",\n nextRun:\n input.triggerType === \"schedule\"\n ? nextOccurrence(schedule).toISOString()\n : undefined,\n model: input.model?.trim() || undefined,\n mcpTools: mcpTools?.length ? mcpTools : undefined,\n originScopeId: input.delivery?.originScopeId,\n deliveryPlatform: input.delivery?.platform,\n deliveryDestination: input.delivery?.destination,\n deliveryThreadRef: input.delivery?.threadRef,\n deliveryTenantId: input.delivery?.tenantId,\n };\n const content = buildJobResourceContent(meta, body);\n await resourcePut(owner, path, content);\n return {\n name: automationName(path),\n scope: input.scope,\n meta: { ...meta, triggerType: input.triggerType, mode: \"agentic\" },\n body,\n canUpdate: true,\n };\n}\n\nexport async function updateAutomation(\n actorInput: AutomationActor,\n input: UpdateAutomationInput,\n): Promise<AutomationDefinition> {\n const definition = await readDefinition(actorInput, input.scope, input.name);\n if (!definition.canUpdate) {\n throw httpError(\n \"Only the automation's creator or an organization admin can update it.\",\n 403,\n );\n }\n const { meta } = definition;\n if (input.schedule !== undefined) {\n if (meta.triggerType !== \"schedule\") {\n throw httpError(\"Event automations do not have a cron schedule.\", 400);\n }\n if (!isValidCron(input.schedule)) {\n throw httpError(`Invalid cron expression \"${input.schedule}\".`, 400);\n }\n meta.schedule = input.schedule;\n meta.nextRun = nextOccurrence(input.schedule).toISOString();\n }\n if (input.enabled !== undefined) {\n meta.enabled = input.enabled;\n if (\n input.enabled &&\n meta.triggerType === \"schedule\" &&\n isValidCron(meta.schedule)\n ) {\n meta.nextRun = nextOccurrence(meta.schedule).toISOString();\n }\n }\n if (input.condition !== undefined) {\n meta.condition = input.condition?.trim() || undefined;\n }\n if (input.delegatedPolicyId !== undefined) {\n meta.delegatedPolicyId = input.delegatedPolicyId?.trim() || undefined;\n }\n if (input.model !== undefined) {\n meta.model = input.model?.trim() || undefined;\n }\n if (input.mcpTools !== undefined) {\n const mcpTools = normalizeJobMcpTools(input.mcpTools);\n meta.mcpTools = mcpTools?.length ? mcpTools : undefined;\n }\n if (input.scope === \"organization\") {\n meta.orgId = organizationIdFromResourceOwner(definition.resource.owner)!;\n meta.runAs = \"creator\";\n }\n const body = input.body === undefined ? definition.body : input.body.trim();\n if (!body) throw httpError(\"Automation body is required.\", 400);\n await resourcePut(\n definition.resource.owner,\n definition.resource.path,\n buildJobResourceContent(meta, body),\n );\n return { ...definition, meta, body };\n}\n\nexport async function deleteAutomation(\n actorInput: AutomationActor,\n scope: AutomationScope,\n name: string,\n): Promise<void> {\n const definition = await readDefinition(actorInput, scope, name);\n if (!definition.canUpdate) {\n throw httpError(\n \"Only the automation's creator or an organization admin can delete it.\",\n 403,\n );\n }\n await resourceDelete(definition.resource.id);\n}\n\nexport interface AutomationExecutionIdentity {\n userEmail: string;\n orgId?: string;\n eventOwner: string;\n}\n\nexport type AutomationExecutionIdentityResult =\n | { ok: true; identity: AutomationExecutionIdentity }\n | { ok: false; reason: string };\n\n/**\n * Resolve the identity used by an explicit automation run.\n *\n * Organization automations are visible through their organization owner, but\n * always execute as their immutable creator. Event dispatchers must also\n * require EventMeta.owner to equal `eventOwner`; organization visibility does\n * not make an event organization-wide.\n */\nexport async function resolveAutomationExecutionIdentity(\n resourceOwner: string,\n meta: JobFrontmatter,\n): Promise<AutomationExecutionIdentityResult> {\n const orgId = organizationIdFromResourceOwner(resourceOwner);\n if (!orgId) {\n const userEmail = (meta.createdBy || resourceOwner).trim().toLowerCase();\n if (!userEmail || userEmail !== resourceOwner.trim().toLowerCase()) {\n return {\n ok: false,\n reason: \"Personal automation creator does not match its owner.\",\n };\n }\n return { ok: true, identity: { userEmail, eventOwner: userEmail } };\n }\n\n const userEmail = meta.createdBy?.trim().toLowerCase();\n if (!userEmail) {\n return {\n ok: false,\n reason: \"Organization automation has no creator identity.\",\n };\n }\n if (meta.runAs !== \"creator\") {\n return {\n ok: false,\n reason: \"Organization automations must run as their creator.\",\n };\n }\n if (meta.orgId && meta.orgId !== orgId) {\n return {\n ok: false,\n reason: \"Organization automation metadata does not match its owner.\",\n };\n }\n\n const user = await getDbExec().execute({\n sql: `SELECT 1 FROM \"user\" WHERE LOWER(email) = ? LIMIT 1`,\n args: [userEmail],\n });\n if (!user.rows.length) {\n return {\n ok: false,\n reason: `Automation creator \"${userEmail}\" no longer exists.`,\n };\n }\n if (!(await readOrganizationMembership(orgId, userEmail))) {\n return {\n ok: false,\n reason: `Automation creator \"${userEmail}\" is no longer a member of organization \"${orgId}\".`,\n };\n }\n return {\n ok: true,\n identity: { userEmail, orgId, eventOwner: userEmail },\n };\n}\n\nexport function automationMatchesEventOwner(\n identity: AutomationExecutionIdentity,\n eventOwner: string | undefined,\n): boolean {\n return (\n typeof eventOwner === \"string\" &&\n eventOwner.trim().toLowerCase() === identity.eventOwner\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/automations/service.ts"],"names":[],"mappings":"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","sourcesContent":["import { getDbExec } from \"../db/client.js\";\nimport { isValidCron, isValidTimezone, nextOccurrence } from \"../jobs/cron.js\";\nimport {\n buildJobResourceContent,\n normalizeJobMcpTools,\n parseJobResource,\n type JobFrontmatter,\n} from \"../jobs/frontmatter.js\";\nimport { deleteAutomationRuns } from \"../jobs/run-history.js\";\nimport { resolveUserSchedulingTimezone } from \"../localization/user-timezone.js\";\nimport {\n organizationIdFromResourceOwner,\n organizationResourceOwner,\n resourceDelete,\n resourceGetByPath,\n resourceList,\n resourcePut,\n type Resource,\n} from \"../resources/store.js\";\n\nexport type AutomationScope = \"personal\" | \"organization\";\n\nexport interface AutomationActor {\n userEmail: string;\n orgId?: string | null;\n}\n\nexport interface AutomationDefinition {\n resource: Resource;\n name: string;\n scope: AutomationScope;\n meta: JobFrontmatter & {\n triggerType: \"schedule\" | \"event\";\n mode: \"agentic\" | \"deterministic\";\n };\n body: string;\n canUpdate: boolean;\n}\n\nexport interface AutomationDelivery {\n originScopeId?: string;\n platform?: string;\n destination?: string;\n threadRef?: string;\n tenantId?: string;\n}\n\nexport interface DefineAutomationInput {\n name: string;\n scope: AutomationScope;\n triggerType: \"schedule\" | \"event\";\n body: string;\n schedule?: string;\n timezone?: string;\n event?: string;\n condition?: string;\n domain?: string;\n delegatedPolicyId?: string;\n model?: string;\n mcpTools?: unknown;\n delivery?: AutomationDelivery;\n}\n\nexport type DefinedAutomation = Omit<AutomationDefinition, \"resource\">;\n\nexport interface UpdateAutomationInput {\n name: string;\n scope: AutomationScope;\n enabled?: boolean;\n body?: string;\n condition?: string | null;\n delegatedPolicyId?: string | null;\n schedule?: string;\n timezone?: string;\n model?: string | null;\n mcpTools?: unknown;\n}\n\ninterface OrganizationMembership {\n role: string;\n}\n\nfunction httpError(message: string, statusCode: number): Error {\n return Object.assign(new Error(message), { statusCode });\n}\n\nfunction normalizeActor(actor: AutomationActor): AutomationActor {\n const userEmail = actor.userEmail.trim().toLowerCase();\n if (!userEmail) throw httpError(\"Not authenticated.\", 401);\n return { userEmail, orgId: actor.orgId?.trim() || null };\n}\n\nfunction automationName(path: string): string {\n return path.replace(/^jobs\\//, \"\").replace(/\\.md$/, \"\");\n}\n\nfunction automationPath(name: string): string {\n const normalized = name\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, \"-\");\n if (!normalized) {\n throw httpError(\"Automation name is required (lowercase, hyphens).\", 400);\n }\n return `jobs/${normalized}.md`;\n}\n\nfunction ownerForScope(actor: AutomationActor, scope: AutomationScope): string {\n if (scope === \"personal\") return actor.userEmail;\n if (!actor.orgId) {\n throw httpError(\n \"An organization is required for organization automations.\",\n 400,\n );\n }\n return organizationResourceOwner(actor.orgId);\n}\n\nasync function readOrganizationMembership(\n orgId: string,\n email: string,\n): Promise<OrganizationMembership | null> {\n const result = await getDbExec().execute({\n sql: \"SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1\",\n args: [orgId, email.toLowerCase()],\n });\n if (!result.rows.length) return null;\n return { role: String(result.rows[0]?.role ?? \"\").toLowerCase() };\n}\n\nasync function requireOrganizationMembership(\n actor: AutomationActor,\n): Promise<OrganizationMembership> {\n if (!actor.orgId) {\n throw httpError(\n \"An organization is required for organization automations.\",\n 400,\n );\n }\n const membership = await readOrganizationMembership(\n actor.orgId,\n actor.userEmail,\n );\n if (!membership) {\n throw httpError(\"You are no longer a member of this organization.\", 403);\n }\n return membership;\n}\n\nfunction isOrganizationAdmin(membership: OrganizationMembership): boolean {\n return membership.role === \"owner\" || membership.role === \"admin\";\n}\n\nasync function mutationAccess(\n actorInput: AutomationActor,\n resource: Resource,\n meta: JobFrontmatter,\n): Promise<{ actor: AutomationActor; canUpdate: boolean }> {\n const actor = normalizeActor(actorInput);\n const resourceOrgId = organizationIdFromResourceOwner(resource.owner);\n if (!resourceOrgId) {\n return {\n actor,\n canUpdate: resource.owner.toLowerCase() === actor.userEmail,\n };\n }\n if (actor.orgId !== resourceOrgId) {\n return { actor, canUpdate: false };\n }\n const membership = await requireOrganizationMembership(actor);\n const isCreator =\n meta.createdBy?.trim().toLowerCase() === actor.userEmail.toLowerCase();\n return {\n actor,\n canUpdate: isCreator || isOrganizationAdmin(membership),\n };\n}\n\n/**\n * Compatibility adapters may expose both explicit automations and legacy\n * scheduled jobs. Keep their mutation authorization on the same boundary as\n * the canonical service without forcing legacy resources through the explicit\n * automation classifier.\n */\nexport async function canUpdateAutomationResource(\n actorInput: AutomationActor,\n resource: Resource,\n): Promise<boolean> {\n const { meta } = parseJobResource(resource.content);\n return (await mutationAccess(actorInput, resource, meta)).canUpdate;\n}\n\nfunction assertExplicitAutomation(\n resource: Resource,\n): Omit<AutomationDefinition, \"name\" | \"scope\" | \"canUpdate\"> {\n const parsed = parseJobResource(resource.content);\n if (parsed.classification.kind !== \"automation\") {\n throw httpError(\n `\"${automationName(resource.path)}\" is a legacy scheduled job. Use manage-jobs for compatibility.`,\n 400,\n );\n }\n return {\n resource,\n meta: {\n ...parsed.meta,\n triggerType: parsed.classification.triggerType,\n mode: parsed.meta.mode ?? \"agentic\",\n },\n body: parsed.body,\n };\n}\n\nasync function readDefinition(\n actorInput: AutomationActor,\n scope: AutomationScope,\n name: string,\n): Promise<AutomationDefinition> {\n const actor = normalizeActor(actorInput);\n if (scope === \"organization\") await requireOrganizationMembership(actor);\n const owner = ownerForScope(actor, scope);\n const path = automationPath(name);\n const resource = await resourceGetByPath(owner, path);\n if (!resource) {\n throw httpError(`Automation \"${automationName(path)}\" not found.`, 404);\n }\n const definition = assertExplicitAutomation(resource);\n const access = await mutationAccess(actor, resource, definition.meta);\n return {\n ...definition,\n name: automationName(resource.path),\n scope,\n canUpdate: access.canUpdate,\n };\n}\n\nexport async function listAutomationDefinitions(\n actorInput: AutomationActor,\n scope: AutomationScope,\n): Promise<AutomationDefinition[]> {\n const actor = normalizeActor(actorInput);\n const membership =\n scope === \"organization\"\n ? await requireOrganizationMembership(actor)\n : undefined;\n const owner = ownerForScope(actor, scope);\n const resources = await resourceList(owner, \"jobs/\");\n const automations: AutomationDefinition[] = [];\n\n for (const resourceMeta of resources) {\n if (\n !resourceMeta.path.endsWith(\".md\") ||\n resourceMeta.path.endsWith(\".keep\")\n ) {\n continue;\n }\n const resource = await resourceGetByPath(owner, resourceMeta.path);\n if (!resource) continue;\n const parsed = parseJobResource(resource.content);\n if (parsed.classification.kind !== \"automation\") continue;\n const isCreator =\n parsed.meta.createdBy?.trim().toLowerCase() === actor.userEmail;\n automations.push({\n resource,\n name: automationName(resource.path),\n scope,\n meta: {\n ...parsed.meta,\n triggerType: parsed.classification.triggerType,\n mode: parsed.meta.mode ?? \"agentic\",\n },\n body: parsed.body,\n canUpdate:\n scope === \"personal\" ||\n isCreator ||\n (membership ? isOrganizationAdmin(membership) : false),\n });\n }\n\n return automations;\n}\n\nexport async function defineAutomation(\n actorInput: AutomationActor,\n input: DefineAutomationInput,\n): Promise<DefinedAutomation> {\n const actor = normalizeActor(actorInput);\n if (input.scope === \"organization\") {\n await requireOrganizationMembership(actor);\n }\n const owner = ownerForScope(actor, input.scope);\n const path = automationPath(input.name);\n if (await resourceGetByPath(owner, path)) {\n throw httpError(\n `An automation named \"${automationName(path)}\" already exists.`,\n 409,\n );\n }\n const body = input.body.trim();\n if (!body) throw httpError(\"body is required.\", 400);\n\n const schedule = input.schedule?.trim() ?? \"\";\n const event = input.event?.trim() ?? \"\";\n if (input.triggerType === \"schedule\" && !isValidCron(schedule)) {\n throw httpError(\n schedule\n ? `invalid cron expression \"${schedule}\".`\n : \"schedule is required for scheduled automations.\",\n 400,\n );\n }\n if (input.triggerType === \"event\" && !event) {\n throw httpError(\"event is required for event-triggered automations.\", 400);\n }\n\n if (input.timezone && !isValidTimezone(input.timezone)) {\n throw httpError(`Unknown timezone \"${input.timezone}\".`, 400);\n }\n // Resolve now and persist it: a schedule whose zone is implicit means\n // something different the moment it is read on a differently-zoned host.\n const timezone =\n input.triggerType === \"schedule\"\n ? input.timezone || (await resolveUserSchedulingTimezone(actor.userEmail))\n : undefined;\n\n const mcpTools = normalizeJobMcpTools(input.mcpTools);\n const meta: JobFrontmatter = {\n schedule: input.triggerType === \"schedule\" ? schedule : \"\",\n timezone,\n enabled: true,\n triggerType: input.triggerType,\n event: input.triggerType === \"event\" ? event : undefined,\n condition: input.condition?.trim() || undefined,\n mode: \"agentic\",\n domain: input.domain?.trim() || undefined,\n delegatedPolicyId: input.delegatedPolicyId?.trim() || undefined,\n createdBy: actor.userEmail,\n orgId: input.scope === \"organization\" ? actor.orgId! : undefined,\n runAs: \"creator\",\n nextRun:\n input.triggerType === \"schedule\"\n ? nextOccurrence(schedule, undefined, timezone).toISOString()\n : undefined,\n model: input.model?.trim() || undefined,\n mcpTools: mcpTools?.length ? mcpTools : undefined,\n originScopeId: input.delivery?.originScopeId,\n deliveryPlatform: input.delivery?.platform,\n deliveryDestination: input.delivery?.destination,\n deliveryThreadRef: input.delivery?.threadRef,\n deliveryTenantId: input.delivery?.tenantId,\n };\n const content = buildJobResourceContent(meta, body);\n await resourcePut(owner, path, content);\n return {\n name: automationName(path),\n scope: input.scope,\n meta: { ...meta, triggerType: input.triggerType, mode: \"agentic\" },\n body,\n canUpdate: true,\n };\n}\n\nexport async function updateAutomation(\n actorInput: AutomationActor,\n input: UpdateAutomationInput,\n): Promise<AutomationDefinition> {\n const definition = await readDefinition(actorInput, input.scope, input.name);\n if (!definition.canUpdate) {\n throw httpError(\n \"Only the automation's creator or an organization admin can update it.\",\n 403,\n );\n }\n const { meta } = definition;\n if (input.schedule !== undefined) {\n if (meta.triggerType !== \"schedule\") {\n throw httpError(\"Event automations do not have a cron schedule.\", 400);\n }\n if (!isValidCron(input.schedule)) {\n throw httpError(`Invalid cron expression \"${input.schedule}\".`, 400);\n }\n meta.schedule = input.schedule;\n }\n if (input.timezone !== undefined) {\n if (!isValidTimezone(input.timezone)) {\n throw httpError(`Unknown timezone \"${input.timezone}\".`, 400);\n }\n if (meta.triggerType !== \"schedule\") {\n throw httpError(\"Event automations do not have a timezone.\", 400);\n }\n meta.timezone = input.timezone;\n }\n if (input.schedule !== undefined || input.timezone !== undefined) {\n meta.nextRun = nextOccurrence(\n meta.schedule,\n undefined,\n meta.timezone,\n ).toISOString();\n }\n if (input.enabled !== undefined) {\n meta.enabled = input.enabled;\n if (\n input.enabled &&\n meta.triggerType === \"schedule\" &&\n isValidCron(meta.schedule)\n ) {\n meta.nextRun = nextOccurrence(\n meta.schedule,\n undefined,\n meta.timezone,\n ).toISOString();\n }\n }\n if (input.condition !== undefined) {\n meta.condition = input.condition?.trim() || undefined;\n }\n if (input.delegatedPolicyId !== undefined) {\n meta.delegatedPolicyId = input.delegatedPolicyId?.trim() || undefined;\n }\n if (input.model !== undefined) {\n meta.model = input.model?.trim() || undefined;\n }\n if (input.mcpTools !== undefined) {\n const mcpTools = normalizeJobMcpTools(input.mcpTools);\n meta.mcpTools = mcpTools?.length ? mcpTools : undefined;\n }\n if (input.scope === \"organization\") {\n meta.orgId = organizationIdFromResourceOwner(definition.resource.owner)!;\n meta.runAs = \"creator\";\n }\n const body = input.body === undefined ? definition.body : input.body.trim();\n if (!body) throw httpError(\"Automation body is required.\", 400);\n await resourcePut(\n definition.resource.owner,\n definition.resource.path,\n buildJobResourceContent(meta, body),\n );\n return { ...definition, meta, body };\n}\n\nexport async function deleteAutomation(\n actorInput: AutomationActor,\n scope: AutomationScope,\n name: string,\n): Promise<void> {\n const definition = await readDefinition(actorInput, scope, name);\n if (!definition.canUpdate) {\n throw httpError(\n \"Only the automation's creator or an organization admin can delete it.\",\n 403,\n );\n }\n await resourceDelete(definition.resource.id);\n // Names are reusable, so leaving history behind would attach these runs to\n // whatever automation is created under the same name next.\n await deleteAutomationRuns(definition.resource.owner, name);\n}\n\nexport interface AutomationExecutionIdentity {\n userEmail: string;\n orgId?: string;\n eventOwner: string;\n}\n\nexport type AutomationExecutionIdentityResult =\n | { ok: true; identity: AutomationExecutionIdentity }\n | { ok: false; reason: string };\n\n/**\n * Resolve the identity used by an explicit automation run.\n *\n * Organization automations are visible through their organization owner, but\n * always execute as their immutable creator. Event dispatchers must also\n * require EventMeta.owner to equal `eventOwner`; organization visibility does\n * not make an event organization-wide.\n */\nexport async function resolveAutomationExecutionIdentity(\n resourceOwner: string,\n meta: JobFrontmatter,\n): Promise<AutomationExecutionIdentityResult> {\n const orgId = organizationIdFromResourceOwner(resourceOwner);\n if (!orgId) {\n const userEmail = (meta.createdBy || resourceOwner).trim().toLowerCase();\n if (!userEmail || userEmail !== resourceOwner.trim().toLowerCase()) {\n return {\n ok: false,\n reason: \"Personal automation creator does not match its owner.\",\n };\n }\n return { ok: true, identity: { userEmail, eventOwner: userEmail } };\n }\n\n const userEmail = meta.createdBy?.trim().toLowerCase();\n if (!userEmail) {\n return {\n ok: false,\n reason: \"Organization automation has no creator identity.\",\n };\n }\n if (meta.runAs !== \"creator\") {\n return {\n ok: false,\n reason: \"Organization automations must run as their creator.\",\n };\n }\n if (meta.orgId && meta.orgId !== orgId) {\n return {\n ok: false,\n reason: \"Organization automation metadata does not match its owner.\",\n };\n }\n\n const user = await getDbExec().execute({\n sql: `SELECT 1 FROM \"user\" WHERE LOWER(email) = ? LIMIT 1`,\n args: [userEmail],\n });\n if (!user.rows.length) {\n return {\n ok: false,\n reason: `Automation creator \"${userEmail}\" no longer exists.`,\n };\n }\n if (!(await readOrganizationMembership(orgId, userEmail))) {\n return {\n ok: false,\n reason: `Automation creator \"${userEmail}\" is no longer a member of organization \"${orgId}\".`,\n };\n }\n return {\n ok: true,\n identity: { userEmail, orgId, eventOwner: userEmail },\n };\n}\n\nexport function automationMatchesEventOwner(\n identity: AutomationExecutionIdentity,\n eventOwner: string | undefined,\n): boolean {\n return (\n typeof eventOwner === \"string\" &&\n eventOwner.trim().toLowerCase() === identity.eventOwner\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-config-writers.d.ts","sourceRoot":"","sources":["../../src/cli/mcp-config-writers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AASH,MAAM,MAAM,QAAQ,GAChB,aAAa,GACb,iBAAiB,GACjB,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,gBAAgB,CAAC;AAErB,eAAO,MAAM,OAAO,EAAE,QAAQ,EAQ7B,CAAC;AAEF,mEAAmE;AACnE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,uEAAuE;AACvE,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,YAAY,CAUd;AAYD,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,QAAQ,EAChB,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA6BzB;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,QAAQ,EAChB,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,SAAiB,GACvB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAuBzB;AAMD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,eAAe,IAAI,MAAM,CAIxC;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAI3C;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,wBAAgB,uBAAuB,IAAI,MAAM,CAmBhD;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,QAAQ,EAChB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,CAwBR;
|
|
1
|
+
{"version":3,"file":"mcp-config-writers.d.ts","sourceRoot":"","sources":["../../src/cli/mcp-config-writers.ts"],"names":[],"mappings":"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"}
|
|
@@ -191,6 +191,23 @@ export function configPathFor(client, baseDir, scope) {
|
|
|
191
191
|
// ---------------------------------------------------------------------------
|
|
192
192
|
// JSON client configs (Claude Code, Claude Code CLI, Cowork)
|
|
193
193
|
// ---------------------------------------------------------------------------
|
|
194
|
+
/**
|
|
195
|
+
* Read an existing MCP config without conflating missing and unreadable files.
|
|
196
|
+
* Only ENOENT means the config is absent; any other read failure must abort
|
|
197
|
+
* before a caller can overwrite existing user configuration.
|
|
198
|
+
*/
|
|
199
|
+
function readExistingConfigFile(file) {
|
|
200
|
+
try {
|
|
201
|
+
return fs.readFileSync(file, "utf-8");
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
if (error.code === "ENOENT")
|
|
205
|
+
return undefined;
|
|
206
|
+
const detail = error instanceof Error ? ` (${error.message})` : "";
|
|
207
|
+
throw new Error(`Cannot read MCP config file: ${file}\n` +
|
|
208
|
+
`Check that the file is readable and re-run. The file has not been modified.${detail}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
194
211
|
/**
|
|
195
212
|
* Read and parse a JSON config file.
|
|
196
213
|
*
|
|
@@ -201,14 +218,9 @@ export function configPathFor(client, baseDir, scope) {
|
|
|
201
218
|
* file with only the new MCP entry (data-loss hazard).
|
|
202
219
|
*/
|
|
203
220
|
function readJsonFile(file) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
raw = fs.readFileSync(file, "utf-8");
|
|
207
|
-
}
|
|
208
|
-
catch {
|
|
209
|
-
// Missing (ENOENT) or unreadable file — treat as empty.
|
|
221
|
+
const raw = readExistingConfigFile(file);
|
|
222
|
+
if (raw === undefined)
|
|
210
223
|
return {};
|
|
211
|
-
}
|
|
212
224
|
if (!raw.trim())
|
|
213
225
|
return {};
|
|
214
226
|
try {
|
|
@@ -480,13 +492,7 @@ export function buildCodexLocalBlock(name, args, env, command = "agent-native")
|
|
|
480
492
|
* Identical algorithm to `mcp.ts`'s `writeCodexBlock` so the two never diverge.
|
|
481
493
|
*/
|
|
482
494
|
export function writeCodexBlock(file, name, block) {
|
|
483
|
-
|
|
484
|
-
try {
|
|
485
|
-
content = fs.readFileSync(file, "utf-8");
|
|
486
|
-
}
|
|
487
|
-
catch {
|
|
488
|
-
content = "";
|
|
489
|
-
}
|
|
495
|
+
const content = readExistingConfigFile(file) ?? "";
|
|
490
496
|
const lines = content.split(/\r?\n/);
|
|
491
497
|
const out = [];
|
|
492
498
|
let i = 0;
|
|
@@ -520,15 +526,10 @@ export function writeCodexBlock(file, name, block) {
|
|
|
520
526
|
writeFileAtomic(file, next);
|
|
521
527
|
}
|
|
522
528
|
export function codexHasBlock(file, name) {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
.some((line) => codexServerNameOfHeader(line) === name);
|
|
528
|
-
}
|
|
529
|
-
catch {
|
|
530
|
-
return false;
|
|
531
|
-
}
|
|
529
|
+
const content = readExistingConfigFile(file);
|
|
530
|
+
return (content
|
|
531
|
+
?.split(/\r?\n/)
|
|
532
|
+
.some((line) => codexServerNameOfHeader(line) === name) ?? false);
|
|
532
533
|
}
|
|
533
534
|
// ---------------------------------------------------------------------------
|
|
534
535
|
// Unified write helper
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-config-writers.js","sourceRoot":"","sources":["../../src/cli/mcp-config-writers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared MCP client-config writers.\n *\n * Extracted so both `agent-native mcp install` (see `mcp.ts`) and\n * `agent-native connect` (see `connect.ts`) write the EXACT same on-disk\n * config file targets and formats for every supported client.\n *\n * Supported clients and their config files:\n * - claude-code / claude-code-cli → `.mcp.json` (project) or\n * `~/.claude.json` (user). JSON `mcpServers[name] = entry`.\n * - cowork → `~/.cowork/mcp.json`. Same JSON shape.\n * - cursor → `.cursor/mcp.json` (project) or\n * `~/.cursor/mcp.json` (user). JSON `mcpServers[name] = entry`.\n * - opencode → `opencode.json` (project) or\n * `~/.config/opencode/opencode.json` (user). JSON `mcp[name] = entry`.\n * - github-copilot → `.vscode/mcp.json` (project) or the\n * VS Code user `mcp.json`. JSON `servers[name] = entry`.\n * - codex → `$CODEX_HOME/config.toml` when set,\n * otherwise `~/.codex/config.toml`.\n * `[mcp_servers.<name>]` block.\n *\n * Node-only. No new npm deps — hand-rolled JSON merge + minimal TOML block\n * merge, mirroring `mcp.ts`.\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nconst MCP_LEGACY_ROUTE_PREFIX = \"/_agent-native/mcp\";\nconst MCP_PUBLIC_ROUTE_PREFIX = \"/mcp\";\n\nexport type ClientId =\n | \"claude-code\"\n | \"claude-code-cli\"\n | \"codex\"\n | \"cowork\"\n | \"cursor\"\n | \"opencode\"\n | \"github-copilot\";\n\nexport const CLIENTS: ClientId[] = [\n \"claude-code\",\n \"claude-code-cli\",\n \"codex\",\n \"cowork\",\n \"cursor\",\n \"opencode\",\n \"github-copilot\",\n];\n\n/** The HTTP MCP server entry written into a JSON client config. */\nexport interface HttpMcpEntry {\n type: \"http\";\n url: string;\n headers?: Record<string, string>;\n}\n\n/** Build the HTTP MCP server entry for a deployed agent-native app. */\nexport function buildHttpMcpEntry(\n mcpUrl: string,\n token?: string,\n headers?: Record<string, string>,\n): HttpMcpEntry {\n const mergedHeaders = {\n ...(headers ?? {}),\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n };\n return {\n type: \"http\",\n url: mcpUrl,\n ...(Object.keys(mergedHeaders).length ? { headers: mergedHeaders } : {}),\n };\n}\n\nfunction mergedHeadersFor(\n token?: string,\n headers?: Record<string, string>,\n): Record<string, string> {\n return {\n ...(headers ?? {}),\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n };\n}\n\nexport function buildHttpMcpEntryForClient(\n client: ClientId,\n mcpUrl: string,\n token?: string,\n headers?: Record<string, string>,\n): Record<string, unknown> {\n const mergedHeaders = mergedHeadersFor(token, headers);\n if (client === \"cursor\") {\n return {\n url: mcpUrl,\n ...(Object.keys(mergedHeaders).length ? { headers: mergedHeaders } : {}),\n };\n }\n if (client === \"opencode\") {\n return {\n type: \"remote\",\n url: mcpUrl,\n enabled: true,\n ...(Object.keys(mergedHeaders).length ? { headers: mergedHeaders } : {}),\n };\n }\n if (client === \"github-copilot\") {\n return {\n type: \"http\",\n url: mcpUrl,\n ...(Object.keys(mergedHeaders).length\n ? { requestInit: { headers: mergedHeaders } }\n : {}),\n };\n }\n return buildHttpMcpEntry(mcpUrl, token, headers) as unknown as Record<\n string,\n unknown\n >;\n}\n\nexport function buildLocalMcpEntryForClient(\n client: ClientId,\n args: string[],\n env?: Record<string, string>,\n command = \"agent-native\",\n): Record<string, unknown> {\n const cleanEnv = env ? Object.fromEntries(Object.entries(env)) : {};\n if (client === \"opencode\") {\n return {\n type: \"local\",\n command: [command, ...args],\n enabled: true,\n ...(Object.keys(cleanEnv).length ? { environment: cleanEnv } : {}),\n };\n }\n if (client === \"github-copilot\") {\n return {\n type: \"stdio\",\n command,\n args,\n ...(Object.keys(cleanEnv).length ? { env: cleanEnv } : {}),\n };\n }\n return {\n command,\n args,\n ...(Object.keys(cleanEnv).length ? { env: cleanEnv } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Config file locations — kept identical to `mcp.ts`.\n// ---------------------------------------------------------------------------\n\n/**\n * Cowork consumes MCP exactly like Claude Code (same JSON server-entry\n * shape). Resolved lazily so `os.homedir()` reflects the current `$HOME`.\n */\nexport function coworkConfigPath(): string {\n return path.join(os.homedir(), \".cowork\", \"mcp.json\");\n}\n\nexport function claudeCodeProjectConfig(baseDir: string): string {\n return path.join(baseDir, \".mcp.json\");\n}\n\nexport function claudeCodeUserConfig(): string {\n return path.join(os.homedir(), \".claude.json\");\n}\n\nexport function codexConfigPath(): string {\n const codexHome = process.env.CODEX_HOME?.trim();\n if (codexHome) return path.join(codexHome, \"config.toml\");\n return path.join(os.homedir(), \".codex\", \"config.toml\");\n}\n\nexport function cursorProjectConfig(baseDir: string): string {\n return path.join(baseDir, \".cursor\", \"mcp.json\");\n}\n\nexport function cursorUserConfig(): string {\n return path.join(os.homedir(), \".cursor\", \"mcp.json\");\n}\n\nexport function opencodeProjectConfig(baseDir: string): string {\n return path.join(baseDir, \"opencode.json\");\n}\n\nexport function opencodeUserConfig(): string {\n const xdgConfigHome = process.env.XDG_CONFIG_HOME?.trim();\n const configRoot = xdgConfigHome || path.join(os.homedir(), \".config\");\n return path.join(configRoot, \"opencode\", \"opencode.json\");\n}\n\nexport function githubCopilotProjectConfig(baseDir: string): string {\n return path.join(baseDir, \".vscode\", \"mcp.json\");\n}\n\nexport function githubCopilotUserConfig(): string {\n if (process.platform === \"darwin\") {\n return path.join(\n os.homedir(),\n \"Library\",\n \"Application Support\",\n \"Code\",\n \"User\",\n \"mcp.json\",\n );\n }\n if (process.platform === \"win32\") {\n const appData =\n process.env.APPDATA || path.join(os.homedir(), \"AppData\", \"Roaming\");\n return path.join(appData, \"Code\", \"User\", \"mcp.json\");\n }\n const xdgConfigHome = process.env.XDG_CONFIG_HOME?.trim();\n const configRoot = xdgConfigHome || path.join(os.homedir(), \".config\");\n return path.join(configRoot, \"Code\", \"User\", \"mcp.json\");\n}\n\n/**\n * Resolve the on-disk config path for a client.\n *\n * `scope` only affects Claude Code / Claude Code CLI: `\"user\"` → the global\n * `~/.claude.json`, anything else → the project-local `.mcp.json` rooted at\n * `baseDir`.\n */\nexport function configPathFor(\n client: ClientId,\n baseDir: string,\n scope: string | undefined,\n): string {\n switch (client) {\n case \"claude-code\":\n case \"claude-code-cli\":\n return scope === \"user\"\n ? claudeCodeUserConfig()\n : claudeCodeProjectConfig(baseDir);\n case \"cowork\":\n return coworkConfigPath();\n case \"codex\":\n return codexConfigPath();\n case \"cursor\":\n return scope === \"user\"\n ? cursorUserConfig()\n : cursorProjectConfig(baseDir);\n case \"opencode\":\n return scope === \"user\"\n ? opencodeUserConfig()\n : opencodeProjectConfig(baseDir);\n case \"github-copilot\":\n return scope === \"user\"\n ? githubCopilotUserConfig()\n : githubCopilotProjectConfig(baseDir);\n }\n}\n\n// ---------------------------------------------------------------------------\n// JSON client configs (Claude Code, Claude Code CLI, Cowork)\n// ---------------------------------------------------------------------------\n\n/**\n * Read and parse a JSON config file.\n *\n * - Missing file → returns `{}` (fresh config).\n * - Empty file → returns `{}` (treat as not-yet-initialised).\n * - Non-empty file that fails to parse → throws a descriptive Error so the\n * caller can surface it to the user instead of silently overwriting the\n * file with only the new MCP entry (data-loss hazard).\n */\nfunction readJsonFile(file: string): Record<string, any> {\n let raw: string;\n try {\n raw = fs.readFileSync(file, \"utf-8\");\n } catch {\n // Missing (ENOENT) or unreadable file — treat as empty.\n return {};\n }\n if (!raw.trim()) return {};\n try {\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === \"object\" ? parsed : {};\n } catch {\n throw new Error(\n `Cannot parse JSON config file: ${file}\\n` +\n `Fix or move the file and re-run. The file has not been modified.`,\n );\n }\n}\n\n/**\n * Write `data` to `file` atomically: write a sibling temp file, then rename it\n * over the target. `rename(2)` is atomic on the same filesystem, so a crash or\n * `kill` mid-write can never leave a half-written/truncated file. This matters\n * most for `~/.claude.json`, which is Claude Code's entire user state (projects,\n * history, auth) — a torn write there would corrupt the user's whole config,\n * not just our MCP entry. The temp file lives in the target's directory so the\n * rename stays within one filesystem.\n */\nexport function writeFileAtomic(file: string, data: string): void {\n const dir = path.dirname(file);\n fs.mkdirSync(dir, { recursive: true });\n // Preserve the target's existing permission bits. A fresh temp file would\n // otherwise be created with the umask default (typically 0644), silently\n // loosening a secret-bearing file the user locked down to 0600 (e.g. .env).\n let mode: number | undefined;\n try {\n mode = fs.statSync(file).mode & 0o777;\n } catch {\n // Target doesn't exist yet — let the default creation mode apply.\n }\n const tmp = path.join(dir, `.${path.basename(file)}.tmp-${process.pid}`);\n try {\n fs.writeFileSync(tmp, data, \"utf-8\");\n if (mode !== undefined) fs.chmodSync(tmp, mode);\n fs.renameSync(tmp, file);\n } catch (err) {\n try {\n fs.rmSync(tmp, { force: true });\n } catch {}\n throw err;\n }\n}\n\n/**\n * Idempotently write `mcpServers[name] = entry` into a JSON config file.\n * Pass `entry === null` to delete the named entry. Re-running with the same\n * name replaces the existing entry in place — never duplicates.\n */\nexport function jsonMcpConfigKeyForClient(client: ClientId): string {\n if (client === \"opencode\") return \"mcp\";\n if (client === \"github-copilot\") return \"servers\";\n return \"mcpServers\";\n}\n\nfunction writeJsonMcpEntryAtKey(\n file: string,\n serversKey: string,\n name: string,\n entry: Record<string, unknown> | null,\n): void {\n const config = readJsonFile(file);\n if (!config[serversKey] || typeof config[serversKey] !== \"object\") {\n config[serversKey] = {};\n }\n const servers = config[serversKey] as Record<string, unknown>;\n if (entry === null) {\n delete servers[name];\n } else {\n servers[name] = entry;\n }\n writeFileAtomic(file, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\nexport function writeJsonMcpEntry(\n file: string,\n name: string,\n entry: Record<string, unknown> | null,\n): void {\n writeJsonMcpEntryAtKey(file, \"mcpServers\", name, entry);\n}\n\nexport function writeJsonMcpEntryForClient(\n client: ClientId,\n file: string,\n name: string,\n entry: Record<string, unknown> | null,\n): void {\n writeJsonMcpEntryAtKey(file, jsonMcpConfigKeyForClient(client), name, entry);\n}\n\nexport function hasJsonMcpEntry(file: string, name: string): boolean {\n const config = readJsonFile(file);\n return !!config?.mcpServers && name in config.mcpServers;\n}\n\nexport function hasJsonMcpEntryForClient(\n client: ClientId,\n file: string,\n name: string,\n): boolean {\n const config = readJsonFile(file);\n const servers = config?.[jsonMcpConfigKeyForClient(client)];\n return !!servers && typeof servers === \"object\" && name in servers;\n}\n\n// ---------------------------------------------------------------------------\n// Codex TOML (hand-rolled minimal block merge, no new dep)\n// ---------------------------------------------------------------------------\n\nfunction tomlQuote(s: string): string {\n return `\"${s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\nfunction codexMcpHeader(name: string): string {\n return `[mcp_servers.${tomlQuote(name)}]`;\n}\n\n/**\n * Parse a TOML table-header line such as `[mcp_servers.\"plan\".http_headers]`\n * or `[mcp_servers.plan] # local note` into its decoded dotted-key components\n * (`[\"mcp_servers\", \"plan\", \"http_headers\"]`). Returns `null` when the line is\n * not a single `[table]` header — blank lines, key/value pairs, comments,\n * invalid trailing content, and `[[array-of-tables]]` headers all return `null`,\n * so the result doubles as a reliable \"is this line a table boundary?\" check.\n *\n * Handles bare keys (`A-Za-z0-9_-`) and quoted keys (basic `\"...\"` with `\\`\n * escapes, and literal `'...'`), tolerating whitespace around the dot\n * separators per the TOML spec. Quoted-key escape handling mirrors the inverse\n * of `tomlQuote` (`\\\"` → `\"`, `\\\\` → `\\`).\n */\nfunction parseTomlTableHeader(line: string): string[] | null {\n const trimmed = line.trim();\n if (trimmed.length < 2 || trimmed[0] !== \"[\") return null;\n // `[[array-of-tables]]` is a different construct — leave it untouched.\n if (trimmed[1] === \"[\") return null;\n\n let quote: '\"' | \"'\" | null = null;\n let escaped = false;\n let closeIndex = -1;\n for (let i = 1; i < trimmed.length; i++) {\n const ch = trimmed[i];\n if (quote === '\"') {\n if (escaped) {\n escaped = false;\n continue;\n }\n if (ch === \"\\\\\") {\n escaped = true;\n continue;\n }\n if (ch === '\"') quote = null;\n continue;\n }\n if (quote === \"'\") {\n if (ch === \"'\") quote = null;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch;\n continue;\n }\n if (ch === \"]\") {\n closeIndex = i;\n break;\n }\n }\n if (closeIndex < 0) return null;\n const trailing = trimmed.slice(closeIndex + 1).trim();\n if (trailing && !trailing.startsWith(\"#\")) return null;\n\n const inner = trimmed.slice(1, closeIndex);\n const keys: string[] = [];\n const isWs = (c: string) => c === \" \" || c === \"\\t\";\n const isBare = (c: string) => /[A-Za-z0-9_-]/.test(c);\n let i = 0;\n let expectKey = true;\n while (i < inner.length) {\n while (i < inner.length && isWs(inner[i])) i++;\n if (i >= inner.length) break;\n const ch = inner[i];\n if (ch === \".\") {\n if (expectKey) return null; // leading or doubled dot\n expectKey = true;\n i++;\n continue;\n }\n if (!expectKey) return null; // two keys with no dot between them\n if (ch === '\"' || ch === \"'\") {\n const quote = ch;\n i++;\n let key = \"\";\n while (i < inner.length && inner[i] !== quote) {\n if (quote === '\"' && inner[i] === \"\\\\\" && i + 1 < inner.length) {\n const next = inner[i + 1];\n key += next === '\"' ? '\"' : next === \"\\\\\" ? \"\\\\\" : `\\\\${next}`;\n i += 2;\n continue;\n }\n key += inner[i];\n i++;\n }\n if (i >= inner.length) return null; // unterminated quote\n i++; // consume the closing quote\n keys.push(key);\n expectKey = false;\n } else if (isBare(ch)) {\n let key = \"\";\n while (i < inner.length && isBare(inner[i])) {\n key += inner[i];\n i++;\n }\n keys.push(key);\n expectKey = false;\n } else {\n return null; // unexpected character — not a table header\n }\n }\n if (expectKey) return null; // empty header or trailing dot\n return keys.length ? keys : null;\n}\n\n/**\n * The MCP server name a TOML table header belongs to, or `undefined` when the\n * header is not under `[mcp_servers.*]`. The server's own table\n * (`[mcp_servers.<name>]`) AND every sub-table of it\n * (`[mcp_servers.<name>.http_headers]`, `[mcp_servers.<name>.env]`, …) resolve\n * to the same `<name>`, so callers can treat a server and all its sub-tables as\n * one removable unit. This is what prevents a re-install from orphaning a stale\n * `[mcp_servers.<name>.http_headers]` sub-table that would then collide with the\n * freshly written inline `http_headers` (a TOML duplicate-key error).\n */\nfunction codexServerNameOfHeader(line: string): string | undefined {\n const keys = parseTomlTableHeader(line);\n if (!keys || keys.length < 2 || keys[0] !== \"mcp_servers\") return undefined;\n return keys[1];\n}\n\n/** Build a `[mcp_servers.<name>]` block for an HTTP-type MCP server. */\nexport function buildCodexHttpBlock(\n name: string,\n mcpUrl: string,\n token?: string,\n headers?: Record<string, string>,\n): string {\n const lines: string[] = [codexMcpHeader(name)];\n lines.push(`url = ${tomlQuote(mcpUrl)}`);\n const mergedHeaders = {\n ...(headers ?? {}),\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n };\n const headerEntries = Object.entries(mergedHeaders);\n if (headerEntries.length) {\n lines.push(\n `http_headers = { ${headerEntries\n .map(([key, value]) => `${tomlQuote(key)} = ${tomlQuote(value)}`)\n .join(\", \")} }`,\n );\n }\n return lines.join(\"\\n\") + \"\\n\";\n}\n\nexport function buildCodexLocalBlock(\n name: string,\n args: string[],\n env?: Record<string, string>,\n command = \"agent-native\",\n): string {\n const lines: string[] = [codexMcpHeader(name)];\n lines.push(`command = ${tomlQuote(command)}`);\n lines.push(`args = [${args.map(tomlQuote).join(\", \")}]`);\n const cleanEnv = env ? Object.fromEntries(Object.entries(env)) : {};\n if (Object.keys(cleanEnv).length) {\n const inline = Object.entries(cleanEnv)\n .map(([key, value]) => `${key} = ${tomlQuote(value)}`)\n .join(\", \");\n lines.push(`env = { ${inline} }`);\n }\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/**\n * Replace (or append) the entire `[mcp_servers.<name>]` footprint in a TOML\n * file without disturbing other content. The footprint is the server's own\n * table AND every sub-table of it (`[mcp_servers.<name>.http_headers]`,\n * `[mcp_servers.<name>.env]`, …), each spanning its header line plus every\n * following line until the next table header or EOF. Removing the whole\n * footprint — wherever the pieces sit in the file — is what keeps a re-install\n * from leaving a stale sub-table that collides with the freshly written inline\n * block (a TOML duplicate-key error). Matches both the canonical quoted header\n * and the legacy bare header. Pass `block === null` to remove the footprint.\n * Identical algorithm to `mcp.ts`'s `writeCodexBlock` so the two never diverge.\n */\nexport function writeCodexBlock(\n file: string,\n name: string,\n block: string | null,\n): void {\n let content = \"\";\n try {\n content = fs.readFileSync(file, \"utf-8\");\n } catch {\n content = \"\";\n }\n\n const lines = content.split(/\\r?\\n/);\n const out: string[] = [];\n let i = 0;\n let removed = false;\n while (i < lines.length) {\n const line = lines[i];\n if (codexServerNameOfHeader(line) === name) {\n // Skip this table and its body (until the next table header), covering\n // the server table itself and any of its sub-tables.\n removed = true;\n i++;\n while (i < lines.length && parseTomlTableHeader(lines[i]) === null) i++;\n continue;\n }\n out.push(line);\n i++;\n }\n\n let next = out\n .join(\"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .replace(/\\n*$/, \"\\n\");\n if (block !== null) {\n next = next.replace(/\\n*$/, \"\\n\");\n if (next.trim().length) next += \"\\n\";\n next += block;\n }\n if (block === null && !removed) return; // nothing to do\n\n writeFileAtomic(file, next);\n}\n\nexport function codexHasBlock(file: string, name: string): boolean {\n try {\n const content = fs.readFileSync(file, \"utf-8\");\n return content\n .split(/\\r?\\n/)\n .some((line) => codexServerNameOfHeader(line) === name);\n } catch {\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Unified write helper\n// ---------------------------------------------------------------------------\n\n/**\n * Idempotently write the HTTP MCP server entry for `serverName` into the\n * given client's config file and return the file path that was written.\n * Re-running replaces the same named entry — never duplicates.\n */\nexport function writeHttpEntryForClient(\n client: ClientId,\n serverName: string,\n mcpUrl: string,\n token: string | undefined,\n baseDir: string,\n scope: string | undefined,\n headers?: Record<string, string>,\n): string {\n const file = configPathFor(client, baseDir, scope);\n if (client === \"codex\") {\n writeCodexBlock(\n file,\n serverName,\n buildCodexHttpBlock(serverName, mcpUrl, token, headers),\n );\n } else {\n writeJsonMcpEntryForClient(\n client,\n file,\n serverName,\n buildHttpMcpEntryForClient(client, mcpUrl, token, headers),\n );\n }\n return file;\n}\n\n// ---------------------------------------------------------------------------\n// Same-URL duplicate removal\n// ---------------------------------------------------------------------------\n\n/**\n * Canonicalise a URL for comparison: strip hash, search params, and trailing\n * slashes. Returns `undefined` for invalid URLs.\n */\nexport function canonicalUrl(value: string | undefined): string | undefined {\n if (!value) return undefined;\n try {\n const u = new URL(value);\n u.hash = \"\";\n u.search = \"\";\n const pathname = u.pathname.replace(/\\/+$/, \"\");\n if (\n pathname === MCP_LEGACY_ROUTE_PREFIX ||\n pathname.endsWith(MCP_LEGACY_ROUTE_PREFIX)\n ) {\n u.pathname = `${pathname.slice(0, -MCP_LEGACY_ROUTE_PREFIX.length)}${MCP_PUBLIC_ROUTE_PREFIX}`;\n }\n return u.toString().replace(/\\/+$/, \"\");\n } catch {\n return undefined;\n }\n}\n\n/**\n * After writing the canonical `keepName` entry into a JSON config file,\n * remove any OTHER entries whose URL normalises to the same value as\n * `mcpUrl`. This cleans up stale alias names, legacy default names, and\n * leftover custom names that all pointed at the same server.\n *\n * Returns the list of entry names that were removed.\n */\nfunction removeJsonSameUrlDuplicatesAtKey(\n file: string,\n serversKey: string,\n mcpUrl: string,\n keepName: string,\n): string[] {\n let config: Record<string, any>;\n try {\n const raw = fs.readFileSync(file, \"utf-8\");\n if (!raw.trim()) return [];\n config = JSON.parse(raw);\n } catch {\n return [];\n }\n const servers = config?.[serversKey];\n if (!servers || typeof servers !== \"object\" || Array.isArray(servers)) {\n return [];\n }\n const targetCanonical = canonicalUrl(mcpUrl);\n if (!targetCanonical) return [];\n\n const toRemove: string[] = [];\n for (const name of Object.keys(servers)) {\n if (name === keepName) continue;\n const entry = servers[name];\n if (!entry || typeof entry !== \"object\") continue;\n const entryUrl = typeof entry.url === \"string\" ? entry.url : undefined;\n if (canonicalUrl(entryUrl) === targetCanonical) {\n toRemove.push(name);\n }\n }\n if (toRemove.length === 0) return [];\n for (const name of toRemove) {\n delete servers[name];\n }\n writeFileAtomic(file, JSON.stringify(config, null, 2) + \"\\n\");\n return toRemove;\n}\n\nexport function removeJsonSameUrlDuplicates(\n file: string,\n mcpUrl: string,\n keepName: string,\n): string[] {\n return removeJsonSameUrlDuplicatesAtKey(file, \"mcpServers\", mcpUrl, keepName);\n}\n\n/**\n * After writing the canonical `keepName` Codex block, remove any OTHER\n * `[mcp_servers.*]` servers in the same TOML file whose `url =` line normalises\n * to the same value as `mcpUrl`. A server's entire footprint is removed — its\n * own table AND any sub-tables (`.http_headers`, `.env`, …), even when they are\n * not contiguous — so cleanup never leaves an orphaned sub-table behind.\n * Returns removed entry names in first-seen order.\n */\nexport function removeCodexSameUrlDuplicates(\n file: string,\n mcpUrl: string,\n keepName: string,\n): string[] {\n let content = \"\";\n try {\n content = fs.readFileSync(file, \"utf-8\");\n } catch {\n return [];\n }\n const targetCanonical = canonicalUrl(mcpUrl);\n if (!targetCanonical) return [];\n\n const lines = content.split(/\\r?\\n/);\n\n // Pass 1: map each server name to the canonical URL declared on its own\n // table, preserving first-seen order. Sub-tables don't carry the URL, so they\n // only register the name.\n const serverUrls = new Map<string, string | undefined>();\n let i = 0;\n while (i < lines.length) {\n const keys = parseTomlTableHeader(lines[i]);\n const name =\n keys && keys.length >= 2 && keys[0] === \"mcp_servers\"\n ? keys[1]\n : undefined;\n if (name === undefined) {\n i++;\n continue;\n }\n const isServerTable = keys!.length === 2;\n const body: string[] = [];\n i++;\n while (i < lines.length && parseTomlTableHeader(lines[i]) === null) {\n body.push(lines[i]);\n i++;\n }\n if (isServerTable) {\n const urlMatch = body\n .join(\"\\n\")\n .match(/^\\s*url\\s*=\\s*\"((?:\\\\.|[^\"])*)\"/m);\n const blockUrl = urlMatch\n ? urlMatch[1].replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, \"\\\\\")\n : undefined;\n serverUrls.set(name, canonicalUrl(blockUrl));\n } else if (!serverUrls.has(name)) {\n serverUrls.set(name, undefined);\n }\n }\n\n const removeSet = new Set<string>();\n for (const [name, canonical] of serverUrls) {\n if (name !== keepName && canonical && canonical === targetCanonical) {\n removeSet.add(name);\n }\n }\n if (removeSet.size === 0) return [];\n\n // Pass 2: rebuild, dropping every table/sub-table belonging to a removed\n // server.\n const out: string[] = [];\n i = 0;\n while (i < lines.length) {\n const name = codexServerNameOfHeader(lines[i]);\n if (name !== undefined && removeSet.has(name)) {\n i++;\n while (i < lines.length && parseTomlTableHeader(lines[i]) === null) i++;\n continue;\n }\n out.push(lines[i]);\n i++;\n }\n\n const next = out\n .join(\"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .replace(/\\n*$/, \"\\n\");\n writeFileAtomic(file, next);\n return [...removeSet];\n}\n\n/**\n * Unified helper: after writing the canonical `serverName` entry for the\n * given `client`, remove same-URL duplicates from its config file.\n * Returns the list of removed names (empty if nothing was cleaned up).\n */\nexport function removeSameUrlDuplicatesForClient(\n client: ClientId,\n serverName: string,\n mcpUrl: string,\n baseDir: string,\n scope: string | undefined,\n): string[] {\n const file = configPathFor(client, baseDir, scope);\n if (client === \"codex\") {\n return removeCodexSameUrlDuplicates(file, mcpUrl, serverName);\n }\n return removeJsonSameUrlDuplicatesAtKey(\n file,\n jsonMcpConfigKeyForClient(client),\n mcpUrl,\n serverName,\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mcp-config-writers.js","sourceRoot":"","sources":["../../src/cli/mcp-config-writers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared MCP client-config writers.\n *\n * Extracted so both `agent-native mcp install` (see `mcp.ts`) and\n * `agent-native connect` (see `connect.ts`) write the EXACT same on-disk\n * config file targets and formats for every supported client.\n *\n * Supported clients and their config files:\n * - claude-code / claude-code-cli → `.mcp.json` (project) or\n * `~/.claude.json` (user). JSON `mcpServers[name] = entry`.\n * - cowork → `~/.cowork/mcp.json`. Same JSON shape.\n * - cursor → `.cursor/mcp.json` (project) or\n * `~/.cursor/mcp.json` (user). JSON `mcpServers[name] = entry`.\n * - opencode → `opencode.json` (project) or\n * `~/.config/opencode/opencode.json` (user). JSON `mcp[name] = entry`.\n * - github-copilot → `.vscode/mcp.json` (project) or the\n * VS Code user `mcp.json`. JSON `servers[name] = entry`.\n * - codex → `$CODEX_HOME/config.toml` when set,\n * otherwise `~/.codex/config.toml`.\n * `[mcp_servers.<name>]` block.\n *\n * Node-only. No new npm deps — hand-rolled JSON merge + minimal TOML block\n * merge, mirroring `mcp.ts`.\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nconst MCP_LEGACY_ROUTE_PREFIX = \"/_agent-native/mcp\";\nconst MCP_PUBLIC_ROUTE_PREFIX = \"/mcp\";\n\nexport type ClientId =\n | \"claude-code\"\n | \"claude-code-cli\"\n | \"codex\"\n | \"cowork\"\n | \"cursor\"\n | \"opencode\"\n | \"github-copilot\";\n\nexport const CLIENTS: ClientId[] = [\n \"claude-code\",\n \"claude-code-cli\",\n \"codex\",\n \"cowork\",\n \"cursor\",\n \"opencode\",\n \"github-copilot\",\n];\n\n/** The HTTP MCP server entry written into a JSON client config. */\nexport interface HttpMcpEntry {\n type: \"http\";\n url: string;\n headers?: Record<string, string>;\n}\n\n/** Build the HTTP MCP server entry for a deployed agent-native app. */\nexport function buildHttpMcpEntry(\n mcpUrl: string,\n token?: string,\n headers?: Record<string, string>,\n): HttpMcpEntry {\n const mergedHeaders = {\n ...(headers ?? {}),\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n };\n return {\n type: \"http\",\n url: mcpUrl,\n ...(Object.keys(mergedHeaders).length ? { headers: mergedHeaders } : {}),\n };\n}\n\nfunction mergedHeadersFor(\n token?: string,\n headers?: Record<string, string>,\n): Record<string, string> {\n return {\n ...(headers ?? {}),\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n };\n}\n\nexport function buildHttpMcpEntryForClient(\n client: ClientId,\n mcpUrl: string,\n token?: string,\n headers?: Record<string, string>,\n): Record<string, unknown> {\n const mergedHeaders = mergedHeadersFor(token, headers);\n if (client === \"cursor\") {\n return {\n url: mcpUrl,\n ...(Object.keys(mergedHeaders).length ? { headers: mergedHeaders } : {}),\n };\n }\n if (client === \"opencode\") {\n return {\n type: \"remote\",\n url: mcpUrl,\n enabled: true,\n ...(Object.keys(mergedHeaders).length ? { headers: mergedHeaders } : {}),\n };\n }\n if (client === \"github-copilot\") {\n return {\n type: \"http\",\n url: mcpUrl,\n ...(Object.keys(mergedHeaders).length\n ? { requestInit: { headers: mergedHeaders } }\n : {}),\n };\n }\n return buildHttpMcpEntry(mcpUrl, token, headers) as unknown as Record<\n string,\n unknown\n >;\n}\n\nexport function buildLocalMcpEntryForClient(\n client: ClientId,\n args: string[],\n env?: Record<string, string>,\n command = \"agent-native\",\n): Record<string, unknown> {\n const cleanEnv = env ? Object.fromEntries(Object.entries(env)) : {};\n if (client === \"opencode\") {\n return {\n type: \"local\",\n command: [command, ...args],\n enabled: true,\n ...(Object.keys(cleanEnv).length ? { environment: cleanEnv } : {}),\n };\n }\n if (client === \"github-copilot\") {\n return {\n type: \"stdio\",\n command,\n args,\n ...(Object.keys(cleanEnv).length ? { env: cleanEnv } : {}),\n };\n }\n return {\n command,\n args,\n ...(Object.keys(cleanEnv).length ? { env: cleanEnv } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Config file locations — kept identical to `mcp.ts`.\n// ---------------------------------------------------------------------------\n\n/**\n * Cowork consumes MCP exactly like Claude Code (same JSON server-entry\n * shape). Resolved lazily so `os.homedir()` reflects the current `$HOME`.\n */\nexport function coworkConfigPath(): string {\n return path.join(os.homedir(), \".cowork\", \"mcp.json\");\n}\n\nexport function claudeCodeProjectConfig(baseDir: string): string {\n return path.join(baseDir, \".mcp.json\");\n}\n\nexport function claudeCodeUserConfig(): string {\n return path.join(os.homedir(), \".claude.json\");\n}\n\nexport function codexConfigPath(): string {\n const codexHome = process.env.CODEX_HOME?.trim();\n if (codexHome) return path.join(codexHome, \"config.toml\");\n return path.join(os.homedir(), \".codex\", \"config.toml\");\n}\n\nexport function cursorProjectConfig(baseDir: string): string {\n return path.join(baseDir, \".cursor\", \"mcp.json\");\n}\n\nexport function cursorUserConfig(): string {\n return path.join(os.homedir(), \".cursor\", \"mcp.json\");\n}\n\nexport function opencodeProjectConfig(baseDir: string): string {\n return path.join(baseDir, \"opencode.json\");\n}\n\nexport function opencodeUserConfig(): string {\n const xdgConfigHome = process.env.XDG_CONFIG_HOME?.trim();\n const configRoot = xdgConfigHome || path.join(os.homedir(), \".config\");\n return path.join(configRoot, \"opencode\", \"opencode.json\");\n}\n\nexport function githubCopilotProjectConfig(baseDir: string): string {\n return path.join(baseDir, \".vscode\", \"mcp.json\");\n}\n\nexport function githubCopilotUserConfig(): string {\n if (process.platform === \"darwin\") {\n return path.join(\n os.homedir(),\n \"Library\",\n \"Application Support\",\n \"Code\",\n \"User\",\n \"mcp.json\",\n );\n }\n if (process.platform === \"win32\") {\n const appData =\n process.env.APPDATA || path.join(os.homedir(), \"AppData\", \"Roaming\");\n return path.join(appData, \"Code\", \"User\", \"mcp.json\");\n }\n const xdgConfigHome = process.env.XDG_CONFIG_HOME?.trim();\n const configRoot = xdgConfigHome || path.join(os.homedir(), \".config\");\n return path.join(configRoot, \"Code\", \"User\", \"mcp.json\");\n}\n\n/**\n * Resolve the on-disk config path for a client.\n *\n * `scope` only affects Claude Code / Claude Code CLI: `\"user\"` → the global\n * `~/.claude.json`, anything else → the project-local `.mcp.json` rooted at\n * `baseDir`.\n */\nexport function configPathFor(\n client: ClientId,\n baseDir: string,\n scope: string | undefined,\n): string {\n switch (client) {\n case \"claude-code\":\n case \"claude-code-cli\":\n return scope === \"user\"\n ? claudeCodeUserConfig()\n : claudeCodeProjectConfig(baseDir);\n case \"cowork\":\n return coworkConfigPath();\n case \"codex\":\n return codexConfigPath();\n case \"cursor\":\n return scope === \"user\"\n ? cursorUserConfig()\n : cursorProjectConfig(baseDir);\n case \"opencode\":\n return scope === \"user\"\n ? opencodeUserConfig()\n : opencodeProjectConfig(baseDir);\n case \"github-copilot\":\n return scope === \"user\"\n ? githubCopilotUserConfig()\n : githubCopilotProjectConfig(baseDir);\n }\n}\n\n// ---------------------------------------------------------------------------\n// JSON client configs (Claude Code, Claude Code CLI, Cowork)\n// ---------------------------------------------------------------------------\n\n/**\n * Read an existing MCP config without conflating missing and unreadable files.\n * Only ENOENT means the config is absent; any other read failure must abort\n * before a caller can overwrite existing user configuration.\n */\nfunction readExistingConfigFile(file: string): string | undefined {\n try {\n return fs.readFileSync(file, \"utf-8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n const detail = error instanceof Error ? ` (${error.message})` : \"\";\n throw new Error(\n `Cannot read MCP config file: ${file}\\n` +\n `Check that the file is readable and re-run. The file has not been modified.${detail}`,\n );\n }\n}\n\n/**\n * Read and parse a JSON config file.\n *\n * - Missing file → returns `{}` (fresh config).\n * - Empty file → returns `{}` (treat as not-yet-initialised).\n * - Non-empty file that fails to parse → throws a descriptive Error so the\n * caller can surface it to the user instead of silently overwriting the\n * file with only the new MCP entry (data-loss hazard).\n */\nfunction readJsonFile(file: string): Record<string, any> {\n const raw = readExistingConfigFile(file);\n if (raw === undefined) return {};\n if (!raw.trim()) return {};\n try {\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === \"object\" ? parsed : {};\n } catch {\n throw new Error(\n `Cannot parse JSON config file: ${file}\\n` +\n `Fix or move the file and re-run. The file has not been modified.`,\n );\n }\n}\n\n/**\n * Write `data` to `file` atomically: write a sibling temp file, then rename it\n * over the target. `rename(2)` is atomic on the same filesystem, so a crash or\n * `kill` mid-write can never leave a half-written/truncated file. This matters\n * most for `~/.claude.json`, which is Claude Code's entire user state (projects,\n * history, auth) — a torn write there would corrupt the user's whole config,\n * not just our MCP entry. The temp file lives in the target's directory so the\n * rename stays within one filesystem.\n */\nexport function writeFileAtomic(file: string, data: string): void {\n const dir = path.dirname(file);\n fs.mkdirSync(dir, { recursive: true });\n // Preserve the target's existing permission bits. A fresh temp file would\n // otherwise be created with the umask default (typically 0644), silently\n // loosening a secret-bearing file the user locked down to 0600 (e.g. .env).\n let mode: number | undefined;\n try {\n mode = fs.statSync(file).mode & 0o777;\n } catch {\n // Target doesn't exist yet — let the default creation mode apply.\n }\n const tmp = path.join(dir, `.${path.basename(file)}.tmp-${process.pid}`);\n try {\n fs.writeFileSync(tmp, data, \"utf-8\");\n if (mode !== undefined) fs.chmodSync(tmp, mode);\n fs.renameSync(tmp, file);\n } catch (err) {\n try {\n fs.rmSync(tmp, { force: true });\n } catch {}\n throw err;\n }\n}\n\n/**\n * Idempotently write `mcpServers[name] = entry` into a JSON config file.\n * Pass `entry === null` to delete the named entry. Re-running with the same\n * name replaces the existing entry in place — never duplicates.\n */\nexport function jsonMcpConfigKeyForClient(client: ClientId): string {\n if (client === \"opencode\") return \"mcp\";\n if (client === \"github-copilot\") return \"servers\";\n return \"mcpServers\";\n}\n\nfunction writeJsonMcpEntryAtKey(\n file: string,\n serversKey: string,\n name: string,\n entry: Record<string, unknown> | null,\n): void {\n const config = readJsonFile(file);\n if (!config[serversKey] || typeof config[serversKey] !== \"object\") {\n config[serversKey] = {};\n }\n const servers = config[serversKey] as Record<string, unknown>;\n if (entry === null) {\n delete servers[name];\n } else {\n servers[name] = entry;\n }\n writeFileAtomic(file, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\nexport function writeJsonMcpEntry(\n file: string,\n name: string,\n entry: Record<string, unknown> | null,\n): void {\n writeJsonMcpEntryAtKey(file, \"mcpServers\", name, entry);\n}\n\nexport function writeJsonMcpEntryForClient(\n client: ClientId,\n file: string,\n name: string,\n entry: Record<string, unknown> | null,\n): void {\n writeJsonMcpEntryAtKey(file, jsonMcpConfigKeyForClient(client), name, entry);\n}\n\nexport function hasJsonMcpEntry(file: string, name: string): boolean {\n const config = readJsonFile(file);\n return !!config?.mcpServers && name in config.mcpServers;\n}\n\nexport function hasJsonMcpEntryForClient(\n client: ClientId,\n file: string,\n name: string,\n): boolean {\n const config = readJsonFile(file);\n const servers = config?.[jsonMcpConfigKeyForClient(client)];\n return !!servers && typeof servers === \"object\" && name in servers;\n}\n\n// ---------------------------------------------------------------------------\n// Codex TOML (hand-rolled minimal block merge, no new dep)\n// ---------------------------------------------------------------------------\n\nfunction tomlQuote(s: string): string {\n return `\"${s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\nfunction codexMcpHeader(name: string): string {\n return `[mcp_servers.${tomlQuote(name)}]`;\n}\n\n/**\n * Parse a TOML table-header line such as `[mcp_servers.\"plan\".http_headers]`\n * or `[mcp_servers.plan] # local note` into its decoded dotted-key components\n * (`[\"mcp_servers\", \"plan\", \"http_headers\"]`). Returns `null` when the line is\n * not a single `[table]` header — blank lines, key/value pairs, comments,\n * invalid trailing content, and `[[array-of-tables]]` headers all return `null`,\n * so the result doubles as a reliable \"is this line a table boundary?\" check.\n *\n * Handles bare keys (`A-Za-z0-9_-`) and quoted keys (basic `\"...\"` with `\\`\n * escapes, and literal `'...'`), tolerating whitespace around the dot\n * separators per the TOML spec. Quoted-key escape handling mirrors the inverse\n * of `tomlQuote` (`\\\"` → `\"`, `\\\\` → `\\`).\n */\nfunction parseTomlTableHeader(line: string): string[] | null {\n const trimmed = line.trim();\n if (trimmed.length < 2 || trimmed[0] !== \"[\") return null;\n // `[[array-of-tables]]` is a different construct — leave it untouched.\n if (trimmed[1] === \"[\") return null;\n\n let quote: '\"' | \"'\" | null = null;\n let escaped = false;\n let closeIndex = -1;\n for (let i = 1; i < trimmed.length; i++) {\n const ch = trimmed[i];\n if (quote === '\"') {\n if (escaped) {\n escaped = false;\n continue;\n }\n if (ch === \"\\\\\") {\n escaped = true;\n continue;\n }\n if (ch === '\"') quote = null;\n continue;\n }\n if (quote === \"'\") {\n if (ch === \"'\") quote = null;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch;\n continue;\n }\n if (ch === \"]\") {\n closeIndex = i;\n break;\n }\n }\n if (closeIndex < 0) return null;\n const trailing = trimmed.slice(closeIndex + 1).trim();\n if (trailing && !trailing.startsWith(\"#\")) return null;\n\n const inner = trimmed.slice(1, closeIndex);\n const keys: string[] = [];\n const isWs = (c: string) => c === \" \" || c === \"\\t\";\n const isBare = (c: string) => /[A-Za-z0-9_-]/.test(c);\n let i = 0;\n let expectKey = true;\n while (i < inner.length) {\n while (i < inner.length && isWs(inner[i])) i++;\n if (i >= inner.length) break;\n const ch = inner[i];\n if (ch === \".\") {\n if (expectKey) return null; // leading or doubled dot\n expectKey = true;\n i++;\n continue;\n }\n if (!expectKey) return null; // two keys with no dot between them\n if (ch === '\"' || ch === \"'\") {\n const quote = ch;\n i++;\n let key = \"\";\n while (i < inner.length && inner[i] !== quote) {\n if (quote === '\"' && inner[i] === \"\\\\\" && i + 1 < inner.length) {\n const next = inner[i + 1];\n key += next === '\"' ? '\"' : next === \"\\\\\" ? \"\\\\\" : `\\\\${next}`;\n i += 2;\n continue;\n }\n key += inner[i];\n i++;\n }\n if (i >= inner.length) return null; // unterminated quote\n i++; // consume the closing quote\n keys.push(key);\n expectKey = false;\n } else if (isBare(ch)) {\n let key = \"\";\n while (i < inner.length && isBare(inner[i])) {\n key += inner[i];\n i++;\n }\n keys.push(key);\n expectKey = false;\n } else {\n return null; // unexpected character — not a table header\n }\n }\n if (expectKey) return null; // empty header or trailing dot\n return keys.length ? keys : null;\n}\n\n/**\n * The MCP server name a TOML table header belongs to, or `undefined` when the\n * header is not under `[mcp_servers.*]`. The server's own table\n * (`[mcp_servers.<name>]`) AND every sub-table of it\n * (`[mcp_servers.<name>.http_headers]`, `[mcp_servers.<name>.env]`, …) resolve\n * to the same `<name>`, so callers can treat a server and all its sub-tables as\n * one removable unit. This is what prevents a re-install from orphaning a stale\n * `[mcp_servers.<name>.http_headers]` sub-table that would then collide with the\n * freshly written inline `http_headers` (a TOML duplicate-key error).\n */\nfunction codexServerNameOfHeader(line: string): string | undefined {\n const keys = parseTomlTableHeader(line);\n if (!keys || keys.length < 2 || keys[0] !== \"mcp_servers\") return undefined;\n return keys[1];\n}\n\n/** Build a `[mcp_servers.<name>]` block for an HTTP-type MCP server. */\nexport function buildCodexHttpBlock(\n name: string,\n mcpUrl: string,\n token?: string,\n headers?: Record<string, string>,\n): string {\n const lines: string[] = [codexMcpHeader(name)];\n lines.push(`url = ${tomlQuote(mcpUrl)}`);\n const mergedHeaders = {\n ...(headers ?? {}),\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n };\n const headerEntries = Object.entries(mergedHeaders);\n if (headerEntries.length) {\n lines.push(\n `http_headers = { ${headerEntries\n .map(([key, value]) => `${tomlQuote(key)} = ${tomlQuote(value)}`)\n .join(\", \")} }`,\n );\n }\n return lines.join(\"\\n\") + \"\\n\";\n}\n\nexport function buildCodexLocalBlock(\n name: string,\n args: string[],\n env?: Record<string, string>,\n command = \"agent-native\",\n): string {\n const lines: string[] = [codexMcpHeader(name)];\n lines.push(`command = ${tomlQuote(command)}`);\n lines.push(`args = [${args.map(tomlQuote).join(\", \")}]`);\n const cleanEnv = env ? Object.fromEntries(Object.entries(env)) : {};\n if (Object.keys(cleanEnv).length) {\n const inline = Object.entries(cleanEnv)\n .map(([key, value]) => `${key} = ${tomlQuote(value)}`)\n .join(\", \");\n lines.push(`env = { ${inline} }`);\n }\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/**\n * Replace (or append) the entire `[mcp_servers.<name>]` footprint in a TOML\n * file without disturbing other content. The footprint is the server's own\n * table AND every sub-table of it (`[mcp_servers.<name>.http_headers]`,\n * `[mcp_servers.<name>.env]`, …), each spanning its header line plus every\n * following line until the next table header or EOF. Removing the whole\n * footprint — wherever the pieces sit in the file — is what keeps a re-install\n * from leaving a stale sub-table that collides with the freshly written inline\n * block (a TOML duplicate-key error). Matches both the canonical quoted header\n * and the legacy bare header. Pass `block === null` to remove the footprint.\n * Identical algorithm to `mcp.ts`'s `writeCodexBlock` so the two never diverge.\n */\nexport function writeCodexBlock(\n file: string,\n name: string,\n block: string | null,\n): void {\n const content = readExistingConfigFile(file) ?? \"\";\n\n const lines = content.split(/\\r?\\n/);\n const out: string[] = [];\n let i = 0;\n let removed = false;\n while (i < lines.length) {\n const line = lines[i];\n if (codexServerNameOfHeader(line) === name) {\n // Skip this table and its body (until the next table header), covering\n // the server table itself and any of its sub-tables.\n removed = true;\n i++;\n while (i < lines.length && parseTomlTableHeader(lines[i]) === null) i++;\n continue;\n }\n out.push(line);\n i++;\n }\n\n let next = out\n .join(\"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .replace(/\\n*$/, \"\\n\");\n if (block !== null) {\n next = next.replace(/\\n*$/, \"\\n\");\n if (next.trim().length) next += \"\\n\";\n next += block;\n }\n if (block === null && !removed) return; // nothing to do\n\n writeFileAtomic(file, next);\n}\n\nexport function codexHasBlock(file: string, name: string): boolean {\n const content = readExistingConfigFile(file);\n return (\n content\n ?.split(/\\r?\\n/)\n .some((line) => codexServerNameOfHeader(line) === name) ?? false\n );\n}\n\n// ---------------------------------------------------------------------------\n// Unified write helper\n// ---------------------------------------------------------------------------\n\n/**\n * Idempotently write the HTTP MCP server entry for `serverName` into the\n * given client's config file and return the file path that was written.\n * Re-running replaces the same named entry — never duplicates.\n */\nexport function writeHttpEntryForClient(\n client: ClientId,\n serverName: string,\n mcpUrl: string,\n token: string | undefined,\n baseDir: string,\n scope: string | undefined,\n headers?: Record<string, string>,\n): string {\n const file = configPathFor(client, baseDir, scope);\n if (client === \"codex\") {\n writeCodexBlock(\n file,\n serverName,\n buildCodexHttpBlock(serverName, mcpUrl, token, headers),\n );\n } else {\n writeJsonMcpEntryForClient(\n client,\n file,\n serverName,\n buildHttpMcpEntryForClient(client, mcpUrl, token, headers),\n );\n }\n return file;\n}\n\n// ---------------------------------------------------------------------------\n// Same-URL duplicate removal\n// ---------------------------------------------------------------------------\n\n/**\n * Canonicalise a URL for comparison: strip hash, search params, and trailing\n * slashes. Returns `undefined` for invalid URLs.\n */\nexport function canonicalUrl(value: string | undefined): string | undefined {\n if (!value) return undefined;\n try {\n const u = new URL(value);\n u.hash = \"\";\n u.search = \"\";\n const pathname = u.pathname.replace(/\\/+$/, \"\");\n if (\n pathname === MCP_LEGACY_ROUTE_PREFIX ||\n pathname.endsWith(MCP_LEGACY_ROUTE_PREFIX)\n ) {\n u.pathname = `${pathname.slice(0, -MCP_LEGACY_ROUTE_PREFIX.length)}${MCP_PUBLIC_ROUTE_PREFIX}`;\n }\n return u.toString().replace(/\\/+$/, \"\");\n } catch {\n return undefined;\n }\n}\n\n/**\n * After writing the canonical `keepName` entry into a JSON config file,\n * remove any OTHER entries whose URL normalises to the same value as\n * `mcpUrl`. This cleans up stale alias names, legacy default names, and\n * leftover custom names that all pointed at the same server.\n *\n * Returns the list of entry names that were removed.\n */\nfunction removeJsonSameUrlDuplicatesAtKey(\n file: string,\n serversKey: string,\n mcpUrl: string,\n keepName: string,\n): string[] {\n let config: Record<string, any>;\n try {\n const raw = fs.readFileSync(file, \"utf-8\");\n if (!raw.trim()) return [];\n config = JSON.parse(raw);\n } catch {\n return [];\n }\n const servers = config?.[serversKey];\n if (!servers || typeof servers !== \"object\" || Array.isArray(servers)) {\n return [];\n }\n const targetCanonical = canonicalUrl(mcpUrl);\n if (!targetCanonical) return [];\n\n const toRemove: string[] = [];\n for (const name of Object.keys(servers)) {\n if (name === keepName) continue;\n const entry = servers[name];\n if (!entry || typeof entry !== \"object\") continue;\n const entryUrl = typeof entry.url === \"string\" ? entry.url : undefined;\n if (canonicalUrl(entryUrl) === targetCanonical) {\n toRemove.push(name);\n }\n }\n if (toRemove.length === 0) return [];\n for (const name of toRemove) {\n delete servers[name];\n }\n writeFileAtomic(file, JSON.stringify(config, null, 2) + \"\\n\");\n return toRemove;\n}\n\nexport function removeJsonSameUrlDuplicates(\n file: string,\n mcpUrl: string,\n keepName: string,\n): string[] {\n return removeJsonSameUrlDuplicatesAtKey(file, \"mcpServers\", mcpUrl, keepName);\n}\n\n/**\n * After writing the canonical `keepName` Codex block, remove any OTHER\n * `[mcp_servers.*]` servers in the same TOML file whose `url =` line normalises\n * to the same value as `mcpUrl`. A server's entire footprint is removed — its\n * own table AND any sub-tables (`.http_headers`, `.env`, …), even when they are\n * not contiguous — so cleanup never leaves an orphaned sub-table behind.\n * Returns removed entry names in first-seen order.\n */\nexport function removeCodexSameUrlDuplicates(\n file: string,\n mcpUrl: string,\n keepName: string,\n): string[] {\n let content = \"\";\n try {\n content = fs.readFileSync(file, \"utf-8\");\n } catch {\n return [];\n }\n const targetCanonical = canonicalUrl(mcpUrl);\n if (!targetCanonical) return [];\n\n const lines = content.split(/\\r?\\n/);\n\n // Pass 1: map each server name to the canonical URL declared on its own\n // table, preserving first-seen order. Sub-tables don't carry the URL, so they\n // only register the name.\n const serverUrls = new Map<string, string | undefined>();\n let i = 0;\n while (i < lines.length) {\n const keys = parseTomlTableHeader(lines[i]);\n const name =\n keys && keys.length >= 2 && keys[0] === \"mcp_servers\"\n ? keys[1]\n : undefined;\n if (name === undefined) {\n i++;\n continue;\n }\n const isServerTable = keys!.length === 2;\n const body: string[] = [];\n i++;\n while (i < lines.length && parseTomlTableHeader(lines[i]) === null) {\n body.push(lines[i]);\n i++;\n }\n if (isServerTable) {\n const urlMatch = body\n .join(\"\\n\")\n .match(/^\\s*url\\s*=\\s*\"((?:\\\\.|[^\"])*)\"/m);\n const blockUrl = urlMatch\n ? urlMatch[1].replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, \"\\\\\")\n : undefined;\n serverUrls.set(name, canonicalUrl(blockUrl));\n } else if (!serverUrls.has(name)) {\n serverUrls.set(name, undefined);\n }\n }\n\n const removeSet = new Set<string>();\n for (const [name, canonical] of serverUrls) {\n if (name !== keepName && canonical && canonical === targetCanonical) {\n removeSet.add(name);\n }\n }\n if (removeSet.size === 0) return [];\n\n // Pass 2: rebuild, dropping every table/sub-table belonging to a removed\n // server.\n const out: string[] = [];\n i = 0;\n while (i < lines.length) {\n const name = codexServerNameOfHeader(lines[i]);\n if (name !== undefined && removeSet.has(name)) {\n i++;\n while (i < lines.length && parseTomlTableHeader(lines[i]) === null) i++;\n continue;\n }\n out.push(lines[i]);\n i++;\n }\n\n const next = out\n .join(\"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .replace(/\\n*$/, \"\\n\");\n writeFileAtomic(file, next);\n return [...removeSet];\n}\n\n/**\n * Unified helper: after writing the canonical `serverName` entry for the\n * given `client`, remove same-URL duplicates from its config file.\n * Returns the list of removed names (empty if nothing was cleaned up).\n */\nexport function removeSameUrlDuplicatesForClient(\n client: ClientId,\n serverName: string,\n mcpUrl: string,\n baseDir: string,\n scope: string | undefined,\n): string[] {\n const file = configPathFor(client, baseDir, scope);\n if (client === \"codex\") {\n return removeCodexSameUrlDuplicates(file, mcpUrl, serverName);\n }\n return removeJsonSameUrlDuplicatesAtKey(\n file,\n jsonMcpConfigKeyForClient(client),\n mcpUrl,\n serverName,\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentJobsTab.d.ts","sourceRoot":"","sources":["../../../src/client/agent-page/AgentJobsTab.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AgentJobsTab.d.ts","sourceRoot":"","sources":["../../../src/client/agent-page/AgentJobsTab.tsx"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAqIpD,wBAAgB,qCAAqC,IAAI,MAAM,CAE9D;AAED,wBAAgB,YAAY,CAAC,EAAE,YAAoB,EAAE,EAAE,iBAAiB,+BAugBvE"}
|