dsh-agent-plugins-market 0.5.3 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -3
- package/README.zh.md +29 -3
- package/client/client.js +1395 -202
- package/client/client.js.map +1 -1
- package/lib/application/catalog.js +537 -71
- package/lib/application/details.js +39 -12
- package/lib/catalog/archive.js +341 -0
- package/lib/catalog/git.js +85 -12
- package/lib/catalog/legacy-root-migration.js +51 -0
- package/lib/catalog/lsp-spec.js +87 -0
- package/lib/catalog/manifests.js +84 -32
- package/lib/catalog/paths.js +65 -7
- package/lib/catalog/scan-pipeline.js +50 -0
- package/lib/catalog/scan-resolvers.js +402 -0
- package/lib/catalog/source-catalog.js +22 -8
- package/lib/catalog/suite-scanner.js +5 -176
- package/lib/catalog/surfaces.js +80 -30
- package/lib/contracts/lsp-status.js +2 -0
- package/lib/contracts/market.js +8 -1
- package/lib/index.js +118 -13
- package/lib/model/state.js +14 -1
- package/lib/model/types.js +21 -2
- package/lib/routes.js +88 -6
- package/lib/runtime/commands-mounts.js +6 -2
- package/lib/runtime/hooks-mounts.js +9 -6
- package/lib/runtime/lsp-direct-config.js +44 -0
- package/lib/runtime/lsp-mounts.js +236 -0
- package/lib/runtime/lsp-status.js +96 -0
- package/lib/runtime/mcp-backend.js +60 -0
- package/lib/runtime/mcp-client/bridge.js +126 -0
- package/lib/runtime/mcp-client/config.js +42 -0
- package/lib/runtime/mcp-client/connection.js +380 -0
- package/lib/runtime/mcp-client/host-seams.js +88 -0
- package/lib/runtime/mcp-client/json-schema-subset.js +181 -0
- package/lib/runtime/mcp-client/oauth.js +379 -0
- package/lib/runtime/mcp-client/tools.js +432 -0
- package/lib/runtime/mcp-client/transport.js +103 -0
- package/lib/runtime/mcp-config.js +202 -56
- package/lib/runtime/mcp-credentials.js +20 -0
- package/lib/runtime/mcp-mounts.js +245 -27
- package/lib/runtime/mcp-overrides.js +64 -6
- package/lib/runtime/mcp-redaction.js +92 -0
- package/lib/runtime/mcp-status.js +74 -31
- package/lib/runtime/reconciler.js +35 -1
- package/lib/runtime/regions.js +56 -0
- package/lib/types/application/catalog.d.ts +191 -14
- package/lib/types/application/details.d.ts +1 -6
- package/lib/types/application/queries.d.ts +28 -1
- package/lib/types/catalog/archive.d.ts +48 -0
- package/lib/types/catalog/git.d.ts +27 -3
- package/lib/types/catalog/legacy-root-migration.d.ts +14 -0
- package/lib/types/catalog/lsp-spec.d.ts +14 -0
- package/lib/types/catalog/manifests.d.ts +16 -1
- package/lib/types/catalog/paths.d.ts +23 -2
- package/lib/types/catalog/scan-pipeline.d.ts +76 -0
- package/lib/types/catalog/scan-resolvers.d.ts +81 -0
- package/lib/types/catalog/source-catalog.d.ts +5 -0
- package/lib/types/catalog/suite-scanner.d.ts +14 -7
- package/lib/types/catalog/surfaces.d.ts +3 -3
- package/lib/types/contracts/lsp-status.d.ts +53 -0
- package/lib/types/contracts/market.d.ts +55 -1
- package/lib/types/contracts/mcp-status.d.ts +14 -2
- package/lib/types/index.d.ts +24 -8
- package/lib/types/model/types.d.ts +52 -3
- package/lib/types/runtime/lsp-direct-config.d.ts +12 -0
- package/lib/types/runtime/lsp-mounts.d.ts +89 -0
- package/lib/types/runtime/lsp-status.d.ts +30 -0
- package/lib/types/runtime/mcp-backend.d.ts +49 -0
- package/lib/types/runtime/mcp-client/bridge.d.ts +37 -0
- package/lib/types/runtime/mcp-client/config.d.ts +123 -0
- package/lib/types/runtime/mcp-client/connection.d.ts +82 -0
- package/lib/types/runtime/mcp-client/host-seams.d.ts +89 -0
- package/lib/types/runtime/mcp-client/json-schema-subset.d.ts +58 -0
- package/lib/types/runtime/mcp-client/oauth.d.ts +121 -0
- package/lib/types/runtime/mcp-client/tools.d.ts +136 -0
- package/lib/types/runtime/mcp-client/transport.d.ts +36 -0
- package/lib/types/runtime/mcp-config.d.ts +38 -15
- package/lib/types/runtime/mcp-credentials.d.ts +9 -0
- package/lib/types/runtime/mcp-mounts.d.ts +56 -6
- package/lib/types/runtime/mcp-overrides.d.ts +23 -4
- package/lib/types/runtime/mcp-redaction.d.ts +7 -0
- package/lib/types/runtime/mcp-status.d.ts +4 -2
- package/lib/types/runtime/reconciler.d.ts +22 -4
- package/lib/types/runtime/regions.d.ts +37 -0
- package/package.json +16 -12
- package/schemas/1.0.0/mcp.schema.json +22 -0
package/client/client.js
CHANGED
|
@@ -2,7 +2,7 @@ window.__ModuleLoader__.load({ id: "dsh-agent-plugins-market", factory: (require
|
|
|
2
2
|
|
|
3
3
|
var module = { exports: {} };
|
|
4
4
|
var exports = module.exports;
|
|
5
|
-
(function(){if(typeof document!=="undefined"){var s=document.createElement("style");s.setAttribute("data-dsh-client","dsh-agent-plugins-market");s.textContent="._72qoAq_market {\n min-width: 0;\n height: 100%;\n min-height: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n gap: 24px;\n display: flex;\n}\n\n._72qoAq_pageMode {\n width: 100%;\n min-width: 0;\n}\n\n._72qoAq_marketControls {\n flex-direction: column;\n gap: 8px;\n min-height: 0;\n display: flex;\n}\n\n._72qoAq_mcpSurface {\n flex: 1;\n min-height: 0;\n display: flex;\n}\n\n._72qoAq_surfaceSwitch {\n border: 1px solid var(--dsw-alias-border-l2, #d4dce8);\n background: var(--dsw-alias-bg-layer-1, #fff);\n height: 26px;\n color: var(--dsw-alias-brand-primary, #4966f5);\n cursor: pointer;\n border-radius: 7px;\n flex: none;\n align-self: center;\n padding: 0 10px;\n font-size: 11px;\n}\n\n._72qoAq_surfaceSwitch:hover {\n background: var(--dsw-alias-bg-selected, #edf1ff);\n}\n\nhtml[data-dsh-agent-plugins-market-page] [data-pane=\"conversation\"], html[data-dsh-agent-plugins-market-page] [class*=\"centerCol\"] {\n position: relative;\n}\n\n._72qoAq_pageView {\n z-index: 60;\n background: var(--dsw-alias-bg-base, #f7f8fa);\n min-width: 0;\n min-height: 0;\n padding: 20px 24px;\n display: none;\n position: absolute;\n inset: 0;\n overflow: hidden;\n}\n\nhtml[data-dsh-agent-plugins-market-page] ._72qoAq_pageView {\n display: flex;\n}\n\nhtml[data-dsh-agent-plugins-market-page] [data-pane=\"conversation\"] > :not([data-dsh-agent-plugins-market-page-view]), html[data-dsh-agent-plugins-market-page] [class*=\"centerCol\"] > :not([data-dsh-agent-plugins-market-page-view]) {\n display: none !important;\n}\n\n._72qoAq_pageEntry {\n width: 100%;\n min-height: 32px;\n color: var(--dsw-alias-label-primary, #1f2328);\n cursor: pointer;\n font: inherit;\n text-align: left;\n background: none;\n border: none;\n border-radius: 8px;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n font-size: 13px;\n line-height: 20px;\n display: flex;\n}\n\n._72qoAq_pageEntry:hover {\n background: var(--dsw-alias-bg-hover, #0000000d);\n}\n\n._72qoAq_pageEntry:active {\n background: var(--dsw-alias-bg-active, #00000014);\n}\n\n._72qoAq_pageEntry svg {\n color: var(--dsw-alias-label-secondary, #6b7280);\n flex-shrink: 0;\n}\n\n._72qoAq_pageEntry span {\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n overflow: hidden;\n}\n\n[data-dsh-frame][data-sidebar-collapsed] ._72qoAq_pageEntry {\n justify-content: center;\n padding-inline: 0;\n}\n\n[data-dsh-frame][data-sidebar-collapsed] ._72qoAq_pageEntry span {\n display: none;\n}\n\n._72qoAq_pageEntry:focus-visible, ._72qoAq_srcTabMain:focus-visible, ._72qoAq_srcTabEdit:focus-visible, ._72qoAq_srcTabDel:focus-visible, ._72qoAq_seg:focus-visible, ._72qoAq_segOn:focus-visible, ._72qoAq_detailItemRow:focus-visible, ._72qoAq_detailItemOpen:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 2px;\n}\n\n._72qoAq_header {\n flex-direction: column;\n flex-shrink: 0;\n gap: 8px;\n display: flex;\n}\n\n._72qoAq_titleRow {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n._72qoAq_title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n}\n\n._72qoAq_sub {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n align-items: center;\n gap: 8px;\n min-width: 0;\n margin: 0;\n font-size: 13px;\n line-height: 20px;\n display: flex;\n overflow: hidden;\n}\n\n._72qoAq_spacer {\n flex: 1;\n}\n\n._72qoAq_searchGroup {\n align-items: center;\n gap: 2px;\n display: flex;\n}\n\n._72qoAq_body {\n flex: 1;\n align-items: flex-start;\n gap: 20px;\n min-height: 0;\n display: flex;\n}\n\n._72qoAq_sourceTabsRow {\n padding: 0;\n display: block;\n}\n\n._72qoAq_sourceTabsScroll {\n grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));\n gap: 4px;\n display: grid;\n}\n\n._72qoAq_srcTabEdit {\n font: inherit;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n background: none;\n border: none;\n flex-shrink: 0;\n padding: 2px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_srcTabEdit:hover {\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n._72qoAq_srcTabOn ._72qoAq_srcTabEdit, ._72qoAq_srcTabOn ._72qoAq_srcTabEdit:hover {\n color: var(--dsw-alias-label-primary-foreground, #fff);\n}\n\n._72qoAq_srcTab, ._72qoAq_srcTabOn {\n border: 1px solid var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-bg-layer-1, #fff);\n border-radius: 999px;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 24px;\n display: inline-flex;\n overflow: hidden;\n}\n\n._72qoAq_srcTabMain {\n font: inherit;\n color: var(--dsw-alias-label-primary, #1f2328);\n cursor: pointer;\n white-space: nowrap;\n text-overflow: ellipsis;\n background: none;\n border: none;\n flex: 1;\n min-width: 0;\n padding: 2px 2px 2px 10px;\n font-size: 12px;\n line-height: 18px;\n overflow: hidden;\n}\n\n._72qoAq_srcTabMain:hover {\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n._72qoAq_srcTabOn {\n background: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);\n border-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);\n}\n\n._72qoAq_srcTabOn ._72qoAq_srcTabMain {\n color: var(--dsw-alias-label-primary-foreground, #fff);\n font-weight: 600;\n}\n\n._72qoAq_srcTabDel {\n font: inherit;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n background: none;\n border: none;\n flex-shrink: 0;\n padding: 2px 8px 2px 2px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_srcTabDel:hover {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n._72qoAq_srcTabOn ._72qoAq_srcTabDel, ._72qoAq_srcTabOn ._72qoAq_srcTabDel:hover {\n color: var(--dsw-alias-label-primary-foreground, #fff);\n}\n\n._72qoAq_grid {\n scrollbar-gutter: stable;\n flex: 1;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n align-content: start;\n gap: 12px;\n min-width: 0;\n min-height: 0;\n padding-right: 4px;\n display: grid;\n overflow-y: auto;\n}\n\n._72qoAq_list {\n scrollbar-gutter: stable;\n flex-direction: column;\n flex: 1;\n gap: 8px;\n min-width: 0;\n min-height: 0;\n padding-right: 4px;\n display: flex;\n overflow-y: auto;\n}\n\n._72qoAq_list ._72qoAq_card {\n flex-flow: wrap;\n align-items: center;\n gap: 8px 14px;\n}\n\n._72qoAq_list ._72qoAq_cardTop {\n flex: none;\n}\n\n._72qoAq_list ._72qoAq_cardDesc {\n -webkit-line-clamp: 1;\n flex: 1;\n min-width: 200px;\n min-height: 0;\n}\n\n._72qoAq_list ._72qoAq_cardActions {\n flex: none;\n}\n\n._72qoAq_list ._72qoAq_meta {\n flex-basis: 100%;\n}\n\n._72qoAq_empty {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-align: center;\n grid-column: 1 / -1;\n padding: 48px 0;\n font-size: 13px;\n}\n\n._72qoAq_card {\n background: var(--dsw-alias-bg-layer-1, #fff);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 12px;\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n padding: 12px 14px;\n display: flex;\n}\n\n._72qoAq_cardTop {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n._72qoAq_cardTitle {\n flex: 1;\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_cardName {\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n font-weight: 600;\n line-height: 22px;\n overflow: hidden;\n}\n\n._72qoAq_version {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-variant-numeric: tabular-nums;\n flex-shrink: 0;\n font-size: 12px;\n line-height: 20px;\n}\n\n._72qoAq_cardActions {\n flex-shrink: 0;\n align-items: center;\n gap: 4px;\n display: flex;\n}\n\n._72qoAq_switchOn, ._72qoAq_switchOff {\n cursor: pointer;\n border: none;\n border-radius: 999px;\n flex-shrink: 0;\n width: 38px;\n height: 22px;\n padding: 0;\n transition: background-color .15s;\n position: relative;\n}\n\n._72qoAq_switchOn {\n background: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n._72qoAq_switchOff {\n background: var(--dsw-alias-state-neutral, #d1d5db);\n}\n\n._72qoAq_switchOn:disabled, ._72qoAq_switchOff:disabled {\n opacity: .6;\n cursor: default;\n}\n\n._72qoAq_switchThumb {\n pointer-events: none;\n background: #fff;\n border-radius: 50%;\n width: 16px;\n height: 16px;\n transition: left .15s;\n position: absolute;\n top: 3px;\n left: 3px;\n box-shadow: 0 1px 2px #0003;\n}\n\n._72qoAq_switchOn ._72qoAq_switchThumb {\n left: 19px;\n}\n\n._72qoAq_desc {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n min-height: 36px;\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n display: -webkit-box;\n overflow: hidden;\n}\n\n._72qoAq_meta {\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n._72qoAq_src {\n color: var(--dsw-alias-label-secondary, #9ca3af);\n font-size: 12px;\n text-decoration: none;\n}\n\n._72qoAq_tag {\n border: 1px solid var(--dsw-alias-border-l3, #d9dde3);\n color: var(--dsw-alias-label-secondary, #6b7280);\n border-radius: 4px;\n flex-shrink: 0;\n padding: 1px 6px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_okState {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n white-space: nowrap;\n font-size: 12px;\n font-weight: 600;\n}\n\n._72qoAq_warnLine {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n cursor: help;\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n}\n\n._72qoAq_modalFooter {\n justify-content: flex-end;\n gap: 8px;\n width: 100%;\n display: flex;\n}\n\n._72qoAq_modalFooterLeft {\n gap: 8px;\n margin-right: auto;\n display: flex;\n}\n\n._72qoAq_editorDialog {\n width: min(500px, 92vw);\n}\n\n._72qoAq_installConfirmBody {\n flex-direction: column;\n gap: 10px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_installConfirmSuite {\n color: var(--dsw-alias-label-primary, #111827);\n font-weight: 600;\n}\n\n._72qoAq_installConfirmMeta {\n color: var(--dsw-alias-label-secondary, #4b5563);\n font-size: 12px;\n}\n\n._72qoAq_installConfirmCommit {\n color: var(--dsw-alias-label-secondary, #4b5563);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12px;\n}\n\n._72qoAq_installConfirmTags {\n flex-wrap: wrap;\n gap: 6px;\n display: flex;\n}\n\n._72qoAq_installConfirmWarn {\n color: var(--dsw-alias-danger, #b45309);\n border: 1px solid var(--dsw-alias-danger, #b45309);\n border-radius: 8px;\n padding: 8px 10px;\n font-size: 12px;\n}\n\n._72qoAq_editorForm {\n flex-direction: column;\n gap: 14px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_modeRow {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n background: var(--dsw-alias-bg-layer-2, #f3f4f6);\n border-radius: 10px;\n align-self: flex-start;\n gap: 6px;\n padding: 3px;\n display: flex;\n}\n\n._72qoAq_seg, ._72qoAq_segOn {\n font: inherit;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 8px;\n padding: 5px 14px;\n font-size: 13px;\n line-height: 20px;\n}\n\n._72qoAq_segOn {\n background: var(--dsw-alias-bg-layer-1, #fff);\n color: var(--dsw-alias-label-primary, #1f2328);\n font-weight: 600;\n box-shadow: 0 1px 2px #00000014;\n}\n\n._72qoAq_fieldGroup {\n flex-direction: column;\n gap: 5px;\n display: flex;\n}\n\n._72qoAq_fieldLabel {\n color: var(--dsw-alias-label-secondary, #6b7280);\n font-size: 12px;\n font-weight: 600;\n}\n\n._72qoAq_fieldHint {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 12px;\n line-height: 16px;\n}\n\n._72qoAq_staticId {\n border: 1px dashed var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-bg-layer-2, #f3f4f6);\n border-radius: 8px;\n align-items: center;\n gap: 8px;\n padding: 7px 10px;\n display: flex;\n}\n\n._72qoAq_staticIdValue {\n color: var(--dsw-alias-label-primary, #1f2328);\n font-size: 13px;\n font-weight: 600;\n}\n\n._72qoAq_detailDialog {\n width: min(800px, 94vw);\n}\n\n._72qoAq_detailBody {\n flex-direction: column;\n gap: 14px;\n max-height: 78vh;\n display: flex;\n overflow-y: auto;\n}\n\n._72qoAq_detailSections {\n flex-direction: column;\n gap: 14px;\n display: flex;\n}\n\n._72qoAq_detailSection {\n flex-direction: column;\n gap: 6px;\n display: flex;\n}\n\n._72qoAq_detailHead {\n color: var(--dsw-alias-label-secondary, #6b7280);\n border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n margin: 0;\n padding-bottom: 4px;\n font-size: 13px;\n font-weight: 600;\n}\n\n._72qoAq_detailGrid {\n grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n gap: 6px 14px;\n display: grid;\n}\n\n._72qoAq_detailCell {\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_detailKey {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 12px;\n}\n\n._72qoAq_detailValue {\n color: var(--dsw-alias-label-primary, #1f2328);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n overflow: hidden;\n}\n\n._72qoAq_detailDesc {\n color: var(--dsw-alias-label-secondary, #6b7280);\n margin: 4px 0 0;\n font-size: 13px;\n line-height: 20px;\n}\n\n._72qoAq_mono {\n word-break: break-all;\n white-space: pre-wrap;\n color: var(--dsw-alias-label-primary, #1f2328);\n margin: 0;\n font-family: ui-monospace, Menlo, Consolas, monospace;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_detailItem {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 8px;\n flex-direction: column;\n display: flex;\n overflow: hidden;\n}\n\n._72qoAq_detailItemRow, ._72qoAq_detailItemOpen {\n width: 100%;\n font: inherit;\n text-align: left;\n cursor: pointer;\n color: var(--dsw-alias-label-primary, #1f2328);\n background: none;\n border: none;\n align-items: center;\n gap: 8px;\n padding: 7px 10px;\n display: flex;\n}\n\n._72qoAq_detailItemRow:hover {\n background: var(--dsw-alias-bg-hover, #0000000d);\n}\n\n._72qoAq_detailItemOpen {\n background: var(--dsw-alias-bg-selected, #4f6ef714);\n}\n\n._72qoAq_detailItemName {\n flex-shrink: 0;\n font-size: 13px;\n font-weight: 600;\n}\n\n._72qoAq_detailItemDesc {\n min-width: 0;\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n font-size: 12px;\n overflow: hidden;\n}\n\n._72qoAq_detailChevron {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n flex-shrink: 0;\n}\n\n._72qoAq_skillContent {\n border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n max-height: 320px;\n color: var(--dsw-alias-label-primary, #1f2328);\n padding: 10px 12px;\n font-size: 13px;\n line-height: 20px;\n overflow-y: auto;\n}\n\n._72qoAq_progress, ._72qoAq_progressError {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n background: var(--dsw-alias-bg-layer-2, #7f7f7f0f);\n color: var(--dsw-alias-label-primary, #1f2328);\n border-radius: 8px;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n font-size: 13px;\n line-height: 20px;\n display: flex;\n}\n\n._72qoAq_progressError {\n border-color: var(--dsw-alias-danger, #e5484d);\n color: var(--dsw-alias-danger, #e5484d);\n}\n\n._72qoAq_progressSpin {\n border: 2px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-top-color: var(--dsw-alias-brand-primary, #4f6ef7);\n border-radius: 50%;\n flex-shrink: 0;\n width: 14px;\n height: 14px;\n animation: .8s linear infinite _72qoAq_dshApmSpin;\n}\n\n@keyframes _72qoAq_dshApmSpin {\n to {\n transform: rotate(360deg);\n }\n}\n\n._72qoAq_progressFail {\n flex-shrink: 0;\n font-size: 13px;\n}\n\n._72qoAq_progressText {\n overflow-wrap: anywhere;\n min-width: 0;\n}\n\n@media (width <= 720px) {\n ._72qoAq_pageView {\n padding: 14px;\n }\n\n ._72qoAq_titleRow {\n flex-wrap: wrap;\n }\n\n ._72qoAq_title {\n flex: 1 0 auto;\n }\n\n ._72qoAq_sub {\n white-space: normal;\n flex: 1 0 100%;\n order: 3;\n }\n\n ._72qoAq_searchGroup {\n flex: 1 0 100%;\n order: 4;\n }\n\n ._72qoAq_sourceTabsScroll {\n scrollbar-width: thin;\n padding-bottom: 2px;\n display: flex;\n overflow-x: auto;\n }\n\n ._72qoAq_srcTab, ._72qoAq_srcTabOn {\n flex: none;\n width: auto;\n min-width: 128px;\n }\n\n ._72qoAq_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n ._72qoAq_list ._72qoAq_cardTop, ._72qoAq_list ._72qoAq_cardActions {\n max-width: 100%;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._72qoAq_progressSpin, ._72qoAq_switchOn, ._72qoAq_switchOff, ._72qoAq_switchThumb {\n transition: none;\n animation: none;\n }\n}\n\n._72qoAq_surfaceToggles {\n flex-wrap: wrap;\n align-items: center;\n gap: 4px 14px;\n display: flex;\n}\n\n._72qoAq_surfaceToggle {\n color: var(--dsw-alias-text-2, #5a6070);\n cursor: pointer;\n user-select: none;\n align-items: center;\n gap: 5px;\n font-size: 12px;\n display: inline-flex;\n}\n\n._72qoAq_surfaceToggle input[type=\"checkbox\"] {\n accent-color: var(--dsw-alias-accent, #4b6bfb);\n margin: 0;\n}\n\n._72qoAq_mcpOverrideForm {\n border: 1px solid var(--dsw-alias-border, #d8dbe2);\n border-radius: 8px;\n flex-direction: column;\n gap: 8px;\n margin: 0 0 10px;\n padding: 10px;\n display: flex;\n}\n\n._72qoAq_mcpOverrideCheck {\n cursor: pointer;\n user-select: none;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n display: inline-flex;\n}\n\n._72qoAq_mcpOverrideInput {\n box-sizing: border-box;\n width: 100%;\n padding: 6px 8px;\n font-size: 12px;\n}\n\n._72qoAq_mcpOverrideArea {\n box-sizing: border-box;\n resize: vertical;\n width: 100%;\n padding: 6px 8px;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12px;\n}\n\n._72qoAq_mcpOverrideActions {\n gap: 8px;\n display: flex;\n}\n.vavGuW_toolbar {\n grid-template-columns: minmax(0, 1fr) 12px auto auto auto 8px auto;\n align-items: flex-end;\n gap: 0;\n min-width: 0;\n display: grid;\n}\n\n.vavGuW_filterGap, .vavGuW_viewGap {\n min-width: 0;\n}\n\n.vavGuW_search {\n box-sizing: border-box;\n align-items: center;\n width: 100%;\n min-width: 0;\n height: 36px;\n display: flex;\n}\n\n.vavGuW_search input {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n height: 36px;\n min-height: 36px;\n max-height: 36px;\n padding-top: 0;\n padding-bottom: 0;\n font-size: 12px;\n line-height: 20px;\n}\n\n.vavGuW_filter, .vavGuW_filterOn {\n min-width: 54px;\n height: 36px;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n font: inherit;\n white-space: nowrap;\n background: none;\n border: none;\n border-bottom: 2px solid #0000;\n justify-content: center;\n align-items: center;\n gap: 5px;\n padding: 7px 9px;\n font-size: 13px;\n display: inline-flex;\n}\n\n.vavGuW_filterOn {\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n border-bottom-color: var(--dsw-alias-brand-primary, #4f6ef7);\n font-weight: 600;\n}\n\n.vavGuW_filter svg, .vavGuW_filterOn svg, .vavGuW_viewSwitch svg {\n stroke: currentColor;\n stroke-width: 1.5px;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n.vavGuW_filterCount {\n font-variant-numeric: tabular-nums;\n}\n\n.vavGuW_viewSwitch {\n width: 34px;\n height: 36px;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n background: none;\n border: none;\n border-bottom: 2px solid #0000;\n justify-content: center;\n align-items: center;\n display: inline-flex;\n}\n\n.vavGuW_viewSwitch:hover {\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n.vavGuW_viewSwitch:focus-visible, .vavGuW_filter:focus-visible, .vavGuW_filterOn:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 2px;\n}\n\n@media (width <= 760px) {\n .vavGuW_toolbar {\n grid-template-columns: auto auto auto 8px auto;\n justify-content: end;\n overflow-x: auto;\n }\n\n .vavGuW_search {\n grid-column: 1 / -1;\n }\n\n .vavGuW_filterGap {\n display: none;\n }\n}\n.AUWlZW_surface {\n height: 100%;\n min-height: 0;\n max-height: 100%;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n.AUWlZW_header {\n flex: none;\n align-items: center;\n gap: 8px;\n padding: 4px 0 8px;\n display: flex;\n}\n\n.AUWlZW_title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n}\n\n.AUWlZW_subtitle {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n margin: 2px 0 0;\n font-size: 13px;\n line-height: 20px;\n}\n\n.AUWlZW_headerActions {\n align-items: center;\n gap: 8px;\n margin-left: auto;\n display: flex;\n}\n\n.AUWlZW_summary {\n color: var(--dsw-alias-label-secondary, #667085);\n white-space: nowrap;\n align-items: center;\n gap: 7px;\n font-size: 12px;\n display: inline-flex;\n}\n\n.AUWlZW_errorSummary {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n font-variant-numeric: tabular-nums;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n display: inline-flex;\n}\n\n.AUWlZW_summaryDotGreen, .AUWlZW_summaryDotRed {\n border-radius: 50%;\n width: 7px;\n height: 7px;\n}\n\n.AUWlZW_summaryDotGreen {\n background: var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_summaryDotRed {\n background: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_toolbar {\n flex: none;\n margin-bottom: 24px;\n}\n\n.AUWlZW_grid {\n scrollbar-gutter: stable;\n flex: 1;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n align-content: start;\n gap: 12px;\n min-width: 0;\n min-height: 0;\n padding-right: 4px;\n display: grid;\n overflow-y: auto;\n}\n\n.AUWlZW_list {\n scrollbar-gutter: stable;\n flex-direction: column;\n flex: 1;\n gap: 8px;\n min-width: 0;\n min-height: 0;\n padding-right: 4px;\n display: flex;\n overflow-y: auto;\n}\n\n.AUWlZW_list .AUWlZW_card {\n flex-flow: wrap;\n align-items: center;\n gap: 8px 14px;\n}\n\n.AUWlZW_list .AUWlZW_cardTop {\n flex: 0 260px;\n}\n\n.AUWlZW_list .AUWlZW_endpoint {\n -webkit-line-clamp: 1;\n flex: 200px;\n min-height: 0;\n}\n\n.AUWlZW_list .AUWlZW_meta {\n flex: 0 auto;\n}\n\n.AUWlZW_list .AUWlZW_cardReason {\n flex-basis: 100%;\n}\n\n.AUWlZW_card {\n min-width: 0;\n min-height: 0;\n color: inherit;\n background: var(--dsw-alias-bg-layer-1, #fff);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n cursor: pointer;\n font: inherit;\n text-align: left;\n border-radius: 12px;\n flex-direction: column;\n gap: 8px;\n padding: 12px 14px;\n display: flex;\n}\n\n.AUWlZW_card:hover {\n border-color: var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-bg-hover, #00000009);\n}\n\n.AUWlZW_card:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 2px;\n}\n\n.AUWlZW_cardTop {\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.AUWlZW_statusDot {\n background: var(--dsw-alias-state-success-primary, #16a34a);\n border-radius: 50%;\n flex: none;\n width: 7px;\n height: 7px;\n}\n\n.AUWlZW_statusconnected {\n background: var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_statusdegraded {\n background: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_statusfailed {\n background: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_statusdisabled {\n background: var(--dsw-alias-label-tertiary, #98a2b3);\n}\n\n.AUWlZW_service {\n flex: 1;\n min-width: 0;\n}\n\n.AUWlZW_name {\n color: var(--dsw-alias-label-primary, #1f2328);\n text-overflow: ellipsis;\n white-space: nowrap;\n font: 600 13px / 22px ui-monospace, Menlo, Consolas, monospace;\n display: block;\n overflow: hidden;\n}\n\n.AUWlZW_endpoint {\n min-height: 36px;\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n -webkit-line-clamp: 2;\n overflow-wrap: anywhere;\n -webkit-box-orient: vertical;\n margin: 0;\n font: 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n display: -webkit-box;\n overflow: hidden;\n}\n\n.AUWlZW_meta {\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n.AUWlZW_sourcePlugin, .AUWlZW_sourceDirect, .AUWlZW_transport, .AUWlZW_toolCount {\n min-width: 0;\n max-width: 100%;\n color: var(--dsw-alias-label-secondary, #6b7280);\n border: 1px solid var(--dsw-alias-border-l3, #d9dde3);\n text-overflow: ellipsis;\n white-space: nowrap;\n border-radius: 4px;\n align-items: center;\n gap: 5px;\n padding: 1px 6px;\n font-size: 12px;\n line-height: 18px;\n display: inline-flex;\n}\n\n.AUWlZW_sourcePlugin svg, .AUWlZW_sourceDirect svg {\n color: currentColor;\n stroke: currentColor;\n stroke-width: 1.35px;\n stroke-linecap: round;\n stroke-linejoin: round;\n flex: none;\n width: 14px;\n height: 14px;\n}\n\n.AUWlZW_transport {\n font-family: ui-monospace, Menlo, Consolas, monospace;\n}\n\n.AUWlZW_toolCount {\n color: var(--dsw-alias-label-primary, #1f2328);\n flex: none;\n font-weight: 600;\n}\n\n.AUWlZW_cardReason {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n overflow-wrap: anywhere;\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n}\n\n.AUWlZW_state, .AUWlZW_detailState {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n white-space: nowrap;\n align-items: center;\n gap: 5px;\n font-size: 11px;\n display: inline-flex;\n}\n\n.AUWlZW_state:before, .AUWlZW_detailState:before {\n content: \"\";\n background: currentColor;\n border-radius: 50%;\n width: 6px;\n height: 6px;\n}\n\n.AUWlZW_stateconnected, .AUWlZW_detailStateconnected {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_statedegraded, .AUWlZW_detailStatedegraded {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_statefailed, .AUWlZW_detailStatefailed {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_statedisabled, .AUWlZW_detailStatedisabled {\n color: var(--dsw-alias-label-tertiary, #98a2b3);\n}\n\n.AUWlZW_chevron {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 18px;\n}\n\n.AUWlZW_empty, .AUWlZW_detailEmpty {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-align: center;\n padding: 24px;\n font-size: 12px;\n}\n\n.AUWlZW_error {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n align-items: center;\n gap: 8px;\n margin: 16px 0;\n font-size: 12px;\n display: flex;\n}\n\n.AUWlZW_boundary {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border-left: 2px solid var(--dsw-alias-border-l3, #d9dde3);\n margin: 10px 0 0;\n padding: 9px 10px;\n font-size: 11px;\n line-height: 17px;\n}\n\n.AUWlZW_detailDialog {\n width: min(720px, 94vw);\n}\n\n.AUWlZW_detailBody {\n max-height: 72vh;\n overflow-y: auto;\n}\n\n.AUWlZW_modalFooter {\n justify-content: flex-end;\n width: 100%;\n display: flex;\n}\n\n.AUWlZW_detail {\n flex-direction: column;\n gap: 16px;\n display: flex;\n}\n\n.AUWlZW_detailMeta {\n flex-wrap: wrap;\n gap: 6px;\n display: flex;\n}\n\n.AUWlZW_reason {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-bg-error, #dc26260f);\n border-left: 2px solid;\n padding: 9px 10px;\n font-size: 11px;\n line-height: 16px;\n}\n\n.AUWlZW_detailSection {\n flex-direction: column;\n gap: 7px;\n display: flex;\n}\n\n.AUWlZW_detailHead {\n color: var(--dsw-alias-label-secondary, #667085);\n border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n margin: 0;\n padding-bottom: 5px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.AUWlZW_config {\n max-height: 220px;\n color: var(--dsw-alias-label-primary, #344054);\n background: var(--dsw-alias-bg-layer-2, #f6f8fc);\n border: 1px solid var(--dsw-alias-border-l1, #e2e7ef);\n white-space: pre-wrap;\n word-break: break-word;\n border-radius: 7px;\n margin: 0;\n padding: 10px;\n font: 11px / 17px ui-monospace, Menlo, Consolas, monospace;\n overflow: auto;\n}\n\n.AUWlZW_toolList {\n flex-direction: column;\n display: flex;\n}\n\n.AUWlZW_tool {\n border-bottom: 1px solid var(--dsw-alias-border-l1, #eef1f5);\n grid-template-columns: 26px minmax(120px, auto) minmax(0, 1fr);\n align-items: center;\n gap: 8px;\n padding: 7px 0;\n display: grid;\n}\n\n.AUWlZW_tool:last-child {\n border-bottom: none;\n}\n\n.AUWlZW_toolIndex {\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n font: 10px / 16px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.AUWlZW_toolName {\n color: var(--dsw-alias-label-primary, #1f2328);\n text-overflow: ellipsis;\n white-space: nowrap;\n font: 11px / 16px ui-monospace, Menlo, Consolas, monospace;\n overflow: hidden;\n}\n\n.AUWlZW_toolDescription {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 10px;\n overflow: hidden;\n}\n\n@media (width <= 760px) {\n .AUWlZW_header, .AUWlZW_toolbar {\n padding-left: 0;\n padding-right: 0;\n }\n\n .AUWlZW_header {\n flex-direction: column;\n }\n\n .AUWlZW_headerActions {\n justify-content: space-between;\n width: 100%;\n margin-left: 0;\n }\n\n .AUWlZW_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .AUWlZW_list .AUWlZW_cardTop, .AUWlZW_list .AUWlZW_meta {\n max-width: 100%;\n }\n\n .AUWlZW_tool {\n grid-template-columns: 26px minmax(0, 1fr);\n }\n\n .AUWlZW_toolDescription {\n display: none;\n }\n}\n";document.head.appendChild(s);}})();
|
|
5
|
+
(function(){if(typeof document!=="undefined"){var s=document.createElement("style");s.setAttribute("data-dsh-client","dsh-agent-plugins-market");s.textContent="._72qoAq_market {\n min-width: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n gap: 24px;\n display: flex;\n}\n\n._72qoAq_pageMode {\n width: 100%;\n min-width: 0;\n height: 100%;\n min-height: 0;\n}\n\n._72qoAq_marketControls {\n flex-direction: column;\n gap: 8px;\n min-height: 0;\n display: flex;\n}\n\n._72qoAq_mcpSurface {\n flex: 1;\n min-height: 0;\n display: flex;\n}\n\n._72qoAq_surfaceSwitch {\n border: 1px solid var(--dsw-alias-border-l2, #d4dce8);\n background: var(--dsw-alias-bg-layer-1, #fff);\n height: 26px;\n color: var(--dsw-alias-brand-primary, #4966f5);\n cursor: pointer;\n border-radius: 7px;\n flex: none;\n align-self: center;\n padding: 0 10px;\n font-size: 11px;\n}\n\n._72qoAq_surfaceSwitch:hover {\n background: var(--dsw-alias-state-business-tertiary, #e4edfd);\n}\n\nhtml[data-dsh-agent-plugins-market-page] [data-pane=\"conversation\"], html[data-dsh-agent-plugins-market-page] [class*=\"centerCol\"] {\n position: relative;\n}\n\n._72qoAq_pageView {\n z-index: 60;\n background: var(--dsw-alias-bg-base, #f7f8fa);\n min-width: 0;\n min-height: 0;\n padding: 20px 24px;\n display: none;\n position: absolute;\n inset: 0;\n overflow: hidden;\n}\n\nhtml[data-dsh-agent-plugins-market-page] ._72qoAq_pageView {\n display: flex;\n}\n\nhtml[data-dsh-agent-plugins-market-page] [data-pane=\"conversation\"] > :not([data-dsh-agent-plugins-market-page-view]), html[data-dsh-agent-plugins-market-page] [class*=\"centerCol\"] > :not([data-dsh-agent-plugins-market-page-view]) {\n display: none !important;\n}\n\n._72qoAq_pageEntry {\n width: 100%;\n min-height: 32px;\n color: var(--dsw-alias-label-primary, #1f2328);\n cursor: pointer;\n font: inherit;\n text-align: left;\n background: none;\n border: none;\n border-radius: 8px;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n font-size: 13px;\n line-height: 20px;\n display: flex;\n}\n\n._72qoAq_pageEntry:hover {\n background: var(--dsw-alias-interactive-bg-hover, #2631480f);\n}\n\n._72qoAq_pageEntry:active {\n background: var(--dsw-alias-interactive-bg-active, #2631481a);\n}\n\n._72qoAq_pageEntry svg {\n color: var(--dsw-alias-label-secondary, #6b7280);\n flex-shrink: 0;\n}\n\n._72qoAq_pageEntry span {\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n overflow: hidden;\n}\n\n[data-dsh-frame][data-sidebar-collapsed] ._72qoAq_pageEntry {\n justify-content: center;\n padding-inline: 0;\n}\n\n[data-dsh-frame][data-sidebar-collapsed] ._72qoAq_pageEntry span {\n display: none;\n}\n\n._72qoAq_pageEntry:focus-visible, ._72qoAq_srcTabMain:focus-visible, ._72qoAq_srcTabEdit:focus-visible, ._72qoAq_srcTabDel:focus-visible, ._72qoAq_seg:focus-visible, ._72qoAq_segOn:focus-visible, ._72qoAq_detailItemRow:focus-visible, ._72qoAq_detailItemOpen:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 2px;\n}\n\n._72qoAq_header {\n flex-direction: column;\n flex-shrink: 0;\n gap: 8px;\n display: flex;\n}\n\n._72qoAq_titleRow {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n._72qoAq_title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n}\n\n._72qoAq_sub {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n align-items: center;\n gap: 8px;\n min-width: 0;\n margin: 0;\n font-size: 13px;\n line-height: 20px;\n display: flex;\n overflow: hidden;\n}\n\n._72qoAq_spacer {\n flex: 1;\n}\n\n._72qoAq_searchGroup {\n align-items: center;\n gap: 2px;\n display: flex;\n}\n\n._72qoAq_body {\n flex: 1;\n align-items: flex-start;\n gap: 20px;\n min-height: 0;\n display: flex;\n}\n\n._72qoAq_sourceTabsRow {\n padding: 0;\n display: block;\n}\n\n._72qoAq_sourceTabsScroll {\n grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));\n gap: 4px;\n display: grid;\n}\n\n._72qoAq_unmanagedRow {\n color: var(--dsw-alias-label-secondary, #57606a);\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n margin-top: 6px;\n font-size: 12px;\n display: flex;\n}\n\n._72qoAq_unmanagedLabel {\n flex-shrink: 0;\n}\n\n._72qoAq_unmanagedChip {\n border: 1px dashed var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-bg-layer-1, #fff);\n border-radius: 999px;\n align-items: center;\n gap: 2px;\n max-width: 220px;\n height: 22px;\n padding: 0 4px 0 8px;\n display: inline-flex;\n}\n\n._72qoAq_unmanagedChipName {\n white-space: nowrap;\n text-overflow: ellipsis;\n font-size: 12px;\n overflow: hidden;\n}\n\n._72qoAq_unmanagedAdopt {\n font: inherit;\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n cursor: pointer;\n background: none;\n border: none;\n flex-shrink: 0;\n padding: 0 4px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_unmanagedAdopt:disabled {\n cursor: default;\n opacity: .5;\n}\n\n._72qoAq_srcTabEdit {\n font: inherit;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n background: none;\n border: none;\n flex-shrink: 0;\n padding: 2px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_srcTabEdit:hover {\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n._72qoAq_srcTabOn ._72qoAq_srcTabEdit, ._72qoAq_srcTabOn ._72qoAq_srcTabEdit:hover {\n color: var(--dsw-alias-label-primary-foreground, #fff);\n}\n\n._72qoAq_srcTab, ._72qoAq_srcTabOn {\n border: 1px solid var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-bg-layer-1, #fff);\n border-radius: 999px;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 24px;\n display: inline-flex;\n overflow: hidden;\n}\n\n._72qoAq_srcTabMain {\n font: inherit;\n color: var(--dsw-alias-label-primary, #1f2328);\n cursor: pointer;\n white-space: nowrap;\n text-overflow: ellipsis;\n background: none;\n border: none;\n flex: 1;\n min-width: 0;\n padding: 2px 2px 2px 10px;\n font-size: 12px;\n line-height: 18px;\n overflow: hidden;\n}\n\n._72qoAq_srcTabMain:hover {\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n._72qoAq_srcTabOn {\n background: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);\n border-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);\n}\n\n._72qoAq_srcTabOn ._72qoAq_srcTabMain {\n color: var(--dsw-alias-label-primary-foreground, #fff);\n font-weight: 600;\n}\n\n._72qoAq_srcTabDel {\n font: inherit;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n background: none;\n border: none;\n flex-shrink: 0;\n padding: 2px 8px 2px 2px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_srcTabDel:hover {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n._72qoAq_srcTabOn ._72qoAq_srcTabDel, ._72qoAq_srcTabOn ._72qoAq_srcTabDel:hover {\n color: var(--dsw-alias-label-primary-foreground, #fff);\n}\n\n._72qoAq_grid {\n flex: 1;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n align-content: start;\n gap: 12px;\n min-width: 0;\n min-height: 0;\n display: grid;\n}\n\n._72qoAq_pageMode ._72qoAq_grid {\n scrollbar-gutter: stable;\n padding-right: 4px;\n overflow-y: auto;\n}\n\n._72qoAq_list {\n flex-direction: column;\n flex: 1;\n gap: 8px;\n min-width: 0;\n min-height: 0;\n display: flex;\n}\n\n._72qoAq_pageMode ._72qoAq_list {\n scrollbar-gutter: stable;\n padding-right: 4px;\n overflow-y: auto;\n}\n\n._72qoAq_list ._72qoAq_card {\n flex-flow: wrap;\n align-items: center;\n gap: 8px 14px;\n}\n\n._72qoAq_list ._72qoAq_cardTop {\n flex: none;\n}\n\n._72qoAq_list ._72qoAq_cardDesc {\n flex: 1;\n min-width: 200px;\n min-height: 0;\n max-height: 18px;\n overflow: hidden;\n}\n\n._72qoAq_list ._72qoAq_cardActions {\n flex: none;\n}\n\n._72qoAq_list ._72qoAq_meta, ._72qoAq_list ._72qoAq_tagRow {\n flex-basis: 100%;\n}\n\n._72qoAq_empty {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-align: center;\n grid-column: 1 / -1;\n padding: 48px 0;\n font-size: 13px;\n}\n\n._72qoAq_card {\n background: var(--dsw-alias-bg-layer-1, #fff);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n cursor: pointer;\n border-radius: 12px;\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n padding: 12px 14px;\n transition: border-color .15s, background .15s, box-shadow .15s;\n display: flex;\n}\n\n._72qoAq_card:hover {\n border-color: var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-interactive-bg-hover, #2631480f);\n box-shadow: 0 1px 4px #1018280f;\n}\n\n._72qoAq_cardOn {\n border-left: 3px solid var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n._72qoAq_cardMuted {\n border-left: 3px solid var(--dsw-alias-label-tertiary, #98a2b3);\n}\n\n._72qoAq_cardTop {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n._72qoAq_cardTitle {\n flex: 1;\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_cardName {\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n font-weight: 600;\n line-height: 22px;\n overflow: hidden;\n}\n\n._72qoAq_version {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-variant-numeric: tabular-nums;\n flex-shrink: 0;\n font-size: 12px;\n line-height: 20px;\n}\n\n._72qoAq_cardActions {\n flex-shrink: 0;\n align-items: center;\n gap: 4px;\n display: flex;\n}\n\n._72qoAq_iconBtn {\n cursor: pointer;\n width: 26px;\n height: 26px;\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n background: none;\n border: none;\n border-radius: 999px;\n justify-content: center;\n align-items: center;\n padding: 0;\n transition: background .15s, color .15s;\n display: inline-flex;\n}\n\n._72qoAq_iconBtn svg {\n fill: none;\n stroke: currentColor;\n stroke-width: 1.8px;\n stroke-linecap: round;\n stroke-linejoin: round;\n width: 15px;\n height: 15px;\n}\n\n._72qoAq_iconBtn:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, #2631480f);\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n._72qoAq_iconBtn:active:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-active, #2631481a);\n}\n\n._72qoAq_iconBtn:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 1px;\n}\n\n._72qoAq_iconBtn:disabled {\n cursor: default;\n opacity: .4;\n}\n\n._72qoAq_iconBtnDanger:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n color: var(--dsw-alias-state-error-primary, #ec1313);\n}\n\n._72qoAq_switchOn, ._72qoAq_switchOff {\n cursor: pointer;\n border: none;\n border-radius: 999px;\n flex-shrink: 0;\n width: 38px;\n height: 22px;\n padding: 0;\n transition: background-color .15s;\n position: relative;\n}\n\n._72qoAq_switchOn {\n background: var(--dsw-alias-button-primary-fill, var(--dsw-alias-brand-primary, #4f6ef7));\n}\n\n._72qoAq_switchOff {\n background: var(--dsw-alias-label-dimmed, #e1e5ee);\n}\n\n._72qoAq_switchOn:disabled, ._72qoAq_switchOff:disabled {\n opacity: .6;\n cursor: default;\n}\n\n._72qoAq_switchThumb {\n pointer-events: none;\n background: #fff;\n border-radius: 50%;\n width: 16px;\n height: 16px;\n transition: left .15s;\n position: absolute;\n top: 3px;\n left: 3px;\n box-shadow: 0 1px 2px #0003;\n}\n\n._72qoAq_switchOn ._72qoAq_switchThumb {\n left: 19px;\n}\n\n._72qoAq_desc {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n max-height: 36px;\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n overflow: hidden;\n}\n\n._72qoAq_meta, ._72qoAq_tagRow {\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n._72qoAq_src {\n color: var(--dsw-alias-label-secondary, #9ca3af);\n font-size: 12px;\n text-decoration: none;\n}\n\n._72qoAq_tag {\n border: 1px solid var(--dsw-alias-border-l3, #d9dde3);\n color: var(--dsw-alias-label-secondary, #6b7280);\n border-radius: 4px;\n flex-shrink: 0;\n padding: 1px 6px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_okState {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n white-space: nowrap;\n font-size: 12px;\n font-weight: 600;\n}\n\n._72qoAq_warnLine {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n cursor: help;\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n}\n\n._72qoAq_modalFooter {\n justify-content: flex-end;\n gap: 8px;\n width: 100%;\n display: flex;\n}\n\n._72qoAq_modalFooterLeft {\n gap: 8px;\n margin-right: auto;\n display: flex;\n}\n\n._72qoAq_editorDialog {\n width: min(500px, 92vw);\n}\n\n._72qoAq_installConfirmBody {\n flex-direction: column;\n gap: 10px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_installConfirmSuite {\n color: var(--dsw-alias-label-primary, #111827);\n font-weight: 600;\n}\n\n._72qoAq_installConfirmMeta {\n color: var(--dsw-alias-label-secondary, #4b5563);\n font-size: 12px;\n}\n\n._72qoAq_installConfirmCommit {\n color: var(--dsw-alias-label-secondary, #4b5563);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12px;\n}\n\n._72qoAq_installConfirmTags {\n flex-wrap: wrap;\n gap: 6px;\n display: flex;\n}\n\n._72qoAq_installConfirmWarn {\n color: var(--dsw-alias-state-warn-label, #dd8629);\n border: 1px solid var(--dsw-alias-state-warn-label, #dd8629);\n border-radius: 8px;\n padding: 8px 10px;\n font-size: 12px;\n}\n\n._72qoAq_editorForm {\n flex-direction: column;\n gap: 14px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_modeRow {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n background: var(--dsw-alias-bg-layer-2, #f3f4f6);\n border-radius: 10px;\n align-self: flex-start;\n gap: 6px;\n padding: 3px;\n display: flex;\n}\n\n._72qoAq_seg, ._72qoAq_segOn {\n font: inherit;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 8px;\n padding: 5px 14px;\n font-size: 13px;\n line-height: 20px;\n}\n\n._72qoAq_segOn {\n background: var(--dsw-alias-bg-layer-1, #fff);\n color: var(--dsw-alias-label-primary, #1f2328);\n font-weight: 600;\n box-shadow: 0 1px 2px #00000014;\n}\n\n._72qoAq_fieldGroup {\n flex-direction: column;\n gap: 5px;\n display: flex;\n}\n\n._72qoAq_fieldLabel {\n color: var(--dsw-alias-label-secondary, #6b7280);\n font-size: 12px;\n font-weight: 600;\n}\n\n._72qoAq_fieldHint {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 12px;\n line-height: 16px;\n}\n\n._72qoAq_staticId {\n border: 1px dashed var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-bg-layer-2, #f3f4f6);\n border-radius: 8px;\n align-items: center;\n gap: 8px;\n padding: 7px 10px;\n display: flex;\n}\n\n._72qoAq_staticIdValue {\n color: var(--dsw-alias-label-primary, #1f2328);\n font-size: 13px;\n font-weight: 600;\n}\n\n._72qoAq_detailDialog {\n width: min(800px, 94vw);\n}\n\n._72qoAq_detailBody {\n flex-direction: column;\n gap: 14px;\n max-height: 78vh;\n display: flex;\n overflow-y: auto;\n}\n\n._72qoAq_detailSections {\n flex-direction: column;\n gap: 14px;\n display: flex;\n}\n\n._72qoAq_detailSection {\n flex-direction: column;\n gap: 6px;\n display: flex;\n}\n\n._72qoAq_detailHead {\n color: var(--dsw-alias-label-secondary, #6b7280);\n border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n margin: 0;\n padding-bottom: 4px;\n font-size: 13px;\n font-weight: 600;\n}\n\n._72qoAq_detailGrid {\n grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n gap: 6px 14px;\n display: grid;\n}\n\n._72qoAq_detailCell {\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_detailKey {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 12px;\n}\n\n._72qoAq_detailValue {\n color: var(--dsw-alias-label-primary, #1f2328);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n overflow: hidden;\n}\n\n._72qoAq_detailDesc {\n color: var(--dsw-alias-label-secondary, #6b7280);\n margin: 4px 0 0;\n font-size: 13px;\n line-height: 20px;\n}\n\n._72qoAq_mono {\n word-break: break-all;\n white-space: pre-wrap;\n color: var(--dsw-alias-label-primary, #1f2328);\n margin: 0;\n font-family: ui-monospace, Menlo, Consolas, monospace;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_detailItem {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 8px;\n flex-direction: column;\n display: flex;\n overflow: hidden;\n}\n\n._72qoAq_detailItemRow, ._72qoAq_detailItemOpen {\n width: 100%;\n font: inherit;\n text-align: left;\n cursor: pointer;\n color: var(--dsw-alias-label-primary, #1f2328);\n background: none;\n border: none;\n align-items: center;\n gap: 8px;\n padding: 7px 10px;\n display: flex;\n}\n\n._72qoAq_detailItemRow:hover {\n background: var(--dsw-alias-interactive-bg-hover, #2631480f);\n}\n\n._72qoAq_detailItemOpen {\n background: var(--dsw-alias-state-business-tertiary, #e4edfd);\n}\n\n._72qoAq_detailItemName {\n flex-shrink: 0;\n font-size: 13px;\n font-weight: 600;\n}\n\n._72qoAq_detailItemDesc {\n min-width: 0;\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n font-size: 12px;\n overflow: hidden;\n}\n\n._72qoAq_detailChevron {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n flex-shrink: 0;\n}\n\n._72qoAq_skillContent {\n border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n max-height: 320px;\n color: var(--dsw-alias-label-primary, #1f2328);\n padding: 10px 12px;\n font-size: 13px;\n line-height: 20px;\n overflow-y: auto;\n}\n\n._72qoAq_progress, ._72qoAq_progressError {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n background: var(--dsw-alias-bg-layer-2, #7f7f7f0f);\n color: var(--dsw-alias-label-primary, #1f2328);\n border-radius: 8px;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n font-size: 13px;\n line-height: 20px;\n display: flex;\n}\n\n._72qoAq_progressError {\n border-color: var(--dsw-alias-state-error-primary, #ec1313);\n color: var(--dsw-alias-state-error-primary, #ec1313);\n}\n\n._72qoAq_progressSpin {\n border: 2px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-top-color: var(--dsw-alias-brand-primary, #4f6ef7);\n border-radius: 50%;\n flex-shrink: 0;\n width: 14px;\n height: 14px;\n animation: .8s linear infinite _72qoAq_dshApmSpin;\n}\n\n@keyframes _72qoAq_dshApmSpin {\n to {\n transform: rotate(360deg);\n }\n}\n\n._72qoAq_progressFail {\n flex-shrink: 0;\n font-size: 13px;\n}\n\n._72qoAq_progressText {\n overflow-wrap: anywhere;\n min-width: 0;\n}\n\n@media (width <= 720px) {\n ._72qoAq_pageView {\n padding: 14px;\n }\n\n ._72qoAq_titleRow {\n flex-wrap: wrap;\n }\n\n ._72qoAq_title {\n flex: 1 0 auto;\n }\n\n ._72qoAq_sub {\n white-space: normal;\n flex: 1 0 100%;\n order: 3;\n }\n\n ._72qoAq_searchGroup {\n flex: 1 0 100%;\n order: 4;\n }\n\n ._72qoAq_sourceTabsScroll {\n scrollbar-width: thin;\n padding-bottom: 2px;\n display: flex;\n overflow-x: auto;\n }\n\n ._72qoAq_srcTab, ._72qoAq_srcTabOn {\n flex: none;\n width: auto;\n min-width: 128px;\n }\n\n ._72qoAq_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n ._72qoAq_list ._72qoAq_cardTop, ._72qoAq_list ._72qoAq_cardActions {\n max-width: 100%;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._72qoAq_progressSpin, ._72qoAq_switchOn, ._72qoAq_switchOff, ._72qoAq_switchThumb {\n transition: none;\n animation: none;\n }\n}\n\n._72qoAq_surfaceToggles {\n flex-wrap: wrap;\n align-items: center;\n gap: 4px 14px;\n display: flex;\n}\n\n._72qoAq_surfaceToggle {\n color: var(--dsw-alias-label-secondary, #61666b);\n cursor: pointer;\n user-select: none;\n align-items: center;\n gap: 5px;\n font-size: 12px;\n display: inline-flex;\n}\n\n._72qoAq_surfaceToggle input[type=\"checkbox\"] {\n accent-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);\n margin: 0;\n}\n\n._72qoAq_mcpOverrideForm, ._72qoAq_mcpCredentialForm {\n border: 1px solid var(--dsw-alias-border-l2, #0000001a);\n border-radius: 8px;\n flex-direction: column;\n gap: 8px;\n margin: 0 0 10px;\n padding: 10px;\n display: flex;\n}\n\n._72qoAq_mcpCredentialRow {\n flex-direction: column;\n gap: 5px;\n display: flex;\n}\n\n._72qoAq_mcpCredentialControls, ._72qoAq_mcpCredentialEditor {\n flex-direction: column;\n gap: 6px;\n display: flex;\n}\n\n._72qoAq_mcpOverrideCheck {\n cursor: pointer;\n user-select: none;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n display: inline-flex;\n}\n\n._72qoAq_mcpOverrideInput {\n box-sizing: border-box;\n width: 100%;\n padding: 6px 8px;\n font-size: 12px;\n}\n\n._72qoAq_mcpOverrideArea {\n box-sizing: border-box;\n resize: vertical;\n width: 100%;\n padding: 6px 8px;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12px;\n}\n\n._72qoAq_mcpOverrideActions {\n gap: 8px;\n display: flex;\n}\n\n._72qoAq_backendBlock {\n border: 1px solid var(--dsw-alias-border-l2, #0000001a);\n opacity: 1;\n border-radius: 10px;\n flex-direction: column;\n gap: 6px;\n padding: 12px 14px;\n display: flex;\n}\n\n._72qoAq_backendBlock[data-busy=\"true\"] {\n opacity: .6;\n pointer-events: none;\n}\n\n._72qoAq_backendRow {\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n display: flex;\n}\n\n._72qoAq_backendTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n}\n\n._72qoAq_backendCurrent {\n margin: 0;\n font-size: 12px;\n font-weight: 500;\n}\n\n._72qoAq_backendHint {\n opacity: .7;\n margin: 0;\n font-size: 11px;\n}\n\n._72qoAq_backendVersion {\n opacity: .55;\n margin: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n}\n\n._72qoAq_pluginCard {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n background: var(--dsw-alias-bg-layer-3, #fff);\n border-radius: 12px;\n list-style: none;\n transition: border-color .16s, background .16s;\n}\n\n._72qoAq_pluginCard:hover {\n border-color: var(--dsw-alias-label-dimmed, #c8ccd4);\n}\n\n._72qoAq_pluginCardOpen {\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border-color: var(--dsw-alias-label-dimmed, #c8ccd4);\n}\n\n._72qoAq_pluginCard[data-busy=\"true\"] {\n opacity: .6;\n pointer-events: none;\n}\n\n._72qoAq_pluginCardHeader {\n appearance: none;\n width: 100%;\n font: inherit;\n color: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n border-radius: 12px;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n display: flex;\n}\n\n._72qoAq_pluginCardHeader:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: -2px;\n}\n\n._72qoAq_pluginCardBody {\n border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n flex-direction: column;\n gap: 8px;\n margin: 0 16px;\n padding: 4px 0 8px;\n display: flex;\n}\n\n._72qoAq_pluginCardRow {\n justify-content: space-between;\n align-items: center;\n gap: 16px;\n padding: 8px 0 4px;\n display: flex;\n}\n\n._72qoAq_pluginCardText {\n flex-direction: column;\n flex: 1;\n gap: 4px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_pluginCardTitle {\n color: var(--dsw-alias-label-primary, #1f2328);\n font-size: 15px;\n font-weight: 600;\n line-height: 1.4;\n}\n\n._72qoAq_pluginCardDesc {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 13px;\n line-height: 1.5;\n}\n\n._72qoAq_pluginCardRowLabel {\n font-size: 13px;\n font-weight: 500;\n line-height: 20px;\n}\n\n._72qoAq_pluginCardError {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n}\n\n._72qoAq_pluginChevron {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n flex: none;\n transition: transform .16s;\n display: inline-flex;\n}\n\n._72qoAq_pluginChevronOpen {\n transform: rotate(180deg);\n}\n\n._72qoAq_regionSeg {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 8px;\n flex: none;\n gap: 2px;\n padding: 2px;\n display: inline-flex;\n}\n\n._72qoAq_regionSegBtn {\n appearance: none;\n font: inherit;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 6px;\n padding: 3px 10px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_regionSegOn {\n appearance: none;\n font: inherit;\n cursor: pointer;\n background: var(--dsw-alias-bg-layer-2, #eef0f4);\n color: var(--dsw-alias-label-primary, #1f2328);\n border: none;\n border-radius: 6px;\n padding: 3px 10px;\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n}\n\n._72qoAq_regionSegBtn:disabled, ._72qoAq_regionSegOn:disabled {\n cursor: default;\n opacity: .5;\n}\n.G2mDja_form {\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 10px;\n flex-direction: column;\n gap: 10px;\n padding: 12px 14px;\n display: flex;\n}\n\n.G2mDja_head {\n color: var(--dsw-alias-label-secondary, #667085);\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n}\n\n.G2mDja_error {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n overflow-wrap: anywhere;\n border-radius: 8px;\n padding: 8px 10px;\n font-size: 12px;\n line-height: 18px;\n}\n\n.G2mDja_row {\n border-top: 1px solid var(--dsw-alias-border-l1, #eef1f5);\n flex-direction: column;\n gap: 6px;\n min-width: 0;\n padding-top: 8px;\n display: flex;\n}\n\n.G2mDja_ref {\n color: var(--dsw-alias-label-primary, #1f2328);\n font: 600 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.G2mDja_controls {\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.G2mDja_facts {\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n.G2mDja_factOk, .G2mDja_factMiss {\n border-radius: 999px;\n padding: 1px 8px;\n font-size: 11px;\n line-height: 17px;\n}\n\n.G2mDja_factOk {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n background: var(--dsw-alias-state-success-tertiary, #e6faed);\n}\n\n.G2mDja_factMiss {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n background: var(--dsw-alias-state-warn-tertiary, #fef5e7);\n}\n\n.G2mDja_note {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 11px;\n line-height: 17px;\n}\n\n.G2mDja_editor {\n flex-direction: column;\n gap: 8px;\n display: flex;\n}\n\n.G2mDja_input {\n box-sizing: border-box;\n width: 100%;\n color: var(--dsw-alias-label-primary, #1f2328);\n background: var(--dsw-alias-bg-layer-1, #fff);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 8px;\n padding: 7px 10px;\n font-size: 12px;\n}\n\n.G2mDja_input:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 1px;\n}\n\n.G2mDja_actions {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n.vavGuW_toolbar {\n align-items: flex-end;\n gap: 6px;\n min-width: 0;\n display: flex;\n}\n\n.vavGuW_filterGap, .vavGuW_viewGap {\n flex: 1 0 12px;\n min-width: 0;\n}\n\n.vavGuW_search {\n box-sizing: border-box;\n flex: 240px;\n align-items: center;\n min-width: 0;\n height: 36px;\n display: flex;\n}\n\n.vavGuW_search input {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n height: 36px;\n min-height: 36px;\n max-height: 36px;\n padding-top: 0;\n padding-bottom: 0;\n font-size: 12px;\n line-height: 20px;\n}\n\n.vavGuW_filter, .vavGuW_filterOn {\n min-width: 54px;\n height: 36px;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n font: inherit;\n white-space: nowrap;\n background: none;\n border: none;\n border-bottom: 2px solid #0000;\n flex: none;\n justify-content: center;\n align-items: center;\n gap: 5px;\n padding: 7px 9px;\n font-size: 13px;\n display: inline-flex;\n}\n\n.vavGuW_filterOn {\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n border-bottom-color: var(--dsw-alias-brand-primary, #4f6ef7);\n font-weight: 600;\n}\n\n.vavGuW_filter svg, .vavGuW_filterOn svg, .vavGuW_viewSwitch svg {\n stroke: currentColor;\n stroke-width: 1.5px;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n.vavGuW_filterCount {\n font-variant-numeric: tabular-nums;\n}\n\n.vavGuW_viewSwitch {\n width: 34px;\n height: 36px;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n background: none;\n border: none;\n border-bottom: 2px solid #0000;\n flex: none;\n justify-content: center;\n align-items: center;\n display: inline-flex;\n}\n\n.vavGuW_viewSwitch:hover {\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n.vavGuW_viewSwitch:focus-visible, .vavGuW_filter:focus-visible, .vavGuW_filterOn:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 2px;\n}\n\n@media (width <= 760px) {\n .vavGuW_toolbar {\n flex-wrap: wrap;\n justify-content: flex-end;\n }\n\n .vavGuW_search {\n flex-basis: 100%;\n }\n\n .vavGuW_filterGap {\n display: none;\n }\n}\n.AUWlZW_surface {\n min-width: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n display: flex;\n}\n\n.AUWlZW_header {\n flex: none;\n align-items: center;\n gap: 8px;\n padding: 4px 0 8px;\n display: flex;\n}\n\n.AUWlZW_title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n}\n\n.AUWlZW_subtitle {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n margin: 2px 0 0;\n font-size: 13px;\n line-height: 20px;\n}\n\n.AUWlZW_headerActions {\n align-items: center;\n gap: 8px;\n margin-left: auto;\n display: flex;\n}\n\n.AUWlZW_summary {\n color: var(--dsw-alias-label-secondary, #667085);\n white-space: nowrap;\n align-items: center;\n gap: 7px;\n font-size: 12px;\n display: inline-flex;\n}\n\n.AUWlZW_errorSummary {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n font-variant-numeric: tabular-nums;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n display: inline-flex;\n}\n\n.AUWlZW_summaryBar {\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 10px;\n flex-wrap: wrap;\n flex: none;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n display: flex;\n}\n\n.AUWlZW_summaryChip {\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n border-radius: 999px;\n align-items: center;\n gap: 6px;\n padding: 3px 10px;\n font-size: 12px;\n line-height: 18px;\n display: inline-flex;\n}\n\n.AUWlZW_chiporphaned, .AUWlZW_chipfailed {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n}\n\n.AUWlZW_chipneedsCredentials, .AUWlZW_chipdegraded {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n background: var(--dsw-alias-state-warn-tertiary, #fef5e7);\n}\n\n.AUWlZW_chipdisabled {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n background: var(--dsw-alias-bg-layer-1, #fff);\n}\n\n.AUWlZW_summaryAllGood {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n align-items: center;\n gap: 7px;\n font-size: 12px;\n display: inline-flex;\n}\n\n.AUWlZW_summaryCount {\n font-weight: 700;\n}\n\n.AUWlZW_summaryLabel {\n color: inherit;\n}\n\n.AUWlZW_observedAt {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n white-space: nowrap;\n margin-left: auto;\n font-size: 11px;\n}\n\n.AUWlZW_summaryDotGreen, .AUWlZW_summaryDotRed {\n border-radius: 50%;\n width: 7px;\n height: 7px;\n}\n\n.AUWlZW_summaryDotGreen {\n background: var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_summaryDotRed {\n background: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_summaryDotWarn {\n background: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_summaryDotInfo {\n background: var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n.AUWlZW_toolbar {\n flex: none;\n margin-bottom: 24px;\n}\n\n.AUWlZW_grid {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n align-content: start;\n gap: 12px;\n min-width: 0;\n display: grid;\n}\n\n.AUWlZW_list {\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.AUWlZW_list .AUWlZW_card {\n flex-flow: wrap;\n align-items: center;\n gap: 8px 14px;\n}\n\n.AUWlZW_list .AUWlZW_cardTop {\n flex: 0 260px;\n}\n\n.AUWlZW_list .AUWlZW_endpoint {\n flex: 200px;\n max-height: 18px;\n}\n\n.AUWlZW_card {\n min-width: 0;\n min-height: 0;\n color: inherit;\n background: var(--dsw-alias-bg-layer-1, #fff);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n cursor: pointer;\n font: inherit;\n text-align: left;\n user-select: none;\n border-radius: 12px;\n flex-direction: column;\n transition: border-color .15s, background .15s, box-shadow .15s;\n display: flex;\n}\n\n.AUWlZW_card:hover {\n border-color: var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-interactive-bg-hover, #2631480f);\n box-shadow: 0 1px 4px #1018280f;\n}\n\n.AUWlZW_cardBody {\n flex-direction: column;\n flex: 1;\n gap: 8px;\n min-width: 0;\n padding: 12px 14px 10px;\n display: flex;\n}\n\n.AUWlZW_card:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 2px;\n}\n\n.AUWlZW_cardTop {\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.AUWlZW_statusDot {\n background: var(--dsw-alias-state-success-primary, #16a34a);\n border-radius: 50%;\n flex: none;\n width: 7px;\n height: 7px;\n}\n\n.AUWlZW_statusconnected {\n background: var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_statusdegraded {\n background: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_statusfailed {\n background: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_statusneeds-credentials {\n background: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_statusorphaned {\n background: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_statusdisabled {\n background: var(--dsw-alias-label-tertiary, #98a2b3);\n}\n\n.AUWlZW_service {\n flex: 1;\n min-width: 0;\n}\n\n.AUWlZW_name {\n color: var(--dsw-alias-label-primary, #1f2328);\n text-overflow: ellipsis;\n white-space: nowrap;\n font: 600 13px / 22px ui-monospace, Menlo, Consolas, monospace;\n display: block;\n overflow: hidden;\n}\n\n.AUWlZW_endpoint {\n max-height: 36px;\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n overflow-wrap: anywhere;\n margin: 0;\n font: 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n overflow: hidden;\n}\n\n.AUWlZW_sourcePlugin, .AUWlZW_sourceDirect, .AUWlZW_transport, .AUWlZW_toolCount {\n min-width: 0;\n max-width: 100%;\n color: var(--dsw-alias-label-secondary, #6b7280);\n border: 1px solid var(--dsw-alias-border-l3, #d9dde3);\n text-overflow: ellipsis;\n white-space: nowrap;\n border-radius: 4px;\n align-items: center;\n gap: 5px;\n padding: 1px 6px;\n font-size: 12px;\n line-height: 18px;\n display: inline-flex;\n overflow: hidden;\n}\n\n.AUWlZW_sourcePlugin svg, .AUWlZW_sourceDirect svg {\n color: currentColor;\n stroke: currentColor;\n stroke-width: 1.35px;\n stroke-linecap: round;\n stroke-linejoin: round;\n flex: none;\n width: 14px;\n height: 14px;\n}\n\n.AUWlZW_transport {\n font-family: ui-monospace, Menlo, Consolas, monospace;\n}\n\n.AUWlZW_toolCount {\n color: var(--dsw-alias-label-primary, #1f2328);\n flex: none;\n font-weight: 600;\n}\n\n.AUWlZW_reasonLabel {\n opacity: .85;\n flex: none;\n font-weight: 600;\n}\n\n.AUWlZW_statePill {\n white-space: nowrap;\n border-radius: 999px;\n align-items: center;\n gap: 5px;\n padding: 1px 8px;\n font-size: 11px;\n font-weight: 600;\n line-height: 17px;\n display: inline-flex;\n}\n\n.AUWlZW_statePill:before {\n content: \"\";\n background: currentColor;\n border-radius: 50%;\n width: 6px;\n height: 6px;\n}\n\n.AUWlZW_stateconnected {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n background: var(--dsw-alias-state-success-tertiary, #e6faed);\n}\n\n.AUWlZW_statedegraded, .AUWlZW_stateneeds-credentials {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n background: var(--dsw-alias-state-warn-tertiary, #fef5e7);\n}\n\n.AUWlZW_statefailed, .AUWlZW_stateorphaned {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n}\n\n.AUWlZW_statedisabled {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n}\n\n.AUWlZW_cardConnected {\n border-left: 3px solid var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_cardDegraded, .AUWlZW_cardNeedsCredentials {\n border-left: 3px solid var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_cardFailed, .AUWlZW_cardOrphaned {\n border-left: 3px solid var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_cardDisabled {\n border-left: 3px solid var(--dsw-alias-label-tertiary, #98a2b3);\n}\n\n.AUWlZW_state, .AUWlZW_detailState {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n white-space: nowrap;\n align-items: center;\n gap: 5px;\n font-size: 11px;\n display: inline-flex;\n}\n\n.AUWlZW_state:before, .AUWlZW_detailState:before {\n content: \"\";\n background: currentColor;\n border-radius: 50%;\n width: 6px;\n height: 6px;\n}\n\n.AUWlZW_stateconnected, .AUWlZW_detailStateconnected {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_statedegraded, .AUWlZW_detailStatedegraded {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_statefailed, .AUWlZW_detailStatefailed {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_stateneeds-credentials, .AUWlZW_detailStateneeds-credentials {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_stateorphaned, .AUWlZW_detailStateorphaned {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_statedisabled, .AUWlZW_detailStatedisabled {\n color: var(--dsw-alias-label-tertiary, #98a2b3);\n}\n\n.AUWlZW_chevron {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 18px;\n}\n\n.AUWlZW_empty, .AUWlZW_detailEmpty {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-align: center;\n padding: 24px;\n font-size: 12px;\n}\n\n.AUWlZW_error {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n align-items: center;\n gap: 8px;\n margin: 16px 0;\n font-size: 12px;\n display: flex;\n}\n\n.AUWlZW_boundary {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border-left: 2px solid var(--dsw-alias-border-l3, #d9dde3);\n margin: 10px 0 0;\n padding: 9px 10px;\n font-size: 11px;\n line-height: 17px;\n}\n\n.AUWlZW_detailDialog {\n width: min(720px, 94vw);\n}\n\n.AUWlZW_detailBody {\n max-height: 72vh;\n overflow-y: auto;\n}\n\n.AUWlZW_modalFooter {\n justify-content: flex-end;\n width: 100%;\n display: flex;\n}\n\n.AUWlZW_detail {\n flex-direction: column;\n gap: 16px;\n display: flex;\n}\n\n.AUWlZW_detailMeta {\n flex-wrap: wrap;\n gap: 6px;\n display: flex;\n}\n\n.AUWlZW_detailHero {\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 10px;\n align-items: center;\n gap: 10px;\n padding: 12px 14px;\n display: flex;\n}\n\n.AUWlZW_detailHeroText {\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n display: flex;\n}\n\n.AUWlZW_detailEndpoint {\n color: var(--dsw-alias-label-secondary, #667085);\n overflow-wrap: anywhere;\n margin: 0;\n font: 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.AUWlZW_reason {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n border-left: 2px solid;\n padding: 9px 10px;\n font-size: 11px;\n line-height: 16px;\n}\n\n.AUWlZW_reasonBox {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n border-radius: 8px;\n flex-direction: column;\n gap: 4px;\n padding: 10px 12px;\n display: flex;\n}\n\n.AUWlZW_reasonText {\n overflow-wrap: anywhere;\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n}\n\n.AUWlZW_detailSection {\n flex-direction: column;\n gap: 7px;\n display: flex;\n}\n\n.AUWlZW_detailHead {\n color: var(--dsw-alias-label-secondary, #667085);\n border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n margin: 0;\n padding-bottom: 5px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.AUWlZW_config {\n max-height: 220px;\n color: var(--dsw-alias-label-primary, #344054);\n background: var(--dsw-alias-bg-layer-2, #f6f8fc);\n border: 1px solid var(--dsw-alias-border-l1, #e2e7ef);\n white-space: pre-wrap;\n word-break: break-word;\n border-radius: 7px;\n margin: 0;\n padding: 10px;\n font: 11px / 17px ui-monospace, Menlo, Consolas, monospace;\n overflow: auto;\n}\n\n.AUWlZW_toolList {\n flex-direction: column;\n display: flex;\n}\n\n.AUWlZW_tool {\n border-bottom: 1px solid var(--dsw-alias-border-l1, #eef1f5);\n grid-template-columns: minmax(140px, max-content) minmax(0, 1fr);\n align-items: center;\n gap: 12px;\n padding: 7px 0;\n display: grid;\n}\n\n.AUWlZW_tool:last-child {\n border-bottom: none;\n}\n\n.AUWlZW_toolName {\n color: var(--dsw-alias-label-primary, #1f2328);\n text-overflow: ellipsis;\n white-space: nowrap;\n font: 11px / 16px ui-monospace, Menlo, Consolas, monospace;\n overflow: hidden;\n}\n\n.AUWlZW_toolDescription {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 10px;\n overflow: hidden;\n}\n\n@media (width <= 760px) {\n .AUWlZW_header, .AUWlZW_toolbar {\n padding-left: 0;\n padding-right: 0;\n }\n\n .AUWlZW_header {\n flex-direction: column;\n }\n\n .AUWlZW_headerActions {\n justify-content: space-between;\n width: 100%;\n margin-left: 0;\n }\n\n .AUWlZW_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .AUWlZW_list .AUWlZW_cardTop {\n max-width: 100%;\n }\n\n .AUWlZW_tool {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .AUWlZW_toolDescription {\n display: none;\n }\n\n .AUWlZW_summaryBar {\n gap: 6px;\n padding: 8px 10px;\n }\n\n .AUWlZW_observedAt {\n flex-basis: 100%;\n margin-left: 0;\n }\n}\n\n.AUWlZW_statemounted {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n background: var(--dsw-alias-state-success-tertiary, #e6faed);\n}\n\n.AUWlZW_statehost-missing {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n background: var(--dsw-alias-state-warn-tertiary, #fef5e7);\n}\n\n.AUWlZW_stateconflict {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n}\n\n.AUWlZW_statusmounted {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_statushost-missing {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_statusconflict {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_cardMounted {\n border-left: 3px solid var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_cardHostMissing {\n border-left: 3px solid var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_cardConflict {\n border-left: 3px solid var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_chipmounted {\n background: var(--dsw-alias-state-success-tertiary, #e6faed);\n}\n\n.AUWlZW_chipblocked {\n background: var(--dsw-alias-state-warn-tertiary, #fef5e7);\n}\n\n.AUWlZW_summaryBar + .AUWlZW_toolbar, .AUWlZW_toolbar, .AUWlZW_header + .AUWlZW_summaryBar {\n margin-top: 12px;\n}\n\n.AUWlZW_list .AUWlZW_card {\n min-height: 0;\n padding: 2px 0;\n}\n\n.AUWlZW_list .AUWlZW_cardBody {\n flex-flow: row;\n align-items: center;\n gap: 12px;\n padding: 8px 14px;\n}\n\n.AUWlZW_list .AUWlZW_cardTop {\n flex: 0 300px;\n min-width: 0;\n}\n\n.AUWlZW_list .AUWlZW_endpoint {\n white-space: nowrap;\n text-overflow: ellipsis;\n flex: 240px;\n max-height: 22px;\n overflow: hidden;\n}\n\n.AUWlZW_extRow {\n border-bottom: 1px solid var(--dsw-alias-border-l1, #eef1f5);\n grid-template-columns: minmax(64px, auto) 20px minmax(0, 1fr);\n align-items: center;\n gap: 10px;\n padding: 7px 0;\n display: grid;\n}\n\n.AUWlZW_extRow:last-child {\n border-bottom: none;\n}\n\n.AUWlZW_extName {\n color: var(--dsw-alias-label-primary, #1f2328);\n font: 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.AUWlZW_extArrow {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n}\n\n.AUWlZW_extLanguage {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n font: 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n overflow: hidden;\n}\n\n.AUWlZW_retryStack {\n align-items: center;\n gap: 10px;\n margin-right: 4px;\n display: inline-flex;\n}\n\n.AUWlZW_retrySpinner {\n font-size: 13px;\n line-height: 1;\n display: inline-flex;\n}\n\n.AUWlZW_spinning {\n animation: .9s linear infinite AUWlZW_mcp-retry-spin;\n}\n\n@keyframes AUWlZW_mcp-retry-spin {\n from {\n transform: rotate(0);\n }\n\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .AUWlZW_spinning {\n animation: none;\n }\n}\n\n.AUWlZW_retryEchoSuccess, .AUWlZW_retryEchoFailure {\n white-space: nowrap;\n font-size: 12px;\n line-height: 18px;\n}\n\n.AUWlZW_retryEchoSuccess {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_retryEchoFailure {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_statusstarting {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n animation: 1.2s ease-in-out infinite AUWlZW_lspStartingPulse;\n}\n\n@keyframes AUWlZW_lspStartingPulse {\n 50% {\n opacity: .35;\n }\n}\n\n.AUWlZW_statusforeign {\n background: var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n.AUWlZW_cardForeign {\n border-left: 3px solid var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n.AUWlZW_reasonRaw {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n word-break: break-all;\n margin: 6px 0 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n line-height: 1.5;\n}\n";document.head.appendChild(s);}})();
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
7
|
//#region \0rolldown/runtime.js
|
|
8
8
|
var __create = Object.create;
|
|
@@ -30,6 +30,120 @@ let react = require("react");
|
|
|
30
30
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
31
31
|
_deepseek_ai_dsh_client_ui_primitives = __toESM(_deepseek_ai_dsh_client_ui_primitives, 1);
|
|
32
32
|
let react_dom_client = require("react-dom/client");
|
|
33
|
+
//#region src/contracts/market.ts
|
|
34
|
+
/** Browser-safe market wire records and route constants shared by host and client. */
|
|
35
|
+
/** Prefix for all Agent Plugins Market HTTP routes. */
|
|
36
|
+
const MARKET_API_PREFIX = "/api/agent-plugins/";
|
|
37
|
+
/** Fixed Agent Plugins Market HTTP routes. */
|
|
38
|
+
const MARKET_ROUTES = {
|
|
39
|
+
overview: `${MARKET_API_PREFIX}overview`,
|
|
40
|
+
mcpStatus: `${MARKET_API_PREFIX}mcp-status`,
|
|
41
|
+
lspStatus: `${MARKET_API_PREFIX}lsp-status`,
|
|
42
|
+
lspServers: `${MARKET_API_PREFIX}lsp-servers`,
|
|
43
|
+
progress: `${MARKET_API_PREFIX}progress`,
|
|
44
|
+
config: `${MARKET_API_PREFIX}config`,
|
|
45
|
+
suite: `${MARKET_API_PREFIX}suite`,
|
|
46
|
+
skill: `${MARKET_API_PREFIX}skill`,
|
|
47
|
+
addSource: `${MARKET_API_PREFIX}sources/add`,
|
|
48
|
+
updateSource: `${MARKET_API_PREFIX}sources/update`,
|
|
49
|
+
adoptSource: `${MARKET_API_PREFIX}sources/adopt`,
|
|
50
|
+
removeSource: `${MARKET_API_PREFIX}sources/remove`,
|
|
51
|
+
refreshSource: `${MARKET_API_PREFIX}sources/refresh`,
|
|
52
|
+
install: `${MARKET_API_PREFIX}install`,
|
|
53
|
+
uninstall: `${MARKET_API_PREFIX}uninstall`,
|
|
54
|
+
setEnabled: `${MARKET_API_PREFIX}set-enabled`,
|
|
55
|
+
setSurface: `${MARKET_API_PREFIX}set-surface`,
|
|
56
|
+
mcpOverrides: `${MARKET_API_PREFIX}mcp-overrides`,
|
|
57
|
+
setMcpOverride: `${MARKET_API_PREFIX}set-mcp-override`,
|
|
58
|
+
mcpRetry: `${MARKET_API_PREFIX}mcp-retry`,
|
|
59
|
+
mcpReauthorize: `${MARKET_API_PREFIX}mcp-reauthorize`,
|
|
60
|
+
mcpBackend: `${MARKET_API_PREFIX}mcp-backend`,
|
|
61
|
+
setMcpBackend: `${MARKET_API_PREFIX}set-mcp-backend`
|
|
62
|
+
};
|
|
63
|
+
/** Build a suite-detail URL without duplicating route or query encoding logic. */
|
|
64
|
+
function suiteRoute(sourceId, suiteId) {
|
|
65
|
+
return `${MARKET_ROUTES.suite}?sourceId=${encodeURIComponent(sourceId)}&suiteId=${encodeURIComponent(suiteId)}`;
|
|
66
|
+
}
|
|
67
|
+
/** Build a skill-content URL without duplicating route or query encoding logic. */
|
|
68
|
+
function skillRoute(sourceId, suiteId, skill) {
|
|
69
|
+
return `${MARKET_ROUTES.skill}?sourceId=${encodeURIComponent(sourceId)}&suiteId=${encodeURIComponent(suiteId)}&skill=${encodeURIComponent(skill)}`;
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
//#region src/client/api.ts
|
|
73
|
+
/** Typed fetch helpers over the host's `/api/agent-plugins/*` routes. */
|
|
74
|
+
async function fetchOverview() {
|
|
75
|
+
const response = await fetch(MARKET_ROUTES.overview, { credentials: "same-origin" });
|
|
76
|
+
if (!response.ok) throw new Error(`overview failed: ${response.status}`);
|
|
77
|
+
return response.json();
|
|
78
|
+
}
|
|
79
|
+
async function fetchSourceProgress() {
|
|
80
|
+
const response = await fetch(MARKET_ROUTES.progress, { credentials: "same-origin" });
|
|
81
|
+
if (!response.ok) throw new Error(`progress failed: ${response.status}`);
|
|
82
|
+
return response.json();
|
|
83
|
+
}
|
|
84
|
+
async function fetchSuiteDetail(sourceId, suiteId) {
|
|
85
|
+
const response = await fetch(suiteRoute(sourceId, suiteId), { credentials: "same-origin" });
|
|
86
|
+
if (!response.ok) throw new Error(`suite detail failed: ${response.status}`);
|
|
87
|
+
return response.json();
|
|
88
|
+
}
|
|
89
|
+
async function fetchMcpStatus() {
|
|
90
|
+
const response = await fetch(MARKET_ROUTES.mcpStatus, { credentials: "same-origin" });
|
|
91
|
+
if (!response.ok) throw new Error(`MCP status failed: ${response.status}`);
|
|
92
|
+
return response.json();
|
|
93
|
+
}
|
|
94
|
+
async function fetchLspStatus() {
|
|
95
|
+
const response = await fetch(MARKET_ROUTES.lspStatus, { credentials: "same-origin" });
|
|
96
|
+
if (!response.ok) throw new Error(`LSP status failed: ${response.status}`);
|
|
97
|
+
return response.json();
|
|
98
|
+
}
|
|
99
|
+
/** The user's direct LSP server table (normalized specs). */
|
|
100
|
+
async function fetchLspServers() {
|
|
101
|
+
const response = await fetch(MARKET_ROUTES.lspServers, { credentials: "same-origin" });
|
|
102
|
+
if (!response.ok) throw new Error(`LSP servers failed: ${response.status}`);
|
|
103
|
+
return (await response.json()).lspServers ?? {};
|
|
104
|
+
}
|
|
105
|
+
/** Validate and persist the user's direct LSP server table. */
|
|
106
|
+
async function saveLspServers(lspServers) {
|
|
107
|
+
const response = await fetch(MARKET_ROUTES.lspServers, {
|
|
108
|
+
method: "POST",
|
|
109
|
+
credentials: "same-origin",
|
|
110
|
+
headers: { "content-type": "application/json" },
|
|
111
|
+
body: JSON.stringify({ lspServers })
|
|
112
|
+
});
|
|
113
|
+
const body = await response.json();
|
|
114
|
+
if (!response.ok || body.ok === false) throw new Error(body.error ?? `LSP servers save failed: ${response.status}`);
|
|
115
|
+
return body.lspServers ?? {};
|
|
116
|
+
}
|
|
117
|
+
async function fetchSkillContent(sourceId, suiteId, skill) {
|
|
118
|
+
const response = await fetch(skillRoute(sourceId, suiteId, skill), { credentials: "same-origin" });
|
|
119
|
+
if (!response.ok) throw new Error(`skill content failed: ${response.status}`);
|
|
120
|
+
return response.json();
|
|
121
|
+
}
|
|
122
|
+
/** Re-run the host MCP reconcile: retries failed mounts, clears residual tools. */
|
|
123
|
+
async function retryMcpMounts() {
|
|
124
|
+
await postAction("mcp-retry", {});
|
|
125
|
+
}
|
|
126
|
+
/** Drop one server's OAuth grant so its next mount re-runs browser authorization. */
|
|
127
|
+
async function reauthorizeMcpServer(serverName) {
|
|
128
|
+
await postAction("mcp-reauthorize", { serverName });
|
|
129
|
+
}
|
|
130
|
+
async function fetchMcpBackend() {
|
|
131
|
+
const response = await fetch(MARKET_ROUTES.mcpBackend, { credentials: "same-origin" });
|
|
132
|
+
if (!response.ok) throw new Error(`mcp backend failed: ${response.status}`);
|
|
133
|
+
return response.json();
|
|
134
|
+
}
|
|
135
|
+
async function postAction(path, body) {
|
|
136
|
+
const response = await fetch(`${MARKET_API_PREFIX}${path}`, {
|
|
137
|
+
method: "POST",
|
|
138
|
+
credentials: "same-origin",
|
|
139
|
+
headers: { "content-type": "application/json" },
|
|
140
|
+
body: JSON.stringify(body)
|
|
141
|
+
});
|
|
142
|
+
const payload = await response.json();
|
|
143
|
+
if (!response.ok || payload.ok !== true) throw new Error(payload.error ?? `request failed: ${response.status}`);
|
|
144
|
+
return payload;
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
33
147
|
//#region src/client/locales.ts
|
|
34
148
|
/** Chinese is the source-of-truth key set; English is checked against it below. */
|
|
35
149
|
const zh = {
|
|
@@ -44,10 +158,18 @@ const zh = {
|
|
|
44
158
|
sourceIdPh: "源 id(小写字母数字)",
|
|
45
159
|
sourceUrlPh: "git 仓库地址",
|
|
46
160
|
sourceUrlLocalPh: "本地仓库路径(绝对路径或 ~/…)",
|
|
161
|
+
sourceUrlArchivePh: "压缩包地址(.zip / .tar.gz)",
|
|
47
162
|
sourceModeGit: "远程 git",
|
|
163
|
+
sourceModeArchive: "压缩包",
|
|
48
164
|
sourceModeLocal: "本地目录",
|
|
49
165
|
branchPh: "分支(可选)",
|
|
50
166
|
sourceLocal: "本地",
|
|
167
|
+
sourceArchive: "压缩包",
|
|
168
|
+
sourceAdopted: "已收编",
|
|
169
|
+
sha256Ph: "SHA-256(可选,64 位十六进制)",
|
|
170
|
+
unmanagedTitle: "检测到未登记的本地仓库:",
|
|
171
|
+
unmanagedAdopt: "收编为源(只登记,不克隆不删除)",
|
|
172
|
+
unmanagedNoRemote: "非 git 目录:将以本地目录形式登记",
|
|
51
173
|
editSource: "编辑当前源",
|
|
52
174
|
editSourceTitle: "编辑仓库源",
|
|
53
175
|
addSourceTitle: "新增仓库源",
|
|
@@ -70,7 +192,7 @@ const zh = {
|
|
|
70
192
|
disabledLabel: "已停用",
|
|
71
193
|
notInstalledLabel: "未安装",
|
|
72
194
|
surfaceTogglesSection: "运行时注入开关",
|
|
73
|
-
surfaceTogglesHint: "按能力面控制注入:关闭后立即卸载对应注入(技能 / MCP / Hooks / 命令 /
|
|
195
|
+
surfaceTogglesHint: "按能力面控制注入:关闭后立即卸载对应注入(技能 / MCP / Hooks / 命令 / 子代理 / LSP)",
|
|
74
196
|
mcpOverrideEdit: "编辑覆盖",
|
|
75
197
|
mcpOverrideSave: "保存覆盖",
|
|
76
198
|
mcpOverrideReset: "重置为源配置",
|
|
@@ -89,11 +211,14 @@ const zh = {
|
|
|
89
211
|
editorHint: "仓库源提供 Agent Plugins。本地目录直接读取(实时反映工作树);git 源克隆到 ~/.dsh/agent-plugins/.sources/<id>。",
|
|
90
212
|
idHint: "小写字母/数字/连字符,全局唯一",
|
|
91
213
|
urlGitHint: "git 仓库地址,例如 https://github.com/org/repo.git",
|
|
214
|
+
urlArchiveHint: "HTTPS 压缩包地址,例如 https://example.com/plugin.zip;下载后解压为源目录",
|
|
92
215
|
urlLocalHint: "绝对路径或 ~/…,直接读取本地目录(不克隆、移除源时不会删除)",
|
|
93
216
|
branchHint: "可选;不填则跟踪默认分支",
|
|
217
|
+
sha256Hint: "可选;填写后校验下载内容的 SHA-256,不匹配即拒绝安装",
|
|
94
218
|
idFixed: "id 不可修改(源标识全局唯一)",
|
|
95
219
|
progressStarting: "正在提交…",
|
|
96
220
|
progressCloning: "正在克隆仓库(git clone),可能需要几十秒…",
|
|
221
|
+
progressDownloading: "正在下载并解压压缩包,可能需要几十秒…",
|
|
97
222
|
progressReading: "正在读取插件清单…",
|
|
98
223
|
idAutoLabel: "源 ID(自动生成)",
|
|
99
224
|
idAutoHint: "自动从插件清单名或仓库名解析,无需填写",
|
|
@@ -146,6 +271,7 @@ const zh = {
|
|
|
146
271
|
sourceNotCloned: "未克隆",
|
|
147
272
|
sourceCloned: "已克隆",
|
|
148
273
|
errors: "校验问题",
|
|
274
|
+
scanNotes: "扫描提示",
|
|
149
275
|
sourceErrorSeparator: ";",
|
|
150
276
|
viewMode: "视图模式",
|
|
151
277
|
grid: "网格",
|
|
@@ -157,6 +283,10 @@ const zh = {
|
|
|
157
283
|
countInstalled: "已装 {n}",
|
|
158
284
|
countEnabled: "启用 {n}",
|
|
159
285
|
mcpStatusNav: "MCP 服务",
|
|
286
|
+
lspStatusNav: "LSP 服务",
|
|
287
|
+
lspSearch: "搜索 LSP 服务",
|
|
288
|
+
lspAllMounted: "全部已挂载",
|
|
289
|
+
lspDirect: "直接安装",
|
|
160
290
|
mcpStatusTitle: "MCP 服务",
|
|
161
291
|
mcpStatusSubtitle: "连接状态、来源和工具清单",
|
|
162
292
|
mcpSearch: "搜索 MCP 名称、来源或地址…",
|
|
@@ -167,9 +297,49 @@ const zh = {
|
|
|
167
297
|
mcpSource: "来源",
|
|
168
298
|
mcpTransport: "传输",
|
|
169
299
|
mcpTools: "工具",
|
|
300
|
+
mcpTool: "工具",
|
|
301
|
+
mcpAllConnected: "全部已连接",
|
|
302
|
+
mcpReasonLabel: "原因",
|
|
303
|
+
mcpRetryNote: "已自动重试多次仍失败。点击「重试」立即重连,或在插件市场中检查该服务的配置。",
|
|
304
|
+
mcpRetrying: "正在重连…",
|
|
305
|
+
mcpRetrySuccess: "重连成功,服务已恢复",
|
|
306
|
+
mcpRetryFailure: "重连失败,请检查原因说明",
|
|
307
|
+
mcpReauthorize: "重新授权",
|
|
308
|
+
mcpConnect: "连接",
|
|
309
|
+
mcpReauthorizing: "等待浏览器授权…",
|
|
310
|
+
marketCardDesc: "Agent Plugins 市场套件的安装、启用与运行时行为配置。",
|
|
311
|
+
mcpCardTitle: "MCP 增强模式",
|
|
312
|
+
mcpCardDescOn: "已开启:支持 OAuth 授权、SSE、授权保持等功能。",
|
|
313
|
+
mcpCardDescOff: "已关闭:使用宿主 dsh-mcp-client。",
|
|
314
|
+
mcpCardReadonly: "当前环境设置文档只读,无法切换。",
|
|
315
|
+
mcpForeign: "已由其他客户端挂载",
|
|
316
|
+
mcpForeignHint: "该服务器已通过其他途径(原生配置或另一插件)挂载了同名 MCP,市场已跳过以避免重复挂载。如需由市场接管,请先停用另一来源的该服务器;若确认是残留挂载,重启宿主即可清除。",
|
|
317
|
+
mcpDuplicateHint: "另一来源已挂载了相同的服务器,本副本未注册——同一服务器挂载两份对模型没有额外意义。卸载另一来源的套件后,本副本会在下次刷新时自动接管。",
|
|
318
|
+
regionLabel: "下载区域",
|
|
319
|
+
regionHint: "中国大陆走镜像线路,仅影响下载线路。",
|
|
320
|
+
regionGlobal: "全球",
|
|
321
|
+
regionChina: "中国大陆",
|
|
322
|
+
mcpBackendHostMissing: "宿主 dsh-mcp-client 在当前环境不可用,无法切换到兼容模式。",
|
|
323
|
+
mcpReauthHint: "删除已保存的授权令牌并重新走浏览器授权——用于权限范围选少了的场景。点击后请在弹出的页面完成登录。",
|
|
324
|
+
mcpConnectHint: "删除旧的授权记录并重新发起浏览器登录。点击后请在弹出的页面完成授权,服务会自动连接。",
|
|
325
|
+
mcpReauthSuccess: "已清除旧授权,请在弹出的浏览器页面重新登录",
|
|
326
|
+
mcpReauthFailure: "重新授权失败,请稍后重试",
|
|
327
|
+
mcpZeroTools: "该服务已连接,但未声明任何工具。",
|
|
170
328
|
mcpConnected: "已连接",
|
|
171
329
|
mcpDegraded: "降级",
|
|
172
330
|
mcpFailed: "失败",
|
|
331
|
+
mcpNeedsCredentials: "需要凭据",
|
|
332
|
+
mcpOrphaned: "插件已卸载,工具残留",
|
|
333
|
+
mcpConfigureCredentials: "配置凭据",
|
|
334
|
+
mcpViewDetails: "查看详情",
|
|
335
|
+
mcpCredentialTitle: "凭据配置",
|
|
336
|
+
mcpCredentialConfigured: "已配置",
|
|
337
|
+
mcpCredentialMissing: "未配置",
|
|
338
|
+
mcpCredentialReadOnly: "由启动环境提供(只读;修改后需重启 DSH)",
|
|
339
|
+
mcpCredentialUnavailable: "当前 profile 未提供凭据服务,请在启动 DSH 前设置环境变量。",
|
|
340
|
+
mcpCredentialPlaceholder: "输入凭据(不会回显)",
|
|
341
|
+
mcpCredentialSave: "保存凭据",
|
|
342
|
+
mcpCredentialUnset: "删除凭据",
|
|
173
343
|
mcpDisabled: "未启用",
|
|
174
344
|
mcpObservedEndpoint: "当前工具表观测",
|
|
175
345
|
mcpServiceDetail: "服务详情",
|
|
@@ -180,7 +350,38 @@ const zh = {
|
|
|
180
350
|
mcpDirectConfigUnavailable: "宿主未提供直接安装 MCP 的配置记录",
|
|
181
351
|
mcpDirectBoundary: "直接安装 MCP 仅显示当前工具表中可观测的服务;宿主未提供配置与连接状态 API。",
|
|
182
352
|
mcpBackToMarket: "返回市场",
|
|
183
|
-
mcpRetry: "重试"
|
|
353
|
+
mcpRetry: "重试",
|
|
354
|
+
mcpFilterAllHint: "全部:插件套件声明的 MCP 服务与宿主直接安装的 MCP",
|
|
355
|
+
mcpFilterPluginHint: "Plugin:来自插件市场套件的 mcp.json 声明",
|
|
356
|
+
mcpFilterDirectHint: "直接安装:宿主工具表中观测到、非套件来源的 MCP",
|
|
357
|
+
lspStatusTitle: "LSP 服务",
|
|
358
|
+
lspStatusSubtitle: "语言服务器声明与挂载状态",
|
|
359
|
+
lspAll: "全部",
|
|
360
|
+
lspMounted: "已挂载",
|
|
361
|
+
lspStarting: "启动中…",
|
|
362
|
+
lspBlocked: "被阻塞",
|
|
363
|
+
lspFailed: "失败",
|
|
364
|
+
lspDisabled: "未启用",
|
|
365
|
+
lspHostMissingShort: "宿主缺失",
|
|
366
|
+
lspConflict: "扩展冲突",
|
|
367
|
+
lspHostMissing: "当前 DSH 运行时未携带 LSP 组件(@deepseek-ai/dsh-lsp、dsh-lsp-stdio、dsh-tool-lsp),声明不会被挂载;升级宿主并在 profile 中挂载这三层后重新启用套件即可。",
|
|
368
|
+
lspEmpty: "没有已声明的 LSP 服务器",
|
|
369
|
+
lspReasonLabel: "原因",
|
|
370
|
+
lspFilterAllHint: "全部:套件声明与用户自配的全部语言服务器",
|
|
371
|
+
lspFilterPluginHint: "Plugin:来自插件市场套件的内联 lspServers 声明",
|
|
372
|
+
lspFilterDirectHint: "直接安装:用户自行配置的语言服务器(本面板配置)",
|
|
373
|
+
lspFilterBlockedHint: "被阻塞:缺宿主组件、挂载失败或扩展冲突,点击卡片查看原因",
|
|
374
|
+
lspFilterDisabledHint: "未启用:套件的 LSP 能力面开关已关闭",
|
|
375
|
+
lspPlugin: "Plugin",
|
|
376
|
+
lspConfigure: "配置 LSP",
|
|
377
|
+
lspConfigureHint: "编辑用户自配的语言服务器表(Claude Code lspServers 格式),保存后自动挂载",
|
|
378
|
+
lspSave: "保存",
|
|
379
|
+
lspDetailSubtitle: "语言服务器详情",
|
|
380
|
+
lspDetailCommand: "启动命令",
|
|
381
|
+
lspDetailExtensions: "扩展映射",
|
|
382
|
+
mdCodeCopy: "复制",
|
|
383
|
+
mdCodeCopied: "已复制",
|
|
384
|
+
mdFootnotes: "脚注"
|
|
184
385
|
};
|
|
185
386
|
const en = {
|
|
186
387
|
nav: "Agent Plugins Market",
|
|
@@ -194,10 +395,18 @@ const en = {
|
|
|
194
395
|
sourceIdPh: "source id (lowercase alnum)",
|
|
195
396
|
sourceUrlPh: "git repository URL",
|
|
196
397
|
sourceUrlLocalPh: "local repository path (absolute or ~/…)",
|
|
398
|
+
sourceUrlArchivePh: "archive URL (.zip / .tar.gz)",
|
|
197
399
|
sourceModeGit: "remote git",
|
|
400
|
+
sourceModeArchive: "archive",
|
|
198
401
|
sourceModeLocal: "local dir",
|
|
199
402
|
branchPh: "branch (optional)",
|
|
200
403
|
sourceLocal: "local",
|
|
404
|
+
sourceArchive: "archive",
|
|
405
|
+
sourceAdopted: "adopted",
|
|
406
|
+
sha256Ph: "SHA-256 (optional, 64 hex chars)",
|
|
407
|
+
unmanagedTitle: "Unregistered local checkouts found:",
|
|
408
|
+
unmanagedAdopt: "Adopt as a source (register only — no clone, no deletion)",
|
|
409
|
+
unmanagedNoRemote: "Not a git checkout: registered as a local directory source",
|
|
201
410
|
editSource: "Edit source",
|
|
202
411
|
editSourceTitle: "Edit source",
|
|
203
412
|
addSourceTitle: "Add source",
|
|
@@ -220,7 +429,7 @@ const en = {
|
|
|
220
429
|
disabledLabel: "disabled",
|
|
221
430
|
notInstalledLabel: "not installed",
|
|
222
431
|
surfaceTogglesSection: "Runtime injection toggles",
|
|
223
|
-
surfaceTogglesHint: "Control injection per surface: turning one off unmounts that surface immediately (skills / MCP / hooks / commands / subagents)",
|
|
432
|
+
surfaceTogglesHint: "Control injection per surface: turning one off unmounts that surface immediately (skills / MCP / hooks / commands / subagents / LSP)",
|
|
224
433
|
mcpOverrideEdit: "Edit override",
|
|
225
434
|
mcpOverrideSave: "Save override",
|
|
226
435
|
mcpOverrideReset: "Reset to source config",
|
|
@@ -239,11 +448,14 @@ const en = {
|
|
|
239
448
|
editorHint: "A source provides suites (Agent Plugins). Local directories are read in place (live working tree); git sources clone into ~/.dsh/agent-plugins/.sources/<id>.",
|
|
240
449
|
idHint: "lowercase letters / digits / hyphens, globally unique",
|
|
241
450
|
urlGitHint: "git repository URL, e.g. https://github.com/org/repo.git",
|
|
451
|
+
urlArchiveHint: "HTTPS archive URL, e.g. https://example.com/plugin.zip — downloaded and extracted as the source directory",
|
|
242
452
|
urlLocalHint: "absolute path or ~/…, read in place (never cloned, never deleted on removal)",
|
|
243
453
|
branchHint: "optional; defaults to the repository default branch",
|
|
454
|
+
sha256Hint: "optional; when set, the download SHA-256 is verified and mismatches reject the install",
|
|
244
455
|
idFixed: "id is fixed (the source identifier is globally unique)",
|
|
245
456
|
progressStarting: "Submitting…",
|
|
246
457
|
progressCloning: "Cloning the repository (git clone) — this can take tens of seconds…",
|
|
458
|
+
progressDownloading: "Downloading and extracting the archive — this can take tens of seconds…",
|
|
247
459
|
progressReading: "Reading plugin manifests…",
|
|
248
460
|
idAutoLabel: "Source ID (auto)",
|
|
249
461
|
idAutoHint: "Derived from the suite or repo name — no need to type it",
|
|
@@ -296,6 +508,7 @@ const en = {
|
|
|
296
508
|
sourceNotCloned: "not cloned",
|
|
297
509
|
sourceCloned: "cloned",
|
|
298
510
|
errors: "validation issues",
|
|
511
|
+
scanNotes: "scan notes",
|
|
299
512
|
sourceErrorSeparator: "; ",
|
|
300
513
|
viewMode: "View mode",
|
|
301
514
|
grid: "grid",
|
|
@@ -307,6 +520,10 @@ const en = {
|
|
|
307
520
|
countInstalled: "{n} installed",
|
|
308
521
|
countEnabled: "{n} enabled",
|
|
309
522
|
mcpStatusNav: "MCP services",
|
|
523
|
+
lspStatusNav: "LSP servers",
|
|
524
|
+
lspSearch: "Search LSP servers",
|
|
525
|
+
lspAllMounted: "All mounted",
|
|
526
|
+
lspDirect: "Direct",
|
|
310
527
|
mcpStatusTitle: "MCP services",
|
|
311
528
|
mcpStatusSubtitle: "Connection state, sources, and tools",
|
|
312
529
|
mcpSearch: "Search MCP names, sources, or endpoints…",
|
|
@@ -317,9 +534,49 @@ const en = {
|
|
|
317
534
|
mcpSource: "Source",
|
|
318
535
|
mcpTransport: "Transport",
|
|
319
536
|
mcpTools: "tools",
|
|
537
|
+
mcpTool: "tool",
|
|
538
|
+
mcpAllConnected: "All connected",
|
|
539
|
+
mcpReasonLabel: "Reason",
|
|
540
|
+
mcpRetryNote: "Automatic retries were exhausted. Use Retry to reconnect now, or check the server configuration in the market.",
|
|
541
|
+
mcpRetrying: "Reconnecting…",
|
|
542
|
+
mcpRetrySuccess: "Reconnected — the service is live again",
|
|
543
|
+
mcpRetryFailure: "Reconnect failed — see the reason above",
|
|
544
|
+
mcpReauthorize: "Re-authorize",
|
|
545
|
+
mcpConnect: "Connect",
|
|
546
|
+
mcpReauthorizing: "Waiting for browser authorization…",
|
|
547
|
+
marketCardDesc: "Install, enable, and runtime settings for Agent Plugins Market suites.",
|
|
548
|
+
mcpCardTitle: "MCP enhancement",
|
|
549
|
+
mcpCardDescOn: "On: enables OAuth authorization, SSE, authorization hold, and more.",
|
|
550
|
+
mcpCardDescOff: "Off: uses the host dsh-mcp-client.",
|
|
551
|
+
mcpCardReadonly: "The settings document is read-only in this environment; the switch is unavailable.",
|
|
552
|
+
mcpForeign: "Mounted elsewhere",
|
|
553
|
+
mcpForeignHint: "This server is already mounted through another path (native config or another plugin); the market skipped it to avoid a duplicate. To let the market take over, disable the other source first. If it is a leftover mount, a Host restart clears it.",
|
|
554
|
+
mcpDuplicateHint: "Another source already mounted this server, so this copy was not registered — mounting the same server twice adds nothing for the model. Uninstall the other source's suite and this copy takes over on the next refresh.",
|
|
555
|
+
regionLabel: "Download region",
|
|
556
|
+
regionHint: "China mainland routes through a mirror. Affects the download route only.",
|
|
557
|
+
regionGlobal: "Global",
|
|
558
|
+
regionChina: "China mainland",
|
|
559
|
+
mcpBackendHostMissing: "The host dsh-mcp-client is not available here; compat mode cannot be enabled.",
|
|
560
|
+
mcpReauthHint: "Drops the saved OAuth token and re-runs the browser authorization — for when you picked too narrow a scope. Finish the sign-in in the page that opens.",
|
|
561
|
+
mcpConnectHint: "Drops the stale grant and starts a fresh browser sign-in. Approve in the page that opens and the service connects automatically.",
|
|
562
|
+
mcpReauthSuccess: "Old grant dropped — finish the sign-in in the browser page that opened",
|
|
563
|
+
mcpReauthFailure: "Re-authorization failed — try again shortly",
|
|
564
|
+
mcpZeroTools: "Connected, but this service advertises no tools.",
|
|
320
565
|
mcpConnected: "connected",
|
|
321
566
|
mcpDegraded: "degraded",
|
|
322
567
|
mcpFailed: "failed",
|
|
568
|
+
mcpNeedsCredentials: "credentials required",
|
|
569
|
+
mcpOrphaned: "plugin removed; tools remain",
|
|
570
|
+
mcpConfigureCredentials: "Configure credentials",
|
|
571
|
+
mcpViewDetails: "View details",
|
|
572
|
+
mcpCredentialTitle: "Credential configuration",
|
|
573
|
+
mcpCredentialConfigured: "configured",
|
|
574
|
+
mcpCredentialMissing: "not configured",
|
|
575
|
+
mcpCredentialReadOnly: "provided by the launch environment (read-only; restart DSH after changes)",
|
|
576
|
+
mcpCredentialUnavailable: "This profile has no credentials service. Set the environment variable before launching DSH.",
|
|
577
|
+
mcpCredentialPlaceholder: "Enter credential (not echoed)",
|
|
578
|
+
mcpCredentialSave: "Save credential",
|
|
579
|
+
mcpCredentialUnset: "Remove credential",
|
|
323
580
|
mcpDisabled: "disabled",
|
|
324
581
|
mcpObservedEndpoint: "observed from tool registry",
|
|
325
582
|
mcpServiceDetail: "Service detail",
|
|
@@ -330,80 +587,40 @@ const en = {
|
|
|
330
587
|
mcpDirectConfigUnavailable: "The host does not expose direct-MCP configuration",
|
|
331
588
|
mcpDirectBoundary: "Direct MCP entries only show services observed in the current tool registry; the host exposes no config or connection-status API.",
|
|
332
589
|
mcpBackToMarket: "Back to market",
|
|
333
|
-
mcpRetry: "Retry"
|
|
590
|
+
mcpRetry: "Retry",
|
|
591
|
+
mcpFilterAllHint: "All: MCP services declared by plugin suites plus host-installed MCP",
|
|
592
|
+
mcpFilterPluginHint: "Plugin: mcp.json declarations from market suites",
|
|
593
|
+
mcpFilterDirectHint: "Direct: MCP observed in the host tool registry outside any suite",
|
|
594
|
+
lspStatusTitle: "LSP servers",
|
|
595
|
+
lspStatusSubtitle: "Declared language servers and their mount state",
|
|
596
|
+
lspAll: "All",
|
|
597
|
+
lspMounted: "Mounted",
|
|
598
|
+
lspStarting: "Starting…",
|
|
599
|
+
lspBlocked: "Blocked",
|
|
600
|
+
lspFailed: "Failed",
|
|
601
|
+
lspDisabled: "Disabled",
|
|
602
|
+
lspHostMissingShort: "Host missing",
|
|
603
|
+
lspConflict: "Extension conflict",
|
|
604
|
+
lspHostMissing: "This DSH runtime does not carry the LSP packages (@deepseek-ai/dsh-lsp, dsh-lsp-stdio, dsh-tool-lsp), so declarations are not mounted; upgrade the host, mount the three layers in the profile, and re-enable the suite.",
|
|
605
|
+
lspEmpty: "No declared LSP servers",
|
|
606
|
+
lspReasonLabel: "Reason",
|
|
607
|
+
lspFilterAllHint: "All: suite-declared and user-configured language servers",
|
|
608
|
+
lspFilterPluginHint: "Plugin: inline lspServers declarations from market suites",
|
|
609
|
+
lspFilterDirectHint: "Direct: user-configured language servers (configured in this panel)",
|
|
610
|
+
lspFilterBlockedHint: "Blocked: missing host packages, failed mounts, or extension conflicts — open a card for the reason",
|
|
611
|
+
lspFilterDisabledHint: "Disabled: the suite LSP surface toggle is off",
|
|
612
|
+
lspPlugin: "Plugin",
|
|
613
|
+
lspConfigure: "Configure LSP",
|
|
614
|
+
lspConfigureHint: "Edit the user-configured language-server table (Claude Code lspServers format); servers mount automatically after save",
|
|
615
|
+
lspSave: "Save",
|
|
616
|
+
lspDetailSubtitle: "Language server detail",
|
|
617
|
+
lspDetailCommand: "Launch command",
|
|
618
|
+
lspDetailExtensions: "Extension map",
|
|
619
|
+
mdCodeCopy: "Copy",
|
|
620
|
+
mdCodeCopied: "Copied",
|
|
621
|
+
mdFootnotes: "Footnotes"
|
|
334
622
|
};
|
|
335
623
|
//#endregion
|
|
336
|
-
//#region src/contracts/market.ts
|
|
337
|
-
/** Browser-safe market wire records and route constants shared by host and client. */
|
|
338
|
-
/** Prefix for all Agent Plugins Market HTTP routes. */
|
|
339
|
-
const MARKET_API_PREFIX = "/api/agent-plugins/";
|
|
340
|
-
/** Fixed Agent Plugins Market HTTP routes. */
|
|
341
|
-
const MARKET_ROUTES = {
|
|
342
|
-
overview: `${MARKET_API_PREFIX}overview`,
|
|
343
|
-
mcpStatus: `${MARKET_API_PREFIX}mcp-status`,
|
|
344
|
-
progress: `${MARKET_API_PREFIX}progress`,
|
|
345
|
-
config: `${MARKET_API_PREFIX}config`,
|
|
346
|
-
suite: `${MARKET_API_PREFIX}suite`,
|
|
347
|
-
skill: `${MARKET_API_PREFIX}skill`,
|
|
348
|
-
addSource: `${MARKET_API_PREFIX}sources/add`,
|
|
349
|
-
updateSource: `${MARKET_API_PREFIX}sources/update`,
|
|
350
|
-
removeSource: `${MARKET_API_PREFIX}sources/remove`,
|
|
351
|
-
refreshSource: `${MARKET_API_PREFIX}sources/refresh`,
|
|
352
|
-
install: `${MARKET_API_PREFIX}install`,
|
|
353
|
-
uninstall: `${MARKET_API_PREFIX}uninstall`,
|
|
354
|
-
setEnabled: `${MARKET_API_PREFIX}set-enabled`,
|
|
355
|
-
setSurface: `${MARKET_API_PREFIX}set-surface`,
|
|
356
|
-
mcpOverrides: `${MARKET_API_PREFIX}mcp-overrides`,
|
|
357
|
-
setMcpOverride: `${MARKET_API_PREFIX}set-mcp-override`
|
|
358
|
-
};
|
|
359
|
-
/** Build a suite-detail URL without duplicating route or query encoding logic. */
|
|
360
|
-
function suiteRoute(sourceId, suiteId) {
|
|
361
|
-
return `${MARKET_ROUTES.suite}?sourceId=${encodeURIComponent(sourceId)}&suiteId=${encodeURIComponent(suiteId)}`;
|
|
362
|
-
}
|
|
363
|
-
/** Build a skill-content URL without duplicating route or query encoding logic. */
|
|
364
|
-
function skillRoute(sourceId, suiteId, skill) {
|
|
365
|
-
return `${MARKET_ROUTES.skill}?sourceId=${encodeURIComponent(sourceId)}&suiteId=${encodeURIComponent(suiteId)}&skill=${encodeURIComponent(skill)}`;
|
|
366
|
-
}
|
|
367
|
-
//#endregion
|
|
368
|
-
//#region src/client/api.ts
|
|
369
|
-
/** Typed fetch helpers over the host's `/api/agent-plugins/*` routes. */
|
|
370
|
-
async function fetchOverview() {
|
|
371
|
-
const response = await fetch(MARKET_ROUTES.overview, { credentials: "same-origin" });
|
|
372
|
-
if (!response.ok) throw new Error(`overview failed: ${response.status}`);
|
|
373
|
-
return response.json();
|
|
374
|
-
}
|
|
375
|
-
async function fetchSourceProgress() {
|
|
376
|
-
const response = await fetch(MARKET_ROUTES.progress, { credentials: "same-origin" });
|
|
377
|
-
if (!response.ok) throw new Error(`progress failed: ${response.status}`);
|
|
378
|
-
return response.json();
|
|
379
|
-
}
|
|
380
|
-
async function fetchSuiteDetail(sourceId, suiteId) {
|
|
381
|
-
const response = await fetch(suiteRoute(sourceId, suiteId), { credentials: "same-origin" });
|
|
382
|
-
if (!response.ok) throw new Error(`suite detail failed: ${response.status}`);
|
|
383
|
-
return response.json();
|
|
384
|
-
}
|
|
385
|
-
async function fetchMcpStatus() {
|
|
386
|
-
const response = await fetch(MARKET_ROUTES.mcpStatus, { credentials: "same-origin" });
|
|
387
|
-
if (!response.ok) throw new Error(`MCP status failed: ${response.status}`);
|
|
388
|
-
return response.json();
|
|
389
|
-
}
|
|
390
|
-
async function fetchSkillContent(sourceId, suiteId, skill) {
|
|
391
|
-
const response = await fetch(skillRoute(sourceId, suiteId, skill), { credentials: "same-origin" });
|
|
392
|
-
if (!response.ok) throw new Error(`skill content failed: ${response.status}`);
|
|
393
|
-
return response.json();
|
|
394
|
-
}
|
|
395
|
-
async function postAction(path, body) {
|
|
396
|
-
const response = await fetch(`${MARKET_API_PREFIX}${path}`, {
|
|
397
|
-
method: "POST",
|
|
398
|
-
credentials: "same-origin",
|
|
399
|
-
headers: { "content-type": "application/json" },
|
|
400
|
-
body: JSON.stringify(body)
|
|
401
|
-
});
|
|
402
|
-
const payload = await response.json();
|
|
403
|
-
if (!response.ok || payload.ok !== true) throw new Error(payload.error ?? `request failed: ${response.status}`);
|
|
404
|
-
return payload;
|
|
405
|
-
}
|
|
406
|
-
//#endregion
|
|
407
624
|
//#region src/client/features/market/market-resource.ts
|
|
408
625
|
/** Market overview cache, invalidation, and source-progress resource helpers. */
|
|
409
626
|
const EMPTY_OVERVIEW = {
|
|
@@ -417,7 +634,8 @@ const EMPTY_OVERVIEW = {
|
|
|
417
634
|
roots: {
|
|
418
635
|
user: "",
|
|
419
636
|
data: ""
|
|
420
|
-
}
|
|
637
|
+
},
|
|
638
|
+
unmanaged: []
|
|
421
639
|
};
|
|
422
640
|
let cachedOverview;
|
|
423
641
|
let inflightOverview;
|
|
@@ -512,11 +730,19 @@ function searchableFor$1(overview) {
|
|
|
512
730
|
//#endregion
|
|
513
731
|
//#region src/client/market.module.css
|
|
514
732
|
var market_module_default = {
|
|
733
|
+
"backendBlock": "_72qoAq_backendBlock",
|
|
734
|
+
"backendCurrent": "_72qoAq_backendCurrent",
|
|
735
|
+
"backendHint": "_72qoAq_backendHint",
|
|
736
|
+
"backendRow": "_72qoAq_backendRow",
|
|
737
|
+
"backendTitle": "_72qoAq_backendTitle",
|
|
738
|
+
"backendVersion": "_72qoAq_backendVersion",
|
|
515
739
|
"body": "_72qoAq_body",
|
|
516
740
|
"card": "_72qoAq_card",
|
|
517
741
|
"cardActions": "_72qoAq_cardActions",
|
|
518
742
|
"cardDesc": "_72qoAq_cardDesc",
|
|
743
|
+
"cardMuted": "_72qoAq_cardMuted",
|
|
519
744
|
"cardName": "_72qoAq_cardName",
|
|
745
|
+
"cardOn": "_72qoAq_cardOn",
|
|
520
746
|
"cardTitle": "_72qoAq_cardTitle",
|
|
521
747
|
"cardTop": "_72qoAq_cardTop",
|
|
522
748
|
"desc": "_72qoAq_desc",
|
|
@@ -545,6 +771,8 @@ var market_module_default = {
|
|
|
545
771
|
"fieldLabel": "_72qoAq_fieldLabel",
|
|
546
772
|
"grid": "_72qoAq_grid",
|
|
547
773
|
"header": "_72qoAq_header",
|
|
774
|
+
"iconBtn": "_72qoAq_iconBtn",
|
|
775
|
+
"iconBtnDanger": "_72qoAq_iconBtnDanger",
|
|
548
776
|
"installConfirmBody": "_72qoAq_installConfirmBody",
|
|
549
777
|
"installConfirmCommit": "_72qoAq_installConfirmCommit",
|
|
550
778
|
"installConfirmMeta": "_72qoAq_installConfirmMeta",
|
|
@@ -554,6 +782,10 @@ var market_module_default = {
|
|
|
554
782
|
"list": "_72qoAq_list",
|
|
555
783
|
"market": "_72qoAq_market",
|
|
556
784
|
"marketControls": "_72qoAq_marketControls",
|
|
785
|
+
"mcpCredentialControls": "_72qoAq_mcpCredentialControls",
|
|
786
|
+
"mcpCredentialEditor": "_72qoAq_mcpCredentialEditor",
|
|
787
|
+
"mcpCredentialForm": "_72qoAq_mcpCredentialForm",
|
|
788
|
+
"mcpCredentialRow": "_72qoAq_mcpCredentialRow",
|
|
557
789
|
"mcpOverrideActions": "_72qoAq_mcpOverrideActions",
|
|
558
790
|
"mcpOverrideArea": "_72qoAq_mcpOverrideArea",
|
|
559
791
|
"mcpOverrideCheck": "_72qoAq_mcpOverrideCheck",
|
|
@@ -569,11 +801,26 @@ var market_module_default = {
|
|
|
569
801
|
"pageEntry": "_72qoAq_pageEntry",
|
|
570
802
|
"pageMode": "_72qoAq_pageMode",
|
|
571
803
|
"pageView": "_72qoAq_pageView",
|
|
804
|
+
"pluginCard": "_72qoAq_pluginCard",
|
|
805
|
+
"pluginCardBody": "_72qoAq_pluginCardBody",
|
|
806
|
+
"pluginCardDesc": "_72qoAq_pluginCardDesc",
|
|
807
|
+
"pluginCardError": "_72qoAq_pluginCardError",
|
|
808
|
+
"pluginCardHeader": "_72qoAq_pluginCardHeader",
|
|
809
|
+
"pluginCardOpen": "_72qoAq_pluginCardOpen",
|
|
810
|
+
"pluginCardRow": "_72qoAq_pluginCardRow",
|
|
811
|
+
"pluginCardRowLabel": "_72qoAq_pluginCardRowLabel",
|
|
812
|
+
"pluginCardText": "_72qoAq_pluginCardText",
|
|
813
|
+
"pluginCardTitle": "_72qoAq_pluginCardTitle",
|
|
814
|
+
"pluginChevron": "_72qoAq_pluginChevron",
|
|
815
|
+
"pluginChevronOpen": "_72qoAq_pluginChevronOpen",
|
|
572
816
|
"progress": "_72qoAq_progress",
|
|
573
817
|
"progressError": "_72qoAq_progressError",
|
|
574
818
|
"progressFail": "_72qoAq_progressFail",
|
|
575
819
|
"progressSpin": "_72qoAq_progressSpin",
|
|
576
820
|
"progressText": "_72qoAq_progressText",
|
|
821
|
+
"regionSeg": "_72qoAq_regionSeg",
|
|
822
|
+
"regionSegBtn": "_72qoAq_regionSegBtn",
|
|
823
|
+
"regionSegOn": "_72qoAq_regionSegOn",
|
|
577
824
|
"searchGroup": "_72qoAq_searchGroup",
|
|
578
825
|
"seg": "_72qoAq_seg",
|
|
579
826
|
"segOn": "_72qoAq_segOn",
|
|
@@ -597,8 +844,14 @@ var market_module_default = {
|
|
|
597
844
|
"switchOn": "_72qoAq_switchOn",
|
|
598
845
|
"switchThumb": "_72qoAq_switchThumb",
|
|
599
846
|
"tag": "_72qoAq_tag",
|
|
847
|
+
"tagRow": "_72qoAq_tagRow",
|
|
600
848
|
"title": "_72qoAq_title",
|
|
601
849
|
"titleRow": "_72qoAq_titleRow",
|
|
850
|
+
"unmanagedAdopt": "_72qoAq_unmanagedAdopt",
|
|
851
|
+
"unmanagedChip": "_72qoAq_unmanagedChip",
|
|
852
|
+
"unmanagedChipName": "_72qoAq_unmanagedChipName",
|
|
853
|
+
"unmanagedLabel": "_72qoAq_unmanagedLabel",
|
|
854
|
+
"unmanagedRow": "_72qoAq_unmanagedRow",
|
|
602
855
|
"version": "_72qoAq_version",
|
|
603
856
|
"warnLine": "_72qoAq_warnLine"
|
|
604
857
|
};
|
|
@@ -607,8 +860,11 @@ var market_module_default = {
|
|
|
607
860
|
/** A source tab with trailing edit and delete controls. */
|
|
608
861
|
/** A source chip with a trailing delete control (deletion confirms at the section level). */
|
|
609
862
|
function SourceTab(props) {
|
|
610
|
-
const { t, active = false, label, onSelect, onDelete, onEdit } = props;
|
|
611
|
-
return (0, react.createElement)("div", {
|
|
863
|
+
const { t, active = false, label, title, onSelect, onDelete, onEdit } = props;
|
|
864
|
+
return (0, react.createElement)("div", {
|
|
865
|
+
className: active ? market_module_default.srcTabOn : market_module_default.srcTab,
|
|
866
|
+
title
|
|
867
|
+
}, (0, react.createElement)("button", {
|
|
612
868
|
type: "button",
|
|
613
869
|
className: market_module_default.srcTabMain,
|
|
614
870
|
onClick: onSelect
|
|
@@ -635,11 +891,19 @@ function SourceTab(props) {
|
|
|
635
891
|
/** Source editor modal for adding or editing a catalog source. */
|
|
636
892
|
function SourceEditorModal(props) {
|
|
637
893
|
const { t, editor } = props;
|
|
638
|
-
const [
|
|
894
|
+
const [kind, setKind] = (0, react.useState)(editor.mode === "edit" ? editor.source.kind === "archive" ? "archive" : editor.source.local === true ? "local" : "git" : "git");
|
|
639
895
|
const [url, setUrl] = (0, react.useState)(editor.mode === "edit" ? editor.source.url : "");
|
|
640
896
|
const [branch, setBranch] = (0, react.useState)(editor.mode === "edit" ? editor.source.branch ?? "" : "");
|
|
897
|
+
const [sha256, setSha256] = (0, react.useState)("");
|
|
641
898
|
const id = editor.mode === "edit" ? editor.source.id : "";
|
|
642
899
|
const title = editor.mode === "edit" ? t("editSourceTitle") : t("addSourceTitle");
|
|
900
|
+
const urlPlaceholder = kind === "local" ? t("sourceUrlLocalPh") : kind === "archive" ? t("sourceUrlArchivePh") : t("sourceUrlPh");
|
|
901
|
+
const urlHint = kind === "local" ? t("urlLocalHint") : kind === "archive" ? t("urlArchiveHint") : t("urlGitHint");
|
|
902
|
+
const segment = (value, label) => (0, react.createElement)("button", {
|
|
903
|
+
type: "button",
|
|
904
|
+
className: kind === value ? market_module_default.segOn : market_module_default.seg,
|
|
905
|
+
onClick: () => setKind(value)
|
|
906
|
+
}, label);
|
|
643
907
|
return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
644
908
|
open: true,
|
|
645
909
|
onClose: props.onClose,
|
|
@@ -657,26 +921,27 @@ function SourceEditorModal(props) {
|
|
|
657
921
|
variant: "primary",
|
|
658
922
|
disabled: props.busy,
|
|
659
923
|
onClick: () => {
|
|
660
|
-
props.onSave(
|
|
924
|
+
props.onSave({
|
|
925
|
+
url: url.trim(),
|
|
926
|
+
branch: branch.trim(),
|
|
927
|
+
kind,
|
|
928
|
+
sha256: sha256.trim()
|
|
929
|
+
});
|
|
661
930
|
}
|
|
662
931
|
}, t("save"))),
|
|
663
|
-
children: (0, react.createElement)("div", { className: market_module_default.editorForm }, (0, react.createElement)("div", { className: market_module_default.modeRow }, (0, react.createElement)("
|
|
664
|
-
|
|
665
|
-
className: local ? market_module_default.seg : market_module_default.segOn,
|
|
666
|
-
onClick: () => setLocal(false)
|
|
667
|
-
}, t("sourceModeGit")), (0, react.createElement)("button", {
|
|
668
|
-
type: "button",
|
|
669
|
-
className: local ? market_module_default.segOn : market_module_default.seg,
|
|
670
|
-
onClick: () => setLocal(true)
|
|
671
|
-
}, t("sourceModeLocal"))), editor.mode === "edit" ? (0, react.createElement)("div", { className: market_module_default.fieldGroup }, (0, react.createElement)("label", { className: market_module_default.fieldLabel }, t("sourceIdPh")), (0, react.createElement)("div", { className: market_module_default.staticId }, (0, react.createElement)("span", { className: market_module_default.staticIdValue }, id), (0, react.createElement)("span", { className: market_module_default.fieldHint }, t("idFixed")))) : null, (0, react.createElement)("div", { className: market_module_default.fieldGroup }, (0, react.createElement)("label", { className: market_module_default.fieldLabel }, local ? t("sourceUrlLocalPh") : t("sourceUrlPh")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
672
|
-
placeholder: local ? t("sourceUrlLocalPh") : t("sourceUrlPh"),
|
|
932
|
+
children: (0, react.createElement)("div", { className: market_module_default.editorForm }, (0, react.createElement)("div", { className: market_module_default.modeRow }, segment("git", t("sourceModeGit")), segment("archive", t("sourceModeArchive")), segment("local", t("sourceModeLocal"))), editor.mode === "edit" ? (0, react.createElement)("div", { className: market_module_default.fieldGroup }, (0, react.createElement)("label", { className: market_module_default.fieldLabel }, t("sourceIdPh")), (0, react.createElement)("div", { className: market_module_default.staticId }, (0, react.createElement)("span", { className: market_module_default.staticIdValue }, id), (0, react.createElement)("span", { className: market_module_default.fieldHint }, t("idFixed")))) : null, (0, react.createElement)("div", { className: market_module_default.fieldGroup }, (0, react.createElement)("label", { className: market_module_default.fieldLabel }, urlPlaceholder), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
933
|
+
placeholder: urlPlaceholder,
|
|
673
934
|
value: url,
|
|
674
935
|
onChange: (event) => setUrl(event.target.value)
|
|
675
|
-
}), (0, react.createElement)("span", { className: market_module_default.fieldHint },
|
|
936
|
+
}), (0, react.createElement)("span", { className: market_module_default.fieldHint }, urlHint)), kind === "git" ? (0, react.createElement)("div", { className: market_module_default.fieldGroup }, (0, react.createElement)("label", { className: market_module_default.fieldLabel }, t("branchPh")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
676
937
|
placeholder: t("branchPh"),
|
|
677
938
|
value: branch,
|
|
678
939
|
onChange: (event) => setBranch(event.target.value)
|
|
679
|
-
}), (0, react.createElement)("span", { className: market_module_default.fieldHint }, t("branchHint")))
|
|
940
|
+
}), (0, react.createElement)("span", { className: market_module_default.fieldHint }, t("branchHint"))) : null, kind === "archive" ? (0, react.createElement)("div", { className: market_module_default.fieldGroup }, (0, react.createElement)("label", { className: market_module_default.fieldLabel }, t("sha256Ph")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
941
|
+
placeholder: t("sha256Ph"),
|
|
942
|
+
value: sha256,
|
|
943
|
+
onChange: (event) => setSha256(event.target.value)
|
|
944
|
+
}), (0, react.createElement)("span", { className: market_module_default.fieldHint }, t("sha256Hint"))) : null, props.progress.error === void 0 && props.progress.step === void 0 ? null : (0, react.createElement)("div", { className: props.progress.error === void 0 ? market_module_default.progress : market_module_default.progressError }, props.progress.error === void 0 ? (0, react.createElement)("span", { className: market_module_default.progressSpin }) : (0, react.createElement)("span", { className: market_module_default.progressFail }, "✕"), (0, react.createElement)("span", { className: market_module_default.progressText }, props.progress.error === void 0 ? props.progress.step : `${t("actionFail")}: ${props.progress.error}`)))
|
|
680
945
|
});
|
|
681
946
|
}
|
|
682
947
|
//#endregion
|
|
@@ -703,6 +968,10 @@ const SURFACE_TAGS = [
|
|
|
703
968
|
{
|
|
704
969
|
key: "agents",
|
|
705
970
|
labelKey: "surfaceAgents"
|
|
971
|
+
},
|
|
972
|
+
{
|
|
973
|
+
key: "lsp",
|
|
974
|
+
labelKey: "surfaceLsp"
|
|
706
975
|
}
|
|
707
976
|
];
|
|
708
977
|
function InstallConfirmModal(props) {
|
|
@@ -736,7 +1005,7 @@ function InstallConfirmModal(props) {
|
|
|
736
1005
|
}
|
|
737
1006
|
//#endregion
|
|
738
1007
|
//#region src/client/ui/ToggleSwitch.tsx
|
|
739
|
-
/** Shared
|
|
1008
|
+
/** Shared switch control (ON = primary button fill, like every host toggle). */
|
|
740
1009
|
/** A green/gray switch control for suite enable state. */
|
|
741
1010
|
function ToggleSwitch(props) {
|
|
742
1011
|
return (0, react.createElement)("button", {
|
|
@@ -767,19 +1036,46 @@ function SuiteCard(props) {
|
|
|
767
1036
|
].filter(([, count]) => count > 0);
|
|
768
1037
|
const layoutLabel = suite.layout === "agent-plugin-v1" ? t("layoutV1") : suite.layout === "claude-code" ? t("layoutCC") : suite.layout === "codex" ? t("layoutCodex") : suite.layout === "universal" ? t("layoutUniversal") : suite.layout === "cursor" ? t("layoutCursor") : suite.layout === "kimi" ? t("layoutKimi") : suite.layout === "remote" ? t("layoutRemote") : suite.layout === "project-native" ? t("layoutProjectNative") : t("layoutSkills");
|
|
769
1038
|
const isRemote = suite.remoteUrl !== void 0;
|
|
1039
|
+
const hasTagRow = tags.length > 0 || suite.errors.length > 0 || (suite.mcpErrors?.length ?? 0) > 0;
|
|
770
1040
|
const stop = (callback) => (event) => {
|
|
771
1041
|
event.stopPropagation();
|
|
772
1042
|
callback();
|
|
773
1043
|
};
|
|
1044
|
+
const accent = suite.installed ? suite.enabled ? market_module_default.cardOn : market_module_default.cardMuted : void 0;
|
|
774
1045
|
return (0, react.createElement)("article", {
|
|
775
|
-
className: market_module_default.card,
|
|
1046
|
+
className: accent ? `${market_module_default.card} ${accent}` : market_module_default.card,
|
|
776
1047
|
onClick: props.onOpen
|
|
777
|
-
}, (0, react.createElement)("div", { className: market_module_default.cardTop }, (0, react.createElement)("div", { className: market_module_default.cardTitle }, (0, react.createElement)("span", { className: market_module_default.cardName }, suite.name), suite.version === void 0 ? null : (0, react.createElement)("span", { className: market_module_default.version }, `v${suite.version}`)), (0, react.createElement)("div", { className: market_module_default.cardActions }, suite.installed ?
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
1048
|
+
}, (0, react.createElement)("div", { className: market_module_default.cardTop }, (0, react.createElement)("div", { className: market_module_default.cardTitle }, (0, react.createElement)("span", { className: market_module_default.cardName }, suite.name), suite.version === void 0 ? null : (0, react.createElement)("span", { className: market_module_default.version }, `v${suite.version}`)), (0, react.createElement)("div", { className: market_module_default.cardActions }, suite.installed ? [
|
|
1049
|
+
(0, react.createElement)("button", {
|
|
1050
|
+
key: "refresh",
|
|
1051
|
+
type: "button",
|
|
1052
|
+
className: market_module_default.iconBtn,
|
|
1053
|
+
title: t("refresh"),
|
|
1054
|
+
disabled: busy,
|
|
1055
|
+
onClick: stop(props.onRefresh)
|
|
1056
|
+
}, (0, react.createElement)("svg", {
|
|
1057
|
+
viewBox: "0 0 24 24",
|
|
1058
|
+
"aria-hidden": "true"
|
|
1059
|
+
}, (0, react.createElement)("path", { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" }), (0, react.createElement)("path", { d: "M21 3v5h-5" }))),
|
|
1060
|
+
(0, react.createElement)("button", {
|
|
1061
|
+
key: "uninstall",
|
|
1062
|
+
type: "button",
|
|
1063
|
+
className: `${market_module_default.iconBtn} ${market_module_default.iconBtnDanger}`,
|
|
1064
|
+
title: t("uninstall"),
|
|
1065
|
+
disabled: busy,
|
|
1066
|
+
onClick: stop(props.onUninstall)
|
|
1067
|
+
}, (0, react.createElement)("svg", {
|
|
1068
|
+
viewBox: "0 0 24 24",
|
|
1069
|
+
"aria-hidden": "true"
|
|
1070
|
+
}, (0, react.createElement)("path", { d: "M3 6h18" }), (0, react.createElement)("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" }), (0, react.createElement)("path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }))),
|
|
1071
|
+
(0, react.createElement)(ToggleSwitch, {
|
|
1072
|
+
key: "toggle",
|
|
1073
|
+
on: suite.enabled,
|
|
1074
|
+
disabled: busy,
|
|
1075
|
+
title: suite.enabled ? t("disable") : t("enable"),
|
|
1076
|
+
onChange: props.onToggle
|
|
1077
|
+
})
|
|
1078
|
+
] : isRemote ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
783
1079
|
variant: "primary",
|
|
784
1080
|
size: "sm",
|
|
785
1081
|
disabled: busy,
|
|
@@ -790,19 +1086,7 @@ function SuiteCard(props) {
|
|
|
790
1086
|
size: "sm",
|
|
791
1087
|
disabled: busy,
|
|
792
1088
|
onClick: stop(props.onInstall)
|
|
793
|
-
}, t("install")), suite.
|
|
794
|
-
variant: "ghost",
|
|
795
|
-
size: "sm",
|
|
796
|
-
title: t("refresh"),
|
|
797
|
-
disabled: busy,
|
|
798
|
-
onClick: stop(props.onRefresh)
|
|
799
|
-
}, "↻") : null, suite.installed ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
800
|
-
variant: "ghost",
|
|
801
|
-
size: "sm",
|
|
802
|
-
title: t("uninstall"),
|
|
803
|
-
disabled: busy,
|
|
804
|
-
onClick: stop(props.onUninstall)
|
|
805
|
-
}, "🗑") : null)), (0, react.createElement)("p", { className: market_module_default.desc }, suite.description ?? ""), (0, react.createElement)("div", { className: market_module_default.meta }, (0, react.createElement)("span", { className: market_module_default.src }, `${suite.sourceId} · ${isRemote ? t("remoteRef") : suite.dimension === "user" ? t("dimensionUser") : t("dimensionProject")}`), (0, react.createElement)("span", { className: market_module_default.tag }, layoutLabel), suite.installed ? (0, react.createElement)("span", { className: suite.enabled ? market_module_default.okState : market_module_default.tag }, suite.enabled ? `✓ ${t("installedBadge")}` : t("installedBadge")) : null, ...tags.map(([label, count]) => (0, react.createElement)("span", {
|
|
1089
|
+
}, t("install")))), (0, react.createElement)("p", { className: market_module_default.desc }, suite.description ?? ""), (0, react.createElement)("div", { className: market_module_default.meta }, (0, react.createElement)("span", { className: market_module_default.src }, `${suite.sourceId} · ${isRemote ? t("remoteRef") : suite.dimension === "user" ? t("dimensionUser") : t("dimensionProject")}`), (0, react.createElement)("span", { className: market_module_default.tag }, layoutLabel)), hasTagRow ? (0, react.createElement)("div", { className: market_module_default.tagRow }, ...tags.map(([label, count]) => (0, react.createElement)("span", {
|
|
806
1090
|
key: label,
|
|
807
1091
|
className: market_module_default.tag
|
|
808
1092
|
}, `${label} ${count}`)), suite.errors.length === 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
@@ -811,7 +1095,7 @@ function SuiteCard(props) {
|
|
|
811
1095
|
}), (suite.mcpErrors?.length ?? 0) === 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
812
1096
|
label: suite.mcpErrors.slice(0, 8).join(t("sourceErrorSeparator")),
|
|
813
1097
|
children: (0, react.createElement)("span", { className: market_module_default.warnLine }, `⚠ ${t("mcpSection")} ${suite.mcpErrors.length}`)
|
|
814
|
-
})));
|
|
1098
|
+
})) : null);
|
|
815
1099
|
}
|
|
816
1100
|
//#endregion
|
|
817
1101
|
//#region src/client/ui/StatusIcon.tsx
|
|
@@ -856,6 +1140,162 @@ var ErrorBoundary = class extends react.Component {
|
|
|
856
1140
|
}
|
|
857
1141
|
};
|
|
858
1142
|
//#endregion
|
|
1143
|
+
//#region src/client/credentials.ts
|
|
1144
|
+
/** Read one value-free credential view; secret values never enter the browser state. */
|
|
1145
|
+
async function describeCredential(api, ref) {
|
|
1146
|
+
if (api === void 0) return void 0;
|
|
1147
|
+
const response = await api.describe({ refs: [ref] });
|
|
1148
|
+
if (response.result?.ok !== true) throw new Error(response.result?.error?.message ?? "credential lookup failed");
|
|
1149
|
+
return response.result.value?.credentials?.[ref];
|
|
1150
|
+
}
|
|
1151
|
+
async function setCredential(api, ref, value) {
|
|
1152
|
+
const response = await api.set({
|
|
1153
|
+
ref,
|
|
1154
|
+
value
|
|
1155
|
+
});
|
|
1156
|
+
if (response.result?.ok !== true) throw new Error(response.result?.error?.message ?? "credential save failed");
|
|
1157
|
+
}
|
|
1158
|
+
async function unsetCredential(api, ref) {
|
|
1159
|
+
const response = await api.unset({ ref });
|
|
1160
|
+
if (response.result?.ok !== true) throw new Error(response.result?.error?.message ?? "credential removal failed");
|
|
1161
|
+
}
|
|
1162
|
+
/** Adapt the current Host service to the credential editor's wire contract. */
|
|
1163
|
+
function credentialApi(remote) {
|
|
1164
|
+
return {
|
|
1165
|
+
describe: async ({ refs }) => {
|
|
1166
|
+
const result = await remote.describe(refs);
|
|
1167
|
+
return { result: result.ok ? {
|
|
1168
|
+
ok: true,
|
|
1169
|
+
value: { credentials: result.value }
|
|
1170
|
+
} : result };
|
|
1171
|
+
},
|
|
1172
|
+
set: async ({ ref, value }) => ({ result: await remote.set(ref, value) }),
|
|
1173
|
+
unset: async ({ ref }) => ({ result: await remote.unset(ref) })
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1176
|
+
//#endregion
|
|
1177
|
+
//#region src/client/mcp-credential.module.css
|
|
1178
|
+
var mcp_credential_module_default = {
|
|
1179
|
+
"actions": "G2mDja_actions",
|
|
1180
|
+
"controls": "G2mDja_controls",
|
|
1181
|
+
"editor": "G2mDja_editor",
|
|
1182
|
+
"error": "G2mDja_error",
|
|
1183
|
+
"factMiss": "G2mDja_factMiss",
|
|
1184
|
+
"factOk": "G2mDja_factOk",
|
|
1185
|
+
"facts": "G2mDja_facts",
|
|
1186
|
+
"form": "G2mDja_form",
|
|
1187
|
+
"head": "G2mDja_head",
|
|
1188
|
+
"input": "G2mDja_input",
|
|
1189
|
+
"note": "G2mDja_note",
|
|
1190
|
+
"ref": "G2mDja_ref",
|
|
1191
|
+
"row": "G2mDja_row"
|
|
1192
|
+
};
|
|
1193
|
+
//#endregion
|
|
1194
|
+
//#region src/client/McpCredentialEditor.tsx
|
|
1195
|
+
/**
|
|
1196
|
+
* Write-only credential editor for MCP `${ENV_NAME}` references.
|
|
1197
|
+
*
|
|
1198
|
+
* Read facts (configured / source / writable) come from the value-free
|
|
1199
|
+
* credentials wire; a typed value crosses the wire exactly once, inside
|
|
1200
|
+
* `credentials.set`, and never re-enters component state. Read-only
|
|
1201
|
+
* launch-environment credentials render guidance instead of a form that could
|
|
1202
|
+
* only fake success.
|
|
1203
|
+
*/
|
|
1204
|
+
function McpCredentialEditor(props) {
|
|
1205
|
+
const { t, api, refs } = props;
|
|
1206
|
+
const [views, setViews] = (0, react.useState)({});
|
|
1207
|
+
const [drafts, setDrafts] = (0, react.useState)({});
|
|
1208
|
+
const [busy, setBusy] = (0, react.useState)(void 0);
|
|
1209
|
+
const [error, setError] = (0, react.useState)(void 0);
|
|
1210
|
+
const refKey = refs.join("|");
|
|
1211
|
+
(0, react.useEffect)(() => {
|
|
1212
|
+
let cancelled = false;
|
|
1213
|
+
setViews({});
|
|
1214
|
+
setError(void 0);
|
|
1215
|
+
if (api === void 0 || refs.length === 0) return () => {
|
|
1216
|
+
cancelled = true;
|
|
1217
|
+
};
|
|
1218
|
+
Promise.all(refs.map(async (ref) => [ref, await describeCredential(api, ref)])).then((entries) => {
|
|
1219
|
+
if (cancelled) return;
|
|
1220
|
+
setViews(Object.fromEntries(entries.flatMap(([ref, view]) => view === void 0 ? [] : [[ref, view]])));
|
|
1221
|
+
}).catch((reason) => {
|
|
1222
|
+
if (!cancelled) setError(reason instanceof Error ? reason.message : String(reason));
|
|
1223
|
+
});
|
|
1224
|
+
return () => {
|
|
1225
|
+
cancelled = true;
|
|
1226
|
+
};
|
|
1227
|
+
}, [api, refKey]);
|
|
1228
|
+
if (refs.length === 0) return null;
|
|
1229
|
+
const refresh = async (ref) => {
|
|
1230
|
+
if (api === void 0) return;
|
|
1231
|
+
const view = await describeCredential(api, ref);
|
|
1232
|
+
if (view !== void 0) setViews((current) => ({
|
|
1233
|
+
...current,
|
|
1234
|
+
[ref]: view
|
|
1235
|
+
}));
|
|
1236
|
+
};
|
|
1237
|
+
const save = async (ref) => {
|
|
1238
|
+
const value = drafts[ref]?.trim();
|
|
1239
|
+
if (api === void 0 || value === void 0 || value === "") return;
|
|
1240
|
+
setBusy(ref);
|
|
1241
|
+
setError(void 0);
|
|
1242
|
+
try {
|
|
1243
|
+
await setCredential(api, ref, value);
|
|
1244
|
+
setDrafts((current) => ({
|
|
1245
|
+
...current,
|
|
1246
|
+
[ref]: ""
|
|
1247
|
+
}));
|
|
1248
|
+
await refresh(ref);
|
|
1249
|
+
} catch (reason) {
|
|
1250
|
+
setError(reason instanceof Error ? reason.message : String(reason));
|
|
1251
|
+
} finally {
|
|
1252
|
+
setBusy(void 0);
|
|
1253
|
+
}
|
|
1254
|
+
};
|
|
1255
|
+
const unset = async (ref) => {
|
|
1256
|
+
if (api === void 0) return;
|
|
1257
|
+
setBusy(ref);
|
|
1258
|
+
setError(void 0);
|
|
1259
|
+
try {
|
|
1260
|
+
await unsetCredential(api, ref);
|
|
1261
|
+
await refresh(ref);
|
|
1262
|
+
} catch (reason) {
|
|
1263
|
+
setError(reason instanceof Error ? reason.message : String(reason));
|
|
1264
|
+
} finally {
|
|
1265
|
+
setBusy(void 0);
|
|
1266
|
+
}
|
|
1267
|
+
};
|
|
1268
|
+
return (0, react.createElement)("section", { className: mcp_credential_module_default.form }, (0, react.createElement)("h4", { className: mcp_credential_module_default.head }, t("mcpCredentialTitle")), error === void 0 ? null : (0, react.createElement)("div", { className: mcp_credential_module_default.error }, error), refs.map((ref) => {
|
|
1269
|
+
const view = views[ref];
|
|
1270
|
+
const refBusy = busy === ref;
|
|
1271
|
+
return (0, react.createElement)("div", {
|
|
1272
|
+
key: ref,
|
|
1273
|
+
className: mcp_credential_module_default.row
|
|
1274
|
+
}, (0, react.createElement)("code", { className: mcp_credential_module_default.ref }, ref), view === void 0 ? (0, react.createElement)("div", { className: mcp_credential_module_default.note }, api === void 0 ? t("mcpCredentialUnavailable") : t("loading")) : (0, react.createElement)("div", { className: mcp_credential_module_default.controls }, (0, react.createElement)("div", { className: mcp_credential_module_default.facts }, (0, react.createElement)("span", { className: view.configured ? mcp_credential_module_default.factOk : mcp_credential_module_default.factMiss }, view.configured ? t("mcpCredentialConfigured") : t("mcpCredentialMissing")), view.source === void 0 ? null : (0, react.createElement)("span", { className: mcp_credential_module_default.note }, view.source)), view.writable ? (0, react.createElement)("div", { className: mcp_credential_module_default.editor }, (0, react.createElement)("input", {
|
|
1275
|
+
className: mcp_credential_module_default.input,
|
|
1276
|
+
type: "password",
|
|
1277
|
+
autoComplete: "new-password",
|
|
1278
|
+
value: drafts[ref] ?? "",
|
|
1279
|
+
placeholder: t("mcpCredentialPlaceholder"),
|
|
1280
|
+
disabled: refBusy,
|
|
1281
|
+
onChange: (event) => setDrafts((current) => ({
|
|
1282
|
+
...current,
|
|
1283
|
+
[ref]: event.target.value
|
|
1284
|
+
}))
|
|
1285
|
+
}), (0, react.createElement)("div", { className: mcp_credential_module_default.actions }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1286
|
+
variant: "primary",
|
|
1287
|
+
size: "sm",
|
|
1288
|
+
disabled: refBusy || (drafts[ref]?.trim() ?? "") === "",
|
|
1289
|
+
onClick: () => void save(ref)
|
|
1290
|
+
}, t("mcpCredentialSave")), view.configured ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1291
|
+
variant: "ghost",
|
|
1292
|
+
size: "sm",
|
|
1293
|
+
disabled: refBusy,
|
|
1294
|
+
onClick: () => void unset(ref)
|
|
1295
|
+
}, t("mcpCredentialUnset")) : null)) : (0, react.createElement)("div", { className: mcp_credential_module_default.note }, t("mcpCredentialReadOnly"))));
|
|
1296
|
+
}));
|
|
1297
|
+
}
|
|
1298
|
+
//#endregion
|
|
859
1299
|
//#region src/client/features/suite-detail/suite-detail-resource.ts
|
|
860
1300
|
/** Create a request guard for one detail modal instance. */
|
|
861
1301
|
function createLatestRequestGuard() {
|
|
@@ -884,9 +1324,17 @@ const SURFACE_TOGGLE_ROWS = [
|
|
|
884
1324
|
["mcp", "surfaceMcp"],
|
|
885
1325
|
["hooks", "surfaceHooks"],
|
|
886
1326
|
["commands", "surfaceCommands"],
|
|
887
|
-
["agents", "surfaceAgents"]
|
|
1327
|
+
["agents", "surfaceAgents"],
|
|
1328
|
+
["lsp", "surfaceLsp"]
|
|
888
1329
|
];
|
|
889
|
-
function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
|
|
1330
|
+
function SuiteDetailModal({ t, credentials, sourceId, suiteId, onClose }) {
|
|
1331
|
+
const markdownLabels = (0, react.useMemo)(() => ({
|
|
1332
|
+
code: {
|
|
1333
|
+
copyLabel: t("mdCodeCopy"),
|
|
1334
|
+
copiedLabel: t("mdCodeCopied")
|
|
1335
|
+
},
|
|
1336
|
+
footnotes: t("mdFootnotes")
|
|
1337
|
+
}), [t]);
|
|
890
1338
|
const [detail, setDetail] = (0, react.useState)(void 0);
|
|
891
1339
|
const [error, setError] = (0, react.useState)(void 0);
|
|
892
1340
|
const [openSkill, setOpenSkill] = (0, react.useState)(void 0);
|
|
@@ -1006,7 +1454,10 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
|
|
|
1006
1454
|
onClick: () => {
|
|
1007
1455
|
toggleSkill(skill.name);
|
|
1008
1456
|
}
|
|
1009
|
-
}, (0, react.createElement)("span", { className: market_module_default.detailItemName }, skill.name), (0, react.createElement)("span", { className: market_module_default.detailItemDesc }, skill.description), (0, react.createElement)("span", { className: market_module_default.detailChevron }, openSkill === skill.name ? "▾" : "▸")), openSkill !== skill.name ? null : (0, react.createElement)("div", { className: market_module_default.skillContent }, skillLoading ? t("loading") : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
1457
|
+
}, (0, react.createElement)("span", { className: market_module_default.detailItemName }, skill.name), (0, react.createElement)("span", { className: market_module_default.detailItemDesc }, skill.description), (0, react.createElement)("span", { className: market_module_default.detailChevron }, openSkill === skill.name ? "▾" : "▸")), openSkill !== skill.name ? null : (0, react.createElement)("div", { className: market_module_default.skillContent }, skillLoading ? t("loading") : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
1458
|
+
text: skillText ?? "",
|
|
1459
|
+
labels: markdownLabels
|
|
1460
|
+
}))))), (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, `${t("mcpSection")} (${detail.mcpServers.length})`), detail.mcpErrors.length === 0 ? null : (0, react.createElement)("div", {
|
|
1010
1461
|
className: market_module_default.warnLine,
|
|
1011
1462
|
style: { margin: "0 0 6px" }
|
|
1012
1463
|
}, `⚠ ${detail.mcpErrors.join(t("sourceErrorSeparator"))}`), detail.mcpServers.length === 0 ? (0, react.createElement)("div", { className: market_module_default.sidebarEmpty }, "—") : detail.mcpServers.map((server) => {
|
|
@@ -1020,7 +1471,11 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
|
|
|
1020
1471
|
type: "button",
|
|
1021
1472
|
className: openMcp === server.key ? market_module_default.detailItemOpen : market_module_default.detailItemRow,
|
|
1022
1473
|
onClick: () => toggleMcp(server.key)
|
|
1023
|
-
}, (0, react.createElement)("span", { className: market_module_default.detailItemName }, server.key), (0, react.createElement)("span", { className: market_module_default.detailItemDesc }, `${mcpSummary(server)}${disabled ? ` · ${t("mcpOverrideDisabledBadge")}` : overridden ? ` · ${t("mcpOverriddenBadge")}` : ""}`), (0, react.createElement)("span", { className: market_module_default.detailChevron }, openMcp === server.key ? "▾" : "▸")), openMcp === server.key ? (0, react.createElement)("div", { className: market_module_default.skillContent }, detail.installed && detail.surfaceToggles?.mcp !== false ? (0, react.createElement)(
|
|
1474
|
+
}, (0, react.createElement)("span", { className: market_module_default.detailItemName }, server.key), (0, react.createElement)("span", { className: market_module_default.detailItemDesc }, `${mcpSummary(server)}${disabled ? ` · ${t("mcpOverrideDisabledBadge")}` : overridden ? ` · ${t("mcpOverriddenBadge")}` : ""}`), (0, react.createElement)("span", { className: market_module_default.detailChevron }, openMcp === server.key ? "▾" : "▸")), openMcp === server.key ? (0, react.createElement)("div", { className: market_module_default.skillContent }, detail.installed && detail.surfaceToggles?.mcp !== false ? (0, react.createElement)(McpCredentialEditor, {
|
|
1475
|
+
t,
|
|
1476
|
+
api: credentials,
|
|
1477
|
+
refs: server.credentialRefs ?? []
|
|
1478
|
+
}) : null, detail.installed && detail.surfaceToggles?.mcp !== false ? (0, react.createElement)(McpOverrideEditor, {
|
|
1024
1479
|
t,
|
|
1025
1480
|
serverKey: server.key,
|
|
1026
1481
|
transport: server.type,
|
|
@@ -1036,7 +1491,10 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
|
|
|
1036
1491
|
description: command.description,
|
|
1037
1492
|
open: openPreview === `c:${command.name}`,
|
|
1038
1493
|
onToggle: () => setOpenPreview(openPreview === `c:${command.name}` ? void 0 : `c:${command.name}`),
|
|
1039
|
-
children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
1494
|
+
children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
1495
|
+
text: command.content,
|
|
1496
|
+
labels: markdownLabels
|
|
1497
|
+
})
|
|
1040
1498
|
}))), (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, `${t("agentsSection")} (${detail.agents.length})`), detail.agents.length === 0 ? (0, react.createElement)("div", { className: market_module_default.sidebarEmpty }, "—") : detail.agents.map((agent) => (0, react.createElement)(PreviewRow, {
|
|
1041
1499
|
key: `a:${agent.name}`,
|
|
1042
1500
|
t,
|
|
@@ -1044,7 +1502,10 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
|
|
|
1044
1502
|
description: agent.description,
|
|
1045
1503
|
open: openPreview === `a:${agent.name}`,
|
|
1046
1504
|
onToggle: () => setOpenPreview(openPreview === `a:${agent.name}` ? void 0 : `a:${agent.name}`),
|
|
1047
|
-
children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
1505
|
+
children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
1506
|
+
text: agent.content,
|
|
1507
|
+
labels: markdownLabels
|
|
1508
|
+
})
|
|
1048
1509
|
}))), (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, `${t("hooksLabel")} (${detail.hooks.count})`), detail.hooks.count === 0 ? (0, react.createElement)("div", { className: market_module_default.sidebarEmpty }, "—") : detail.hooks.entries.map((hook, index) => (0, react.createElement)(PreviewRow, {
|
|
1049
1510
|
key: `h:${index}`,
|
|
1050
1511
|
t,
|
|
@@ -1053,14 +1514,22 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
|
|
|
1053
1514
|
open: openPreview === `h:${index}`,
|
|
1054
1515
|
onToggle: () => setOpenPreview(openPreview === `h:${index}` ? void 0 : `h:${index}`),
|
|
1055
1516
|
children: (0, react.createElement)("pre", { className: market_module_default.mono }, JSON.stringify(hook, null, 2))
|
|
1056
|
-
}))), (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, `${t("lspSection")} (${detail.lsp.length})`), detail.lsp.length === 0 ? (0, react.createElement)("div", { className: market_module_default.sidebarEmpty }, "—") : detail.lsp.map((
|
|
1517
|
+
}))), (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, `${t("lspSection")} (${detail.lsp.servers.length + detail.lsp.raw.length})`), detail.lsp.servers.length === 0 && detail.lsp.raw.length === 0 ? (0, react.createElement)("div", { className: market_module_default.sidebarEmpty }, "—") : [...detail.lsp.servers.map((server) => (0, react.createElement)(PreviewRow, {
|
|
1518
|
+
key: `l:${server.key}`,
|
|
1519
|
+
t,
|
|
1520
|
+
name: server.key,
|
|
1521
|
+
description: lspSummary(server),
|
|
1522
|
+
open: openPreview === `l:${server.key}`,
|
|
1523
|
+
onToggle: () => setOpenPreview(openPreview === `l:${server.key}` ? void 0 : `l:${server.key}`),
|
|
1524
|
+
children: (0, react.createElement)("pre", { className: market_module_default.mono }, JSON.stringify(server, null, 2))
|
|
1525
|
+
})), ...detail.lsp.raw.map((entry) => (0, react.createElement)(PreviewRow, {
|
|
1057
1526
|
key: `l:${entry.name}`,
|
|
1058
1527
|
t,
|
|
1059
1528
|
name: entry.name,
|
|
1060
1529
|
open: openPreview === `l:${entry.name}`,
|
|
1061
1530
|
onToggle: () => setOpenPreview(openPreview === `l:${entry.name}` ? void 0 : `l:${entry.name}`),
|
|
1062
1531
|
children: (0, react.createElement)("pre", { className: market_module_default.mono }, entry.content)
|
|
1063
|
-
}))), detail.errors.length === 0 ? null : (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, `${t("errors")} (${detail.errors.length})`), detail.errors.map((entry, index) => (0, react.createElement)("div", {
|
|
1532
|
+
}))]), detail.errors.length === 0 ? null : (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, `${t("errors")} (${detail.errors.length})`), detail.errors.map((entry, index) => (0, react.createElement)("div", {
|
|
1064
1533
|
key: index,
|
|
1065
1534
|
className: market_module_default.warnLine
|
|
1066
1535
|
}, entry))))
|
|
@@ -1071,6 +1540,10 @@ function mcpSummary(server) {
|
|
|
1071
1540
|
if (server.type === "stdio") return server.command ?? server.type;
|
|
1072
1541
|
return server.url ?? server.type;
|
|
1073
1542
|
}
|
|
1543
|
+
/** One-line summary of a declared LSP server: command plus mapped extension list. */
|
|
1544
|
+
function lspSummary(server) {
|
|
1545
|
+
return [server.command, Object.keys(server.extensions).join(" ")].join(" · ");
|
|
1546
|
+
}
|
|
1074
1547
|
/** Parse `KEY=VALUE` lines into a record; blank and comment lines are skipped. */
|
|
1075
1548
|
function parseKvLines(text) {
|
|
1076
1549
|
const result = {};
|
|
@@ -1083,10 +1556,11 @@ function parseKvLines(text) {
|
|
|
1083
1556
|
}
|
|
1084
1557
|
return Object.keys(result).length > 0 ? result : void 0;
|
|
1085
1558
|
}
|
|
1086
|
-
/** Format a record back into sorted `KEY=VALUE` lines
|
|
1559
|
+
/** Format a record back into sorted `KEY=VALUE` lines without exposing literal secrets. */
|
|
1560
|
+
const SENSITIVE_KEY = /(authorization|token|secret|password|credential|api[-_]?key)/i;
|
|
1087
1561
|
function formatKvLines(map) {
|
|
1088
1562
|
if (map === void 0) return "";
|
|
1089
|
-
return Object.keys(map).sort().map((key) => `${key}=${map[key]}`).join("\n");
|
|
1563
|
+
return Object.keys(map).filter((key) => !SENSITIVE_KEY.test(key) || map[key]?.includes("${")).sort().map((key) => `${key}=${map[key]}`).join("\n");
|
|
1090
1564
|
}
|
|
1091
1565
|
/**
|
|
1092
1566
|
* Per-server MCP override editor: enable/disable plus connection-input
|
|
@@ -1217,8 +1691,8 @@ function SearchFilterToolbar(props) {
|
|
|
1217
1691
|
key: filter.id,
|
|
1218
1692
|
type: "button",
|
|
1219
1693
|
className: filter.active ? SearchFilterToolbar_module_default.filterOn : SearchFilterToolbar_module_default.filter,
|
|
1220
|
-
title: `${filter.label} ${filter.count}`,
|
|
1221
|
-
"aria-label": `${filter.label} ${filter.count}`,
|
|
1694
|
+
title: filter.hint ?? `${filter.label} ${filter.count}`,
|
|
1695
|
+
"aria-label": filter.hint ?? `${filter.label} ${filter.count}`,
|
|
1222
1696
|
onClick: filter.onSelect
|
|
1223
1697
|
}, filter.icon, (0, react.createElement)("span", { className: SearchFilterToolbar_module_default.filterCount }, filter.count))), (0, react.createElement)("div", { className: SearchFilterToolbar_module_default.viewGap }), (0, react.createElement)("button", {
|
|
1224
1698
|
type: "button",
|
|
@@ -1275,6 +1749,7 @@ function ViewIcon({ mode }) {
|
|
|
1275
1749
|
/** Host step keys -> translation keys, resolved against the active t(). */
|
|
1276
1750
|
const PROGRESS_STEP_LABELS = {
|
|
1277
1751
|
cloning: "progressCloning",
|
|
1752
|
+
downloading: "progressDownloading",
|
|
1278
1753
|
reading: "progressReading"
|
|
1279
1754
|
};
|
|
1280
1755
|
function progressStepLabel(t, step) {
|
|
@@ -1285,7 +1760,7 @@ function progressStepLabel(t, step) {
|
|
|
1285
1760
|
function interpolate(text, params) {
|
|
1286
1761
|
return text.replace(/\{(\w+)\}/g, (match, key) => key in params ? String(params[key]) : match);
|
|
1287
1762
|
}
|
|
1288
|
-
function MarketSection({ t, mode = "settings" }) {
|
|
1763
|
+
function MarketSection({ t, credentials, mode = "settings" }) {
|
|
1289
1764
|
const [overview, setOverview] = (0, react.useState)(() => loadOverview().initial);
|
|
1290
1765
|
const [loading, setLoading] = (0, react.useState)(() => loadOverview().revalidating);
|
|
1291
1766
|
const [search, setSearch] = (0, react.useState)("");
|
|
@@ -1366,6 +1841,10 @@ function MarketSection({ t, mode = "settings" }) {
|
|
|
1366
1841
|
category
|
|
1367
1842
|
]);
|
|
1368
1843
|
const selectedSource = category === "all" ? void 0 : overview.sources.find((source) => source.id === category);
|
|
1844
|
+
const adoptSource = (0, react.useCallback)(async (id) => {
|
|
1845
|
+
await action(`s:adopt:${id}`, "sources/adopt", { id });
|
|
1846
|
+
}, [action]);
|
|
1847
|
+
const unmanaged = overview.unmanaged ?? [];
|
|
1369
1848
|
return (0, react.createElement)(ErrorBoundary, {
|
|
1370
1849
|
fallback: (error) => (0, react.createElement)("div", { className: market_module_default.empty }, `${t("actionFail")}: ${error.message}`),
|
|
1371
1850
|
children: (0, react.createElement)("div", { className: mode === "page" ? `${market_module_default.market} ${market_module_default.pageMode}` : market_module_default.market }, (0, react.createElement)("header", { className: market_module_default.header }, (0, react.createElement)("div", { className: market_module_default.titleRow }, (0, react.createElement)("h2", { className: market_module_default.title }, t("nav")), (0, react.createElement)("div", { className: market_module_default.spacer }), (0, react.createElement)("div", { className: market_module_default.searchGroup }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
@@ -1386,21 +1865,39 @@ function MarketSection({ t, mode = "settings" }) {
|
|
|
1386
1865
|
active: category === "all",
|
|
1387
1866
|
label: `${t("tabAll")} ${overview.totals.all}`,
|
|
1388
1867
|
onSelect: () => setCategory("all")
|
|
1389
|
-
}), ...[...overview.sources].sort((a, b) => a.id.localeCompare(b.id)).map((source) =>
|
|
1390
|
-
|
|
1391
|
-
t,
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1868
|
+
}), ...[...overview.sources].sort((a, b) => a.id.localeCompare(b.id)).map((source) => {
|
|
1869
|
+
const notes = source.scanNotes ?? [];
|
|
1870
|
+
const noteHint = notes.length === 0 ? void 0 : `${t("scanNotes")}: ${notes.slice(0, 8).join(t("sourceErrorSeparator"))}`;
|
|
1871
|
+
const kindBadge = source.local === true ? t("sourceLocal") : source.kind === "archive" ? t("sourceArchive") : source.adopted === true ? t("sourceAdopted") : void 0;
|
|
1872
|
+
return (0, react.createElement)(SourceTab, {
|
|
1873
|
+
key: source.id,
|
|
1874
|
+
t,
|
|
1875
|
+
active: category === source.id,
|
|
1876
|
+
label: `${source.id}${kindBadge === void 0 ? "" : ` · ${kindBadge}`} ${source.suiteIds.length}${source.cloned === false || notes.length > 0 ? " ⚠" : ""}`,
|
|
1877
|
+
title: noteHint,
|
|
1878
|
+
onSelect: () => setCategory(source.id),
|
|
1879
|
+
onDelete: () => setConfirm({
|
|
1880
|
+
kind: "removeSource",
|
|
1881
|
+
sourceId: source.id
|
|
1882
|
+
}),
|
|
1883
|
+
onEdit: selectedSource?.id === source.id ? () => setEditor({
|
|
1884
|
+
mode: "edit",
|
|
1885
|
+
source
|
|
1886
|
+
}) : void 0
|
|
1887
|
+
});
|
|
1888
|
+
}))), unmanaged.length === 0 ? null : (0, react.createElement)("div", { className: market_module_default.unmanagedRow }, (0, react.createElement)("span", { className: market_module_default.unmanagedLabel }, t("unmanagedTitle")), ...unmanaged.map((entry) => (0, react.createElement)("span", {
|
|
1889
|
+
key: entry.id,
|
|
1890
|
+
className: market_module_default.unmanagedChip,
|
|
1891
|
+
title: entry.url ?? t("unmanagedNoRemote")
|
|
1892
|
+
}, (0, react.createElement)("span", { className: market_module_default.unmanagedChipName }, entry.id), (0, react.createElement)("button", {
|
|
1893
|
+
type: "button",
|
|
1894
|
+
className: market_module_default.unmanagedAdopt,
|
|
1895
|
+
disabled: busy !== void 0,
|
|
1896
|
+
title: t("unmanagedAdopt"),
|
|
1897
|
+
onClick: () => {
|
|
1898
|
+
adoptSource(entry.id);
|
|
1899
|
+
}
|
|
1900
|
+
}, "+")))), (0, react.createElement)(SearchFilterToolbar, {
|
|
1404
1901
|
search,
|
|
1405
1902
|
searchLabel: t("searchPh"),
|
|
1406
1903
|
searchPlaceholder: t("searchPh"),
|
|
@@ -1500,6 +1997,7 @@ function MarketSection({ t, mode = "settings" }) {
|
|
|
1500
1997
|
}, t("confirmDelete")))
|
|
1501
1998
|
}), detail === void 0 ? null : (0, react.createElement)(SuiteDetailModal, {
|
|
1502
1999
|
t,
|
|
2000
|
+
credentials,
|
|
1503
2001
|
sourceId: detail.sourceId,
|
|
1504
2002
|
suiteId: detail.suiteId,
|
|
1505
2003
|
onClose: () => setDetail(void 0)
|
|
@@ -1509,13 +2007,15 @@ function MarketSection({ t, mode = "settings" }) {
|
|
|
1509
2007
|
busy: busy !== void 0,
|
|
1510
2008
|
progress,
|
|
1511
2009
|
onClose: () => setEditor(void 0),
|
|
1512
|
-
onSave: async (url, branch,
|
|
2010
|
+
onSave: async ({ url, branch, kind, sha256 }) => {
|
|
1513
2011
|
const key = editor.mode === "edit" ? `s:edit:${editor.source.id}` : `s:add:${url}`;
|
|
1514
2012
|
const body = {
|
|
1515
2013
|
url,
|
|
1516
|
-
|
|
1517
|
-
|
|
2014
|
+
local: kind === "local",
|
|
2015
|
+
kind
|
|
1518
2016
|
};
|
|
2017
|
+
if (branch !== "" && kind === "git") body["branch"] = branch;
|
|
2018
|
+
if (sha256 !== "" && kind === "archive") body["sha256"] = sha256;
|
|
1519
2019
|
if (editor.mode === "add") {
|
|
1520
2020
|
setBusy(key);
|
|
1521
2021
|
setProgress({
|
|
@@ -1574,16 +2074,30 @@ function deriveMcpStatusViewModel(payload, filter, search) {
|
|
|
1574
2074
|
plugin: 0,
|
|
1575
2075
|
direct: 0
|
|
1576
2076
|
};
|
|
1577
|
-
|
|
1578
|
-
|
|
2077
|
+
const visibleTotals = {
|
|
2078
|
+
all: 0,
|
|
2079
|
+
connected: 0,
|
|
2080
|
+
degraded: 0,
|
|
2081
|
+
failed: 0,
|
|
2082
|
+
needsCredentials: 0,
|
|
2083
|
+
orphaned: 0,
|
|
2084
|
+
disabled: 0,
|
|
2085
|
+
foreign: 0
|
|
2086
|
+
};
|
|
1579
2087
|
const filtered = [];
|
|
1580
2088
|
const needle = search.trim().toLowerCase();
|
|
1581
2089
|
for (const item of searchable) {
|
|
1582
2090
|
const entry = item.entry;
|
|
1583
2091
|
filterCounts.all++;
|
|
1584
2092
|
filterCounts[entry.kind]++;
|
|
1585
|
-
|
|
1586
|
-
if (entry.state === "
|
|
2093
|
+
visibleTotals.all++;
|
|
2094
|
+
if (entry.state === "connected") visibleTotals.connected++;
|
|
2095
|
+
if (entry.state === "degraded") visibleTotals.degraded++;
|
|
2096
|
+
if (entry.state === "failed") visibleTotals.failed++;
|
|
2097
|
+
if (entry.state === "needs-credentials") visibleTotals.needsCredentials++;
|
|
2098
|
+
if (entry.state === "orphaned") visibleTotals.orphaned++;
|
|
2099
|
+
if (entry.state === "disabled") visibleTotals.disabled++;
|
|
2100
|
+
if (entry.state === "foreign") visibleTotals.foreign++;
|
|
1587
2101
|
if (filter !== "all" && entry.kind !== filter) continue;
|
|
1588
2102
|
if (needle !== "" && !item.haystack.includes(needle)) continue;
|
|
1589
2103
|
filtered.push(entry);
|
|
@@ -1592,11 +2106,7 @@ function deriveMcpStatusViewModel(payload, filter, search) {
|
|
|
1592
2106
|
activeEntries,
|
|
1593
2107
|
filtered,
|
|
1594
2108
|
filterCounts,
|
|
1595
|
-
visibleTotals
|
|
1596
|
-
all: activeEntries.length,
|
|
1597
|
-
connected,
|
|
1598
|
-
failed
|
|
1599
|
-
}
|
|
2109
|
+
visibleTotals
|
|
1600
2110
|
};
|
|
1601
2111
|
}
|
|
1602
2112
|
function searchableFor(payload) {
|
|
@@ -1604,7 +2114,7 @@ function searchableFor(payload) {
|
|
|
1604
2114
|
if (cached !== void 0) return cached;
|
|
1605
2115
|
const searchable = payload.entries.filter((entry) => entry.state !== "disabled").map((entry) => ({
|
|
1606
2116
|
entry,
|
|
1607
|
-
haystack: `${entry.name} ${entry.source ?? ""} ${entry.endpoint ?? ""} ${entry.transport}`.toLowerCase()
|
|
2117
|
+
haystack: `${entry.name} ${entry.source ?? ""} ${entry.endpoint ?? ""} ${entry.transport} ${entry.reason ?? ""} ${(entry.credentialRefs ?? []).join(" ")}`.toLowerCase()
|
|
1608
2118
|
}));
|
|
1609
2119
|
searchableCache.set(payload, searchable);
|
|
1610
2120
|
return searchable;
|
|
@@ -1614,15 +2124,35 @@ function searchableFor(payload) {
|
|
|
1614
2124
|
var mcp_status_module_default = {
|
|
1615
2125
|
"boundary": "AUWlZW_boundary",
|
|
1616
2126
|
"card": "AUWlZW_card",
|
|
1617
|
-
"
|
|
2127
|
+
"cardBody": "AUWlZW_cardBody",
|
|
2128
|
+
"cardConflict": "AUWlZW_cardConflict",
|
|
2129
|
+
"cardConnected": "AUWlZW_cardConnected",
|
|
2130
|
+
"cardDegraded": "AUWlZW_cardDegraded",
|
|
2131
|
+
"cardDisabled": "AUWlZW_cardDisabled",
|
|
2132
|
+
"cardFailed": "AUWlZW_cardFailed",
|
|
2133
|
+
"cardForeign": "AUWlZW_cardForeign",
|
|
2134
|
+
"cardHostMissing": "AUWlZW_cardHostMissing",
|
|
2135
|
+
"cardMounted": "AUWlZW_cardMounted",
|
|
2136
|
+
"cardNeedsCredentials": "AUWlZW_cardNeedsCredentials",
|
|
2137
|
+
"cardOrphaned": "AUWlZW_cardOrphaned",
|
|
1618
2138
|
"cardTop": "AUWlZW_cardTop",
|
|
1619
2139
|
"chevron": "AUWlZW_chevron",
|
|
2140
|
+
"chipblocked": "AUWlZW_chipblocked",
|
|
2141
|
+
"chipdegraded": "AUWlZW_chipdegraded",
|
|
2142
|
+
"chipdisabled": "AUWlZW_chipdisabled",
|
|
2143
|
+
"chipfailed": "AUWlZW_chipfailed",
|
|
2144
|
+
"chipmounted": "AUWlZW_chipmounted",
|
|
2145
|
+
"chipneedsCredentials": "AUWlZW_chipneedsCredentials",
|
|
2146
|
+
"chiporphaned": "AUWlZW_chiporphaned",
|
|
1620
2147
|
"config": "AUWlZW_config",
|
|
1621
2148
|
"detail": "AUWlZW_detail",
|
|
1622
2149
|
"detailBody": "AUWlZW_detailBody",
|
|
1623
2150
|
"detailDialog": "AUWlZW_detailDialog",
|
|
1624
2151
|
"detailEmpty": "AUWlZW_detailEmpty",
|
|
2152
|
+
"detailEndpoint": "AUWlZW_detailEndpoint",
|
|
1625
2153
|
"detailHead": "AUWlZW_detailHead",
|
|
2154
|
+
"detailHero": "AUWlZW_detailHero",
|
|
2155
|
+
"detailHeroText": "AUWlZW_detailHeroText",
|
|
1626
2156
|
"detailMeta": "AUWlZW_detailMeta",
|
|
1627
2157
|
"detailSection": "AUWlZW_detailSection",
|
|
1628
2158
|
"detailState": "AUWlZW_detailState",
|
|
@@ -1630,49 +2160,85 @@ var mcp_status_module_default = {
|
|
|
1630
2160
|
"detailStatedegraded": "AUWlZW_detailStatedegraded",
|
|
1631
2161
|
"detailStatedisabled": "AUWlZW_detailStatedisabled",
|
|
1632
2162
|
"detailStatefailed": "AUWlZW_detailStatefailed",
|
|
2163
|
+
"detailStateneeds-credentials": "AUWlZW_detailStateneeds-credentials",
|
|
2164
|
+
"detailStateorphaned": "AUWlZW_detailStateorphaned",
|
|
1633
2165
|
"empty": "AUWlZW_empty",
|
|
1634
2166
|
"endpoint": "AUWlZW_endpoint",
|
|
1635
2167
|
"error": "AUWlZW_error",
|
|
1636
2168
|
"errorSummary": "AUWlZW_errorSummary",
|
|
2169
|
+
"extArrow": "AUWlZW_extArrow",
|
|
2170
|
+
"extLanguage": "AUWlZW_extLanguage",
|
|
2171
|
+
"extName": "AUWlZW_extName",
|
|
2172
|
+
"extRow": "AUWlZW_extRow",
|
|
1637
2173
|
"grid": "AUWlZW_grid",
|
|
1638
2174
|
"header": "AUWlZW_header",
|
|
1639
2175
|
"headerActions": "AUWlZW_headerActions",
|
|
1640
2176
|
"list": "AUWlZW_list",
|
|
1641
|
-
"
|
|
2177
|
+
"lspStartingPulse": "AUWlZW_lspStartingPulse",
|
|
2178
|
+
"mcp-retry-spin": "AUWlZW_mcp-retry-spin",
|
|
1642
2179
|
"modalFooter": "AUWlZW_modalFooter",
|
|
1643
2180
|
"name": "AUWlZW_name",
|
|
2181
|
+
"observedAt": "AUWlZW_observedAt",
|
|
1644
2182
|
"reason": "AUWlZW_reason",
|
|
2183
|
+
"reasonBox": "AUWlZW_reasonBox",
|
|
2184
|
+
"reasonLabel": "AUWlZW_reasonLabel",
|
|
2185
|
+
"reasonRaw": "AUWlZW_reasonRaw",
|
|
2186
|
+
"reasonText": "AUWlZW_reasonText",
|
|
2187
|
+
"retryEchoFailure": "AUWlZW_retryEchoFailure",
|
|
2188
|
+
"retryEchoSuccess": "AUWlZW_retryEchoSuccess",
|
|
2189
|
+
"retrySpinner": "AUWlZW_retrySpinner",
|
|
2190
|
+
"retryStack": "AUWlZW_retryStack",
|
|
1645
2191
|
"service": "AUWlZW_service",
|
|
1646
2192
|
"sourceDirect": "AUWlZW_sourceDirect",
|
|
1647
2193
|
"sourcePlugin": "AUWlZW_sourcePlugin",
|
|
2194
|
+
"spinning": "AUWlZW_spinning",
|
|
1648
2195
|
"state": "AUWlZW_state",
|
|
2196
|
+
"stateconflict": "AUWlZW_stateconflict",
|
|
1649
2197
|
"stateconnected": "AUWlZW_stateconnected",
|
|
1650
2198
|
"statedegraded": "AUWlZW_statedegraded",
|
|
1651
2199
|
"statedisabled": "AUWlZW_statedisabled",
|
|
1652
2200
|
"statefailed": "AUWlZW_statefailed",
|
|
2201
|
+
"statehost-missing": "AUWlZW_statehost-missing",
|
|
2202
|
+
"statemounted": "AUWlZW_statemounted",
|
|
2203
|
+
"stateneeds-credentials": "AUWlZW_stateneeds-credentials",
|
|
2204
|
+
"stateorphaned": "AUWlZW_stateorphaned",
|
|
2205
|
+
"statePill": "AUWlZW_statePill",
|
|
2206
|
+
"statusconflict": "AUWlZW_statusconflict",
|
|
1653
2207
|
"statusconnected": "AUWlZW_statusconnected",
|
|
1654
2208
|
"statusdegraded": "AUWlZW_statusdegraded",
|
|
1655
2209
|
"statusdisabled": "AUWlZW_statusdisabled",
|
|
1656
2210
|
"statusDot": "AUWlZW_statusDot",
|
|
1657
2211
|
"statusfailed": "AUWlZW_statusfailed",
|
|
2212
|
+
"statusforeign": "AUWlZW_statusforeign",
|
|
2213
|
+
"statushost-missing": "AUWlZW_statushost-missing",
|
|
2214
|
+
"statusmounted": "AUWlZW_statusmounted",
|
|
2215
|
+
"statusneeds-credentials": "AUWlZW_statusneeds-credentials",
|
|
2216
|
+
"statusorphaned": "AUWlZW_statusorphaned",
|
|
2217
|
+
"statusstarting": "AUWlZW_statusstarting",
|
|
1658
2218
|
"subtitle": "AUWlZW_subtitle",
|
|
1659
2219
|
"summary": "AUWlZW_summary",
|
|
2220
|
+
"summaryAllGood": "AUWlZW_summaryAllGood",
|
|
2221
|
+
"summaryBar": "AUWlZW_summaryBar",
|
|
2222
|
+
"summaryChip": "AUWlZW_summaryChip",
|
|
2223
|
+
"summaryCount": "AUWlZW_summaryCount",
|
|
1660
2224
|
"summaryDotGreen": "AUWlZW_summaryDotGreen",
|
|
2225
|
+
"summaryDotInfo": "AUWlZW_summaryDotInfo",
|
|
1661
2226
|
"summaryDotRed": "AUWlZW_summaryDotRed",
|
|
2227
|
+
"summaryDotWarn": "AUWlZW_summaryDotWarn",
|
|
2228
|
+
"summaryLabel": "AUWlZW_summaryLabel",
|
|
1662
2229
|
"surface": "AUWlZW_surface",
|
|
1663
2230
|
"title": "AUWlZW_title",
|
|
1664
2231
|
"tool": "AUWlZW_tool",
|
|
1665
2232
|
"toolbar": "AUWlZW_toolbar",
|
|
1666
2233
|
"toolCount": "AUWlZW_toolCount",
|
|
1667
2234
|
"toolDescription": "AUWlZW_toolDescription",
|
|
1668
|
-
"toolIndex": "AUWlZW_toolIndex",
|
|
1669
2235
|
"toolList": "AUWlZW_toolList",
|
|
1670
2236
|
"toolName": "AUWlZW_toolName",
|
|
1671
2237
|
"transport": "AUWlZW_transport"
|
|
1672
2238
|
};
|
|
1673
2239
|
//#endregion
|
|
1674
2240
|
//#region src/client/McpStatusPanel.tsx
|
|
1675
|
-
const EMPTY_STATUS = {
|
|
2241
|
+
const EMPTY_STATUS$1 = {
|
|
1676
2242
|
entries: [],
|
|
1677
2243
|
observedAt: "",
|
|
1678
2244
|
totals: {
|
|
@@ -1680,19 +2246,41 @@ const EMPTY_STATUS = {
|
|
|
1680
2246
|
connected: 0,
|
|
1681
2247
|
degraded: 0,
|
|
1682
2248
|
failed: 0,
|
|
1683
|
-
|
|
2249
|
+
needsCredentials: 0,
|
|
2250
|
+
orphaned: 0,
|
|
2251
|
+
disabled: 0,
|
|
2252
|
+
foreign: 0
|
|
1684
2253
|
},
|
|
1685
2254
|
directObservationOnly: true
|
|
1686
2255
|
};
|
|
1687
|
-
/** DSH-native MCP inventory
|
|
1688
|
-
function McpStatusPanel({ t }) {
|
|
1689
|
-
const [payload, setPayload] = (0, react.useState)(EMPTY_STATUS);
|
|
2256
|
+
/** DSH-native MCP inventory with a per-state overview and per-service detail. */
|
|
2257
|
+
function McpStatusPanel({ t, credentials }) {
|
|
2258
|
+
const [payload, setPayload] = (0, react.useState)(EMPTY_STATUS$1);
|
|
1690
2259
|
const [loading, setLoading] = (0, react.useState)(true);
|
|
1691
2260
|
const [error, setError] = (0, react.useState)(void 0);
|
|
1692
2261
|
const [filter, setFilter] = (0, react.useState)("all");
|
|
1693
2262
|
const [search, setSearch] = (0, react.useState)("");
|
|
1694
2263
|
const [view, setView] = (0, react.useState)("grid");
|
|
1695
2264
|
const [selected, setSelected] = (0, react.useState)(void 0);
|
|
2265
|
+
const retry = (entryId) => {
|
|
2266
|
+
return retryMcpMounts().then(async () => {
|
|
2267
|
+
const refreshed = await fetchMcpStatus().catch(() => void 0);
|
|
2268
|
+
if (refreshed !== void 0) setPayload(refreshed);
|
|
2269
|
+
return refreshed?.entries.some((entry) => entry.id === entryId && entry.state === "connected") === true;
|
|
2270
|
+
}).catch(async (caught) => {
|
|
2271
|
+
setError(caught instanceof Error ? caught.message : String(caught));
|
|
2272
|
+
const refreshed = await fetchMcpStatus().catch(() => void 0);
|
|
2273
|
+
if (refreshed !== void 0) setPayload(refreshed);
|
|
2274
|
+
return refreshed?.entries.some((entry) => entry.id === entryId && entry.state === "connected") === true;
|
|
2275
|
+
}).finally(() => setLoading(false));
|
|
2276
|
+
};
|
|
2277
|
+
const reauthorize = (serverName) => {
|
|
2278
|
+
return reauthorizeMcpServer(serverName).then(() => retryMcpMounts()).then(async () => {
|
|
2279
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
2280
|
+
const refreshed = await fetchMcpStatus().catch(() => void 0);
|
|
2281
|
+
if (refreshed !== void 0) setPayload(refreshed);
|
|
2282
|
+
});
|
|
2283
|
+
};
|
|
1696
2284
|
const refresh = () => {
|
|
1697
2285
|
setLoading(true);
|
|
1698
2286
|
setError(void 0);
|
|
@@ -1704,16 +2292,18 @@ function McpStatusPanel({ t }) {
|
|
|
1704
2292
|
refresh();
|
|
1705
2293
|
}, []);
|
|
1706
2294
|
const { activeEntries, filtered, filterCounts, visibleTotals } = deriveMcpStatusViewModel(payload, filter, search);
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
title: `${visibleTotals.failed} ${t("mcpFailed")}`
|
|
1710
|
-
}, (0, react.createElement)("span", { className: mcp_status_module_default.summaryDotRed }), visibleTotals.failed) : null, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2295
|
+
const allHealthy = activeEntries.length > 0 && visibleTotals.connected === activeEntries.length;
|
|
2296
|
+
return (0, react.createElement)("div", { className: mcp_status_module_default.surface }, (0, react.createElement)("header", { className: mcp_status_module_default.header }, (0, react.createElement)("div", { className: mcp_status_module_default.headerText }, (0, react.createElement)("h2", { className: mcp_status_module_default.title }, t("mcpStatusTitle")), (0, react.createElement)("p", { className: mcp_status_module_default.subtitle }, t("mcpStatusSubtitle"))), (0, react.createElement)("div", { className: mcp_status_module_default.headerActions }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1711
2297
|
variant: "ghost",
|
|
1712
2298
|
size: "sm",
|
|
1713
2299
|
onClick: refresh,
|
|
1714
2300
|
disabled: loading,
|
|
1715
2301
|
title: t("refresh")
|
|
1716
|
-
}, "
|
|
2302
|
+
}, `↻ ${t("refresh")}`))), activeEntries.length === 0 || allHealthy || loading ? null : (0, react.createElement)(StatusSummaryBar, {
|
|
2303
|
+
t,
|
|
2304
|
+
totals: visibleTotals,
|
|
2305
|
+
observedAt: payload.observedAt
|
|
2306
|
+
}), (0, react.createElement)(SearchFilterToolbar, {
|
|
1717
2307
|
className: mcp_status_module_default.toolbar,
|
|
1718
2308
|
search,
|
|
1719
2309
|
searchLabel: t("mcpSearch"),
|
|
@@ -1729,7 +2319,8 @@ function McpStatusPanel({ t }) {
|
|
|
1729
2319
|
count: filterCounts[kind],
|
|
1730
2320
|
icon: (0, react.createElement)(McpFilterIcon, { kind }),
|
|
1731
2321
|
active: filter === kind,
|
|
1732
|
-
onSelect: () => setFilter(kind)
|
|
2322
|
+
onSelect: () => setFilter(kind),
|
|
2323
|
+
hint: mcpFilterHint(t, kind)
|
|
1733
2324
|
})),
|
|
1734
2325
|
view,
|
|
1735
2326
|
gridLabel: t("grid"),
|
|
@@ -1747,31 +2338,94 @@ function McpStatusPanel({ t }) {
|
|
|
1747
2338
|
}))), selected === void 0 ? null : (0, react.createElement)(McpDetailModal, {
|
|
1748
2339
|
entry: selected,
|
|
1749
2340
|
t,
|
|
1750
|
-
|
|
2341
|
+
credentials,
|
|
2342
|
+
onClose: () => setSelected(void 0),
|
|
2343
|
+
onRetry: retry,
|
|
2344
|
+
onReauthorize: reauthorize
|
|
1751
2345
|
}));
|
|
1752
2346
|
}
|
|
2347
|
+
/**
|
|
2348
|
+
* One chip per non-healthy state, shown only when that state is non-zero.
|
|
2349
|
+
*
|
|
2350
|
+
* The chips are ordered by severity so the first one the eye lands on is the
|
|
2351
|
+
* state that most needs attention, and the whole bar collapses to a single
|
|
2352
|
+
* "all connected" confirmation when nothing is wrong.
|
|
2353
|
+
*/
|
|
2354
|
+
function StatusSummaryBar({ t, totals, observedAt }) {
|
|
2355
|
+
const chips = [
|
|
2356
|
+
{
|
|
2357
|
+
key: "orphaned",
|
|
2358
|
+
count: totals.orphaned,
|
|
2359
|
+
label: t("mcpOrphaned")
|
|
2360
|
+
},
|
|
2361
|
+
{
|
|
2362
|
+
key: "failed",
|
|
2363
|
+
count: totals.failed,
|
|
2364
|
+
label: t("mcpFailed")
|
|
2365
|
+
},
|
|
2366
|
+
{
|
|
2367
|
+
key: "needsCredentials",
|
|
2368
|
+
count: totals.needsCredentials,
|
|
2369
|
+
label: t("mcpNeedsCredentials")
|
|
2370
|
+
},
|
|
2371
|
+
{
|
|
2372
|
+
key: "degraded",
|
|
2373
|
+
count: totals.degraded,
|
|
2374
|
+
label: t("mcpDegraded")
|
|
2375
|
+
},
|
|
2376
|
+
{
|
|
2377
|
+
key: "foreign",
|
|
2378
|
+
count: totals.foreign,
|
|
2379
|
+
label: t("mcpForeign")
|
|
2380
|
+
},
|
|
2381
|
+
{
|
|
2382
|
+
key: "disabled",
|
|
2383
|
+
count: totals.disabled,
|
|
2384
|
+
label: t("mcpDisabled")
|
|
2385
|
+
}
|
|
2386
|
+
].filter((chip) => chip.count > 0);
|
|
2387
|
+
return (0, react.createElement)("div", { className: mcp_status_module_default.summaryBar }, chips.length === 0 ? (0, react.createElement)("span", { className: mcp_status_module_default.summaryAllGood }, (0, react.createElement)("span", { className: mcp_status_module_default.summaryDotGreen }), t("mcpAllConnected")) : chips.map((chip) => (0, react.createElement)("span", {
|
|
2388
|
+
key: chip.key,
|
|
2389
|
+
className: `${mcp_status_module_default.summaryChip} ${mcp_status_module_default[`chip${chip.key}`]}`,
|
|
2390
|
+
title: `${chip.count} ${chip.label}`
|
|
2391
|
+
}, (0, react.createElement)("span", { className: mcp_status_module_default[`summaryDot${dotTone(chip.key)}`] }), (0, react.createElement)("span", { className: mcp_status_module_default.summaryCount }, chip.count), (0, react.createElement)("span", { className: mcp_status_module_default.summaryLabel }, chip.label))), (0, react.createElement)("span", { className: mcp_status_module_default.observedAt }, observedAt === "" ? "" : formatObservedAt$1(observedAt)));
|
|
2392
|
+
}
|
|
2393
|
+
function dotTone(key) {
|
|
2394
|
+
if (key === "foreign") return "Info";
|
|
2395
|
+
if (key === "degraded" || key === "needsCredentials") return "Warn";
|
|
2396
|
+
return "Red";
|
|
2397
|
+
}
|
|
2398
|
+
function formatObservedAt$1(iso) {
|
|
2399
|
+
const date = new Date(iso);
|
|
2400
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
2401
|
+
return date.toLocaleTimeString();
|
|
2402
|
+
}
|
|
1753
2403
|
function McpCard({ entry, t, onClick }) {
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
onClick
|
|
1758
|
-
|
|
2404
|
+
const interactive = {
|
|
2405
|
+
role: "button",
|
|
2406
|
+
tabIndex: 0,
|
|
2407
|
+
onClick,
|
|
2408
|
+
onKeyDown: (event) => {
|
|
2409
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
2410
|
+
event.preventDefault();
|
|
2411
|
+
onClick();
|
|
2412
|
+
}
|
|
2413
|
+
};
|
|
2414
|
+
return (0, react.createElement)("div", {
|
|
2415
|
+
className: `${mcp_status_module_default.card} ${mcp_status_module_default[`card${stateClass(entry.state)}`]}`,
|
|
2416
|
+
...interactive
|
|
2417
|
+
}, (0, react.createElement)("div", { className: mcp_status_module_default.cardBody }, (0, react.createElement)("div", { className: mcp_status_module_default.cardTop }, (0, react.createElement)("span", {
|
|
1759
2418
|
className: `${mcp_status_module_default.statusDot} ${mcp_status_module_default[`status${entry.state}`]}`,
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
}), (0, react.createElement)("span", { className: mcp_status_module_default.service }, (0, react.createElement)("span", { className: mcp_status_module_default.name }, entry.name)), (0, react.createElement)("span", { className: mcp_status_module_default.toolCount }, `${t("mcpTools")} ${entry.tools.length}`)), (0, react.createElement)("p", { className: mcp_status_module_default.endpoint }, entry.endpoint ?? t("mcpObservedEndpoint")), (0, react.createElement)("div", { className: mcp_status_module_default.meta }, (0, react.createElement)(McpSourceBadge, {
|
|
1763
|
-
kind: entry.kind,
|
|
1764
|
-
label: entry.kind === "plugin" ? entry.source ?? "—" : t("mcpDirect"),
|
|
1765
|
-
t
|
|
1766
|
-
}), (0, react.createElement)("span", { className: mcp_status_module_default.transport }, entry.transport)), entry.reason === void 0 ? null : (0, react.createElement)("p", { className: mcp_status_module_default.cardReason }, entry.reason));
|
|
2419
|
+
"aria-hidden": true
|
|
2420
|
+
}), (0, react.createElement)("span", { className: mcp_status_module_default.service }, (0, react.createElement)("span", { className: mcp_status_module_default.name }, entry.name)), (0, react.createElement)("span", { className: mcp_status_module_default.toolCount }, entry.tools.length === 1 ? `${entry.tools.length} ${t("mcpTool")}` : `${entry.tools.length} ${t("mcpTools")}`)), (0, react.createElement)("p", { className: mcp_status_module_default.endpoint }, entry.endpoint ?? t("mcpObservedEndpoint"))));
|
|
1767
2421
|
}
|
|
1768
|
-
function
|
|
1769
|
-
return
|
|
2422
|
+
function stateClass(state) {
|
|
2423
|
+
return state.split("-").map((part, index) => index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)).join("").replace(/^./, (char) => char.toUpperCase());
|
|
1770
2424
|
}
|
|
1771
2425
|
function McpSourceIcon({ kind }) {
|
|
1772
2426
|
const common = {
|
|
1773
|
-
width:
|
|
1774
|
-
height:
|
|
2427
|
+
width: 14,
|
|
2428
|
+
height: 14,
|
|
1775
2429
|
viewBox: "0 0 16 16",
|
|
1776
2430
|
fill: "none",
|
|
1777
2431
|
"aria-hidden": true
|
|
@@ -1793,7 +2447,27 @@ function McpFilterIcon({ kind }) {
|
|
|
1793
2447
|
"aria-hidden": true
|
|
1794
2448
|
}, (0, react.createElement)("path", { d: "M2.5 5 8 2.5 13.5 5 8 7.5 2.5 5Zm0 3L8 10.5 13.5 8M2.5 11 8 13.5 13.5 11" }));
|
|
1795
2449
|
}
|
|
1796
|
-
|
|
2450
|
+
/**
|
|
2451
|
+
* The detail dialog owns every action and every long text: state, reason,
|
|
2452
|
+
* credentials, config, tools, and the retry control with its in-place result
|
|
2453
|
+
* echo. The state pill is dropped entirely — the dot and the reason box carry
|
|
2454
|
+
* that information without a second red stamp.
|
|
2455
|
+
*/
|
|
2456
|
+
function McpDetailModal({ entry, t, credentials, onClose, onRetry, onReauthorize }) {
|
|
2457
|
+
const [retrying, setRetrying] = (0, react.useState)(false);
|
|
2458
|
+
const [retryOutcome, setRetryOutcome] = (0, react.useState)(void 0);
|
|
2459
|
+
const [reauthorizing, setReauthorizing] = (0, react.useState)(false);
|
|
2460
|
+
const [reauthOutcome, setReauthOutcome] = (0, react.useState)(void 0);
|
|
2461
|
+
const retry = () => {
|
|
2462
|
+
setRetrying(true);
|
|
2463
|
+
setRetryOutcome(void 0);
|
|
2464
|
+
onRetry(entry.id).then((success) => setRetryOutcome(success ? "success" : "failure")).catch(() => setRetryOutcome("failure")).finally(() => setRetrying(false));
|
|
2465
|
+
};
|
|
2466
|
+
const reauthorize = () => {
|
|
2467
|
+
setReauthorizing(true);
|
|
2468
|
+
setReauthOutcome(void 0);
|
|
2469
|
+
onReauthorize(entry.name).then(() => setReauthOutcome("success")).catch(() => setReauthOutcome("failure")).finally(() => setReauthorizing(false));
|
|
2470
|
+
};
|
|
1797
2471
|
return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
1798
2472
|
open: true,
|
|
1799
2473
|
onClose,
|
|
@@ -1802,18 +2476,47 @@ function McpDetailModal({ entry, t, onClose }) {
|
|
|
1802
2476
|
closeLabel: t("cancel"),
|
|
1803
2477
|
className: mcp_status_module_default.detailDialog,
|
|
1804
2478
|
contentClassName: mcp_status_module_default.detailBody,
|
|
1805
|
-
footer: (0, react.createElement)("div", { className: mcp_status_module_default.modalFooter }, (0, react.createElement)(
|
|
2479
|
+
footer: (0, react.createElement)("div", { className: mcp_status_module_default.modalFooter }, entry.kind === "direct" || entry.state === "connected" || entry.state === "disabled" || entry.state === "foreign" ? null : (0, react.createElement)("span", { className: mcp_status_module_default.retryStack }, retryOutcome === "success" ? (0, react.createElement)("span", {
|
|
2480
|
+
className: mcp_status_module_default.retryEchoSuccess,
|
|
2481
|
+
role: "status"
|
|
2482
|
+
}, `✓ ${t("mcpRetrySuccess")}`) : retryOutcome === "failure" ? (0, react.createElement)("span", {
|
|
2483
|
+
className: mcp_status_module_default.retryEchoFailure,
|
|
2484
|
+
role: "alert"
|
|
2485
|
+
}, `✕ ${t("mcpRetryFailure")}`) : null, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2486
|
+
variant: "ghost",
|
|
2487
|
+
size: "sm",
|
|
2488
|
+
disabled: retrying,
|
|
2489
|
+
onClick: retry
|
|
2490
|
+
}, (0, react.createElement)("span", {
|
|
2491
|
+
className: retrying ? `${mcp_status_module_default.retrySpinner} ${mcp_status_module_default.spinning}` : mcp_status_module_default.retrySpinner,
|
|
2492
|
+
"aria-hidden": true
|
|
2493
|
+
}, "↻"), retrying ? t("mcpRetrying") : t("mcpRetry"))), entry.kind === "plugin" ? (0, react.createElement)("span", { className: mcp_status_module_default.retryStack }, reauthOutcome === "success" ? (0, react.createElement)("span", {
|
|
2494
|
+
className: mcp_status_module_default.retryEchoSuccess,
|
|
2495
|
+
role: "status"
|
|
2496
|
+
}, `✓ ${t("mcpReauthSuccess")}`) : reauthOutcome === "failure" ? (0, react.createElement)("span", {
|
|
2497
|
+
className: mcp_status_module_default.retryEchoFailure,
|
|
2498
|
+
role: "alert"
|
|
2499
|
+
}, `✕ ${t("mcpReauthFailure")}`) : null, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2500
|
+
variant: "ghost",
|
|
2501
|
+
size: "sm",
|
|
2502
|
+
disabled: reauthorizing,
|
|
2503
|
+
title: entry.state === "failed" ? t("mcpConnectHint") : t("mcpReauthHint"),
|
|
2504
|
+
onClick: reauthorize
|
|
2505
|
+
}, reauthorizing ? t("mcpReauthorizing") : entry.state === "failed" ? t("mcpConnect") : t("mcpReauthorize"))) : null, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1806
2506
|
variant: "ghost",
|
|
1807
2507
|
onClick: onClose
|
|
1808
2508
|
}, t("cancel"))),
|
|
1809
|
-
children: (0, react.createElement)("div", { className: mcp_status_module_default.detail }, (0, react.createElement)("div", { className: mcp_status_module_default.
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
2509
|
+
children: (0, react.createElement)("div", { className: mcp_status_module_default.detail }, (0, react.createElement)("div", { className: mcp_status_module_default.detailHero }, (0, react.createElement)("span", {
|
|
2510
|
+
className: `${mcp_status_module_default.statusDot} ${mcp_status_module_default[`status${entry.state}`]}`,
|
|
2511
|
+
"aria-hidden": true
|
|
2512
|
+
}), (0, react.createElement)("div", { className: mcp_status_module_default.detailHeroText }, entry.endpoint === void 0 ? null : (0, react.createElement)("p", { className: mcp_status_module_default.detailEndpoint }, entry.endpoint), (0, react.createElement)("p", { className: mcp_status_module_default.detailEndpoint }, [entry.kind === "plugin" ? `${t("mcpPlugin")}: ${entry.source ?? "—"}` : t("mcpDirect"), entry.transport].join(" · ")))), entry.state === "foreign" ? (0, react.createElement)("div", { className: mcp_status_module_default.reasonBox }, (0, react.createElement)("span", { className: mcp_status_module_default.reasonLabel }, t("mcpReasonLabel")), (0, react.createElement)("p", { className: mcp_status_module_default.reasonText }, entry.code === "duplicate-mount" ? t("mcpDuplicateHint") : t("mcpForeignHint")), entry.reason === void 0 ? null : (0, react.createElement)("p", { className: mcp_status_module_default.reasonRaw }, entry.reason)) : entry.reason === void 0 ? null : (0, react.createElement)("div", { className: mcp_status_module_default.reasonBox }, (0, react.createElement)("span", { className: mcp_status_module_default.reasonLabel }, t("mcpReasonLabel")), (0, react.createElement)("p", { className: mcp_status_module_default.reasonText }, entry.reason)), entry.kind === "direct" ? (0, react.createElement)("div", { className: mcp_status_module_default.reasonBox }, (0, react.createElement)("p", { className: mcp_status_module_default.reasonText }, t("mcpDirectBoundary"))) : null, entry.credentialRefs?.length === 0 || entry.credentialRefs === void 0 ? null : (0, react.createElement)(McpCredentialEditor, {
|
|
2513
|
+
t,
|
|
2514
|
+
api: credentials,
|
|
2515
|
+
refs: entry.credentialRefs
|
|
2516
|
+
}), (0, react.createElement)("section", { className: mcp_status_module_default.detailSection }, (0, react.createElement)("h4", { className: mcp_status_module_default.detailHead }, t("mcpConfig")), entry.config === void 0 ? (0, react.createElement)("div", { className: mcp_status_module_default.detailEmpty }, t("mcpDirectConfigUnavailable")) : (0, react.createElement)("pre", { className: mcp_status_module_default.config }, JSON.stringify(entry.config, null, 2))), (0, react.createElement)("section", { className: mcp_status_module_default.detailSection }, (0, react.createElement)("h4", { className: mcp_status_module_default.detailHead }, `${t("mcpTools")} (${entry.tools.length})`), entry.tools.length === 0 ? (0, react.createElement)("div", { className: mcp_status_module_default.detailEmpty }, entry.advertisedTools === false && entry.state === "degraded" ? t("mcpZeroTools") : t("mcpNoTools")) : (0, react.createElement)("div", { className: mcp_status_module_default.toolList }, entry.tools.map((tool) => (0, react.createElement)("div", {
|
|
1814
2517
|
key: tool.name,
|
|
1815
2518
|
className: mcp_status_module_default.tool
|
|
1816
|
-
}, (0, react.createElement)("span", { className: mcp_status_module_default.
|
|
2519
|
+
}, (0, react.createElement)("span", { className: mcp_status_module_default.toolName }, tool.name), tool.description === void 0 || tool.description === "" ? null : (0, react.createElement)("span", { className: mcp_status_module_default.toolDescription }, tool.description))))))
|
|
1817
2520
|
});
|
|
1818
2521
|
}
|
|
1819
2522
|
function filterLabel(t, kind) {
|
|
@@ -1821,11 +2524,448 @@ function filterLabel(t, kind) {
|
|
|
1821
2524
|
if (kind === "direct") return t("mcpDirect");
|
|
1822
2525
|
return t("mcpAll");
|
|
1823
2526
|
}
|
|
2527
|
+
/** Hover/aria explanation for each MCP filter tab. */
|
|
2528
|
+
function mcpFilterHint(t, kind) {
|
|
2529
|
+
if (kind === "plugin") return t("mcpFilterPluginHint");
|
|
2530
|
+
if (kind === "direct") return t("mcpFilterDirectHint");
|
|
2531
|
+
return t("mcpFilterAllHint");
|
|
2532
|
+
}
|
|
2533
|
+
//#endregion
|
|
2534
|
+
//#region src/client/LspStatusPanel.tsx
|
|
2535
|
+
/**
|
|
2536
|
+
* LSP status panel: declared language servers of enabled suites with their
|
|
2537
|
+
* mount state. Rows come from the declaration-and-diagnostic model — the DSH
|
|
2538
|
+
* `ctx.lsp` seam has no provider snapshot, so "mounted" means the mount
|
|
2539
|
+
* registration succeeded, not that a process probe ran.
|
|
2540
|
+
*
|
|
2541
|
+
* Visual language mirrors McpStatusPanel: the same shared SearchFilterToolbar,
|
|
2542
|
+
* the same summary chips, cards, and state pills from mcp-status.module.css.
|
|
2543
|
+
* Cards stay lean (state dot + name + command + one state pill); the source
|
|
2544
|
+
* suite and the full extension map live in the detail dialog.
|
|
2545
|
+
*/
|
|
2546
|
+
const EMPTY_STATUS = {
|
|
2547
|
+
entries: [],
|
|
2548
|
+
observedAt: "",
|
|
2549
|
+
totals: {
|
|
2550
|
+
all: 0,
|
|
2551
|
+
mounted: 0,
|
|
2552
|
+
failed: 0,
|
|
2553
|
+
blocked: 0,
|
|
2554
|
+
disabled: 0
|
|
2555
|
+
},
|
|
2556
|
+
hostMissing: true
|
|
2557
|
+
};
|
|
2558
|
+
const FILTER_KEYS = [
|
|
2559
|
+
"all",
|
|
2560
|
+
"plugin",
|
|
2561
|
+
"direct",
|
|
2562
|
+
"blocked"
|
|
2563
|
+
];
|
|
2564
|
+
const FILTER_LABEL_KEYS = {
|
|
2565
|
+
all: "lspAll",
|
|
2566
|
+
plugin: "lspPlugin",
|
|
2567
|
+
direct: "lspDirect",
|
|
2568
|
+
blocked: "lspBlocked"
|
|
2569
|
+
};
|
|
2570
|
+
/** Tooltip text per filter: the counts alone do not explain the grouping. */
|
|
2571
|
+
const FILTER_HINT_KEYS = {
|
|
2572
|
+
all: "lspFilterAllHint",
|
|
2573
|
+
plugin: "lspFilterPluginHint",
|
|
2574
|
+
direct: "lspFilterDirectHint",
|
|
2575
|
+
blocked: "lspFilterBlockedHint"
|
|
2576
|
+
};
|
|
2577
|
+
function matches(entry, filter) {
|
|
2578
|
+
if (filter === "all") return true;
|
|
2579
|
+
if (filter === "plugin" || filter === "direct") return entry.kind === filter;
|
|
2580
|
+
return entry.state === "host-missing" || entry.state === "conflict" || entry.state === "failed";
|
|
2581
|
+
}
|
|
2582
|
+
function severity(entry) {
|
|
2583
|
+
if (entry.state === "failed") return 0;
|
|
2584
|
+
if (entry.state === "conflict") return 1;
|
|
2585
|
+
if (entry.state === "host-missing") return 2;
|
|
2586
|
+
if (entry.state === "starting") return 3;
|
|
2587
|
+
if (entry.state === "disabled") return 4;
|
|
2588
|
+
return 5;
|
|
2589
|
+
}
|
|
2590
|
+
/** Language-server inventory with per-state overview and per-server detail. */
|
|
2591
|
+
function LspStatusPanel({ t }) {
|
|
2592
|
+
const [payload, setPayload] = (0, react.useState)(EMPTY_STATUS);
|
|
2593
|
+
const [loading, setLoading] = (0, react.useState)(true);
|
|
2594
|
+
const [error, setError] = (0, react.useState)(void 0);
|
|
2595
|
+
const [filter, setFilter] = (0, react.useState)("all");
|
|
2596
|
+
const [search, setSearch] = (0, react.useState)("");
|
|
2597
|
+
const [view, setView] = (0, react.useState)("grid");
|
|
2598
|
+
const [selected, setSelected] = (0, react.useState)(void 0);
|
|
2599
|
+
const [editorOpen, setEditorOpen] = (0, react.useState)(false);
|
|
2600
|
+
const refresh = () => {
|
|
2601
|
+
setLoading(true);
|
|
2602
|
+
setError(void 0);
|
|
2603
|
+
fetchLspStatus().then(setPayload).catch((caught) => {
|
|
2604
|
+
setError(caught instanceof Error ? caught.message : String(caught));
|
|
2605
|
+
}).finally(() => setLoading(false));
|
|
2606
|
+
};
|
|
2607
|
+
(0, react.useEffect)(() => {
|
|
2608
|
+
refresh();
|
|
2609
|
+
}, []);
|
|
2610
|
+
const anyStarting = payload.entries.some((entry) => entry.state === "starting");
|
|
2611
|
+
(0, react.useEffect)(() => {
|
|
2612
|
+
if (!anyStarting) return;
|
|
2613
|
+
let cancelled = false;
|
|
2614
|
+
let attempts = 0;
|
|
2615
|
+
const timer = setInterval(() => {
|
|
2616
|
+
attempts += 1;
|
|
2617
|
+
if (cancelled || attempts > 20) {
|
|
2618
|
+
clearInterval(timer);
|
|
2619
|
+
return;
|
|
2620
|
+
}
|
|
2621
|
+
fetchLspStatus().then((value) => {
|
|
2622
|
+
if (!cancelled) setPayload(value);
|
|
2623
|
+
}).catch(() => {});
|
|
2624
|
+
}, 1e3);
|
|
2625
|
+
return () => {
|
|
2626
|
+
cancelled = true;
|
|
2627
|
+
clearInterval(timer);
|
|
2628
|
+
};
|
|
2629
|
+
}, [anyStarting]);
|
|
2630
|
+
const needle = search.trim().toLowerCase();
|
|
2631
|
+
const counts = FILTER_KEYS.reduce((acc, key) => {
|
|
2632
|
+
acc[key] = payload.entries.filter((entry) => matches(entry, key)).length;
|
|
2633
|
+
return acc;
|
|
2634
|
+
}, {});
|
|
2635
|
+
const visible = payload.entries.filter((entry) => matches(entry, filter)).filter((entry) => needle === "" || `${entry.serverKey} ${entry.suiteName} ${entry.command}`.toLowerCase().includes(needle));
|
|
2636
|
+
const settled = payload.entries.filter((entry) => entry.state !== "starting");
|
|
2637
|
+
const allHealthy = settled.length > 0 && settled.every((entry) => entry.state === "mounted");
|
|
2638
|
+
return (0, react.createElement)("div", { className: mcp_status_module_default.surface }, (0, react.createElement)("header", { className: mcp_status_module_default.header }, (0, react.createElement)("div", { className: mcp_status_module_default.headerText }, (0, react.createElement)("h2", { className: mcp_status_module_default.title }, t("lspStatusTitle")), (0, react.createElement)("p", { className: mcp_status_module_default.subtitle }, t("lspStatusSubtitle"))), (0, react.createElement)("div", { className: mcp_status_module_default.headerActions }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2639
|
+
variant: "ghost",
|
|
2640
|
+
size: "sm",
|
|
2641
|
+
onClick: () => setEditorOpen(true),
|
|
2642
|
+
disabled: loading,
|
|
2643
|
+
title: t("lspConfigure")
|
|
2644
|
+
}, t("lspConfigure")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2645
|
+
variant: "ghost",
|
|
2646
|
+
size: "sm",
|
|
2647
|
+
onClick: refresh,
|
|
2648
|
+
disabled: loading,
|
|
2649
|
+
title: t("refresh")
|
|
2650
|
+
}, `↻ ${t("refresh")}`))), allHealthy || payload.entries.length === 0 || loading ? null : (0, react.createElement)("div", { className: mcp_status_module_default.summaryBar }, payload.hostMissing ? (0, react.createElement)("span", {
|
|
2651
|
+
className: `${mcp_status_module_default.summaryChip} ${mcp_status_module_default.chipblocked}`,
|
|
2652
|
+
title: t("lspHostMissing")
|
|
2653
|
+
}, t("lspHostMissingShort")) : [
|
|
2654
|
+
{
|
|
2655
|
+
key: "failed",
|
|
2656
|
+
count: payload.totals.failed,
|
|
2657
|
+
label: t("lspFailed")
|
|
2658
|
+
},
|
|
2659
|
+
{
|
|
2660
|
+
key: "blocked",
|
|
2661
|
+
count: payload.totals.blocked,
|
|
2662
|
+
label: t("lspBlocked")
|
|
2663
|
+
},
|
|
2664
|
+
{
|
|
2665
|
+
key: "disabled",
|
|
2666
|
+
count: payload.totals.disabled,
|
|
2667
|
+
label: t("lspDisabled")
|
|
2668
|
+
}
|
|
2669
|
+
].filter((chip) => chip.count > 0).map((chip) => (0, react.createElement)("span", {
|
|
2670
|
+
key: chip.key,
|
|
2671
|
+
className: `${mcp_status_module_default.summaryChip} ${mcp_status_module_default[`chip${chip.key}`]}`,
|
|
2672
|
+
title: `${chip.count} ${chip.label}`
|
|
2673
|
+
}, (0, react.createElement)("span", { className: mcp_status_module_default.summaryCount }, chip.count), (0, react.createElement)("span", { className: mcp_status_module_default.summaryLabel }, chip.label))), (0, react.createElement)("span", { className: mcp_status_module_default.observedAt }, formatObservedAt(payload.observedAt))), (0, react.createElement)(SearchFilterToolbar, {
|
|
2674
|
+
className: mcp_status_module_default.toolbar,
|
|
2675
|
+
search,
|
|
2676
|
+
searchLabel: t("lspSearch"),
|
|
2677
|
+
searchPlaceholder: t("lspSearch"),
|
|
2678
|
+
onSearchChange: setSearch,
|
|
2679
|
+
filters: FILTER_KEYS.map((key) => ({
|
|
2680
|
+
id: key,
|
|
2681
|
+
label: t(FILTER_LABEL_KEYS[key]),
|
|
2682
|
+
count: counts[key] ?? 0,
|
|
2683
|
+
icon: (0, react.createElement)(LspFilterIcon, { k: key }),
|
|
2684
|
+
active: filter === key,
|
|
2685
|
+
onSelect: () => setFilter(key),
|
|
2686
|
+
hint: FILTER_HINT_KEYS[key] === void 0 ? void 0 : t(FILTER_HINT_KEYS[key])
|
|
2687
|
+
})),
|
|
2688
|
+
view,
|
|
2689
|
+
gridLabel: t("grid"),
|
|
2690
|
+
listLabel: t("list"),
|
|
2691
|
+
onViewChange: (nextView) => setView(nextView)
|
|
2692
|
+
}), error !== void 0 ? (0, react.createElement)("div", { className: mcp_status_module_default.error }, error, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2693
|
+
variant: "ghost",
|
|
2694
|
+
size: "sm",
|
|
2695
|
+
onClick: refresh
|
|
2696
|
+
}, t("mcpRetry"))) : loading && payload.entries.length === 0 ? (0, react.createElement)("div", { className: mcp_status_module_default.empty }, t("loading")) : visible.length === 0 ? (0, react.createElement)("div", { className: mcp_status_module_default.empty }, t("lspEmpty")) : (0, react.createElement)("div", { className: view === "grid" ? mcp_status_module_default.grid : mcp_status_module_default.list }, [...visible].sort((left, right) => severity(left) - severity(right)).map((entry) => (0, react.createElement)(LspRow, {
|
|
2697
|
+
key: entry.id,
|
|
2698
|
+
entry,
|
|
2699
|
+
t,
|
|
2700
|
+
onOpen: () => setSelected(entry)
|
|
2701
|
+
}))), selected === void 0 ? null : (0, react.createElement)(LspDetailModal, {
|
|
2702
|
+
entry: selected,
|
|
2703
|
+
t,
|
|
2704
|
+
onClose: () => setSelected(void 0)
|
|
2705
|
+
}), editorOpen ? (0, react.createElement)(LspConfigEditor, {
|
|
2706
|
+
t,
|
|
2707
|
+
onClose: () => setEditorOpen(false),
|
|
2708
|
+
onSaved: () => {
|
|
2709
|
+
setEditorOpen(false);
|
|
2710
|
+
refresh();
|
|
2711
|
+
}
|
|
2712
|
+
}) : null);
|
|
2713
|
+
}
|
|
2714
|
+
/**
|
|
2715
|
+
* Direct LSP configuration editor: one JSON document shaped like Claude
|
|
2716
|
+
* Code's `lspServers` table. The host validates with the same fail-closed
|
|
2717
|
+
* rules as suite declarations and mounts direct servers on the next
|
|
2718
|
+
* reconcile pass.
|
|
2719
|
+
*/
|
|
2720
|
+
function LspConfigEditor({ t, onClose, onSaved }) {
|
|
2721
|
+
const [text, setText] = (0, react.useState)(void 0);
|
|
2722
|
+
const [busy, setBusy] = (0, react.useState)(false);
|
|
2723
|
+
const [error, setError] = (0, react.useState)(void 0);
|
|
2724
|
+
(0, react.useEffect)(() => {
|
|
2725
|
+
let cancelled = false;
|
|
2726
|
+
fetchLspServers().then((servers) => {
|
|
2727
|
+
if (cancelled) return;
|
|
2728
|
+
setText(JSON.stringify({ lspServers: servers }, null, 2));
|
|
2729
|
+
}).catch((reason) => {
|
|
2730
|
+
if (cancelled) setError(reason instanceof Error ? reason.message : String(reason));
|
|
2731
|
+
});
|
|
2732
|
+
return () => {
|
|
2733
|
+
cancelled = true;
|
|
2734
|
+
};
|
|
2735
|
+
}, []);
|
|
2736
|
+
const save = async () => {
|
|
2737
|
+
setBusy(true);
|
|
2738
|
+
setError(void 0);
|
|
2739
|
+
try {
|
|
2740
|
+
await saveLspServers(JSON.parse(text ?? ""));
|
|
2741
|
+
onSaved();
|
|
2742
|
+
} catch (reason) {
|
|
2743
|
+
setError(reason instanceof Error ? reason.message : String(reason));
|
|
2744
|
+
} finally {
|
|
2745
|
+
setBusy(false);
|
|
2746
|
+
}
|
|
2747
|
+
};
|
|
2748
|
+
return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
2749
|
+
open: true,
|
|
2750
|
+
onClose,
|
|
2751
|
+
title: t("lspConfigure"),
|
|
2752
|
+
description: t("lspConfigureHint"),
|
|
2753
|
+
closeLabel: t("cancel"),
|
|
2754
|
+
className: mcp_status_module_default.detailDialog,
|
|
2755
|
+
contentClassName: mcp_status_module_default.detailBody,
|
|
2756
|
+
footer: (0, react.createElement)("div", { className: mcp_status_module_default.modalFooter }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2757
|
+
variant: "ghost",
|
|
2758
|
+
onClick: onClose
|
|
2759
|
+
}, t("cancel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2760
|
+
variant: "primary",
|
|
2761
|
+
disabled: busy || text === void 0,
|
|
2762
|
+
onClick: () => {
|
|
2763
|
+
save();
|
|
2764
|
+
}
|
|
2765
|
+
}, t("lspSave"))),
|
|
2766
|
+
children: (0, react.createElement)("div", { className: mcp_status_module_default.detail }, error === void 0 ? null : (0, react.createElement)("div", { className: mcp_status_module_default.error }, error), text === void 0 ? (0, react.createElement)("div", { className: mcp_status_module_default.empty }, t("loading")) : (0, react.createElement)("textarea", {
|
|
2767
|
+
className: mcp_status_module_default.config,
|
|
2768
|
+
rows: 16,
|
|
2769
|
+
spellcheck: false,
|
|
2770
|
+
value: text,
|
|
2771
|
+
onChange: (event) => setText(event.target.value)
|
|
2772
|
+
}))
|
|
2773
|
+
});
|
|
2774
|
+
}
|
|
2775
|
+
/** Lean row: state dot, server key, command. The card accent + status dot
|
|
2776
|
+
* carry the state; no redundant pill for the healthy case. Kind badge shows
|
|
2777
|
+
* where the declaration comes from (suite vs user configuration). */
|
|
2778
|
+
function LspRow({ entry, t, onOpen }) {
|
|
2779
|
+
const interactive = {
|
|
2780
|
+
role: "button",
|
|
2781
|
+
tabIndex: 0,
|
|
2782
|
+
onClick: onOpen,
|
|
2783
|
+
onKeyDown: (event) => {
|
|
2784
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
2785
|
+
event.preventDefault();
|
|
2786
|
+
onOpen();
|
|
2787
|
+
}
|
|
2788
|
+
};
|
|
2789
|
+
const showPill = entry.state !== "mounted";
|
|
2790
|
+
return (0, react.createElement)("div", {
|
|
2791
|
+
className: `${mcp_status_module_default.card} ${mcp_status_module_default[`card${accentClass(entry.state)}`]}`,
|
|
2792
|
+
...interactive
|
|
2793
|
+
}, (0, react.createElement)("div", { className: mcp_status_module_default.cardBody }, (0, react.createElement)("div", { className: mcp_status_module_default.cardTop }, (0, react.createElement)("span", {
|
|
2794
|
+
className: `${mcp_status_module_default.statusDot} ${mcp_status_module_default[`status${dotClass(entry.state)}`]}`,
|
|
2795
|
+
"aria-hidden": true
|
|
2796
|
+
}), (0, react.createElement)("span", { className: mcp_status_module_default.service }, (0, react.createElement)("span", { className: mcp_status_module_default.name }, entry.serverKey)), entry.kind === "plugin" ? (0, react.createElement)("span", { className: mcp_status_module_default.sourcePlugin }, entry.suiteName) : (0, react.createElement)("span", { className: mcp_status_module_default.sourceDirect }, t("lspDirect")), showPill ? (0, react.createElement)("span", { className: `${mcp_status_module_default.statePill} ${mcp_status_module_default[`state${pillClass(entry.state)}`]}` }, stateLabel(t, entry.state)) : null), (0, react.createElement)("p", { className: mcp_status_module_default.endpoint }, [entry.command, ...entry.args].join(" "))));
|
|
2797
|
+
}
|
|
2798
|
+
function LspDetailModal({ entry, t, onClose }) {
|
|
2799
|
+
const extensions = Object.entries(entry.extensions);
|
|
2800
|
+
return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
2801
|
+
open: true,
|
|
2802
|
+
onClose,
|
|
2803
|
+
title: entry.serverKey,
|
|
2804
|
+
description: t("lspDetailSubtitle"),
|
|
2805
|
+
closeLabel: t("cancel"),
|
|
2806
|
+
className: mcp_status_module_default.detailDialog,
|
|
2807
|
+
contentClassName: mcp_status_module_default.detailBody,
|
|
2808
|
+
footer: (0, react.createElement)("div", { className: mcp_status_module_default.modalFooter }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2809
|
+
variant: "ghost",
|
|
2810
|
+
onClick: onClose
|
|
2811
|
+
}, t("cancel"))),
|
|
2812
|
+
children: (0, react.createElement)("div", { className: mcp_status_module_default.detail }, (0, react.createElement)("div", { className: mcp_status_module_default.detailHero }, (0, react.createElement)("span", {
|
|
2813
|
+
className: `${mcp_status_module_default.statusDot} ${mcp_status_module_default[`status${dotClass(entry.state)}`]}`,
|
|
2814
|
+
"aria-hidden": true
|
|
2815
|
+
}), (0, react.createElement)("div", { className: mcp_status_module_default.detailHeroText }, entry.state === "mounted" ? null : (0, react.createElement)("span", { className: `${mcp_status_module_default.statePill} ${mcp_status_module_default[`state${pillClass(entry.state)}`]}` }, stateLabel(t, entry.state)), (0, react.createElement)("p", { className: mcp_status_module_default.detailEndpoint }, `${entry.suiteName} · ${entry.sourceId}`))), entry.reason === void 0 ? null : (0, react.createElement)("div", { className: mcp_status_module_default.reasonBox }, (0, react.createElement)("span", { className: mcp_status_module_default.reasonLabel }, t("lspReasonLabel")), (0, react.createElement)("p", { className: mcp_status_module_default.reasonText }, entry.reason)), (0, react.createElement)("section", { className: mcp_status_module_default.detailSection }, (0, react.createElement)("h4", { className: mcp_status_module_default.detailHead }, t("lspDetailCommand")), (0, react.createElement)("pre", { className: mcp_status_module_default.config }, [entry.command, ...entry.args].join(" "))), (0, react.createElement)("section", { className: mcp_status_module_default.detailSection }, (0, react.createElement)("h4", { className: mcp_status_module_default.detailHead }, `${t("lspDetailExtensions")} (${extensions.length})`), (0, react.createElement)("div", { className: mcp_status_module_default.toolList }, extensions.map(([ext, languageId]) => (0, react.createElement)("div", {
|
|
2816
|
+
key: ext,
|
|
2817
|
+
className: mcp_status_module_default.extRow
|
|
2818
|
+
}, (0, react.createElement)("span", { className: mcp_status_module_default.extName }, ext), (0, react.createElement)("span", {
|
|
2819
|
+
className: mcp_status_module_default.extArrow,
|
|
2820
|
+
"aria-hidden": true
|
|
2821
|
+
}, "→"), (0, react.createElement)("span", { className: mcp_status_module_default.extLanguage }, languageId))))))
|
|
2822
|
+
});
|
|
2823
|
+
}
|
|
2824
|
+
/** Filter icons mirroring McpFilterIcon's language: shared glyph shapes for
|
|
2825
|
+
* all/plugin/direct so the two panels read as one system, plus a warning
|
|
2826
|
+
* triangle for the blocked state. */
|
|
2827
|
+
function LspFilterIcon({ k }) {
|
|
2828
|
+
const common = {
|
|
2829
|
+
width: 16,
|
|
2830
|
+
height: 16,
|
|
2831
|
+
viewBox: "0 0 16 16",
|
|
2832
|
+
fill: "none",
|
|
2833
|
+
"aria-hidden": true
|
|
2834
|
+
};
|
|
2835
|
+
if (k === "plugin") return (0, react.createElement)("svg", common, (0, react.createElement)("path", { d: "M6 2.5v2H4A1.5 1.5 0 0 0 2.5 6v2h2a1.5 1.5 0 1 1 0 3h-2v2A1.5 1.5 0 0 0 4 14.5h2v-2a1.5 1.5 0 1 1 3 0v2h2a1.5 1.5 0 0 0 1.5-1.5v-2h-2a1.5 1.5 0 1 1 0-3h2V6A1.5 1.5 0 0 0 11 4.5H9v-2a1.5 1.5 0 1 0-3 0Z" }));
|
|
2836
|
+
if (k === "direct") return (0, react.createElement)("svg", common, (0, react.createElement)("circle", {
|
|
2837
|
+
cx: 8,
|
|
2838
|
+
cy: 5,
|
|
2839
|
+
r: 2.2
|
|
2840
|
+
}), (0, react.createElement)("path", { d: "M3.5 13c.6-2.2 2.1-3.3 4.5-3.3s3.9 1.1 4.5 3.3" }));
|
|
2841
|
+
if (k === "blocked") return (0, react.createElement)("svg", common, (0, react.createElement)("path", {
|
|
2842
|
+
d: "M8 2.5 14 13H2L8 2.5Z",
|
|
2843
|
+
stroke: "currentColor",
|
|
2844
|
+
strokeLinejoin: "round"
|
|
2845
|
+
}), (0, react.createElement)("path", {
|
|
2846
|
+
d: "M8 6.5v3M8 11.2v.3",
|
|
2847
|
+
stroke: "currentColor",
|
|
2848
|
+
strokeLinecap: "round"
|
|
2849
|
+
}));
|
|
2850
|
+
return (0, react.createElement)("svg", common, (0, react.createElement)("path", { d: "M2.5 5 8 2.5 13.5 5 8 7.5 2.5 5Zm0 3L8 10.5 13.5 8M2.5 11 8 13.5 13.5 11" }));
|
|
2851
|
+
}
|
|
2852
|
+
/** The card-accent CSS suffix; host-missing uses the warn palette. */
|
|
2853
|
+
function accentClass(state) {
|
|
2854
|
+
if (state === "mounted") return "Mounted";
|
|
2855
|
+
if (state === "host-missing") return "HostMissing";
|
|
2856
|
+
if (state === "conflict") return "Conflict";
|
|
2857
|
+
if (state === "failed") return "Failed";
|
|
2858
|
+
return "Disabled";
|
|
2859
|
+
}
|
|
2860
|
+
/** The status-dot CSS suffix (lowercase state names in the stylesheet). */
|
|
2861
|
+
function dotClass(state) {
|
|
2862
|
+
return state === "host-missing" ? "host-missing" : state;
|
|
2863
|
+
}
|
|
2864
|
+
/** The state-pill CSS suffix; conflict borrows the failed palette and
|
|
2865
|
+
* starting borrows the warn palette. */
|
|
2866
|
+
function pillClass(state) {
|
|
2867
|
+
if (state === "conflict") return "failed";
|
|
2868
|
+
if (state === "starting") return "host-missing";
|
|
2869
|
+
return state;
|
|
2870
|
+
}
|
|
1824
2871
|
function stateLabel(t, state) {
|
|
1825
|
-
if (state === "
|
|
1826
|
-
if (state === "
|
|
1827
|
-
if (state === "
|
|
1828
|
-
return t("
|
|
2872
|
+
if (state === "mounted") return t("lspMounted");
|
|
2873
|
+
if (state === "starting") return t("lspStarting");
|
|
2874
|
+
if (state === "host-missing") return t("lspHostMissingShort");
|
|
2875
|
+
if (state === "failed") return t("lspFailed");
|
|
2876
|
+
if (state === "conflict") return t("lspConflict");
|
|
2877
|
+
return t("lspDisabled");
|
|
2878
|
+
}
|
|
2879
|
+
function formatObservedAt(iso) {
|
|
2880
|
+
const date = new Date(iso);
|
|
2881
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
2882
|
+
return date.toLocaleTimeString();
|
|
2883
|
+
}
|
|
2884
|
+
//#endregion
|
|
2885
|
+
//#region src/client/McpPluginCard.tsx
|
|
2886
|
+
/**
|
|
2887
|
+
* The Agent Plugins Market card on the host's 插件配置 (plugin configuration)
|
|
2888
|
+
* tab: the market feature's configuration entry, named after the market
|
|
2889
|
+
* itself. Disclosed inside is the MCP enhancement switch — ON (default)
|
|
2890
|
+
* mounts suite MCP servers through the market's built-in bridge (OAuth
|
|
2891
|
+
* authorization, SSE, browser-leg hold); OFF falls back to the host's
|
|
2892
|
+
* `dsh-mcp-client` compatibility client.
|
|
2893
|
+
*
|
|
2894
|
+
* The switch state is the market's host settings namespace (bound by the
|
|
2895
|
+
* client entry), so a flip persists through the host settings document and
|
|
2896
|
+
* the node half's namespace watcher remounts the servers. The host client
|
|
2897
|
+
* version probe rides the market's own API.
|
|
2898
|
+
*/
|
|
2899
|
+
/** The host's disclosure chevron, matching the native cards' glyph exactly. */
|
|
2900
|
+
const chevronIcon = _deepseek_ai_dsh_client_ui_primitives["IconChevronDownOutline14"];
|
|
2901
|
+
function McpPluginCard({ t, scope, probe }) {
|
|
2902
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
2903
|
+
const [, setTick] = (0, react.useState)(0);
|
|
2904
|
+
const [probeInfo, setProbeInfo] = (0, react.useState)(void 0);
|
|
2905
|
+
const [busy, setBusy] = (0, react.useState)(false);
|
|
2906
|
+
const [error, setError] = (0, react.useState)(void 0);
|
|
2907
|
+
(0, react.useEffect)(() => scope.subscribe(() => setTick((tick) => tick + 1)), [scope]);
|
|
2908
|
+
const refreshProbe = (0, react.useCallback)(async () => {
|
|
2909
|
+
try {
|
|
2910
|
+
setProbeInfo(await probe());
|
|
2911
|
+
} catch {}
|
|
2912
|
+
}, [probe]);
|
|
2913
|
+
(0, react.useEffect)(() => {
|
|
2914
|
+
refreshProbe();
|
|
2915
|
+
}, [refreshProbe]);
|
|
2916
|
+
const enhanced = scope.enhanced();
|
|
2917
|
+
const writable = scope.writable();
|
|
2918
|
+
const regionSetting = scope.region();
|
|
2919
|
+
const effectiveRegion = probeInfo?.downloadRegion.effective ?? (regionSetting === "china" ? "china" : "global");
|
|
2920
|
+
const hostUsable = probeInfo?.hostClient.available === true;
|
|
2921
|
+
const onToggle = () => {
|
|
2922
|
+
if (busy || !writable) return;
|
|
2923
|
+
const next = !enhanced;
|
|
2924
|
+
if (!next && !hostUsable) {
|
|
2925
|
+
setError(t("mcpBackendHostMissing"));
|
|
2926
|
+
return;
|
|
2927
|
+
}
|
|
2928
|
+
setBusy(true);
|
|
2929
|
+
setError(void 0);
|
|
2930
|
+
scope.setEnhanced(next).then(() => {
|
|
2931
|
+
setBusy(false);
|
|
2932
|
+
}).catch((cause) => {
|
|
2933
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
2934
|
+
setBusy(false);
|
|
2935
|
+
});
|
|
2936
|
+
};
|
|
2937
|
+
return (0, react.createElement)("div", {
|
|
2938
|
+
className: open ? `${market_module_default.pluginCard} ${market_module_default.pluginCardOpen}` : market_module_default.pluginCard,
|
|
2939
|
+
"data-busy": busy ? "true" : void 0
|
|
2940
|
+
}, (0, react.createElement)("button", {
|
|
2941
|
+
type: "button",
|
|
2942
|
+
className: market_module_default.pluginCardHeader,
|
|
2943
|
+
"aria-expanded": open,
|
|
2944
|
+
onClick: () => {
|
|
2945
|
+
setOpen((current) => !current);
|
|
2946
|
+
}
|
|
2947
|
+
}, (0, react.createElement)("div", { className: market_module_default.pluginCardText }, (0, react.createElement)("div", { className: market_module_default.pluginCardTitle }, t("nav")), (0, react.createElement)("div", { className: market_module_default.pluginCardDesc }, t("marketCardDesc"))), (0, react.createElement)("span", { className: open ? `${market_module_default.pluginChevron} ${market_module_default.pluginChevronOpen}` : market_module_default.pluginChevron }, chevronIcon !== void 0 ? (0, react.createElement)(chevronIcon, { size: 14 }) : "▾")), open ? (0, react.createElement)("div", { className: market_module_default.pluginCardBody }, (0, react.createElement)("div", { className: market_module_default.pluginCardRow }, (0, react.createElement)("div", { className: market_module_default.pluginCardText }, (0, react.createElement)("div", { className: market_module_default.pluginCardRowLabel }, t("mcpCardTitle")), (0, react.createElement)("div", { className: market_module_default.pluginCardDesc }, enhanced ? t("mcpCardDescOn") : t("mcpCardDescOff"))), (0, react.createElement)(ToggleSwitch, {
|
|
2948
|
+
on: enhanced,
|
|
2949
|
+
disabled: busy || !writable,
|
|
2950
|
+
title: writable ? void 0 : t("mcpCardReadonly"),
|
|
2951
|
+
onChange: onToggle
|
|
2952
|
+
})), error !== void 0 ? (0, react.createElement)("div", { className: market_module_default.pluginCardError }, error) : null, (0, react.createElement)("div", { className: market_module_default.pluginCardRow }, (0, react.createElement)("div", { className: market_module_default.pluginCardText }, (0, react.createElement)("div", { className: market_module_default.pluginCardRowLabel }, t("regionLabel")), (0, react.createElement)("div", { className: market_module_default.pluginCardDesc }, t("regionHint"))), (0, react.createElement)("div", { className: market_module_default.regionSeg }, ["global", "china"].map((region) => (0, react.createElement)("button", {
|
|
2953
|
+
key: region,
|
|
2954
|
+
type: "button",
|
|
2955
|
+
disabled: busy || !writable,
|
|
2956
|
+
className: effectiveRegion === region ? market_module_default.regionSegOn : market_module_default.regionSegBtn,
|
|
2957
|
+
onClick: () => {
|
|
2958
|
+
if (regionSetting === region) return;
|
|
2959
|
+
setBusy(true);
|
|
2960
|
+
setError(void 0);
|
|
2961
|
+
scope.setRegion(region).then(() => {
|
|
2962
|
+
setBusy(false);
|
|
2963
|
+
}).catch((cause) => {
|
|
2964
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
2965
|
+
setBusy(false);
|
|
2966
|
+
});
|
|
2967
|
+
}
|
|
2968
|
+
}, region === "global" ? t("regionGlobal") : t("regionChina")))))) : null);
|
|
1829
2969
|
}
|
|
1830
2970
|
//#endregion
|
|
1831
2971
|
//#region src/client/page-mode-selection.ts
|
|
@@ -1901,6 +3041,7 @@ function mountLegacyPageMode(options) {
|
|
|
1901
3041
|
if (root === void 0) return;
|
|
1902
3042
|
root.render((0, react.createElement)(MarketSection, {
|
|
1903
3043
|
t: options.t,
|
|
3044
|
+
credentials: options.credentials,
|
|
1904
3045
|
mode: "page"
|
|
1905
3046
|
}));
|
|
1906
3047
|
};
|
|
@@ -2042,8 +3183,12 @@ function createEntry(onClick) {
|
|
|
2042
3183
|
*/
|
|
2043
3184
|
const NS = "dsh-agent-plugins-market";
|
|
2044
3185
|
const name = "dsh-agent-plugins-market";
|
|
2045
|
-
const inject = [
|
|
2046
|
-
|
|
3186
|
+
const inject = [
|
|
3187
|
+
"slots",
|
|
3188
|
+
"locale",
|
|
3189
|
+
"remote",
|
|
3190
|
+
"remote.credentials"
|
|
3191
|
+
];
|
|
2047
3192
|
const REQUIRED_PRIMITIVES = [
|
|
2048
3193
|
"Button",
|
|
2049
3194
|
"Input",
|
|
@@ -2051,6 +3196,12 @@ const REQUIRED_PRIMITIVES = [
|
|
|
2051
3196
|
"Toast",
|
|
2052
3197
|
"Tooltip"
|
|
2053
3198
|
];
|
|
3199
|
+
/**
|
|
3200
|
+
* Register the MCP enhancement card into the host's shared 插件配置 tab
|
|
3201
|
+
* (`settings.plugin.item`), the same seat dshmarket uses. Called through
|
|
3202
|
+
* `ctx.inject(['settingsScope'])` at apply time; a host without the
|
|
3203
|
+
* settingsScope service simply skips the card.
|
|
3204
|
+
*/
|
|
2054
3205
|
/** Detect host primitives that predate the exports this UI relies on. */
|
|
2055
3206
|
function missingPrimitives(module, required = REQUIRED_PRIMITIVES) {
|
|
2056
3207
|
return required.filter((name) => module[name] === void 0);
|
|
@@ -2061,6 +3212,7 @@ function apply(ctx) {
|
|
|
2061
3212
|
en
|
|
2062
3213
|
}), "dsh-agent-plugins: dictionaries");
|
|
2063
3214
|
const t = ctx.locale.bind(NS);
|
|
3215
|
+
const credentials = credentialApi(ctx.remote.credentials);
|
|
2064
3216
|
const gaps = missingPrimitives(_deepseek_ai_dsh_client_ui_primitives);
|
|
2065
3217
|
if (gaps.length > 0) {
|
|
2066
3218
|
console.warn(`[dsh-agent-plugins-market] host ui-primitives missing ${gaps.join(", ")} — Agent Plugins Market section disabled (dsh web >= 0.1.0-rc.6 required)`);
|
|
@@ -2069,9 +3221,37 @@ function apply(ctx) {
|
|
|
2069
3221
|
let settingsSurfaceAvailable = false;
|
|
2070
3222
|
ctx.effect(() => mountLegacyPageMode({
|
|
2071
3223
|
t,
|
|
3224
|
+
credentials,
|
|
2072
3225
|
isSettingsSurfaceAvailable: () => settingsSurfaceAvailable,
|
|
2073
3226
|
subscribeLocale: ctx.locale.subscribe === void 0 ? void 0 : (listener) => ctx.locale.subscribe(listener)
|
|
2074
3227
|
}), "dsh-agent-plugins-market: legacy page mode");
|
|
3228
|
+
ctx.inject?.(["settingsScope"], (scoped) => {
|
|
3229
|
+
const service = scoped.settingsScope;
|
|
3230
|
+
const slots = scoped.slots;
|
|
3231
|
+
if (service === void 0 || slots === void 0) return;
|
|
3232
|
+
const tCard = ctx.locale.bind(NS);
|
|
3233
|
+
const scope = service.bind({ namespace: NS });
|
|
3234
|
+
slots.inject("settings.plugin.item", () => slots.register({
|
|
3235
|
+
name: "settings.plugin.item",
|
|
3236
|
+
key: NS,
|
|
3237
|
+
locale: NS,
|
|
3238
|
+
inject: () => ({ t: tCard })
|
|
3239
|
+
}, () => (0, react.createElement)(McpPluginCard, {
|
|
3240
|
+
t: (key) => tCard(key),
|
|
3241
|
+
scope: {
|
|
3242
|
+
enhanced: () => scope.getSnapshot().value?.mcpEnhanced !== false,
|
|
3243
|
+
writable: () => scope.getSnapshot().writable,
|
|
3244
|
+
subscribe: (listener) => scope.subscribe(listener),
|
|
3245
|
+
setEnhanced: (next) => scope.set("mcpEnhanced", next),
|
|
3246
|
+
region: () => {
|
|
3247
|
+
const value = scope.getSnapshot().value?.downloadRegion;
|
|
3248
|
+
return value === "global" || value === "china" ? value : "auto";
|
|
3249
|
+
},
|
|
3250
|
+
setRegion: (next) => scope.set("downloadRegion", next)
|
|
3251
|
+
},
|
|
3252
|
+
probe: () => fetchMcpBackend()
|
|
3253
|
+
})));
|
|
3254
|
+
});
|
|
2075
3255
|
ctx.slots.inject("settings.section", () => {
|
|
2076
3256
|
settingsSurfaceAvailable = true;
|
|
2077
3257
|
notifyPageModeSurfaceChange();
|
|
@@ -2084,6 +3264,7 @@ function apply(ctx) {
|
|
|
2084
3264
|
inject: () => ({ t })
|
|
2085
3265
|
}, () => (0, react.createElement)(MarketSection, {
|
|
2086
3266
|
t,
|
|
3267
|
+
credentials,
|
|
2087
3268
|
mode: "settings"
|
|
2088
3269
|
}));
|
|
2089
3270
|
const mcpDispose = ctx.slots.register({
|
|
@@ -2093,11 +3274,23 @@ function apply(ctx) {
|
|
|
2093
3274
|
label: () => t("mcpStatusNav"),
|
|
2094
3275
|
locale: NS,
|
|
2095
3276
|
inject: () => ({ t })
|
|
2096
|
-
}, () => (0, react.createElement)(McpStatusPanel, {
|
|
3277
|
+
}, () => (0, react.createElement)(McpStatusPanel, {
|
|
3278
|
+
t,
|
|
3279
|
+
credentials
|
|
3280
|
+
}));
|
|
3281
|
+
const lspDispose = ctx.slots.register({
|
|
3282
|
+
name: "settings.section",
|
|
3283
|
+
id: "lsp-status",
|
|
3284
|
+
order: 47,
|
|
3285
|
+
label: () => t("lspStatusNav"),
|
|
3286
|
+
locale: NS,
|
|
3287
|
+
inject: () => ({ t })
|
|
3288
|
+
}, () => (0, react.createElement)(LspStatusPanel, { t }));
|
|
2097
3289
|
return () => {
|
|
2098
3290
|
settingsSurfaceAvailable = false;
|
|
2099
3291
|
notifyPageModeSurfaceChange();
|
|
2100
3292
|
if (typeof mcpDispose === "function") mcpDispose();
|
|
3293
|
+
if (typeof lspDispose === "function") lspDispose();
|
|
2101
3294
|
if (typeof marketDispose === "function") marketDispose();
|
|
2102
3295
|
};
|
|
2103
3296
|
});
|