@openhands/agent-canvas 1.7.1 → 1.8.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/README.md +1 -1
- package/README.windows.md +2 -2
- package/build/assets/{Trans-DP5rcauH.js → Trans-B7lYw4uD.js} +1 -1
- package/build/assets/{acp-providers-BHKZvEm5.js → acp-providers-WUD4tfSq.js} +1 -1
- package/build/assets/active-backend-context-mY7Gff5c.js +2 -0
- package/build/assets/{agent-context-settings-BwAakl29.js → agent-context-settings-BTUmWEzL.js} +1 -1
- package/build/assets/{agent-profiles-settings-BYU6aWus.js → agent-profiles-settings-Ilqid_R5.js} +1 -1
- package/build/assets/agent-server-conversation-service.api-C_7YnjzP.js +41 -0
- package/build/assets/{agent-settings-DEPFl5hR.js → agent-settings-BGTyoT6X.js} +2 -2
- package/build/assets/agent-settings-CxfT4ksO.js +1 -0
- package/build/assets/{alert-banner-C1nzoXBC.js → alert-banner-eRyIwDyU.js} +1 -1
- package/build/assets/api-key-entry-screen-JOx3SH1-.js +1 -0
- package/build/assets/app-settings-D53QZy5p.js +1 -0
- package/build/assets/automation-detail-nEflClmc.js +2 -0
- package/build/assets/{automation-export-Ca2ehC-k.js → automation-export-BO_kfqC8.js} +1 -1
- package/build/assets/{automations-list-ZHQSW8qD.js → automations-list-BYncC7gv.js} +1 -1
- package/build/assets/{back-nav-button-Be_L157B.js → back-nav-button-C02hGa8t.js} +1 -1
- package/build/assets/backend-form-modal-CKrBF80P.js +1 -0
- package/build/assets/{backend-synced-settings-badge-DdUfuSN8.js → backend-synced-settings-badge-CQ9xtNWm.js} +1 -1
- package/build/assets/{badge-B6q3sVom.js → badge-CzXbf7tR.js} +1 -1
- package/build/assets/{base-modal-CSHhJTSr.js → base-modal-DkVyzFMt.js} +1 -1
- package/build/assets/{brand-button-CQO8oqVo.js → brand-button-BUlDL-mz.js} +1 -1
- package/build/assets/{browser-BUDJnBg4.js → browser-3QjrEr1D.js} +1 -1
- package/build/assets/{browser-tab-Cir7KbAL.js → browser-tab-BijpUbdt.js} +1 -1
- package/build/assets/{chat-send-button-D4614wUz.js → chat-send-button-BKsVjhtA.js} +1 -1
- package/build/assets/check-CrxQfJZ2.js +1 -0
- package/build/assets/chevron-down-D_LsyTA7.js +1 -0
- package/build/assets/circle-check-DZn9HkLE.js +1 -0
- package/build/assets/{circle-plus-check-toggle-E3Ecb_gg.js → circle-plus-check-toggle-DdjUiOo1.js} +1 -1
- package/build/assets/cloud-funnel-analytics-NlmDoeo2.js +1 -0
- package/build/assets/{combobox-caret-C8_eGdp2.js → combobox-caret-Dl9UtvD6.js} +1 -1
- package/build/assets/{command-menu-N_BriUy8.js → command-menu-CvLPs7dg.js} +1 -1
- package/build/assets/{condenser-settings-jNGOKFGz.js → condenser-settings-C4Y9CzQV.js} +1 -1
- package/build/assets/{confirmation-modal-gZtbojCm.js → confirmation-modal-CRBJSllP.js} +1 -1
- package/build/assets/{context-menu-list-item-BTHGFhIx.js → context-menu-list-item-FGaafXGh.js} +1 -1
- package/build/assets/conversation-D_ORtpKC.js +1 -0
- package/build/assets/conversation-Dpc5nmGi.js +90 -0
- package/build/assets/conversation-panel-D_ORtpKC.js +1 -0
- package/build/assets/conversation-state-store-CGRQemtx.js +1 -0
- package/build/assets/{conversation-tab-empty-state-BCMHkGQk.js → conversation-tab-empty-state-CDjvNgpG.js} +1 -1
- package/build/assets/{copy-B8Y5ufoR.js → copy-Drwu97Gx.js} +1 -1
- package/build/assets/{copy-to-clipboard-button-C4l3CMSd.js → copy-to-clipboard-button-NbN1clVr.js} +1 -1
- package/build/assets/{device-verify-C_M7Z8xs.js → device-verify-CDm_WrVu.js} +1 -1
- package/build/assets/{dropdown-classes-DQlj-MpS.js → dropdown-classes-CqA2BTCL.js} +1 -1
- package/build/assets/{entry.client-CCrlta8r.js → entry.client-BO2KQj0y.js} +2 -2
- package/build/assets/{enum-filter-dropdown-paB-lFSP.js → enum-filter-dropdown-DSqPZnsD.js} +1 -1
- package/build/assets/{environment-switch-overlay-D0FgCMqs.js → environment-switch-overlay-mGl2pqqx.js} +1 -1
- package/build/assets/extensions-hub-Br3Lgynp.js +1 -0
- package/build/assets/extensions-navigation-BQmstKDZ.js +1 -0
- package/build/assets/{external-link-Cnnd6ikC.js → external-link-D9B2QMPf.js} +1 -1
- package/build/assets/files-tab-4c9HFSLo.js +1 -0
- package/build/assets/{form-control-classes-CSPevi7c.js → form-control-classes-CtVAktAy.js} +1 -1
- package/build/assets/{format-time-delta-DuhE50B-.js → format-time-delta-DICE64sz.js} +1 -1
- package/build/assets/git-provider-icon-0PqmIS_S.js +1 -0
- package/build/assets/{highlighted-source-view-suUKd5if.js → highlighted-source-view-KMsA9c4a.js} +1 -1
- package/build/assets/home-D9JsyEmE.js +1 -0
- package/build/assets/{home-BZclW6kd.js → home-TFhnmZLx.js} +1 -1
- package/build/assets/index-home-D9JsyEmE.js +1 -0
- package/build/assets/install-server-modal-BgGRnqA0.js +1 -0
- package/build/assets/{launch-Bik37u9Y.js → launch-DjkKw55l.js} +1 -1
- package/build/assets/{list-todo-_BXQzOiB.js → list-todo-BpAf7aOT.js} +1 -1
- package/build/assets/{llm-not-configured-banner-znJFsW_O.js → llm-not-configured-banner-Y4W9-sar.js} +4 -4
- package/build/assets/llm-settings-D8zNkIlP.js +1 -0
- package/build/assets/llm-settings-nPwv7hKu.js +1 -0
- package/build/assets/{llm-subscription-service-_QUsVybQ.js → llm-subscription-service-COTgZc1C.js} +1 -1
- package/build/assets/loader-circle-CGD6-Vak.js +1 -0
- package/build/assets/{loading-spinner-CcpnCr_d.js → loading-spinner-DRFyh6Iy.js} +1 -1
- package/build/assets/manage-backends-modal-DiRWE3tJ.js +1 -0
- package/build/assets/manifest-1cf33a7b.js +1 -0
- package/build/assets/markdown-renderer-U40HF0Ak.js +8 -0
- package/build/assets/mcp-xDMaHzOw.js +9 -0
- package/build/assets/{messages-CYztjKLQ.js → messages-CdNfZPgd.js} +2 -2
- package/build/assets/{modal-body-DQhiw-AR.js → modal-body-C3bGicn4.js} +1 -1
- package/build/assets/{modal-classes-YaEEa5eZ.js → modal-classes-DFFO6BMU.js} +1 -1
- package/build/assets/{modal-close-button-turIYn0t.js → modal-close-button-vxkAIRyZ.js} +1 -1
- package/build/assets/{onboarding-9pEMFGtN.js → onboarding-DWuFieEA.js} +1 -1
- package/build/assets/onboarding-modal-C8m72Dpb.js +1 -0
- package/build/assets/organization-service.api-CQ73CB-S.js +1 -0
- package/build/assets/{pencil-8_lvWDoZ.js → pencil-DzW2GB2M.js} +1 -1
- package/build/assets/{planner-tab-Dr8B-ZBI.js → planner-tab-YG0bGxDY.js} +1 -1
- package/build/assets/plugins-management-service-ijhH8OSh.js +1 -0
- package/build/assets/plus-CTGLo3aa.js +1 -0
- package/build/assets/profiles-service.api-C32pPm70.js +1 -0
- package/build/assets/providers-DuSn9s2i.js +1 -0
- package/build/assets/proxy-BiyDhMBd.js +1 -0
- package/build/assets/{puzzle-DXWdfaa7.js → puzzle-DlqT0yvr.js} +1 -1
- package/build/assets/{recommended-automations-launcher-Dye8Li08.js → recommended-automations-launcher-Dru1yN46.js} +2 -2
- package/build/assets/{refresh-cw-D7CYLy-d.js → refresh-cw-Br5254f4.js} +1 -1
- package/build/assets/root-DOLLQteU.js +2 -0
- package/build/assets/root-layout-xmylWoew.js +3 -0
- package/build/assets/schema-field-htfNouTG.js +1 -0
- package/build/assets/{sdk-section-page-Di5mT86Y.js → sdk-section-page-D0K1dBQY.js} +1 -1
- package/build/assets/search-BrpWXWUi.js +1 -0
- package/build/assets/secrets-service-Dbv5Zb8G.js +1 -0
- package/build/assets/{secrets-settings-DPlA3moO.js → secrets-settings-Da4SSaX9.js} +1 -1
- package/build/assets/{segmented-toggle-DbbD3Tve.js → segmented-toggle-CZKOdIly.js} +1 -1
- package/build/assets/settings-F4a09IxY.js +1 -0
- package/build/assets/{settings-dropdown-input-Dx6vlkgf.js → settings-dropdown-input-jOiv5Yrk.js} +1 -1
- package/build/assets/{settings-index-D5dDKrDt.js → settings-index-CyJBf5NA.js} +1 -1
- package/build/assets/{settings-input-BjW_zyTN.js → settings-input-BEaTCem1.js} +1 -1
- package/build/assets/{settings-list-classes-gQdBahdt.js → settings-list-classes-VqMzkYYt.js} +1 -1
- package/build/assets/{settings-modal-DsJk2THd.js → settings-modal-C-S1NpbC.js} +1 -1
- package/build/assets/settings-service.api-CTJRrvMu.js +1 -0
- package/build/assets/{settings-switch-UNSf8K8I.js → settings-switch-B405oU_v.js} +1 -1
- package/build/assets/{shared-conversation-DU1kwDTF.js → shared-conversation-BvWtTwES.js} +1 -1
- package/build/assets/{sidebar-layout-DXHtbEj1.js → sidebar-layout-BGMuyC86.js} +1 -1
- package/build/assets/{sidebar-mobile-menu-toggle-BlmI8OrA.js → sidebar-mobile-menu-toggle-xiKoUfGa.js} +1 -1
- package/build/assets/{sidebar-nav-link-pvUivfK2.js → sidebar-nav-link-DA4_ct9G.js} +1 -1
- package/build/assets/{sidebar-store-DwrYKwYr.js → sidebar-store-FRJ3rADB.js} +1 -1
- package/build/assets/{skill-card-pill-row-D7XCz5uk.js → skill-card-pill-row-BMdhr_sd.js} +1 -1
- package/build/assets/{skill-icon-badge-HqBWZ2Eq.js → skill-icon-badge-CGUkgcVH.js} +1 -1
- package/build/assets/{skills-plugins-YJSV6A0M.js → skills-plugins-C5eJnyft.js} +1 -1
- package/build/assets/{skills-settings-BbREHv_-.js → skills-settings-pUxMr6WZ.js} +1 -1
- package/build/assets/{styled-tooltip-DsjDnR_W.js → styled-tooltip-B3kIdVyH.js} +1 -1
- package/build/assets/{task-list-tab-Dzim5ftn.js → task-list-tab-B3k4W1cK.js} +1 -1
- package/build/assets/{terminal-CYFAMiXx.js → terminal-CBI_41Zc.js} +1 -1
- package/build/assets/{toggle-switch-BptY3XRG.js → toggle-switch-DYRr9CAR.js} +1 -1
- package/build/assets/{trash-2-Bq4lHbTB.js → trash-2-gZPlx23R.js} +1 -1
- package/build/assets/{typography-C6fuRTTT.js → typography-B1UxuuEC.js} +1 -1
- package/build/assets/{use-acp-credential-form-CuBXKNvP.js → use-acp-credential-form-CjSvKWFH.js} +1 -1
- package/build/assets/use-activate-agent-profile-DCRf47e-.js +1 -0
- package/build/assets/use-agent-profiles-DmT9zxAN.js +1 -0
- package/build/assets/{use-can-manage-org-profiles-Uai-HHx2.js → use-can-manage-org-profiles-vBiP7rHF.js} +1 -1
- package/build/assets/use-cloud-current-user-id-BMq9gw93.js +1 -0
- package/build/assets/use-config-C959QcRC.js +1 -0
- package/build/assets/{use-create-conversation-DzcM79TE.js → use-create-conversation-CakhLF0X.js} +1 -1
- package/build/assets/{use-create-secret-2YLjoQw-.js → use-create-secret-RT4QtSS9.js} +1 -1
- package/build/assets/use-llm-profiles-CdaxVpyY.js +1 -0
- package/build/assets/use-onboarding-completion-CJU4MNAY.js +1 -0
- package/build/assets/use-plugins-marketplace-D-93nqtJ.js +1 -0
- package/build/assets/{use-save-agent-profile-Q2M72WgR.js → use-save-agent-profile-DGJ3-u0M.js} +1 -1
- package/build/assets/{use-save-settings-BZK7zVsK.js → use-save-settings--C6LZXfI.js} +1 -1
- package/build/assets/use-settings-DIAo5KFk.js +1 -0
- package/build/assets/use-settings-nav-items-DPK5sxvR.js +16 -0
- package/build/assets/use-skills-D_mLhYNa.js +1 -0
- package/build/assets/use-tracking-COqZLobY.js +1 -0
- package/build/assets/{use-user-conversation-43duhf7D.js → use-user-conversation-DhcAEyJX.js} +1 -1
- package/build/assets/{useMutation-DyQXZFEF.js → useMutation-DHLpZ6J0.js} +1 -1
- package/build/assets/utils-DsWhWn2F.js +1 -0
- package/build/assets/{vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~g4xrpilz-CJ7amdtQ.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~g4xrpilz-CYPMCkX1.js} +1 -1
- package/build/assets/{vendor~files-tab-vm3f67Pz.js → vendor~files-tab-atebg0iG.js} +1 -1
- package/build/assets/{vendor~index-home~home~conversation-panel~conversation-kX4LrGQC.js → vendor~index-home~home~conversation-panel~conversation-G9DMrR7m.js} +1 -1
- package/build/assets/{vendor~root-layout~conversation-panel~conversation-DpA6fir3.js → vendor~root-layout~conversation-panel~conversation-DEhW1h3I.js} +1 -1
- package/build/assets/{vendor~root-layout~index-home~home~conversation-panel~conversation-EShpjxey.js → vendor~root-layout~index-home~home~conversation-panel~conversation-Acmf1sKj.js} +1 -1
- package/build/assets/{vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation-DD_UNO02.js → vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation-CmzCY1BT.js} +1 -1
- package/build/assets/{vendor~root-layout~index-home~home~mcp~automations-list~onboarding-modal-Be63Q2Ln.js → vendor~root-layout~index-home~home~mcp~automations-list~onboarding-modal-C7Yh77RT.js} +1 -1
- package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~bi2r7bko-Bw4AuHN1.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~bi2r7bko-VFnwct3q.js} +1 -1
- package/build/assets/{verification-settings-B4DL3Tez.js → verification-settings-Vr5cN4md.js} +1 -1
- package/build/assets/x-Dx_JbpHA.js +1 -0
- package/build/favicon-16x16.png +0 -0
- package/build/favicon-32x32.png +0 -0
- package/build/favicon.ico +0 -0
- package/build/index.html +4 -4
- package/build/locales/ar/openhands.json +2 -0
- package/build/locales/ca/openhands.json +2 -0
- package/build/locales/de/openhands.json +2 -0
- package/build/locales/en/openhands.json +2 -0
- package/build/locales/es/openhands.json +2 -0
- package/build/locales/fr/openhands.json +2 -0
- package/build/locales/it/openhands.json +2 -0
- package/build/locales/ja/openhands.json +2 -0
- package/build/locales/ko-KR/openhands.json +2 -0
- package/build/locales/no/openhands.json +2 -0
- package/build/locales/pt/openhands.json +2 -0
- package/build/locales/tr/openhands.json +2 -0
- package/build/locales/uk/openhands.json +2 -0
- package/build/locales/zh-CN/openhands.json +2 -0
- package/build/locales/zh-TW/openhands.json +2 -0
- package/config/defaults.json +4 -4
- package/dist/api/agent-server-adapter.cjs +1 -1
- package/dist/api/agent-server-adapter.cjs.map +1 -1
- package/dist/api/agent-server-adapter.js +7 -7
- package/dist/api/agent-server-adapter.js.map +1 -1
- package/dist/api/automation-service/automation-service.api.cjs +1 -1
- package/dist/api/automation-service/automation-service.api.cjs.map +1 -1
- package/dist/api/automation-service/automation-service.api.js +95 -95
- package/dist/api/automation-service/automation-service.api.js.map +1 -1
- package/dist/api/backend-registry/storage.cjs +1 -1
- package/dist/api/backend-registry/storage.cjs.map +1 -1
- package/dist/api/backend-registry/storage.js +1 -1
- package/dist/api/backend-registry/storage.js.map +1 -1
- package/dist/api/backend-registry/types.d.ts +2 -0
- package/dist/api/cloud/conversation-service.api.cjs +1 -1
- package/dist/api/cloud/conversation-service.api.js +22 -22
- package/dist/api/mcp-service/mcp-service.api.cjs +1 -1
- package/dist/api/mcp-service/mcp-service.api.cjs.map +1 -1
- package/dist/api/mcp-service/mcp-service.api.js +19 -19
- package/dist/api/mcp-service/mcp-service.api.js.map +1 -1
- package/dist/api/settings-service/settings-service.api.cjs +1 -1
- package/dist/api/settings-service/settings-service.api.cjs.map +1 -1
- package/dist/api/settings-service/settings-service.api.js +26 -12
- package/dist/api/settings-service/settings-service.api.js.map +1 -1
- package/dist/components/features/mcp-page/custom-server-editor.cjs +1 -1
- package/dist/components/features/mcp-page/custom-server-editor.js +16 -16
- package/dist/components/features/mcp-page/installed-server-card.cjs +1 -1
- package/dist/components/features/mcp-page/installed-server-card.cjs.map +1 -1
- package/dist/components/features/mcp-page/installed-server-card.d.ts +2 -2
- package/dist/components/features/mcp-page/installed-server-card.js +6 -7
- package/dist/components/features/mcp-page/installed-server-card.js.map +1 -1
- package/dist/components/features/mcp-page/installed-servers-section.cjs +1 -1
- package/dist/components/features/mcp-page/installed-servers-section.cjs.map +1 -1
- package/dist/components/features/mcp-page/installed-servers-section.d.ts +2 -2
- package/dist/components/features/mcp-page/installed-servers-section.js +2 -2
- package/dist/components/features/mcp-page/installed-servers-section.js.map +1 -1
- package/dist/components/features/mcp-page/mcp-server-health.cjs +1 -1
- package/dist/components/features/mcp-page/mcp-server-health.js +4 -4
- package/dist/components/features/settings/mcp-settings/mcp-server-form.cjs +1 -1
- package/dist/components/features/settings/mcp-settings/mcp-server-form.cjs.map +1 -1
- package/dist/components/features/settings/mcp-settings/mcp-server-form.js +2 -1
- package/dist/components/features/settings/mcp-settings/mcp-server-form.js.map +1 -1
- package/dist/config/defaults.cjs +1 -1
- package/dist/config/defaults.cjs.map +1 -1
- package/dist/config/defaults.js +3 -3
- package/dist/config/defaults.js.map +1 -1
- package/dist/contexts/active-backend-context.cjs +1 -1
- package/dist/contexts/active-backend-context.cjs.map +1 -1
- package/dist/contexts/active-backend-context.d.ts +3 -2
- package/dist/contexts/active-backend-context.js +55 -42
- package/dist/contexts/active-backend-context.js.map +1 -1
- package/dist/favicon-16x16.png +0 -0
- package/dist/favicon-32x32.png +0 -0
- package/dist/favicon.ico +0 -0
- package/dist/hooks/mutation/use-update-mcp-server.cjs +1 -1
- package/dist/hooks/mutation/use-update-mcp-server.js +5 -5
- package/dist/hooks/query/use-cloud-current-user-id.cjs +1 -1
- package/dist/hooks/query/use-cloud-current-user-id.cjs.map +1 -1
- package/dist/hooks/query/use-cloud-current-user-id.js +7 -5
- package/dist/hooks/query/use-cloud-current-user-id.js.map +1 -1
- package/dist/hooks/query/use-cloud-organizations.cjs +1 -1
- package/dist/hooks/query/use-cloud-organizations.cjs.map +1 -1
- package/dist/hooks/query/use-cloud-organizations.js +5 -1
- package/dist/hooks/query/use-cloud-organizations.js.map +1 -1
- package/dist/hooks/use-can-manage-org-profiles.cjs +1 -1
- package/dist/hooks/use-can-manage-org-profiles.cjs.map +1 -1
- package/dist/hooks/use-can-manage-org-profiles.js +2 -1
- package/dist/hooks/use-can-manage-org-profiles.js.map +1 -1
- package/dist/hooks/use-tracking.cjs +1 -1
- package/dist/hooks/use-tracking.js +9 -9
- package/dist/i18n/declaration.cjs +1 -1
- package/dist/i18n/declaration.cjs.map +1 -1
- package/dist/i18n/declaration.d.ts +2 -0
- package/dist/i18n/declaration.js +1 -1
- package/dist/i18n/declaration.js.map +1 -1
- package/dist/i18n/translation.cjs +1 -1
- package/dist/i18n/translation.cjs.map +1 -1
- package/dist/i18n/translation.js +34 -0
- package/dist/i18n/translation.js.map +1 -1
- package/dist/locales/ar/openhands.json +2 -0
- package/dist/locales/ca/openhands.json +2 -0
- package/dist/locales/de/openhands.json +2 -0
- package/dist/locales/en/openhands.json +2 -0
- package/dist/locales/es/openhands.json +2 -0
- package/dist/locales/fr/openhands.json +2 -0
- package/dist/locales/it/openhands.json +2 -0
- package/dist/locales/ja/openhands.json +2 -0
- package/dist/locales/ko-KR/openhands.json +2 -0
- package/dist/locales/no/openhands.json +2 -0
- package/dist/locales/pt/openhands.json +2 -0
- package/dist/locales/tr/openhands.json +2 -0
- package/dist/locales/uk/openhands.json +2 -0
- package/dist/locales/zh-CN/openhands.json +2 -0
- package/dist/locales/zh-TW/openhands.json +2 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/settings-client.cjs +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/settings-client.cjs.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/settings-client.js +9 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/settings-client.js.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.cjs.map +1 -1
- package/dist/package.js +7 -2
- package/dist/package.js.map +1 -1
- package/dist/routes/app-settings.cjs +1 -1
- package/dist/routes/app-settings.js +5 -5
- package/dist/routes/mcp.cjs +1 -1
- package/dist/routes/mcp.cjs.map +1 -1
- package/dist/routes/mcp.js +73 -82
- package/dist/routes/mcp.js.map +1 -1
- package/dist/services/telemetry.cjs +1 -1
- package/dist/services/telemetry.cjs.map +1 -1
- package/dist/services/telemetry.d.ts +8 -0
- package/dist/services/telemetry.js +163 -116
- package/dist/services/telemetry.js.map +1 -1
- package/dist/types/mcp-server.d.ts +5 -0
- package/dist/types/settings.d.ts +3 -0
- package/dist/utils/mcp-config.cjs +1 -1
- package/dist/utils/mcp-config.cjs.map +1 -1
- package/dist/utils/mcp-config.d.ts +8 -0
- package/dist/utils/mcp-config.js +25 -20
- package/dist/utils/mcp-config.js.map +1 -1
- package/dist/utils/mcp-installed-servers.cjs +1 -1
- package/dist/utils/mcp-installed-servers.cjs.map +1 -1
- package/dist/utils/mcp-installed-servers.js +6 -3
- package/dist/utils/mcp-installed-servers.js.map +1 -1
- package/package.json +7 -2
- package/scripts/check-sdk-version-sync.mjs +6 -6
- package/scripts/dev-safe.mjs +2 -2
- package/scripts/stryker-diff.mjs +137 -0
- package/build/assets/active-backend-context-B9942JGX.js +0 -1
- package/build/assets/agent-server-conversation-service.api-D7qh9amG.js +0 -41
- package/build/assets/agent-settings-BbNLRtoh.js +0 -1
- package/build/assets/api-key-entry-screen-B2kVLRDQ.js +0 -1
- package/build/assets/app-settings-B92bjTei.js +0 -1
- package/build/assets/automation-detail-DoVSHQLs.js +0 -2
- package/build/assets/backend-form-modal-C0CIsQvd.js +0 -1
- package/build/assets/check-BMOG005H.js +0 -1
- package/build/assets/chevron-down-CV1zZP_K.js +0 -1
- package/build/assets/circle-check-lvN_jFN5.js +0 -1
- package/build/assets/client-source-D8jWKBfE.js +0 -1
- package/build/assets/cloud-funnel-analytics-CnCkPgQa.js +0 -1
- package/build/assets/conversation-DceG4LFS.js +0 -90
- package/build/assets/conversation-Do2Vg7uo.js +0 -1
- package/build/assets/conversation-panel-Do2Vg7uo.js +0 -1
- package/build/assets/conversation-state-store-BORusMiV.js +0 -1
- package/build/assets/extensions-hub-B2WudOET.js +0 -1
- package/build/assets/extensions-navigation-CYjIM65d.js +0 -1
- package/build/assets/files-tab-LSBijbEi.js +0 -1
- package/build/assets/git-provider-icon-DeQUgZVE.js +0 -1
- package/build/assets/home-C_R5pEbs.js +0 -1
- package/build/assets/index-home-C_R5pEbs.js +0 -1
- package/build/assets/install-server-modal-xCf76eim.js +0 -1
- package/build/assets/llm-settings-BYo9SN0I.js +0 -1
- package/build/assets/llm-settings-BaM0zJg5.js +0 -1
- package/build/assets/loader-circle-6zlEYCJw.js +0 -1
- package/build/assets/manage-backends-modal-n6PtHOER.js +0 -1
- package/build/assets/manifest-e9bbad7b.js +0 -1
- package/build/assets/markdown-renderer-Dkmjmx_d.js +0 -8
- package/build/assets/mcp-BJUOnO6v.js +0 -9
- package/build/assets/onboarding-modal-dYsjXJwx.js +0 -1
- package/build/assets/organization-service.api-HsxJhNCf.js +0 -1
- package/build/assets/plugins-management-service-DEjBqDoT.js +0 -1
- package/build/assets/plus-vIbGD459.js +0 -1
- package/build/assets/profiles-service.api-BddMsEhq.js +0 -1
- package/build/assets/providers-BxJi3BMO.js +0 -1
- package/build/assets/proxy-CN3HaaOW.js +0 -1
- package/build/assets/root-D4hpCAq9.js +0 -2
- package/build/assets/root-layout-a4-4sfbh.js +0 -3
- package/build/assets/schema-field-CZSs0hQP.js +0 -1
- package/build/assets/search-sKuYKllf.js +0 -1
- package/build/assets/secrets-service-i4CCd-UN.js +0 -1
- package/build/assets/settings-SHSt9Rq2.js +0 -1
- package/build/assets/settings-service.api-i_HHIqJP.js +0 -1
- package/build/assets/telemetry-B-2fXtqV.js +0 -2
- package/build/assets/use-activate-agent-profile-CXDcjVt8.js +0 -1
- package/build/assets/use-agent-profiles-CliaHofi.js +0 -1
- package/build/assets/use-cloud-current-user-id-BzamKpu-.js +0 -1
- package/build/assets/use-config-DPEYpfIj.js +0 -1
- package/build/assets/use-llm-profiles-Ci3zAVzV.js +0 -1
- package/build/assets/use-onboarding-completion-STApsofr.js +0 -1
- package/build/assets/use-plugins-marketplace-CzzdrUSK.js +0 -1
- package/build/assets/use-settings-BKpkUS4y.js +0 -1
- package/build/assets/use-settings-nav-items-BlXge_bf.js +0 -16
- package/build/assets/use-skills-BltA9XrV.js +0 -1
- package/build/assets/use-tracking-De7qByD4.js +0 -1
- package/build/assets/utils-qjs_KuS4.js +0 -1
- package/build/assets/x-EjvKGawc.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-config.cjs","names":[],"sources":["../../src/utils/mcp-config.ts"],"sourcesContent":["import {\n MCPConfig,\n MCPSSEServer,\n MCPSHTTPServer,\n MCPStdioServer,\n SettingsValue,\n} from \"#/types/settings\";\nimport type {\n MCPAuthCredential,\n MCPAuthenticationConfig,\n MCPJsonValue,\n MCPOAuthState,\n} from \"#/types/mcp-auth\";\nimport type { MCPServerConfig } from \"#/types/mcp-server\";\nimport { toMcpServerName } from \"#/utils/mcp-server-name\";\n\nconst EMPTY_MCP_CONFIG: MCPConfig = {\n sse_servers: [],\n stdio_servers: [],\n shttp_servers: [],\n};\n\nexport const REDACTED_MCP_SECRET_VALUE = \"**********\";\n\ntype SdkMcpServerConfig = Record<string, SettingsValue | MCPAuthCredential>;\ntype SdkMcpConfig = Record<string, SdkMcpServerConfig>;\n\n/**\n * The dict key for an SSE/SHTTP server doubles as its display name once a\n * user provides one. Keys that match the auto-generated fallback pattern\n * (``sse``, ``shttp``, ``shttp_1``, …) emitted by {@link toSdkMcpConfig}\n * carry no user intent, so we surface them as \"no name\" — re-serializing\n * regenerates the identical fallback key and existing configs are left\n * untouched.\n */\nfunction userGivenServerName(\n serverName: string,\n base: \"sse\" | \"shttp\",\n): string | undefined {\n const autoGenerated = new RegExp(`^${base}(_\\\\d+)?$`);\n return autoGenerated.test(serverName) ? undefined : serverName;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function getSdkMcpServerMap(\n value: unknown,\n): Record<string, unknown> | null {\n if (!isRecord(value)) return null;\n\n const mcpServers = value.mcpServers;\n if (\n isRecord(mcpServers) &&\n !(\"url\" in mcpServers) &&\n !(\"command\" in mcpServers)\n ) {\n return mcpServers;\n }\n\n return value;\n}\n\nexport function stringRecord(\n value: unknown,\n): Record<string, string> | undefined {\n if (!isRecord(value)) return undefined;\n const entries = Object.entries(value).filter(\n (entry): entry is [string, string] => typeof entry[1] === \"string\",\n );\n return entries.length > 0 ? Object.fromEntries(entries) : undefined;\n}\n\nexport function hasRedactedMcpSecretLeaf(value: unknown): boolean {\n if (value === REDACTED_MCP_SECRET_VALUE) return true;\n if (Array.isArray(value)) return value.some(hasRedactedMcpSecretLeaf);\n if (isRecord(value))\n return Object.values(value).some(hasRedactedMcpSecretLeaf);\n return false;\n}\n\nfunction getOAuthState(value: unknown): MCPOAuthState | undefined {\n if (!isRecord(value)) return undefined;\n const state: MCPOAuthState = {};\n if (isRecord(value.tokens)) {\n state.tokens = value.tokens as NonNullable<MCPOAuthState[\"tokens\"]>;\n }\n if (isRecord(value.client_info)) {\n state.client_info = value.client_info as NonNullable<\n MCPOAuthState[\"client_info\"]\n >;\n }\n if (\n typeof value.token_expires_at === \"number\" ||\n value.token_expires_at === null\n ) {\n state.token_expires_at = value.token_expires_at;\n }\n return Object.keys(state).length > 0 ? state : undefined;\n}\n\nfunction normalizeTaggedAuthCredential(\n value: unknown,\n): MCPAuthCredential | undefined {\n if (!isRecord(value)) return undefined;\n switch (value.strategy) {\n case \"none\":\n return { strategy: \"none\" };\n case \"api_key\":\n if (typeof value.value !== \"string\") return undefined;\n return {\n strategy: \"api_key\",\n value: value.value,\n ...(typeof value.header_name === \"string\" && {\n header_name: value.header_name,\n }),\n };\n case \"bearer\":\n if (typeof value.value !== \"string\") return undefined;\n return { strategy: \"bearer\", value: value.value };\n case \"basic\":\n if (\n typeof value.username !== \"string\" ||\n typeof value.password !== \"string\"\n ) {\n return undefined;\n }\n return {\n strategy: \"basic\",\n username: value.username,\n password: value.password,\n };\n case \"header\": {\n const headers = stringRecord(value.headers);\n return headers ? { strategy: \"header\", headers } : undefined;\n }\n case \"oauth2\": {\n const authentication = getAuthenticationConfig(value.authentication);\n const state = getOAuthState(value.state);\n return {\n strategy: \"oauth2\",\n ...(authentication && { authentication }),\n ...(state && { state }),\n };\n }\n default:\n return undefined;\n }\n}\n\nfunction authCredentialFromServerConfig(\n serverConfig: Record<string, unknown>,\n): MCPAuthCredential | undefined {\n return normalizeTaggedAuthCredential(serverConfig.auth);\n}\n\nfunction getRemoteSecretFields(entry: {\n auth?: MCPAuthCredential;\n headers?: Record<string, string>;\n}): Partial<SdkMcpServerConfig> {\n const fields: Partial<SdkMcpServerConfig> = {};\n if (entry.auth && !hasRedactedMcpSecretLeaf(entry.auth)) {\n fields.auth = entry.auth;\n }\n if (entry.headers && Object.keys(entry.headers).length > 0) {\n fields.headers = entry.headers;\n }\n return fields;\n}\n\nfunction getRemoteServerFields(server: MCPServerConfig) {\n return {\n ...(server.name && { name: server.name }),\n url: server.url!,\n ...(server.headers && { headers: server.headers }),\n ...(server.auth && { auth: server.auth }),\n };\n}\n\nexport function toMcpSseServer(server: MCPServerConfig): MCPSSEServer {\n return getRemoteServerFields(server);\n}\n\nexport function toMcpShttpServer(server: MCPServerConfig): MCPSHTTPServer {\n return {\n ...getRemoteServerFields(server),\n ...(server.timeout !== undefined && { timeout: server.timeout }),\n };\n}\n\nexport function toMcpStdioServer(server: MCPServerConfig): MCPStdioServer {\n return {\n name: server.name!,\n command: server.command!,\n ...(server.args && { args: server.args }),\n ...(server.env && { env: server.env }),\n };\n}\n\nfunction getAuthenticationConfig(\n value: unknown,\n): MCPAuthenticationConfig | undefined {\n if (!value || typeof value !== \"object\") return undefined;\n const record = value as Record<string, unknown>;\n if (record.type !== \"oauth\") return undefined;\n const authentication: MCPAuthenticationConfig = { type: \"oauth\" };\n if (\n record.client_auth_method === \"none\" ||\n record.client_auth_method === \"client_secret_post\" ||\n record.client_auth_method === \"client_secret_basic\" ||\n record.client_auth_method === \"private_key_jwt\"\n ) {\n authentication.client_auth_method = record.client_auth_method;\n }\n if (typeof record.scopes === \"string\") {\n authentication.scopes = record.scopes;\n } else if (\n Array.isArray(record.scopes) &&\n record.scopes.every((scope) => typeof scope === \"string\")\n ) {\n authentication.scopes = record.scopes;\n }\n if (typeof record.client_name === \"string\") {\n authentication.client_name = record.client_name;\n }\n if (typeof record.client_metadata_url === \"string\") {\n authentication.client_metadata_url = record.client_metadata_url;\n }\n if (typeof record.client_id === \"string\") {\n authentication.client_id = record.client_id;\n }\n if (typeof record.client_secret === \"string\") {\n authentication.client_secret = record.client_secret;\n }\n if (\n record.additional_client_metadata &&\n typeof record.additional_client_metadata === \"object\" &&\n !Array.isArray(record.additional_client_metadata)\n ) {\n authentication.additional_client_metadata =\n record.additional_client_metadata as Record<string, MCPJsonValue>;\n }\n return authentication;\n}\n\n/**\n * Parse the SDK-native ``agent_settings.mcp_config`` value and convert it\n * to the frontend MCPConfig format used by UI components.\n */\nexport function parseMcpConfig(value: unknown): MCPConfig {\n const mcpConfig = getSdkMcpServerMap(value);\n if (!mcpConfig) {\n return { ...EMPTY_MCP_CONFIG };\n }\n\n const sseServers: (string | MCPSSEServer)[] = [];\n const stdioServers: MCPStdioServer[] = [];\n const shttpServers: (string | MCPSHTTPServer)[] = [];\n\n for (const [serverName, serverConfig] of Object.entries(mcpConfig)) {\n if (!isRecord(serverConfig)) continue;\n\n const url = serverConfig.url as string | undefined;\n\n if (url) {\n const transport = serverConfig.transport as string | undefined;\n const auth = authCredentialFromServerConfig(serverConfig);\n const headers = stringRecord(serverConfig.headers);\n\n if (transport === \"sse\") {\n const name = userGivenServerName(serverName, \"sse\");\n const server: MCPSSEServer = { url };\n if (name) server.name = name;\n if (auth) server.auth = auth;\n if (headers) server.headers = headers;\n sseServers.push(server);\n } else {\n const name = userGivenServerName(serverName, \"shttp\");\n const server: MCPSHTTPServer = { url };\n if (name) server.name = name;\n if (serverConfig.timeout != null) {\n server.timeout = serverConfig.timeout as number;\n }\n if (auth) server.auth = auth;\n if (headers) server.headers = headers;\n shttpServers.push(server);\n }\n } else {\n if (typeof serverConfig.command !== \"string\") continue;\n const stdioServer: MCPStdioServer = {\n name: serverName,\n command: serverConfig.command,\n };\n if (serverConfig.args) {\n stdioServer.args = serverConfig.args as string[];\n }\n if (serverConfig.env) {\n stdioServer.env = serverConfig.env as Record<string, string>;\n }\n stdioServers.push(stdioServer);\n }\n }\n\n return {\n sse_servers: sseServers,\n stdio_servers: stdioServers,\n shttp_servers: shttpServers,\n };\n}\n\n/**\n * Convert the frontend MCPConfig format back to the SDK-native server map\n * expected by agent_settings.mcp_config on the backend.\n *\n * Names are only suffixed (``_1``, ``_2``, …) when an earlier entry has\n * already claimed the bare base name. We intentionally do NOT use a single\n * monotonic counter across server types: that would, for example, rename a\n * stdio server \"myname\" to \"myname_1\" the moment any sse/shttp entry is\n * persisted ahead of it, and shift the suffix on every save as the count\n * of other server types changes. With per-base collision suffixing,\n * unrelated entries keep their human-meaningful names stable across edits.\n */\nexport function toSdkMcpConfig(config: MCPConfig): SdkMcpConfig | null {\n const mcpConfig: SdkMcpConfig = {};\n\n const reserve = (base: string): string => {\n const safeBase = toMcpServerName(base);\n if (!(safeBase in mcpConfig)) return safeBase;\n let i = 1;\n while (`${safeBase}_${i}` in mcpConfig) i += 1;\n return `${safeBase}_${i}`;\n };\n\n for (const entry of config.sse_servers) {\n const server: SdkMcpServerConfig = {};\n let name: string | undefined;\n if (typeof entry === \"string\") {\n server.url = entry;\n } else {\n name = entry.name;\n server.url = entry.url;\n Object.assign(server, getRemoteSecretFields(entry));\n }\n server.transport = \"sse\";\n mcpConfig[reserve(name || \"sse\")] = server;\n }\n\n for (const entry of config.shttp_servers) {\n const server: SdkMcpServerConfig = { transport: \"http\" };\n let name: string | undefined;\n if (typeof entry === \"string\") {\n server.url = entry;\n } else {\n name = entry.name;\n server.url = entry.url;\n Object.assign(server, getRemoteSecretFields(entry));\n if (entry.timeout != null) server.timeout = entry.timeout;\n }\n mcpConfig[reserve(name || \"shttp\")] = server;\n }\n\n for (const entry of config.stdio_servers) {\n const server: SdkMcpServerConfig = {\n command: entry.command,\n };\n if (entry.args) server.args = entry.args;\n if (entry.env) server.env = entry.env;\n mcpConfig[reserve(entry.name || \"stdio\")] = server;\n }\n\n return Object.keys(mcpConfig).length > 0 ? mcpConfig : null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mcp-config.cjs","names":[],"sources":["../../src/utils/mcp-config.ts"],"sourcesContent":["import {\n MCPConfig,\n MCPSSEServer,\n MCPSHTTPServer,\n MCPStdioServer,\n SettingsValue,\n} from \"#/types/settings\";\nimport type {\n MCPAuthCredential,\n MCPAuthenticationConfig,\n MCPJsonValue,\n MCPOAuthState,\n} from \"#/types/mcp-auth\";\nimport type { MCPServerConfig } from \"#/types/mcp-server\";\nimport { toMcpServerName } from \"#/utils/mcp-server-name\";\n\nconst EMPTY_MCP_CONFIG: MCPConfig = {\n sse_servers: [],\n stdio_servers: [],\n shttp_servers: [],\n};\n\nexport const REDACTED_MCP_SECRET_VALUE = \"**********\";\n\ntype SdkMcpServerConfig = Record<string, SettingsValue | MCPAuthCredential>;\ntype SdkMcpConfig = Record<string, SdkMcpServerConfig>;\n\n/**\n * The dict key for an SSE/SHTTP server doubles as its display name once a\n * user provides one. Keys that match the auto-generated fallback pattern\n * (``sse``, ``shttp``, ``shttp_1``, …) emitted by {@link toSdkMcpConfig}\n * carry no user intent, so we surface them as \"no name\" — re-serializing\n * regenerates the identical fallback key and existing configs are left\n * untouched.\n */\nfunction userGivenServerName(\n serverName: string,\n base: \"sse\" | \"shttp\",\n): string | undefined {\n const autoGenerated = new RegExp(`^${base}(_\\\\d+)?$`);\n return autoGenerated.test(serverName) ? undefined : serverName;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function getSdkMcpServerMap(\n value: unknown,\n): Record<string, unknown> | null {\n if (!isRecord(value)) return null;\n\n const mcpServers = value.mcpServers;\n if (\n isRecord(mcpServers) &&\n !(\"url\" in mcpServers) &&\n !(\"command\" in mcpServers)\n ) {\n return mcpServers;\n }\n\n return value;\n}\n\nexport function stringRecord(\n value: unknown,\n): Record<string, string> | undefined {\n if (!isRecord(value)) return undefined;\n const entries = Object.entries(value).filter(\n (entry): entry is [string, string] => typeof entry[1] === \"string\",\n );\n return entries.length > 0 ? Object.fromEntries(entries) : undefined;\n}\n\nexport function hasRedactedMcpSecretLeaf(value: unknown): boolean {\n if (value === REDACTED_MCP_SECRET_VALUE) return true;\n if (Array.isArray(value)) return value.some(hasRedactedMcpSecretLeaf);\n if (isRecord(value))\n return Object.values(value).some(hasRedactedMcpSecretLeaf);\n return false;\n}\n\nfunction getOAuthState(value: unknown): MCPOAuthState | undefined {\n if (!isRecord(value)) return undefined;\n const state: MCPOAuthState = {};\n if (isRecord(value.tokens)) {\n state.tokens = value.tokens as NonNullable<MCPOAuthState[\"tokens\"]>;\n }\n if (isRecord(value.client_info)) {\n state.client_info = value.client_info as NonNullable<\n MCPOAuthState[\"client_info\"]\n >;\n }\n if (\n typeof value.token_expires_at === \"number\" ||\n value.token_expires_at === null\n ) {\n state.token_expires_at = value.token_expires_at;\n }\n return Object.keys(state).length > 0 ? state : undefined;\n}\n\nfunction normalizeTaggedAuthCredential(\n value: unknown,\n): MCPAuthCredential | undefined {\n if (!isRecord(value)) return undefined;\n switch (value.strategy) {\n case \"none\":\n return { strategy: \"none\" };\n case \"api_key\":\n if (typeof value.value !== \"string\") return undefined;\n return {\n strategy: \"api_key\",\n value: value.value,\n ...(typeof value.header_name === \"string\" && {\n header_name: value.header_name,\n }),\n };\n case \"bearer\":\n if (typeof value.value !== \"string\") return undefined;\n return { strategy: \"bearer\", value: value.value };\n case \"basic\":\n if (\n typeof value.username !== \"string\" ||\n typeof value.password !== \"string\"\n ) {\n return undefined;\n }\n return {\n strategy: \"basic\",\n username: value.username,\n password: value.password,\n };\n case \"header\": {\n const headers = stringRecord(value.headers);\n return headers ? { strategy: \"header\", headers } : undefined;\n }\n case \"oauth2\": {\n const authentication = getAuthenticationConfig(value.authentication);\n const state = getOAuthState(value.state);\n return {\n strategy: \"oauth2\",\n ...(authentication && { authentication }),\n ...(state && { state }),\n };\n }\n default:\n return undefined;\n }\n}\n\nfunction authCredentialFromServerConfig(\n serverConfig: Record<string, unknown>,\n): MCPAuthCredential | undefined {\n return normalizeTaggedAuthCredential(serverConfig.auth);\n}\n\nfunction getRemoteSecretFields(entry: {\n auth?: MCPAuthCredential;\n headers?: Record<string, string>;\n}): Partial<SdkMcpServerConfig> {\n const fields: Partial<SdkMcpServerConfig> = {};\n if (entry.auth && !hasRedactedMcpSecretLeaf(entry.auth)) {\n fields.auth = entry.auth;\n }\n if (entry.headers && Object.keys(entry.headers).length > 0) {\n fields.headers = entry.headers;\n }\n return fields;\n}\n\n/**\n * Only an explicit ``false`` is carried. Every mutation round-trips the whole\n * server map through these converters, so preserving the flag here is what\n * stops adding or deleting one server from silently re-enabling another.\n */\nfunction disabledField(server: { enabled?: boolean }) {\n return server.enabled === false ? { enabled: false as const } : {};\n}\n\nfunction getRemoteServerFields(server: MCPServerConfig) {\n return {\n ...(server.name && { name: server.name }),\n url: server.url!,\n ...(server.headers && { headers: server.headers }),\n ...(server.auth && { auth: server.auth }),\n ...disabledField(server),\n };\n}\n\nexport function toMcpSseServer(server: MCPServerConfig): MCPSSEServer {\n return getRemoteServerFields(server);\n}\n\nexport function toMcpShttpServer(server: MCPServerConfig): MCPSHTTPServer {\n return {\n ...getRemoteServerFields(server),\n ...(server.timeout !== undefined && { timeout: server.timeout }),\n };\n}\n\nexport function toMcpStdioServer(server: MCPServerConfig): MCPStdioServer {\n return {\n name: server.name!,\n command: server.command!,\n ...(server.args && { args: server.args }),\n ...(server.env && { env: server.env }),\n ...disabledField(server),\n };\n}\n\nfunction getAuthenticationConfig(\n value: unknown,\n): MCPAuthenticationConfig | undefined {\n if (!value || typeof value !== \"object\") return undefined;\n const record = value as Record<string, unknown>;\n if (record.type !== \"oauth\") return undefined;\n const authentication: MCPAuthenticationConfig = { type: \"oauth\" };\n if (\n record.client_auth_method === \"none\" ||\n record.client_auth_method === \"client_secret_post\" ||\n record.client_auth_method === \"client_secret_basic\" ||\n record.client_auth_method === \"private_key_jwt\"\n ) {\n authentication.client_auth_method = record.client_auth_method;\n }\n if (typeof record.scopes === \"string\") {\n authentication.scopes = record.scopes;\n } else if (\n Array.isArray(record.scopes) &&\n record.scopes.every((scope) => typeof scope === \"string\")\n ) {\n authentication.scopes = record.scopes;\n }\n if (typeof record.client_name === \"string\") {\n authentication.client_name = record.client_name;\n }\n if (typeof record.client_metadata_url === \"string\") {\n authentication.client_metadata_url = record.client_metadata_url;\n }\n if (typeof record.client_id === \"string\") {\n authentication.client_id = record.client_id;\n }\n if (typeof record.client_secret === \"string\") {\n authentication.client_secret = record.client_secret;\n }\n if (\n record.additional_client_metadata &&\n typeof record.additional_client_metadata === \"object\" &&\n !Array.isArray(record.additional_client_metadata)\n ) {\n authentication.additional_client_metadata =\n record.additional_client_metadata as Record<string, MCPJsonValue>;\n }\n return authentication;\n}\n\n/**\n * Parse the SDK-native ``agent_settings.mcp_config`` value and convert it\n * to the frontend MCPConfig format used by UI components.\n */\nexport function parseMcpConfig(value: unknown): MCPConfig {\n const mcpConfig = getSdkMcpServerMap(value);\n if (!mcpConfig) {\n return { ...EMPTY_MCP_CONFIG };\n }\n\n const sseServers: (string | MCPSSEServer)[] = [];\n const stdioServers: MCPStdioServer[] = [];\n const shttpServers: (string | MCPSHTTPServer)[] = [];\n\n for (const [serverName, serverConfig] of Object.entries(mcpConfig)) {\n if (!isRecord(serverConfig)) continue;\n\n const url = serverConfig.url as string | undefined;\n\n // The SDK omits ``enabled`` while it holds its default (true), so only an\n // explicit ``false`` marks a server as switched off.\n const disabled = serverConfig.enabled === false;\n\n if (url) {\n const transport = serverConfig.transport as string | undefined;\n const auth = authCredentialFromServerConfig(serverConfig);\n const headers = stringRecord(serverConfig.headers);\n\n if (transport === \"sse\") {\n const name = userGivenServerName(serverName, \"sse\");\n const server: MCPSSEServer = { url };\n if (name) server.name = name;\n if (auth) server.auth = auth;\n if (headers) server.headers = headers;\n if (disabled) server.enabled = false;\n sseServers.push(server);\n } else {\n const name = userGivenServerName(serverName, \"shttp\");\n const server: MCPSHTTPServer = { url };\n if (name) server.name = name;\n if (serverConfig.timeout != null) {\n server.timeout = serverConfig.timeout as number;\n }\n if (auth) server.auth = auth;\n if (headers) server.headers = headers;\n if (disabled) server.enabled = false;\n shttpServers.push(server);\n }\n } else {\n if (typeof serverConfig.command !== \"string\") continue;\n const stdioServer: MCPStdioServer = {\n name: serverName,\n command: serverConfig.command,\n };\n if (serverConfig.args) {\n stdioServer.args = serverConfig.args as string[];\n }\n if (serverConfig.env) {\n stdioServer.env = serverConfig.env as Record<string, string>;\n }\n if (disabled) stdioServer.enabled = false;\n stdioServers.push(stdioServer);\n }\n }\n\n return {\n sse_servers: sseServers,\n stdio_servers: stdioServers,\n shttp_servers: shttpServers,\n };\n}\n\n/**\n * Convert the frontend MCPConfig format back to the SDK-native server map\n * expected by agent_settings.mcp_config on the backend.\n *\n * Names are only suffixed (``_1``, ``_2``, …) when an earlier entry has\n * already claimed the bare base name. We intentionally do NOT use a single\n * monotonic counter across server types: that would, for example, rename a\n * stdio server \"myname\" to \"myname_1\" the moment any sse/shttp entry is\n * persisted ahead of it, and shift the suffix on every save as the count\n * of other server types changes. With per-base collision suffixing,\n * unrelated entries keep their human-meaningful names stable across edits.\n *\n * ``enabled`` is only emitted when a server is switched off — the SDK defaults\n * it to true. Omitting it is what *clears* a previously persisted\n * ``enabled: false``, and that only works because ``saveSettings`` pre-clears\n * ``mcp_config`` to null before every write (see\n * ``settings-service.api.ts``), turning the backend's RFC 7386 merge into a\n * full replace. If that pre-clear is ever removed, re-enabling a server\n * becomes a silent no-op.\n */\nexport function toSdkMcpConfig(config: MCPConfig): SdkMcpConfig | null {\n const mcpConfig: SdkMcpConfig = {};\n\n const reserve = (base: string): string => {\n const safeBase = toMcpServerName(base);\n if (!(safeBase in mcpConfig)) return safeBase;\n let i = 1;\n while (`${safeBase}_${i}` in mcpConfig) i += 1;\n return `${safeBase}_${i}`;\n };\n\n for (const entry of config.sse_servers) {\n const server: SdkMcpServerConfig = {};\n let name: string | undefined;\n if (typeof entry === \"string\") {\n server.url = entry;\n } else {\n name = entry.name;\n server.url = entry.url;\n Object.assign(server, getRemoteSecretFields(entry), disabledField(entry));\n }\n server.transport = \"sse\";\n mcpConfig[reserve(name || \"sse\")] = server;\n }\n\n for (const entry of config.shttp_servers) {\n const server: SdkMcpServerConfig = { transport: \"http\" };\n let name: string | undefined;\n if (typeof entry === \"string\") {\n server.url = entry;\n } else {\n name = entry.name;\n server.url = entry.url;\n Object.assign(server, getRemoteSecretFields(entry), disabledField(entry));\n if (entry.timeout != null) server.timeout = entry.timeout;\n }\n mcpConfig[reserve(name || \"shttp\")] = server;\n }\n\n for (const entry of config.stdio_servers) {\n const server: SdkMcpServerConfig = {\n command: entry.command,\n };\n if (entry.args) server.args = entry.args;\n if (entry.env) server.env = entry.env;\n Object.assign(server, disabledField(entry));\n mcpConfig[reserve(entry.name || \"stdio\")] = server;\n }\n\n return Object.keys(mcpConfig).length > 0 ? mcpConfig : null;\n}\n"],"mappings":"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"}
|
|
@@ -26,6 +26,14 @@ export declare function parseMcpConfig(value: unknown): MCPConfig;
|
|
|
26
26
|
* persisted ahead of it, and shift the suffix on every save as the count
|
|
27
27
|
* of other server types changes. With per-base collision suffixing,
|
|
28
28
|
* unrelated entries keep their human-meaningful names stable across edits.
|
|
29
|
+
*
|
|
30
|
+
* ``enabled`` is only emitted when a server is switched off — the SDK defaults
|
|
31
|
+
* it to true. Omitting it is what *clears* a previously persisted
|
|
32
|
+
* ``enabled: false``, and that only works because ``saveSettings`` pre-clears
|
|
33
|
+
* ``mcp_config`` to null before every write (see
|
|
34
|
+
* ``settings-service.api.ts``), turning the backend's RFC 7386 merge into a
|
|
35
|
+
* full replace. If that pre-clear is ever removed, re-enabling a server
|
|
36
|
+
* becomes a silent no-op.
|
|
29
37
|
*/
|
|
30
38
|
export declare function toSdkMcpConfig(config: MCPConfig): SdkMcpConfig | null;
|
|
31
39
|
export {};
|
package/dist/utils/mcp-config.js
CHANGED
|
@@ -54,7 +54,7 @@ function l(e) {
|
|
|
54
54
|
} : void 0;
|
|
55
55
|
}
|
|
56
56
|
case "oauth2": {
|
|
57
|
-
let t =
|
|
57
|
+
let t = _(e.authentication), n = c(e.state);
|
|
58
58
|
return {
|
|
59
59
|
strategy: "oauth2",
|
|
60
60
|
...t && { authentication: t },
|
|
@@ -72,52 +72,57 @@ function d(e) {
|
|
|
72
72
|
return e.auth && !s(e.auth) && (t.auth = e.auth), e.headers && Object.keys(e.headers).length > 0 && (t.headers = e.headers), t;
|
|
73
73
|
}
|
|
74
74
|
function f(e) {
|
|
75
|
+
return e.enabled === !1 ? { enabled: !1 } : {};
|
|
76
|
+
}
|
|
77
|
+
function p(e) {
|
|
75
78
|
return {
|
|
76
79
|
...e.name && { name: e.name },
|
|
77
80
|
url: e.url,
|
|
78
81
|
...e.headers && { headers: e.headers },
|
|
79
|
-
...e.auth && { auth: e.auth }
|
|
82
|
+
...e.auth && { auth: e.auth },
|
|
83
|
+
...f(e)
|
|
80
84
|
};
|
|
81
85
|
}
|
|
82
|
-
function p(e) {
|
|
83
|
-
return f(e);
|
|
84
|
-
}
|
|
85
86
|
function m(e) {
|
|
87
|
+
return p(e);
|
|
88
|
+
}
|
|
89
|
+
function h(e) {
|
|
86
90
|
return {
|
|
87
|
-
...
|
|
91
|
+
...p(e),
|
|
88
92
|
...e.timeout !== void 0 && { timeout: e.timeout }
|
|
89
93
|
};
|
|
90
94
|
}
|
|
91
|
-
function
|
|
95
|
+
function g(e) {
|
|
92
96
|
return {
|
|
93
97
|
name: e.name,
|
|
94
98
|
command: e.command,
|
|
95
99
|
...e.args && { args: e.args },
|
|
96
|
-
...e.env && { env: e.env }
|
|
100
|
+
...e.env && { env: e.env },
|
|
101
|
+
...f(e)
|
|
97
102
|
};
|
|
98
103
|
}
|
|
99
|
-
function
|
|
104
|
+
function _(e) {
|
|
100
105
|
if (!e || typeof e != "object") return;
|
|
101
106
|
let t = e;
|
|
102
107
|
if (t.type !== "oauth") return;
|
|
103
108
|
let n = { type: "oauth" };
|
|
104
109
|
return (t.client_auth_method === "none" || t.client_auth_method === "client_secret_post" || t.client_auth_method === "client_secret_basic" || t.client_auth_method === "private_key_jwt") && (n.client_auth_method = t.client_auth_method), (typeof t.scopes == "string" || Array.isArray(t.scopes) && t.scopes.every((e) => typeof e == "string")) && (n.scopes = t.scopes), typeof t.client_name == "string" && (n.client_name = t.client_name), typeof t.client_metadata_url == "string" && (n.client_metadata_url = t.client_metadata_url), typeof t.client_id == "string" && (n.client_id = t.client_id), typeof t.client_secret == "string" && (n.client_secret = t.client_secret), t.additional_client_metadata && typeof t.additional_client_metadata == "object" && !Array.isArray(t.additional_client_metadata) && (n.additional_client_metadata = t.additional_client_metadata), n;
|
|
105
110
|
}
|
|
106
|
-
function
|
|
111
|
+
function v(e) {
|
|
107
112
|
let n = a(e);
|
|
108
113
|
if (!n) return { ...t };
|
|
109
114
|
let s = [], c = [], l = [];
|
|
110
115
|
for (let [e, t] of Object.entries(n)) {
|
|
111
116
|
if (!i(t)) continue;
|
|
112
|
-
let n = t.url;
|
|
117
|
+
let n = t.url, a = t.enabled === !1;
|
|
113
118
|
if (n) {
|
|
114
|
-
let i = t.transport,
|
|
119
|
+
let i = t.transport, c = u(t), d = o(t.headers);
|
|
115
120
|
if (i === "sse") {
|
|
116
121
|
let t = r(e, "sse"), i = { url: n };
|
|
117
|
-
t && (i.name = t),
|
|
122
|
+
t && (i.name = t), c && (i.auth = c), d && (i.headers = d), a && (i.enabled = !1), s.push(i);
|
|
118
123
|
} else {
|
|
119
124
|
let i = r(e, "shttp"), o = { url: n };
|
|
120
|
-
i && (o.name = i), t.timeout != null && (o.timeout = t.timeout),
|
|
125
|
+
i && (o.name = i), t.timeout != null && (o.timeout = t.timeout), c && (o.auth = c), d && (o.headers = d), a && (o.enabled = !1), l.push(o);
|
|
121
126
|
}
|
|
122
127
|
} else {
|
|
123
128
|
if (typeof t.command != "string") continue;
|
|
@@ -125,7 +130,7 @@ function _(e) {
|
|
|
125
130
|
name: e,
|
|
126
131
|
command: t.command
|
|
127
132
|
};
|
|
128
|
-
t.args && (n.args = t.args), t.env && (n.env = t.env), c.push(n);
|
|
133
|
+
t.args && (n.args = t.args), t.env && (n.env = t.env), a && (n.enabled = !1), c.push(n);
|
|
129
134
|
}
|
|
130
135
|
}
|
|
131
136
|
return {
|
|
@@ -134,7 +139,7 @@ function _(e) {
|
|
|
134
139
|
shttp_servers: l
|
|
135
140
|
};
|
|
136
141
|
}
|
|
137
|
-
function
|
|
142
|
+
function y(t) {
|
|
138
143
|
let n = {}, r = (t) => {
|
|
139
144
|
let r = e(t);
|
|
140
145
|
if (!(r in n)) return r;
|
|
@@ -144,19 +149,19 @@ function v(t) {
|
|
|
144
149
|
};
|
|
145
150
|
for (let e of t.sse_servers) {
|
|
146
151
|
let t = {}, i;
|
|
147
|
-
typeof e == "string" ? t.url = e : (i = e.name, t.url = e.url, Object.assign(t, d(e))), t.transport = "sse", n[r(i || "sse")] = t;
|
|
152
|
+
typeof e == "string" ? t.url = e : (i = e.name, t.url = e.url, Object.assign(t, d(e), f(e))), t.transport = "sse", n[r(i || "sse")] = t;
|
|
148
153
|
}
|
|
149
154
|
for (let e of t.shttp_servers) {
|
|
150
155
|
let t = { transport: "http" }, i;
|
|
151
|
-
typeof e == "string" ? t.url = e : (i = e.name, t.url = e.url, Object.assign(t, d(e)), e.timeout != null && (t.timeout = e.timeout)), n[r(i || "shttp")] = t;
|
|
156
|
+
typeof e == "string" ? t.url = e : (i = e.name, t.url = e.url, Object.assign(t, d(e), f(e)), e.timeout != null && (t.timeout = e.timeout)), n[r(i || "shttp")] = t;
|
|
152
157
|
}
|
|
153
158
|
for (let e of t.stdio_servers) {
|
|
154
159
|
let t = { command: e.command };
|
|
155
|
-
e.args && (t.args = e.args), e.env && (t.env = e.env), n[r(e.name || "stdio")] = t;
|
|
160
|
+
e.args && (t.args = e.args), e.env && (t.env = e.env), Object.assign(t, f(e)), n[r(e.name || "stdio")] = t;
|
|
156
161
|
}
|
|
157
162
|
return Object.keys(n).length > 0 ? n : null;
|
|
158
163
|
}
|
|
159
164
|
//#endregion
|
|
160
|
-
export { n as REDACTED_MCP_SECRET_VALUE, a as getSdkMcpServerMap, s as hasRedactedMcpSecretLeaf,
|
|
165
|
+
export { n as REDACTED_MCP_SECRET_VALUE, a as getSdkMcpServerMap, s as hasRedactedMcpSecretLeaf, v as parseMcpConfig, o as stringRecord, h as toMcpShttpServer, m as toMcpSseServer, g as toMcpStdioServer, y as toSdkMcpConfig };
|
|
161
166
|
|
|
162
167
|
//# sourceMappingURL=mcp-config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-config.js","names":[],"sources":["../../src/utils/mcp-config.ts"],"sourcesContent":["import {\n MCPConfig,\n MCPSSEServer,\n MCPSHTTPServer,\n MCPStdioServer,\n SettingsValue,\n} from \"#/types/settings\";\nimport type {\n MCPAuthCredential,\n MCPAuthenticationConfig,\n MCPJsonValue,\n MCPOAuthState,\n} from \"#/types/mcp-auth\";\nimport type { MCPServerConfig } from \"#/types/mcp-server\";\nimport { toMcpServerName } from \"#/utils/mcp-server-name\";\n\nconst EMPTY_MCP_CONFIG: MCPConfig = {\n sse_servers: [],\n stdio_servers: [],\n shttp_servers: [],\n};\n\nexport const REDACTED_MCP_SECRET_VALUE = \"**********\";\n\ntype SdkMcpServerConfig = Record<string, SettingsValue | MCPAuthCredential>;\ntype SdkMcpConfig = Record<string, SdkMcpServerConfig>;\n\n/**\n * The dict key for an SSE/SHTTP server doubles as its display name once a\n * user provides one. Keys that match the auto-generated fallback pattern\n * (``sse``, ``shttp``, ``shttp_1``, …) emitted by {@link toSdkMcpConfig}\n * carry no user intent, so we surface them as \"no name\" — re-serializing\n * regenerates the identical fallback key and existing configs are left\n * untouched.\n */\nfunction userGivenServerName(\n serverName: string,\n base: \"sse\" | \"shttp\",\n): string | undefined {\n const autoGenerated = new RegExp(`^${base}(_\\\\d+)?$`);\n return autoGenerated.test(serverName) ? undefined : serverName;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function getSdkMcpServerMap(\n value: unknown,\n): Record<string, unknown> | null {\n if (!isRecord(value)) return null;\n\n const mcpServers = value.mcpServers;\n if (\n isRecord(mcpServers) &&\n !(\"url\" in mcpServers) &&\n !(\"command\" in mcpServers)\n ) {\n return mcpServers;\n }\n\n return value;\n}\n\nexport function stringRecord(\n value: unknown,\n): Record<string, string> | undefined {\n if (!isRecord(value)) return undefined;\n const entries = Object.entries(value).filter(\n (entry): entry is [string, string] => typeof entry[1] === \"string\",\n );\n return entries.length > 0 ? Object.fromEntries(entries) : undefined;\n}\n\nexport function hasRedactedMcpSecretLeaf(value: unknown): boolean {\n if (value === REDACTED_MCP_SECRET_VALUE) return true;\n if (Array.isArray(value)) return value.some(hasRedactedMcpSecretLeaf);\n if (isRecord(value))\n return Object.values(value).some(hasRedactedMcpSecretLeaf);\n return false;\n}\n\nfunction getOAuthState(value: unknown): MCPOAuthState | undefined {\n if (!isRecord(value)) return undefined;\n const state: MCPOAuthState = {};\n if (isRecord(value.tokens)) {\n state.tokens = value.tokens as NonNullable<MCPOAuthState[\"tokens\"]>;\n }\n if (isRecord(value.client_info)) {\n state.client_info = value.client_info as NonNullable<\n MCPOAuthState[\"client_info\"]\n >;\n }\n if (\n typeof value.token_expires_at === \"number\" ||\n value.token_expires_at === null\n ) {\n state.token_expires_at = value.token_expires_at;\n }\n return Object.keys(state).length > 0 ? state : undefined;\n}\n\nfunction normalizeTaggedAuthCredential(\n value: unknown,\n): MCPAuthCredential | undefined {\n if (!isRecord(value)) return undefined;\n switch (value.strategy) {\n case \"none\":\n return { strategy: \"none\" };\n case \"api_key\":\n if (typeof value.value !== \"string\") return undefined;\n return {\n strategy: \"api_key\",\n value: value.value,\n ...(typeof value.header_name === \"string\" && {\n header_name: value.header_name,\n }),\n };\n case \"bearer\":\n if (typeof value.value !== \"string\") return undefined;\n return { strategy: \"bearer\", value: value.value };\n case \"basic\":\n if (\n typeof value.username !== \"string\" ||\n typeof value.password !== \"string\"\n ) {\n return undefined;\n }\n return {\n strategy: \"basic\",\n username: value.username,\n password: value.password,\n };\n case \"header\": {\n const headers = stringRecord(value.headers);\n return headers ? { strategy: \"header\", headers } : undefined;\n }\n case \"oauth2\": {\n const authentication = getAuthenticationConfig(value.authentication);\n const state = getOAuthState(value.state);\n return {\n strategy: \"oauth2\",\n ...(authentication && { authentication }),\n ...(state && { state }),\n };\n }\n default:\n return undefined;\n }\n}\n\nfunction authCredentialFromServerConfig(\n serverConfig: Record<string, unknown>,\n): MCPAuthCredential | undefined {\n return normalizeTaggedAuthCredential(serverConfig.auth);\n}\n\nfunction getRemoteSecretFields(entry: {\n auth?: MCPAuthCredential;\n headers?: Record<string, string>;\n}): Partial<SdkMcpServerConfig> {\n const fields: Partial<SdkMcpServerConfig> = {};\n if (entry.auth && !hasRedactedMcpSecretLeaf(entry.auth)) {\n fields.auth = entry.auth;\n }\n if (entry.headers && Object.keys(entry.headers).length > 0) {\n fields.headers = entry.headers;\n }\n return fields;\n}\n\nfunction getRemoteServerFields(server: MCPServerConfig) {\n return {\n ...(server.name && { name: server.name }),\n url: server.url!,\n ...(server.headers && { headers: server.headers }),\n ...(server.auth && { auth: server.auth }),\n };\n}\n\nexport function toMcpSseServer(server: MCPServerConfig): MCPSSEServer {\n return getRemoteServerFields(server);\n}\n\nexport function toMcpShttpServer(server: MCPServerConfig): MCPSHTTPServer {\n return {\n ...getRemoteServerFields(server),\n ...(server.timeout !== undefined && { timeout: server.timeout }),\n };\n}\n\nexport function toMcpStdioServer(server: MCPServerConfig): MCPStdioServer {\n return {\n name: server.name!,\n command: server.command!,\n ...(server.args && { args: server.args }),\n ...(server.env && { env: server.env }),\n };\n}\n\nfunction getAuthenticationConfig(\n value: unknown,\n): MCPAuthenticationConfig | undefined {\n if (!value || typeof value !== \"object\") return undefined;\n const record = value as Record<string, unknown>;\n if (record.type !== \"oauth\") return undefined;\n const authentication: MCPAuthenticationConfig = { type: \"oauth\" };\n if (\n record.client_auth_method === \"none\" ||\n record.client_auth_method === \"client_secret_post\" ||\n record.client_auth_method === \"client_secret_basic\" ||\n record.client_auth_method === \"private_key_jwt\"\n ) {\n authentication.client_auth_method = record.client_auth_method;\n }\n if (typeof record.scopes === \"string\") {\n authentication.scopes = record.scopes;\n } else if (\n Array.isArray(record.scopes) &&\n record.scopes.every((scope) => typeof scope === \"string\")\n ) {\n authentication.scopes = record.scopes;\n }\n if (typeof record.client_name === \"string\") {\n authentication.client_name = record.client_name;\n }\n if (typeof record.client_metadata_url === \"string\") {\n authentication.client_metadata_url = record.client_metadata_url;\n }\n if (typeof record.client_id === \"string\") {\n authentication.client_id = record.client_id;\n }\n if (typeof record.client_secret === \"string\") {\n authentication.client_secret = record.client_secret;\n }\n if (\n record.additional_client_metadata &&\n typeof record.additional_client_metadata === \"object\" &&\n !Array.isArray(record.additional_client_metadata)\n ) {\n authentication.additional_client_metadata =\n record.additional_client_metadata as Record<string, MCPJsonValue>;\n }\n return authentication;\n}\n\n/**\n * Parse the SDK-native ``agent_settings.mcp_config`` value and convert it\n * to the frontend MCPConfig format used by UI components.\n */\nexport function parseMcpConfig(value: unknown): MCPConfig {\n const mcpConfig = getSdkMcpServerMap(value);\n if (!mcpConfig) {\n return { ...EMPTY_MCP_CONFIG };\n }\n\n const sseServers: (string | MCPSSEServer)[] = [];\n const stdioServers: MCPStdioServer[] = [];\n const shttpServers: (string | MCPSHTTPServer)[] = [];\n\n for (const [serverName, serverConfig] of Object.entries(mcpConfig)) {\n if (!isRecord(serverConfig)) continue;\n\n const url = serverConfig.url as string | undefined;\n\n if (url) {\n const transport = serverConfig.transport as string | undefined;\n const auth = authCredentialFromServerConfig(serverConfig);\n const headers = stringRecord(serverConfig.headers);\n\n if (transport === \"sse\") {\n const name = userGivenServerName(serverName, \"sse\");\n const server: MCPSSEServer = { url };\n if (name) server.name = name;\n if (auth) server.auth = auth;\n if (headers) server.headers = headers;\n sseServers.push(server);\n } else {\n const name = userGivenServerName(serverName, \"shttp\");\n const server: MCPSHTTPServer = { url };\n if (name) server.name = name;\n if (serverConfig.timeout != null) {\n server.timeout = serverConfig.timeout as number;\n }\n if (auth) server.auth = auth;\n if (headers) server.headers = headers;\n shttpServers.push(server);\n }\n } else {\n if (typeof serverConfig.command !== \"string\") continue;\n const stdioServer: MCPStdioServer = {\n name: serverName,\n command: serverConfig.command,\n };\n if (serverConfig.args) {\n stdioServer.args = serverConfig.args as string[];\n }\n if (serverConfig.env) {\n stdioServer.env = serverConfig.env as Record<string, string>;\n }\n stdioServers.push(stdioServer);\n }\n }\n\n return {\n sse_servers: sseServers,\n stdio_servers: stdioServers,\n shttp_servers: shttpServers,\n };\n}\n\n/**\n * Convert the frontend MCPConfig format back to the SDK-native server map\n * expected by agent_settings.mcp_config on the backend.\n *\n * Names are only suffixed (``_1``, ``_2``, …) when an earlier entry has\n * already claimed the bare base name. We intentionally do NOT use a single\n * monotonic counter across server types: that would, for example, rename a\n * stdio server \"myname\" to \"myname_1\" the moment any sse/shttp entry is\n * persisted ahead of it, and shift the suffix on every save as the count\n * of other server types changes. With per-base collision suffixing,\n * unrelated entries keep their human-meaningful names stable across edits.\n */\nexport function toSdkMcpConfig(config: MCPConfig): SdkMcpConfig | null {\n const mcpConfig: SdkMcpConfig = {};\n\n const reserve = (base: string): string => {\n const safeBase = toMcpServerName(base);\n if (!(safeBase in mcpConfig)) return safeBase;\n let i = 1;\n while (`${safeBase}_${i}` in mcpConfig) i += 1;\n return `${safeBase}_${i}`;\n };\n\n for (const entry of config.sse_servers) {\n const server: SdkMcpServerConfig = {};\n let name: string | undefined;\n if (typeof entry === \"string\") {\n server.url = entry;\n } else {\n name = entry.name;\n server.url = entry.url;\n Object.assign(server, getRemoteSecretFields(entry));\n }\n server.transport = \"sse\";\n mcpConfig[reserve(name || \"sse\")] = server;\n }\n\n for (const entry of config.shttp_servers) {\n const server: SdkMcpServerConfig = { transport: \"http\" };\n let name: string | undefined;\n if (typeof entry === \"string\") {\n server.url = entry;\n } else {\n name = entry.name;\n server.url = entry.url;\n Object.assign(server, getRemoteSecretFields(entry));\n if (entry.timeout != null) server.timeout = entry.timeout;\n }\n mcpConfig[reserve(name || \"shttp\")] = server;\n }\n\n for (const entry of config.stdio_servers) {\n const server: SdkMcpServerConfig = {\n command: entry.command,\n };\n if (entry.args) server.args = entry.args;\n if (entry.env) server.env = entry.env;\n mcpConfig[reserve(entry.name || \"stdio\")] = server;\n }\n\n return Object.keys(mcpConfig).length > 0 ? mcpConfig : null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mcp-config.js","names":[],"sources":["../../src/utils/mcp-config.ts"],"sourcesContent":["import {\n MCPConfig,\n MCPSSEServer,\n MCPSHTTPServer,\n MCPStdioServer,\n SettingsValue,\n} from \"#/types/settings\";\nimport type {\n MCPAuthCredential,\n MCPAuthenticationConfig,\n MCPJsonValue,\n MCPOAuthState,\n} from \"#/types/mcp-auth\";\nimport type { MCPServerConfig } from \"#/types/mcp-server\";\nimport { toMcpServerName } from \"#/utils/mcp-server-name\";\n\nconst EMPTY_MCP_CONFIG: MCPConfig = {\n sse_servers: [],\n stdio_servers: [],\n shttp_servers: [],\n};\n\nexport const REDACTED_MCP_SECRET_VALUE = \"**********\";\n\ntype SdkMcpServerConfig = Record<string, SettingsValue | MCPAuthCredential>;\ntype SdkMcpConfig = Record<string, SdkMcpServerConfig>;\n\n/**\n * The dict key for an SSE/SHTTP server doubles as its display name once a\n * user provides one. Keys that match the auto-generated fallback pattern\n * (``sse``, ``shttp``, ``shttp_1``, …) emitted by {@link toSdkMcpConfig}\n * carry no user intent, so we surface them as \"no name\" — re-serializing\n * regenerates the identical fallback key and existing configs are left\n * untouched.\n */\nfunction userGivenServerName(\n serverName: string,\n base: \"sse\" | \"shttp\",\n): string | undefined {\n const autoGenerated = new RegExp(`^${base}(_\\\\d+)?$`);\n return autoGenerated.test(serverName) ? undefined : serverName;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function getSdkMcpServerMap(\n value: unknown,\n): Record<string, unknown> | null {\n if (!isRecord(value)) return null;\n\n const mcpServers = value.mcpServers;\n if (\n isRecord(mcpServers) &&\n !(\"url\" in mcpServers) &&\n !(\"command\" in mcpServers)\n ) {\n return mcpServers;\n }\n\n return value;\n}\n\nexport function stringRecord(\n value: unknown,\n): Record<string, string> | undefined {\n if (!isRecord(value)) return undefined;\n const entries = Object.entries(value).filter(\n (entry): entry is [string, string] => typeof entry[1] === \"string\",\n );\n return entries.length > 0 ? Object.fromEntries(entries) : undefined;\n}\n\nexport function hasRedactedMcpSecretLeaf(value: unknown): boolean {\n if (value === REDACTED_MCP_SECRET_VALUE) return true;\n if (Array.isArray(value)) return value.some(hasRedactedMcpSecretLeaf);\n if (isRecord(value))\n return Object.values(value).some(hasRedactedMcpSecretLeaf);\n return false;\n}\n\nfunction getOAuthState(value: unknown): MCPOAuthState | undefined {\n if (!isRecord(value)) return undefined;\n const state: MCPOAuthState = {};\n if (isRecord(value.tokens)) {\n state.tokens = value.tokens as NonNullable<MCPOAuthState[\"tokens\"]>;\n }\n if (isRecord(value.client_info)) {\n state.client_info = value.client_info as NonNullable<\n MCPOAuthState[\"client_info\"]\n >;\n }\n if (\n typeof value.token_expires_at === \"number\" ||\n value.token_expires_at === null\n ) {\n state.token_expires_at = value.token_expires_at;\n }\n return Object.keys(state).length > 0 ? state : undefined;\n}\n\nfunction normalizeTaggedAuthCredential(\n value: unknown,\n): MCPAuthCredential | undefined {\n if (!isRecord(value)) return undefined;\n switch (value.strategy) {\n case \"none\":\n return { strategy: \"none\" };\n case \"api_key\":\n if (typeof value.value !== \"string\") return undefined;\n return {\n strategy: \"api_key\",\n value: value.value,\n ...(typeof value.header_name === \"string\" && {\n header_name: value.header_name,\n }),\n };\n case \"bearer\":\n if (typeof value.value !== \"string\") return undefined;\n return { strategy: \"bearer\", value: value.value };\n case \"basic\":\n if (\n typeof value.username !== \"string\" ||\n typeof value.password !== \"string\"\n ) {\n return undefined;\n }\n return {\n strategy: \"basic\",\n username: value.username,\n password: value.password,\n };\n case \"header\": {\n const headers = stringRecord(value.headers);\n return headers ? { strategy: \"header\", headers } : undefined;\n }\n case \"oauth2\": {\n const authentication = getAuthenticationConfig(value.authentication);\n const state = getOAuthState(value.state);\n return {\n strategy: \"oauth2\",\n ...(authentication && { authentication }),\n ...(state && { state }),\n };\n }\n default:\n return undefined;\n }\n}\n\nfunction authCredentialFromServerConfig(\n serverConfig: Record<string, unknown>,\n): MCPAuthCredential | undefined {\n return normalizeTaggedAuthCredential(serverConfig.auth);\n}\n\nfunction getRemoteSecretFields(entry: {\n auth?: MCPAuthCredential;\n headers?: Record<string, string>;\n}): Partial<SdkMcpServerConfig> {\n const fields: Partial<SdkMcpServerConfig> = {};\n if (entry.auth && !hasRedactedMcpSecretLeaf(entry.auth)) {\n fields.auth = entry.auth;\n }\n if (entry.headers && Object.keys(entry.headers).length > 0) {\n fields.headers = entry.headers;\n }\n return fields;\n}\n\n/**\n * Only an explicit ``false`` is carried. Every mutation round-trips the whole\n * server map through these converters, so preserving the flag here is what\n * stops adding or deleting one server from silently re-enabling another.\n */\nfunction disabledField(server: { enabled?: boolean }) {\n return server.enabled === false ? { enabled: false as const } : {};\n}\n\nfunction getRemoteServerFields(server: MCPServerConfig) {\n return {\n ...(server.name && { name: server.name }),\n url: server.url!,\n ...(server.headers && { headers: server.headers }),\n ...(server.auth && { auth: server.auth }),\n ...disabledField(server),\n };\n}\n\nexport function toMcpSseServer(server: MCPServerConfig): MCPSSEServer {\n return getRemoteServerFields(server);\n}\n\nexport function toMcpShttpServer(server: MCPServerConfig): MCPSHTTPServer {\n return {\n ...getRemoteServerFields(server),\n ...(server.timeout !== undefined && { timeout: server.timeout }),\n };\n}\n\nexport function toMcpStdioServer(server: MCPServerConfig): MCPStdioServer {\n return {\n name: server.name!,\n command: server.command!,\n ...(server.args && { args: server.args }),\n ...(server.env && { env: server.env }),\n ...disabledField(server),\n };\n}\n\nfunction getAuthenticationConfig(\n value: unknown,\n): MCPAuthenticationConfig | undefined {\n if (!value || typeof value !== \"object\") return undefined;\n const record = value as Record<string, unknown>;\n if (record.type !== \"oauth\") return undefined;\n const authentication: MCPAuthenticationConfig = { type: \"oauth\" };\n if (\n record.client_auth_method === \"none\" ||\n record.client_auth_method === \"client_secret_post\" ||\n record.client_auth_method === \"client_secret_basic\" ||\n record.client_auth_method === \"private_key_jwt\"\n ) {\n authentication.client_auth_method = record.client_auth_method;\n }\n if (typeof record.scopes === \"string\") {\n authentication.scopes = record.scopes;\n } else if (\n Array.isArray(record.scopes) &&\n record.scopes.every((scope) => typeof scope === \"string\")\n ) {\n authentication.scopes = record.scopes;\n }\n if (typeof record.client_name === \"string\") {\n authentication.client_name = record.client_name;\n }\n if (typeof record.client_metadata_url === \"string\") {\n authentication.client_metadata_url = record.client_metadata_url;\n }\n if (typeof record.client_id === \"string\") {\n authentication.client_id = record.client_id;\n }\n if (typeof record.client_secret === \"string\") {\n authentication.client_secret = record.client_secret;\n }\n if (\n record.additional_client_metadata &&\n typeof record.additional_client_metadata === \"object\" &&\n !Array.isArray(record.additional_client_metadata)\n ) {\n authentication.additional_client_metadata =\n record.additional_client_metadata as Record<string, MCPJsonValue>;\n }\n return authentication;\n}\n\n/**\n * Parse the SDK-native ``agent_settings.mcp_config`` value and convert it\n * to the frontend MCPConfig format used by UI components.\n */\nexport function parseMcpConfig(value: unknown): MCPConfig {\n const mcpConfig = getSdkMcpServerMap(value);\n if (!mcpConfig) {\n return { ...EMPTY_MCP_CONFIG };\n }\n\n const sseServers: (string | MCPSSEServer)[] = [];\n const stdioServers: MCPStdioServer[] = [];\n const shttpServers: (string | MCPSHTTPServer)[] = [];\n\n for (const [serverName, serverConfig] of Object.entries(mcpConfig)) {\n if (!isRecord(serverConfig)) continue;\n\n const url = serverConfig.url as string | undefined;\n\n // The SDK omits ``enabled`` while it holds its default (true), so only an\n // explicit ``false`` marks a server as switched off.\n const disabled = serverConfig.enabled === false;\n\n if (url) {\n const transport = serverConfig.transport as string | undefined;\n const auth = authCredentialFromServerConfig(serverConfig);\n const headers = stringRecord(serverConfig.headers);\n\n if (transport === \"sse\") {\n const name = userGivenServerName(serverName, \"sse\");\n const server: MCPSSEServer = { url };\n if (name) server.name = name;\n if (auth) server.auth = auth;\n if (headers) server.headers = headers;\n if (disabled) server.enabled = false;\n sseServers.push(server);\n } else {\n const name = userGivenServerName(serverName, \"shttp\");\n const server: MCPSHTTPServer = { url };\n if (name) server.name = name;\n if (serverConfig.timeout != null) {\n server.timeout = serverConfig.timeout as number;\n }\n if (auth) server.auth = auth;\n if (headers) server.headers = headers;\n if (disabled) server.enabled = false;\n shttpServers.push(server);\n }\n } else {\n if (typeof serverConfig.command !== \"string\") continue;\n const stdioServer: MCPStdioServer = {\n name: serverName,\n command: serverConfig.command,\n };\n if (serverConfig.args) {\n stdioServer.args = serverConfig.args as string[];\n }\n if (serverConfig.env) {\n stdioServer.env = serverConfig.env as Record<string, string>;\n }\n if (disabled) stdioServer.enabled = false;\n stdioServers.push(stdioServer);\n }\n }\n\n return {\n sse_servers: sseServers,\n stdio_servers: stdioServers,\n shttp_servers: shttpServers,\n };\n}\n\n/**\n * Convert the frontend MCPConfig format back to the SDK-native server map\n * expected by agent_settings.mcp_config on the backend.\n *\n * Names are only suffixed (``_1``, ``_2``, …) when an earlier entry has\n * already claimed the bare base name. We intentionally do NOT use a single\n * monotonic counter across server types: that would, for example, rename a\n * stdio server \"myname\" to \"myname_1\" the moment any sse/shttp entry is\n * persisted ahead of it, and shift the suffix on every save as the count\n * of other server types changes. With per-base collision suffixing,\n * unrelated entries keep their human-meaningful names stable across edits.\n *\n * ``enabled`` is only emitted when a server is switched off — the SDK defaults\n * it to true. Omitting it is what *clears* a previously persisted\n * ``enabled: false``, and that only works because ``saveSettings`` pre-clears\n * ``mcp_config`` to null before every write (see\n * ``settings-service.api.ts``), turning the backend's RFC 7386 merge into a\n * full replace. If that pre-clear is ever removed, re-enabling a server\n * becomes a silent no-op.\n */\nexport function toSdkMcpConfig(config: MCPConfig): SdkMcpConfig | null {\n const mcpConfig: SdkMcpConfig = {};\n\n const reserve = (base: string): string => {\n const safeBase = toMcpServerName(base);\n if (!(safeBase in mcpConfig)) return safeBase;\n let i = 1;\n while (`${safeBase}_${i}` in mcpConfig) i += 1;\n return `${safeBase}_${i}`;\n };\n\n for (const entry of config.sse_servers) {\n const server: SdkMcpServerConfig = {};\n let name: string | undefined;\n if (typeof entry === \"string\") {\n server.url = entry;\n } else {\n name = entry.name;\n server.url = entry.url;\n Object.assign(server, getRemoteSecretFields(entry), disabledField(entry));\n }\n server.transport = \"sse\";\n mcpConfig[reserve(name || \"sse\")] = server;\n }\n\n for (const entry of config.shttp_servers) {\n const server: SdkMcpServerConfig = { transport: \"http\" };\n let name: string | undefined;\n if (typeof entry === \"string\") {\n server.url = entry;\n } else {\n name = entry.name;\n server.url = entry.url;\n Object.assign(server, getRemoteSecretFields(entry), disabledField(entry));\n if (entry.timeout != null) server.timeout = entry.timeout;\n }\n mcpConfig[reserve(name || \"shttp\")] = server;\n }\n\n for (const entry of config.stdio_servers) {\n const server: SdkMcpServerConfig = {\n command: entry.command,\n };\n if (entry.args) server.args = entry.args;\n if (entry.env) server.env = entry.env;\n Object.assign(server, disabledField(entry));\n mcpConfig[reserve(entry.name || \"stdio\")] = server;\n }\n\n return Object.keys(mcpConfig).length > 0 ? mcpConfig : null;\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require("../_virtual/_rolldown/runtime.cjs");function e(e){return[...e.sse_servers.map((e,t)=>({id:`sse-${t}`,type:`sse`,name:typeof e==`object`?e.name:void 0,url:typeof e==`string`?e:e.url,headers:typeof e==`object`?e.headers:void 0,auth:typeof e==`object`?e.auth:void 0})),...e.stdio_servers.map((e,t)=>({id:`stdio-${t}`,type:`stdio`,name:e.name,command:e.command,args:e.args,env:e.env})),...e.shttp_servers.map((e,t)=>({id:`shttp-${t}`,type:`shttp`,name:typeof e==`object`?e.name:void 0,url:typeof e==`string`?e:e.url,headers:typeof e==`object`?e.headers:void 0,timeout:typeof e==`object`?e.timeout:void 0,auth:typeof e==`object`?e.auth:void 0}))]}exports.flattenMcpConfig=e;
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");function e(e){return[...e.sse_servers.map((e,t)=>({id:`sse-${t}`,type:`sse`,name:typeof e==`object`?e.name:void 0,url:typeof e==`string`?e:e.url,headers:typeof e==`object`?e.headers:void 0,auth:typeof e==`object`?e.auth:void 0,enabled:typeof e==`object`?e.enabled:void 0})),...e.stdio_servers.map((e,t)=>({id:`stdio-${t}`,type:`stdio`,name:e.name,command:e.command,args:e.args,env:e.env,enabled:e.enabled})),...e.shttp_servers.map((e,t)=>({id:`shttp-${t}`,type:`shttp`,name:typeof e==`object`?e.name:void 0,url:typeof e==`string`?e:e.url,headers:typeof e==`object`?e.headers:void 0,timeout:typeof e==`object`?e.timeout:void 0,auth:typeof e==`object`?e.auth:void 0,enabled:typeof e==`object`?e.enabled:void 0}))]}exports.flattenMcpConfig=e;
|
|
2
2
|
//# sourceMappingURL=mcp-installed-servers.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-installed-servers.cjs","names":[],"sources":["../../src/utils/mcp-installed-servers.ts"],"sourcesContent":["import { MCPServerConfig } from \"#/types/mcp-server\";\nimport { MCPConfig } from \"#/types/settings\";\n\nexport function flattenMcpConfig(config: MCPConfig): MCPServerConfig[] {\n return [\n ...config.sse_servers.map((server, index) => ({\n id: `sse-${index}`,\n type: \"sse\" as const,\n name: typeof server === \"object\" ? server.name : undefined,\n url: typeof server === \"string\" ? server : server.url,\n headers: typeof server === \"object\" ? server.headers : undefined,\n auth: typeof server === \"object\" ? server.auth : undefined,\n })),\n ...config.stdio_servers.map((server, index) => ({\n id: `stdio-${index}`,\n type: \"stdio\" as const,\n name: server.name,\n command: server.command,\n args: server.args,\n env: server.env,\n })),\n ...config.shttp_servers.map((server, index) => ({\n id: `shttp-${index}`,\n type: \"shttp\" as const,\n name: typeof server === \"object\" ? server.name : undefined,\n url: typeof server === \"string\" ? server : server.url,\n headers: typeof server === \"object\" ? server.headers : undefined,\n timeout: typeof server === \"object\" ? server.timeout : undefined,\n auth: typeof server === \"object\" ? server.auth : undefined,\n })),\n ];\n}\n"],"mappings":"6CAGA,SAAgB,EAAiB,EAAsC,CACrE,MAAO,CACL,GAAG,EAAO,YAAY,KAAK,EAAQ,KAAW,CAC5C,GAAI,OAAO,IACX,KAAM,MACN,KAAM,OAAO,GAAW,SAAW,EAAO,KAAO,IAAA,GACjD,IAAK,OAAO,GAAW,SAAW,EAAS,EAAO,IAClD,QAAS,OAAO,GAAW,SAAW,EAAO,QAAU,IAAA,GACvD,KAAM,OAAO,GAAW,SAAW,EAAO,KAAO,IAAA,
|
|
1
|
+
{"version":3,"file":"mcp-installed-servers.cjs","names":[],"sources":["../../src/utils/mcp-installed-servers.ts"],"sourcesContent":["import { MCPServerConfig } from \"#/types/mcp-server\";\nimport { MCPConfig } from \"#/types/settings\";\n\nexport function flattenMcpConfig(config: MCPConfig): MCPServerConfig[] {\n return [\n ...config.sse_servers.map((server, index) => ({\n id: `sse-${index}`,\n type: \"sse\" as const,\n name: typeof server === \"object\" ? server.name : undefined,\n url: typeof server === \"string\" ? server : server.url,\n headers: typeof server === \"object\" ? server.headers : undefined,\n auth: typeof server === \"object\" ? server.auth : undefined,\n enabled: typeof server === \"object\" ? server.enabled : undefined,\n })),\n ...config.stdio_servers.map((server, index) => ({\n id: `stdio-${index}`,\n type: \"stdio\" as const,\n name: server.name,\n command: server.command,\n args: server.args,\n env: server.env,\n enabled: server.enabled,\n })),\n ...config.shttp_servers.map((server, index) => ({\n id: `shttp-${index}`,\n type: \"shttp\" as const,\n name: typeof server === \"object\" ? server.name : undefined,\n url: typeof server === \"string\" ? server : server.url,\n headers: typeof server === \"object\" ? server.headers : undefined,\n timeout: typeof server === \"object\" ? server.timeout : undefined,\n auth: typeof server === \"object\" ? server.auth : undefined,\n enabled: typeof server === \"object\" ? server.enabled : undefined,\n })),\n ];\n}\n"],"mappings":"6CAGA,SAAgB,EAAiB,EAAsC,CACrE,MAAO,CACL,GAAG,EAAO,YAAY,KAAK,EAAQ,KAAW,CAC5C,GAAI,OAAO,IACX,KAAM,MACN,KAAM,OAAO,GAAW,SAAW,EAAO,KAAO,IAAA,GACjD,IAAK,OAAO,GAAW,SAAW,EAAS,EAAO,IAClD,QAAS,OAAO,GAAW,SAAW,EAAO,QAAU,IAAA,GACvD,KAAM,OAAO,GAAW,SAAW,EAAO,KAAO,IAAA,GACjD,QAAS,OAAO,GAAW,SAAW,EAAO,QAAU,IAAA,EACzD,EAAE,EACF,GAAG,EAAO,cAAc,KAAK,EAAQ,KAAW,CAC9C,GAAI,SAAS,IACb,KAAM,QACN,KAAM,EAAO,KACb,QAAS,EAAO,QAChB,KAAM,EAAO,KACb,IAAK,EAAO,IACZ,QAAS,EAAO,OAClB,EAAE,EACF,GAAG,EAAO,cAAc,KAAK,EAAQ,KAAW,CAC9C,GAAI,SAAS,IACb,KAAM,QACN,KAAM,OAAO,GAAW,SAAW,EAAO,KAAO,IAAA,GACjD,IAAK,OAAO,GAAW,SAAW,EAAS,EAAO,IAClD,QAAS,OAAO,GAAW,SAAW,EAAO,QAAU,IAAA,GACvD,QAAS,OAAO,GAAW,SAAW,EAAO,QAAU,IAAA,GACvD,KAAM,OAAO,GAAW,SAAW,EAAO,KAAO,IAAA,GACjD,QAAS,OAAO,GAAW,SAAW,EAAO,QAAU,IAAA,EACzD,EAAE,CACJ,CACF"}
|
|
@@ -7,7 +7,8 @@ function e(e) {
|
|
|
7
7
|
name: typeof e == "object" ? e.name : void 0,
|
|
8
8
|
url: typeof e == "string" ? e : e.url,
|
|
9
9
|
headers: typeof e == "object" ? e.headers : void 0,
|
|
10
|
-
auth: typeof e == "object" ? e.auth : void 0
|
|
10
|
+
auth: typeof e == "object" ? e.auth : void 0,
|
|
11
|
+
enabled: typeof e == "object" ? e.enabled : void 0
|
|
11
12
|
})),
|
|
12
13
|
...e.stdio_servers.map((e, t) => ({
|
|
13
14
|
id: `stdio-${t}`,
|
|
@@ -15,7 +16,8 @@ function e(e) {
|
|
|
15
16
|
name: e.name,
|
|
16
17
|
command: e.command,
|
|
17
18
|
args: e.args,
|
|
18
|
-
env: e.env
|
|
19
|
+
env: e.env,
|
|
20
|
+
enabled: e.enabled
|
|
19
21
|
})),
|
|
20
22
|
...e.shttp_servers.map((e, t) => ({
|
|
21
23
|
id: `shttp-${t}`,
|
|
@@ -24,7 +26,8 @@ function e(e) {
|
|
|
24
26
|
url: typeof e == "string" ? e : e.url,
|
|
25
27
|
headers: typeof e == "object" ? e.headers : void 0,
|
|
26
28
|
timeout: typeof e == "object" ? e.timeout : void 0,
|
|
27
|
-
auth: typeof e == "object" ? e.auth : void 0
|
|
29
|
+
auth: typeof e == "object" ? e.auth : void 0,
|
|
30
|
+
enabled: typeof e == "object" ? e.enabled : void 0
|
|
28
31
|
}))
|
|
29
32
|
];
|
|
30
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-installed-servers.js","names":[],"sources":["../../src/utils/mcp-installed-servers.ts"],"sourcesContent":["import { MCPServerConfig } from \"#/types/mcp-server\";\nimport { MCPConfig } from \"#/types/settings\";\n\nexport function flattenMcpConfig(config: MCPConfig): MCPServerConfig[] {\n return [\n ...config.sse_servers.map((server, index) => ({\n id: `sse-${index}`,\n type: \"sse\" as const,\n name: typeof server === \"object\" ? server.name : undefined,\n url: typeof server === \"string\" ? server : server.url,\n headers: typeof server === \"object\" ? server.headers : undefined,\n auth: typeof server === \"object\" ? server.auth : undefined,\n })),\n ...config.stdio_servers.map((server, index) => ({\n id: `stdio-${index}`,\n type: \"stdio\" as const,\n name: server.name,\n command: server.command,\n args: server.args,\n env: server.env,\n })),\n ...config.shttp_servers.map((server, index) => ({\n id: `shttp-${index}`,\n type: \"shttp\" as const,\n name: typeof server === \"object\" ? server.name : undefined,\n url: typeof server === \"string\" ? server : server.url,\n headers: typeof server === \"object\" ? server.headers : undefined,\n timeout: typeof server === \"object\" ? server.timeout : undefined,\n auth: typeof server === \"object\" ? server.auth : undefined,\n })),\n ];\n}\n"],"mappings":";AAGA,SAAgB,EAAiB,GAAsC;CACrE,OAAO;EACL,GAAG,EAAO,YAAY,KAAK,GAAQ,OAAW;GAC5C,IAAI,OAAO;GACX,MAAM;GACN,MAAM,OAAO,KAAW,WAAW,EAAO,OAAO,KAAA;GACjD,KAAK,OAAO,KAAW,WAAW,IAAS,EAAO;GAClD,SAAS,OAAO,KAAW,WAAW,EAAO,UAAU,KAAA;GACvD,MAAM,OAAO,KAAW,WAAW,EAAO,OAAO,KAAA;
|
|
1
|
+
{"version":3,"file":"mcp-installed-servers.js","names":[],"sources":["../../src/utils/mcp-installed-servers.ts"],"sourcesContent":["import { MCPServerConfig } from \"#/types/mcp-server\";\nimport { MCPConfig } from \"#/types/settings\";\n\nexport function flattenMcpConfig(config: MCPConfig): MCPServerConfig[] {\n return [\n ...config.sse_servers.map((server, index) => ({\n id: `sse-${index}`,\n type: \"sse\" as const,\n name: typeof server === \"object\" ? server.name : undefined,\n url: typeof server === \"string\" ? server : server.url,\n headers: typeof server === \"object\" ? server.headers : undefined,\n auth: typeof server === \"object\" ? server.auth : undefined,\n enabled: typeof server === \"object\" ? server.enabled : undefined,\n })),\n ...config.stdio_servers.map((server, index) => ({\n id: `stdio-${index}`,\n type: \"stdio\" as const,\n name: server.name,\n command: server.command,\n args: server.args,\n env: server.env,\n enabled: server.enabled,\n })),\n ...config.shttp_servers.map((server, index) => ({\n id: `shttp-${index}`,\n type: \"shttp\" as const,\n name: typeof server === \"object\" ? server.name : undefined,\n url: typeof server === \"string\" ? server : server.url,\n headers: typeof server === \"object\" ? server.headers : undefined,\n timeout: typeof server === \"object\" ? server.timeout : undefined,\n auth: typeof server === \"object\" ? server.auth : undefined,\n enabled: typeof server === \"object\" ? server.enabled : undefined,\n })),\n ];\n}\n"],"mappings":";AAGA,SAAgB,EAAiB,GAAsC;CACrE,OAAO;EACL,GAAG,EAAO,YAAY,KAAK,GAAQ,OAAW;GAC5C,IAAI,OAAO;GACX,MAAM;GACN,MAAM,OAAO,KAAW,WAAW,EAAO,OAAO,KAAA;GACjD,KAAK,OAAO,KAAW,WAAW,IAAS,EAAO;GAClD,SAAS,OAAO,KAAW,WAAW,EAAO,UAAU,KAAA;GACvD,MAAM,OAAO,KAAW,WAAW,EAAO,OAAO,KAAA;GACjD,SAAS,OAAO,KAAW,WAAW,EAAO,UAAU,KAAA;EACzD,EAAE;EACF,GAAG,EAAO,cAAc,KAAK,GAAQ,OAAW;GAC9C,IAAI,SAAS;GACb,MAAM;GACN,MAAM,EAAO;GACb,SAAS,EAAO;GAChB,MAAM,EAAO;GACb,KAAK,EAAO;GACZ,SAAS,EAAO;EAClB,EAAE;EACF,GAAG,EAAO,cAAc,KAAK,GAAQ,OAAW;GAC9C,IAAI,SAAS;GACb,MAAM;GACN,MAAM,OAAO,KAAW,WAAW,EAAO,OAAO,KAAA;GACjD,KAAK,OAAO,KAAW,WAAW,IAAS,EAAO;GAClD,SAAS,OAAO,KAAW,WAAW,EAAO,UAAU,KAAA;GACvD,SAAS,OAAO,KAAW,WAAW,EAAO,UAAU,KAAA;GACvD,MAAM,OAAO,KAAW,WAAW,EAAO,OAAO,KAAA;GACjD,SAAS,OAAO,KAAW,WAAW,EAAO,UAAU,KAAA;EACzD,EAAE;CACJ;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openhands/agent-canvas",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Agent Canvas UI for OpenHands - run AI coding agents with a visual interface",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@microlink/react-json-view": "1.31.20",
|
|
25
25
|
"@monaco-editor/react": "4.7.0",
|
|
26
26
|
"@openhands/extensions": "0.11.0",
|
|
27
|
-
"@openhands/typescript-client": "1.
|
|
27
|
+
"@openhands/typescript-client": "1.36.1",
|
|
28
28
|
"@react-router/node": "7.17.0",
|
|
29
29
|
"@react-router/serve": "7.17.0",
|
|
30
30
|
"@tailwindcss/vite": "4.2.4",
|
|
@@ -87,6 +87,9 @@
|
|
|
87
87
|
"test:e2e:mock-llm": "playwright test --config=playwright.mock-llm.config.ts",
|
|
88
88
|
"test:e2e:mock-llm:docker": "playwright test --config=playwright.mock-llm-docker.config.ts",
|
|
89
89
|
"test:coverage": "npm run make-i18n && vitest run --coverage",
|
|
90
|
+
"test:mutation": "npm run make-i18n && stryker run",
|
|
91
|
+
"test:mutation:diff": "npm run make-i18n && node scripts/stryker-diff.mjs",
|
|
92
|
+
"test:mutation:incremental": "npm run make-i18n && stryker run --incremental",
|
|
90
93
|
"dev_wsl": "VITE_WATCH_USE_POLLING=true vite",
|
|
91
94
|
"preview": "vite preview",
|
|
92
95
|
"make-i18n": "node scripts/make-i18n-translations.cjs",
|
|
@@ -125,6 +128,8 @@
|
|
|
125
128
|
"@mswjs/socket.io-binding": "0.2.0",
|
|
126
129
|
"@playwright/test": "1.59.1",
|
|
127
130
|
"@react-router/dev": "7.17.0",
|
|
131
|
+
"@stryker-mutator/core": "9.6.1",
|
|
132
|
+
"@stryker-mutator/vitest-runner": "9.6.1",
|
|
128
133
|
"@tailwindcss/typography": "0.5.19",
|
|
129
134
|
"@tanstack/eslint-plugin-query": "5.100.9",
|
|
130
135
|
"@testing-library/dom": "10.4.1",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
*
|
|
20
20
|
* Usage:
|
|
21
21
|
* node scripts/check-sdk-version-sync.mjs
|
|
22
|
-
* EXPECTED_SDK_VERSION=1.
|
|
22
|
+
* EXPECTED_SDK_VERSION=1.39.1 node scripts/check-sdk-version-sync.mjs
|
|
23
23
|
* node scripts/check-sdk-version-sync.mjs --check-pypi
|
|
24
24
|
*
|
|
25
25
|
* Environment variables:
|
|
@@ -78,7 +78,7 @@ Triggering from other repos:
|
|
|
78
78
|
-H "Authorization: token \$GITHUB_TOKEN" \\
|
|
79
79
|
-H "Accept: application/vnd.github.v3+json" \\
|
|
80
80
|
https://api.github.com/repos/OpenHands/OpenHands/dispatches \\
|
|
81
|
-
-d '{"event_type": "sdk-version-check", "client_payload": {"version": "1.
|
|
81
|
+
-d '{"event_type": "sdk-version-check", "client_payload": {"version": "1.39.1"}}'
|
|
82
82
|
`);
|
|
83
83
|
process.exit(0);
|
|
84
84
|
}
|
|
@@ -260,9 +260,9 @@ async function fetchPyPIDependencies(packageName, version) {
|
|
|
260
260
|
* Parse PyPI requires_dist array and extract SDK package versions
|
|
261
261
|
*
|
|
262
262
|
* PyPI returns dependencies in PEP 508 format like:
|
|
263
|
-
* "openhands-sdk>=1.
|
|
264
|
-
* "openhands-tools==1.
|
|
265
|
-
* "openhands-workspace (>=1.
|
|
263
|
+
* "openhands-sdk>=1.39.1,<2.0.0"
|
|
264
|
+
* "openhands-tools==1.39.1"
|
|
265
|
+
* "openhands-workspace (>=1.39.1)"
|
|
266
266
|
*/
|
|
267
267
|
function parseSdkVersionsFromRequiresDist(requiresDist) {
|
|
268
268
|
const versions = {};
|
|
@@ -276,7 +276,7 @@ function parseSdkVersionsFromRequiresDist(requiresDist) {
|
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
// Extract the version number - look for patterns like:
|
|
279
|
-
// ">=1.
|
|
279
|
+
// ">=1.39.1", "==1.39.1", "(>=1.39.1)", "~=1.39.1"
|
|
280
280
|
// After the package name and before any comma or closing paren
|
|
281
281
|
const versionPattern = /[><=~!]+\s*([0-9]+(?:\.[0-9]+)*)/;
|
|
282
282
|
const match = dep.match(versionPattern);
|
package/scripts/dev-safe.mjs
CHANGED
|
@@ -48,7 +48,7 @@ const LOCAL_AGENT_SERVER_SUBDIRS = [
|
|
|
48
48
|
"openhands-workspace",
|
|
49
49
|
];
|
|
50
50
|
const DEFAULT_AGENT_SERVER_VERSION = SHARED_DEFAULTS.versions.agentServer;
|
|
51
|
-
// Temporary transitive-dep pin: openhands-sdk 1.
|
|
51
|
+
// Temporary transitive-dep pin: openhands-sdk 1.39.1 leaves agent-client-protocol
|
|
52
52
|
// unbounded (>=0.10.1), but acp 0.11.0 reordered the ACP prompt() args and breaks
|
|
53
53
|
// the SDK's ACP client. Hold acp <0.11 until a fixed SDK ships. See config/defaults.json.
|
|
54
54
|
const AGENT_CLIENT_PROTOCOL_CONSTRAINT =
|
|
@@ -399,7 +399,7 @@ export function validateFrontendDependencies(
|
|
|
399
399
|
* edits are picked up without a manual reinstall. The agent-server itself
|
|
400
400
|
* is rebuilt from local source on each invocation (--reinstall).
|
|
401
401
|
* - OH_AGENT_SERVER_GIT_REF: Git commit SHA or branch name
|
|
402
|
-
* - OH_AGENT_SERVER_VERSION: Specific PyPI version (e.g., "1.
|
|
402
|
+
* - OH_AGENT_SERVER_VERSION: Specific PyPI version (e.g., "1.39.1")
|
|
403
403
|
*
|
|
404
404
|
* If none are set, defaults to the released version specified by
|
|
405
405
|
* DEFAULT_AGENT_SERVER_VERSION. Set OH_AGENT_SERVER_GIT_REF to use a
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
|
+
|
|
7
|
+
const EXCLUDED_DIRECTORY =
|
|
8
|
+
/(^|\/)(__tests__|tests?|fixtures|__fixtures__|snapshots|__snapshots__|generated|mocks|dev)(\/|$)/;
|
|
9
|
+
const EXCLUDED_FILE = /\.(test|spec|d|gen|generated)\.(ts|tsx)$/;
|
|
10
|
+
|
|
11
|
+
function isProductionTypeScript(file) {
|
|
12
|
+
const normalized = file.replaceAll("\\", "/");
|
|
13
|
+
return (
|
|
14
|
+
/^src\/.+\.(ts|tsx)$/.test(normalized) &&
|
|
15
|
+
!EXCLUDED_DIRECTORY.test(normalized) &&
|
|
16
|
+
!EXCLUDED_FILE.test(normalized)
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {object} ProcessResult
|
|
22
|
+
* @property {Error | undefined} [error]
|
|
23
|
+
* @property {number | null} status
|
|
24
|
+
* @property {string | null} stderr
|
|
25
|
+
* @property {string | null} stdout
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @typedef {object} Dependencies
|
|
30
|
+
* @property {(command: string, args: readonly string[], options?: import("node:child_process").SpawnSyncOptions) => ProcessResult} spawn
|
|
31
|
+
* @property {(message: string) => void} writeError
|
|
32
|
+
* @property {(message: string) => void} writeOutput
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
// Stryker disable all: the real process adapter is verified by the CLI
|
|
36
|
+
// subprocess smoke test, which Vitest cannot attribute to the parent process.
|
|
37
|
+
/** @type {Dependencies} */
|
|
38
|
+
const defaultDependencies = {
|
|
39
|
+
spawn(command, args, options) {
|
|
40
|
+
const result = spawnSync(command, [...args], options);
|
|
41
|
+
return {
|
|
42
|
+
error: result.error,
|
|
43
|
+
status: result.status,
|
|
44
|
+
stderr: result.stderr?.toString() ?? null,
|
|
45
|
+
stdout: result.stdout?.toString() ?? null,
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
writeError(message) {
|
|
49
|
+
process.stderr.write(message);
|
|
50
|
+
},
|
|
51
|
+
writeOutput(message) {
|
|
52
|
+
process.stdout.write(message);
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
// Stryker restore all
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Run mutation testing against production TypeScript files changed from a base
|
|
59
|
+
* git ref. The dependency parameter keeps the process boundary observable in
|
|
60
|
+
* tests while the command-line behavior remains the public API.
|
|
61
|
+
*
|
|
62
|
+
* @param {string[]} argv
|
|
63
|
+
* @param {Partial<Dependencies>} [overrides]
|
|
64
|
+
* @returns {number}
|
|
65
|
+
*/
|
|
66
|
+
export function main(argv, overrides = {}) {
|
|
67
|
+
const dependencies = { ...defaultDependencies, ...overrides };
|
|
68
|
+
const baseRef = argv[0] ?? "main";
|
|
69
|
+
const gitArgs = [
|
|
70
|
+
"diff",
|
|
71
|
+
"--name-only",
|
|
72
|
+
"--diff-filter=ACMRTUXB",
|
|
73
|
+
`${baseRef}...HEAD`,
|
|
74
|
+
];
|
|
75
|
+
const gitResult = dependencies.spawn("git", gitArgs, {
|
|
76
|
+
encoding: "utf8",
|
|
77
|
+
windowsHide: true,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
if (gitResult.error || gitResult.status !== 0) {
|
|
81
|
+
const detail =
|
|
82
|
+
gitResult.stderr || gitResult.error?.message || "unknown error";
|
|
83
|
+
dependencies.writeError(
|
|
84
|
+
`Unable to determine changed files against ${baseRef}: ${detail.trim()}\n`,
|
|
85
|
+
);
|
|
86
|
+
return gitResult.status ?? 1;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const mutationTargets = gitResult.stdout
|
|
90
|
+
.split(/\r?\n/u)
|
|
91
|
+
.filter(isProductionTypeScript);
|
|
92
|
+
|
|
93
|
+
if (mutationTargets.length === 0) {
|
|
94
|
+
dependencies.writeOutput(
|
|
95
|
+
`No changed production files to mutate against ${baseRef}.\n`,
|
|
96
|
+
);
|
|
97
|
+
return 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const strykerCliPath = fileURLToPath(
|
|
101
|
+
new URL(
|
|
102
|
+
"../node_modules/@stryker-mutator/core/bin/stryker.js",
|
|
103
|
+
import.meta.url,
|
|
104
|
+
),
|
|
105
|
+
);
|
|
106
|
+
const strykerResult = dependencies.spawn(
|
|
107
|
+
process.execPath,
|
|
108
|
+
[
|
|
109
|
+
strykerCliPath,
|
|
110
|
+
"run",
|
|
111
|
+
"--incremental",
|
|
112
|
+
"--force",
|
|
113
|
+
"--mutate",
|
|
114
|
+
mutationTargets.join(","),
|
|
115
|
+
],
|
|
116
|
+
{ stdio: "inherit", windowsHide: true },
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
if (strykerResult.error) {
|
|
120
|
+
dependencies.writeError(
|
|
121
|
+
`Unable to start Stryker: ${strykerResult.error.message}\n`,
|
|
122
|
+
);
|
|
123
|
+
return 1;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return strykerResult.status ?? 1;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Stryker disable all: the CLI guard is verified by a real subprocess test,
|
|
130
|
+
// which the Vitest runner cannot attribute to the mutated parent process.
|
|
131
|
+
const isMainModule =
|
|
132
|
+
process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href;
|
|
133
|
+
|
|
134
|
+
if (isMainModule) {
|
|
135
|
+
process.exitCode = main(process.argv.slice(2));
|
|
136
|
+
}
|
|
137
|
+
// Stryker restore all
|