dsh-agent-plugins-market 0.5.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -3
- package/README.zh.md +29 -3
- package/client/client.js +1388 -204
- 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 +196 -54
- package/lib/runtime/mcp-credentials.js +20 -0
- package/lib/runtime/mcp-mounts.js +237 -27
- package/lib/runtime/mcp-overrides.js +64 -6
- package/lib/runtime/mcp-redaction.js +92 -0
- package/lib/runtime/mcp-status.js +76 -32
- 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 +29 -12
- 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 +15 -11
- 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_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: "自动从插件清单名或仓库名解析,无需填写",
|
|
@@ -113,6 +238,7 @@ const zh = {
|
|
|
113
238
|
installConfirmNoSurfaces: "该套件未声明任何运行时能力。",
|
|
114
239
|
installConfirmExecutable: "风险提示:安装后将启动该套件的 MCP 子进程并挂载 hooks(第三方代码)。请确认来源可信后再安装。",
|
|
115
240
|
installConfirmSource: "来源",
|
|
241
|
+
installConfirmLocalTree: "本地目录(工作树,未锁定提交)",
|
|
116
242
|
removeSourceConfirmTitle: "移除仓库源「{sourceId}」",
|
|
117
243
|
removeSourceConfirmDesc: "将删除该源的本地克隆与全部安装记录。",
|
|
118
244
|
enable: "启用",
|
|
@@ -145,6 +271,7 @@ const zh = {
|
|
|
145
271
|
sourceNotCloned: "未克隆",
|
|
146
272
|
sourceCloned: "已克隆",
|
|
147
273
|
errors: "校验问题",
|
|
274
|
+
scanNotes: "扫描提示",
|
|
148
275
|
sourceErrorSeparator: ";",
|
|
149
276
|
viewMode: "视图模式",
|
|
150
277
|
grid: "网格",
|
|
@@ -156,6 +283,10 @@ const zh = {
|
|
|
156
283
|
countInstalled: "已装 {n}",
|
|
157
284
|
countEnabled: "启用 {n}",
|
|
158
285
|
mcpStatusNav: "MCP 服务",
|
|
286
|
+
lspStatusNav: "LSP 服务",
|
|
287
|
+
lspSearch: "搜索 LSP 服务",
|
|
288
|
+
lspAllMounted: "全部已挂载",
|
|
289
|
+
lspDirect: "直接安装",
|
|
159
290
|
mcpStatusTitle: "MCP 服务",
|
|
160
291
|
mcpStatusSubtitle: "连接状态、来源和工具清单",
|
|
161
292
|
mcpSearch: "搜索 MCP 名称、来源或地址…",
|
|
@@ -166,9 +297,48 @@ const zh = {
|
|
|
166
297
|
mcpSource: "来源",
|
|
167
298
|
mcpTransport: "传输",
|
|
168
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
|
+
regionLabel: "下载区域",
|
|
318
|
+
regionHint: "中国大陆走镜像线路,仅影响下载线路。",
|
|
319
|
+
regionGlobal: "全球",
|
|
320
|
+
regionChina: "中国大陆",
|
|
321
|
+
mcpBackendHostMissing: "宿主 dsh-mcp-client 在当前环境不可用,无法切换到兼容模式。",
|
|
322
|
+
mcpReauthHint: "删除已保存的授权令牌并重新走浏览器授权——用于权限范围选少了的场景。点击后请在弹出的页面完成登录。",
|
|
323
|
+
mcpConnectHint: "删除旧的授权记录并重新发起浏览器登录。点击后请在弹出的页面完成授权,服务会自动连接。",
|
|
324
|
+
mcpReauthSuccess: "已清除旧授权,请在弹出的浏览器页面重新登录",
|
|
325
|
+
mcpReauthFailure: "重新授权失败,请稍后重试",
|
|
326
|
+
mcpZeroTools: "该服务已连接,但未声明任何工具。",
|
|
169
327
|
mcpConnected: "已连接",
|
|
170
328
|
mcpDegraded: "降级",
|
|
171
329
|
mcpFailed: "失败",
|
|
330
|
+
mcpNeedsCredentials: "需要凭据",
|
|
331
|
+
mcpOrphaned: "插件已卸载,工具残留",
|
|
332
|
+
mcpConfigureCredentials: "配置凭据",
|
|
333
|
+
mcpViewDetails: "查看详情",
|
|
334
|
+
mcpCredentialTitle: "凭据配置",
|
|
335
|
+
mcpCredentialConfigured: "已配置",
|
|
336
|
+
mcpCredentialMissing: "未配置",
|
|
337
|
+
mcpCredentialReadOnly: "由启动环境提供(只读;修改后需重启 DSH)",
|
|
338
|
+
mcpCredentialUnavailable: "当前 profile 未提供凭据服务,请在启动 DSH 前设置环境变量。",
|
|
339
|
+
mcpCredentialPlaceholder: "输入凭据(不会回显)",
|
|
340
|
+
mcpCredentialSave: "保存凭据",
|
|
341
|
+
mcpCredentialUnset: "删除凭据",
|
|
172
342
|
mcpDisabled: "未启用",
|
|
173
343
|
mcpObservedEndpoint: "当前工具表观测",
|
|
174
344
|
mcpServiceDetail: "服务详情",
|
|
@@ -179,7 +349,38 @@ const zh = {
|
|
|
179
349
|
mcpDirectConfigUnavailable: "宿主未提供直接安装 MCP 的配置记录",
|
|
180
350
|
mcpDirectBoundary: "直接安装 MCP 仅显示当前工具表中可观测的服务;宿主未提供配置与连接状态 API。",
|
|
181
351
|
mcpBackToMarket: "返回市场",
|
|
182
|
-
mcpRetry: "重试"
|
|
352
|
+
mcpRetry: "重试",
|
|
353
|
+
mcpFilterAllHint: "全部:插件套件声明的 MCP 服务与宿主直接安装的 MCP",
|
|
354
|
+
mcpFilterPluginHint: "Plugin:来自插件市场套件的 mcp.json 声明",
|
|
355
|
+
mcpFilterDirectHint: "直接安装:宿主工具表中观测到、非套件来源的 MCP",
|
|
356
|
+
lspStatusTitle: "LSP 服务",
|
|
357
|
+
lspStatusSubtitle: "语言服务器声明与挂载状态",
|
|
358
|
+
lspAll: "全部",
|
|
359
|
+
lspMounted: "已挂载",
|
|
360
|
+
lspStarting: "启动中…",
|
|
361
|
+
lspBlocked: "被阻塞",
|
|
362
|
+
lspFailed: "失败",
|
|
363
|
+
lspDisabled: "未启用",
|
|
364
|
+
lspHostMissingShort: "宿主缺失",
|
|
365
|
+
lspConflict: "扩展冲突",
|
|
366
|
+
lspHostMissing: "当前 DSH 运行时未携带 LSP 组件(@deepseek-ai/dsh-lsp、dsh-lsp-stdio、dsh-tool-lsp),声明不会被挂载;升级宿主并在 profile 中挂载这三层后重新启用套件即可。",
|
|
367
|
+
lspEmpty: "没有已声明的 LSP 服务器",
|
|
368
|
+
lspReasonLabel: "原因",
|
|
369
|
+
lspFilterAllHint: "全部:套件声明与用户自配的全部语言服务器",
|
|
370
|
+
lspFilterPluginHint: "Plugin:来自插件市场套件的内联 lspServers 声明",
|
|
371
|
+
lspFilterDirectHint: "直接安装:用户自行配置的语言服务器(本面板配置)",
|
|
372
|
+
lspFilterBlockedHint: "被阻塞:缺宿主组件、挂载失败或扩展冲突,点击卡片查看原因",
|
|
373
|
+
lspFilterDisabledHint: "未启用:套件的 LSP 能力面开关已关闭",
|
|
374
|
+
lspPlugin: "Plugin",
|
|
375
|
+
lspConfigure: "配置 LSP",
|
|
376
|
+
lspConfigureHint: "编辑用户自配的语言服务器表(Claude Code lspServers 格式),保存后自动挂载",
|
|
377
|
+
lspSave: "保存",
|
|
378
|
+
lspDetailSubtitle: "语言服务器详情",
|
|
379
|
+
lspDetailCommand: "启动命令",
|
|
380
|
+
lspDetailExtensions: "扩展映射",
|
|
381
|
+
mdCodeCopy: "复制",
|
|
382
|
+
mdCodeCopied: "已复制",
|
|
383
|
+
mdFootnotes: "脚注"
|
|
183
384
|
};
|
|
184
385
|
const en = {
|
|
185
386
|
nav: "Agent Plugins Market",
|
|
@@ -193,10 +394,18 @@ const en = {
|
|
|
193
394
|
sourceIdPh: "source id (lowercase alnum)",
|
|
194
395
|
sourceUrlPh: "git repository URL",
|
|
195
396
|
sourceUrlLocalPh: "local repository path (absolute or ~/…)",
|
|
397
|
+
sourceUrlArchivePh: "archive URL (.zip / .tar.gz)",
|
|
196
398
|
sourceModeGit: "remote git",
|
|
399
|
+
sourceModeArchive: "archive",
|
|
197
400
|
sourceModeLocal: "local dir",
|
|
198
401
|
branchPh: "branch (optional)",
|
|
199
402
|
sourceLocal: "local",
|
|
403
|
+
sourceArchive: "archive",
|
|
404
|
+
sourceAdopted: "adopted",
|
|
405
|
+
sha256Ph: "SHA-256 (optional, 64 hex chars)",
|
|
406
|
+
unmanagedTitle: "Unregistered local checkouts found:",
|
|
407
|
+
unmanagedAdopt: "Adopt as a source (register only — no clone, no deletion)",
|
|
408
|
+
unmanagedNoRemote: "Not a git checkout: registered as a local directory source",
|
|
200
409
|
editSource: "Edit source",
|
|
201
410
|
editSourceTitle: "Edit source",
|
|
202
411
|
addSourceTitle: "Add source",
|
|
@@ -219,7 +428,7 @@ const en = {
|
|
|
219
428
|
disabledLabel: "disabled",
|
|
220
429
|
notInstalledLabel: "not installed",
|
|
221
430
|
surfaceTogglesSection: "Runtime injection toggles",
|
|
222
|
-
surfaceTogglesHint: "Control injection per surface: turning one off unmounts that surface immediately (skills / MCP / hooks / commands / subagents)",
|
|
431
|
+
surfaceTogglesHint: "Control injection per surface: turning one off unmounts that surface immediately (skills / MCP / hooks / commands / subagents / LSP)",
|
|
223
432
|
mcpOverrideEdit: "Edit override",
|
|
224
433
|
mcpOverrideSave: "Save override",
|
|
225
434
|
mcpOverrideReset: "Reset to source config",
|
|
@@ -238,11 +447,14 @@ const en = {
|
|
|
238
447
|
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>.",
|
|
239
448
|
idHint: "lowercase letters / digits / hyphens, globally unique",
|
|
240
449
|
urlGitHint: "git repository URL, e.g. https://github.com/org/repo.git",
|
|
450
|
+
urlArchiveHint: "HTTPS archive URL, e.g. https://example.com/plugin.zip — downloaded and extracted as the source directory",
|
|
241
451
|
urlLocalHint: "absolute path or ~/…, read in place (never cloned, never deleted on removal)",
|
|
242
452
|
branchHint: "optional; defaults to the repository default branch",
|
|
453
|
+
sha256Hint: "optional; when set, the download SHA-256 is verified and mismatches reject the install",
|
|
243
454
|
idFixed: "id is fixed (the source identifier is globally unique)",
|
|
244
455
|
progressStarting: "Submitting…",
|
|
245
456
|
progressCloning: "Cloning the repository (git clone) — this can take tens of seconds…",
|
|
457
|
+
progressDownloading: "Downloading and extracting the archive — this can take tens of seconds…",
|
|
246
458
|
progressReading: "Reading plugin manifests…",
|
|
247
459
|
idAutoLabel: "Source ID (auto)",
|
|
248
460
|
idAutoHint: "Derived from the suite or repo name — no need to type it",
|
|
@@ -262,6 +474,7 @@ const en = {
|
|
|
262
474
|
installConfirmNoSurfaces: "This suite declares no runtime surfaces.",
|
|
263
475
|
installConfirmExecutable: "Risk notice: installing starts this suite's MCP child processes and mounts hooks (third-party code). Install only if you trust the source.",
|
|
264
476
|
installConfirmSource: "Source",
|
|
477
|
+
installConfirmLocalTree: "Local directory (working tree, no locked commit)",
|
|
265
478
|
removeSourceConfirmTitle: "Remove source “{sourceId}”",
|
|
266
479
|
removeSourceConfirmDesc: "Deletes the local clone and all install records of this source.",
|
|
267
480
|
enable: "Enable",
|
|
@@ -294,6 +507,7 @@ const en = {
|
|
|
294
507
|
sourceNotCloned: "not cloned",
|
|
295
508
|
sourceCloned: "cloned",
|
|
296
509
|
errors: "validation issues",
|
|
510
|
+
scanNotes: "scan notes",
|
|
297
511
|
sourceErrorSeparator: "; ",
|
|
298
512
|
viewMode: "View mode",
|
|
299
513
|
grid: "grid",
|
|
@@ -305,6 +519,10 @@ const en = {
|
|
|
305
519
|
countInstalled: "{n} installed",
|
|
306
520
|
countEnabled: "{n} enabled",
|
|
307
521
|
mcpStatusNav: "MCP services",
|
|
522
|
+
lspStatusNav: "LSP servers",
|
|
523
|
+
lspSearch: "Search LSP servers",
|
|
524
|
+
lspAllMounted: "All mounted",
|
|
525
|
+
lspDirect: "Direct",
|
|
308
526
|
mcpStatusTitle: "MCP services",
|
|
309
527
|
mcpStatusSubtitle: "Connection state, sources, and tools",
|
|
310
528
|
mcpSearch: "Search MCP names, sources, or endpoints…",
|
|
@@ -315,9 +533,48 @@ const en = {
|
|
|
315
533
|
mcpSource: "Source",
|
|
316
534
|
mcpTransport: "Transport",
|
|
317
535
|
mcpTools: "tools",
|
|
536
|
+
mcpTool: "tool",
|
|
537
|
+
mcpAllConnected: "All connected",
|
|
538
|
+
mcpReasonLabel: "Reason",
|
|
539
|
+
mcpRetryNote: "Automatic retries were exhausted. Use Retry to reconnect now, or check the server configuration in the market.",
|
|
540
|
+
mcpRetrying: "Reconnecting…",
|
|
541
|
+
mcpRetrySuccess: "Reconnected — the service is live again",
|
|
542
|
+
mcpRetryFailure: "Reconnect failed — see the reason above",
|
|
543
|
+
mcpReauthorize: "Re-authorize",
|
|
544
|
+
mcpConnect: "Connect",
|
|
545
|
+
mcpReauthorizing: "Waiting for browser authorization…",
|
|
546
|
+
marketCardDesc: "Install, enable, and runtime settings for Agent Plugins Market suites.",
|
|
547
|
+
mcpCardTitle: "MCP enhancement",
|
|
548
|
+
mcpCardDescOn: "On: enables OAuth authorization, SSE, authorization hold, and more.",
|
|
549
|
+
mcpCardDescOff: "Off: uses the host dsh-mcp-client.",
|
|
550
|
+
mcpCardReadonly: "The settings document is read-only in this environment; the switch is unavailable.",
|
|
551
|
+
mcpForeign: "Mounted elsewhere",
|
|
552
|
+
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.",
|
|
553
|
+
regionLabel: "Download region",
|
|
554
|
+
regionHint: "China mainland routes through a mirror. Affects the download route only.",
|
|
555
|
+
regionGlobal: "Global",
|
|
556
|
+
regionChina: "China mainland",
|
|
557
|
+
mcpBackendHostMissing: "The host dsh-mcp-client is not available here; compat mode cannot be enabled.",
|
|
558
|
+
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.",
|
|
559
|
+
mcpConnectHint: "Drops the stale grant and starts a fresh browser sign-in. Approve in the page that opens and the service connects automatically.",
|
|
560
|
+
mcpReauthSuccess: "Old grant dropped — finish the sign-in in the browser page that opened",
|
|
561
|
+
mcpReauthFailure: "Re-authorization failed — try again shortly",
|
|
562
|
+
mcpZeroTools: "Connected, but this service advertises no tools.",
|
|
318
563
|
mcpConnected: "connected",
|
|
319
564
|
mcpDegraded: "degraded",
|
|
320
565
|
mcpFailed: "failed",
|
|
566
|
+
mcpNeedsCredentials: "credentials required",
|
|
567
|
+
mcpOrphaned: "plugin removed; tools remain",
|
|
568
|
+
mcpConfigureCredentials: "Configure credentials",
|
|
569
|
+
mcpViewDetails: "View details",
|
|
570
|
+
mcpCredentialTitle: "Credential configuration",
|
|
571
|
+
mcpCredentialConfigured: "configured",
|
|
572
|
+
mcpCredentialMissing: "not configured",
|
|
573
|
+
mcpCredentialReadOnly: "provided by the launch environment (read-only; restart DSH after changes)",
|
|
574
|
+
mcpCredentialUnavailable: "This profile has no credentials service. Set the environment variable before launching DSH.",
|
|
575
|
+
mcpCredentialPlaceholder: "Enter credential (not echoed)",
|
|
576
|
+
mcpCredentialSave: "Save credential",
|
|
577
|
+
mcpCredentialUnset: "Remove credential",
|
|
321
578
|
mcpDisabled: "disabled",
|
|
322
579
|
mcpObservedEndpoint: "observed from tool registry",
|
|
323
580
|
mcpServiceDetail: "Service detail",
|
|
@@ -328,79 +585,39 @@ const en = {
|
|
|
328
585
|
mcpDirectConfigUnavailable: "The host does not expose direct-MCP configuration",
|
|
329
586
|
mcpDirectBoundary: "Direct MCP entries only show services observed in the current tool registry; the host exposes no config or connection-status API.",
|
|
330
587
|
mcpBackToMarket: "Back to market",
|
|
331
|
-
mcpRetry: "Retry"
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
588
|
+
mcpRetry: "Retry",
|
|
589
|
+
mcpFilterAllHint: "All: MCP services declared by plugin suites plus host-installed MCP",
|
|
590
|
+
mcpFilterPluginHint: "Plugin: mcp.json declarations from market suites",
|
|
591
|
+
mcpFilterDirectHint: "Direct: MCP observed in the host tool registry outside any suite",
|
|
592
|
+
lspStatusTitle: "LSP servers",
|
|
593
|
+
lspStatusSubtitle: "Declared language servers and their mount state",
|
|
594
|
+
lspAll: "All",
|
|
595
|
+
lspMounted: "Mounted",
|
|
596
|
+
lspStarting: "Starting…",
|
|
597
|
+
lspBlocked: "Blocked",
|
|
598
|
+
lspFailed: "Failed",
|
|
599
|
+
lspDisabled: "Disabled",
|
|
600
|
+
lspHostMissingShort: "Host missing",
|
|
601
|
+
lspConflict: "Extension conflict",
|
|
602
|
+
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.",
|
|
603
|
+
lspEmpty: "No declared LSP servers",
|
|
604
|
+
lspReasonLabel: "Reason",
|
|
605
|
+
lspFilterAllHint: "All: suite-declared and user-configured language servers",
|
|
606
|
+
lspFilterPluginHint: "Plugin: inline lspServers declarations from market suites",
|
|
607
|
+
lspFilterDirectHint: "Direct: user-configured language servers (configured in this panel)",
|
|
608
|
+
lspFilterBlockedHint: "Blocked: missing host packages, failed mounts, or extension conflicts — open a card for the reason",
|
|
609
|
+
lspFilterDisabledHint: "Disabled: the suite LSP surface toggle is off",
|
|
610
|
+
lspPlugin: "Plugin",
|
|
611
|
+
lspConfigure: "Configure LSP",
|
|
612
|
+
lspConfigureHint: "Edit the user-configured language-server table (Claude Code lspServers format); servers mount automatically after save",
|
|
613
|
+
lspSave: "Save",
|
|
614
|
+
lspDetailSubtitle: "Language server detail",
|
|
615
|
+
lspDetailCommand: "Launch command",
|
|
616
|
+
lspDetailExtensions: "Extension map",
|
|
617
|
+
mdCodeCopy: "Copy",
|
|
618
|
+
mdCodeCopied: "Copied",
|
|
619
|
+
mdFootnotes: "Footnotes"
|
|
356
620
|
};
|
|
357
|
-
/** Build a suite-detail URL without duplicating route or query encoding logic. */
|
|
358
|
-
function suiteRoute(sourceId, suiteId) {
|
|
359
|
-
return `${MARKET_ROUTES.suite}?sourceId=${encodeURIComponent(sourceId)}&suiteId=${encodeURIComponent(suiteId)}`;
|
|
360
|
-
}
|
|
361
|
-
/** Build a skill-content URL without duplicating route or query encoding logic. */
|
|
362
|
-
function skillRoute(sourceId, suiteId, skill) {
|
|
363
|
-
return `${MARKET_ROUTES.skill}?sourceId=${encodeURIComponent(sourceId)}&suiteId=${encodeURIComponent(suiteId)}&skill=${encodeURIComponent(skill)}`;
|
|
364
|
-
}
|
|
365
|
-
//#endregion
|
|
366
|
-
//#region src/client/api.ts
|
|
367
|
-
/** Typed fetch helpers over the host's `/api/agent-plugins/*` routes. */
|
|
368
|
-
async function fetchOverview() {
|
|
369
|
-
const response = await fetch(MARKET_ROUTES.overview, { credentials: "same-origin" });
|
|
370
|
-
if (!response.ok) throw new Error(`overview failed: ${response.status}`);
|
|
371
|
-
return response.json();
|
|
372
|
-
}
|
|
373
|
-
async function fetchSourceProgress() {
|
|
374
|
-
const response = await fetch(MARKET_ROUTES.progress, { credentials: "same-origin" });
|
|
375
|
-
if (!response.ok) throw new Error(`progress failed: ${response.status}`);
|
|
376
|
-
return response.json();
|
|
377
|
-
}
|
|
378
|
-
async function fetchSuiteDetail(sourceId, suiteId) {
|
|
379
|
-
const response = await fetch(suiteRoute(sourceId, suiteId), { credentials: "same-origin" });
|
|
380
|
-
if (!response.ok) throw new Error(`suite detail failed: ${response.status}`);
|
|
381
|
-
return response.json();
|
|
382
|
-
}
|
|
383
|
-
async function fetchMcpStatus() {
|
|
384
|
-
const response = await fetch(MARKET_ROUTES.mcpStatus, { credentials: "same-origin" });
|
|
385
|
-
if (!response.ok) throw new Error(`MCP status failed: ${response.status}`);
|
|
386
|
-
return response.json();
|
|
387
|
-
}
|
|
388
|
-
async function fetchSkillContent(sourceId, suiteId, skill) {
|
|
389
|
-
const response = await fetch(skillRoute(sourceId, suiteId, skill), { credentials: "same-origin" });
|
|
390
|
-
if (!response.ok) throw new Error(`skill content failed: ${response.status}`);
|
|
391
|
-
return response.json();
|
|
392
|
-
}
|
|
393
|
-
async function postAction(path, body) {
|
|
394
|
-
const response = await fetch(`${MARKET_API_PREFIX}${path}`, {
|
|
395
|
-
method: "POST",
|
|
396
|
-
credentials: "same-origin",
|
|
397
|
-
headers: { "content-type": "application/json" },
|
|
398
|
-
body: JSON.stringify(body)
|
|
399
|
-
});
|
|
400
|
-
const payload = await response.json();
|
|
401
|
-
if (!response.ok || payload.ok !== true) throw new Error(payload.error ?? `request failed: ${response.status}`);
|
|
402
|
-
return payload;
|
|
403
|
-
}
|
|
404
621
|
//#endregion
|
|
405
622
|
//#region src/client/features/market/market-resource.ts
|
|
406
623
|
/** Market overview cache, invalidation, and source-progress resource helpers. */
|
|
@@ -415,7 +632,8 @@ const EMPTY_OVERVIEW = {
|
|
|
415
632
|
roots: {
|
|
416
633
|
user: "",
|
|
417
634
|
data: ""
|
|
418
|
-
}
|
|
635
|
+
},
|
|
636
|
+
unmanaged: []
|
|
419
637
|
};
|
|
420
638
|
let cachedOverview;
|
|
421
639
|
let inflightOverview;
|
|
@@ -510,11 +728,19 @@ function searchableFor$1(overview) {
|
|
|
510
728
|
//#endregion
|
|
511
729
|
//#region src/client/market.module.css
|
|
512
730
|
var market_module_default = {
|
|
731
|
+
"backendBlock": "_72qoAq_backendBlock",
|
|
732
|
+
"backendCurrent": "_72qoAq_backendCurrent",
|
|
733
|
+
"backendHint": "_72qoAq_backendHint",
|
|
734
|
+
"backendRow": "_72qoAq_backendRow",
|
|
735
|
+
"backendTitle": "_72qoAq_backendTitle",
|
|
736
|
+
"backendVersion": "_72qoAq_backendVersion",
|
|
513
737
|
"body": "_72qoAq_body",
|
|
514
738
|
"card": "_72qoAq_card",
|
|
515
739
|
"cardActions": "_72qoAq_cardActions",
|
|
516
740
|
"cardDesc": "_72qoAq_cardDesc",
|
|
741
|
+
"cardMuted": "_72qoAq_cardMuted",
|
|
517
742
|
"cardName": "_72qoAq_cardName",
|
|
743
|
+
"cardOn": "_72qoAq_cardOn",
|
|
518
744
|
"cardTitle": "_72qoAq_cardTitle",
|
|
519
745
|
"cardTop": "_72qoAq_cardTop",
|
|
520
746
|
"desc": "_72qoAq_desc",
|
|
@@ -543,7 +769,10 @@ var market_module_default = {
|
|
|
543
769
|
"fieldLabel": "_72qoAq_fieldLabel",
|
|
544
770
|
"grid": "_72qoAq_grid",
|
|
545
771
|
"header": "_72qoAq_header",
|
|
772
|
+
"iconBtn": "_72qoAq_iconBtn",
|
|
773
|
+
"iconBtnDanger": "_72qoAq_iconBtnDanger",
|
|
546
774
|
"installConfirmBody": "_72qoAq_installConfirmBody",
|
|
775
|
+
"installConfirmCommit": "_72qoAq_installConfirmCommit",
|
|
547
776
|
"installConfirmMeta": "_72qoAq_installConfirmMeta",
|
|
548
777
|
"installConfirmSuite": "_72qoAq_installConfirmSuite",
|
|
549
778
|
"installConfirmTags": "_72qoAq_installConfirmTags",
|
|
@@ -551,6 +780,10 @@ var market_module_default = {
|
|
|
551
780
|
"list": "_72qoAq_list",
|
|
552
781
|
"market": "_72qoAq_market",
|
|
553
782
|
"marketControls": "_72qoAq_marketControls",
|
|
783
|
+
"mcpCredentialControls": "_72qoAq_mcpCredentialControls",
|
|
784
|
+
"mcpCredentialEditor": "_72qoAq_mcpCredentialEditor",
|
|
785
|
+
"mcpCredentialForm": "_72qoAq_mcpCredentialForm",
|
|
786
|
+
"mcpCredentialRow": "_72qoAq_mcpCredentialRow",
|
|
554
787
|
"mcpOverrideActions": "_72qoAq_mcpOverrideActions",
|
|
555
788
|
"mcpOverrideArea": "_72qoAq_mcpOverrideArea",
|
|
556
789
|
"mcpOverrideCheck": "_72qoAq_mcpOverrideCheck",
|
|
@@ -566,11 +799,26 @@ var market_module_default = {
|
|
|
566
799
|
"pageEntry": "_72qoAq_pageEntry",
|
|
567
800
|
"pageMode": "_72qoAq_pageMode",
|
|
568
801
|
"pageView": "_72qoAq_pageView",
|
|
802
|
+
"pluginCard": "_72qoAq_pluginCard",
|
|
803
|
+
"pluginCardBody": "_72qoAq_pluginCardBody",
|
|
804
|
+
"pluginCardDesc": "_72qoAq_pluginCardDesc",
|
|
805
|
+
"pluginCardError": "_72qoAq_pluginCardError",
|
|
806
|
+
"pluginCardHeader": "_72qoAq_pluginCardHeader",
|
|
807
|
+
"pluginCardOpen": "_72qoAq_pluginCardOpen",
|
|
808
|
+
"pluginCardRow": "_72qoAq_pluginCardRow",
|
|
809
|
+
"pluginCardRowLabel": "_72qoAq_pluginCardRowLabel",
|
|
810
|
+
"pluginCardText": "_72qoAq_pluginCardText",
|
|
811
|
+
"pluginCardTitle": "_72qoAq_pluginCardTitle",
|
|
812
|
+
"pluginChevron": "_72qoAq_pluginChevron",
|
|
813
|
+
"pluginChevronOpen": "_72qoAq_pluginChevronOpen",
|
|
569
814
|
"progress": "_72qoAq_progress",
|
|
570
815
|
"progressError": "_72qoAq_progressError",
|
|
571
816
|
"progressFail": "_72qoAq_progressFail",
|
|
572
817
|
"progressSpin": "_72qoAq_progressSpin",
|
|
573
818
|
"progressText": "_72qoAq_progressText",
|
|
819
|
+
"regionSeg": "_72qoAq_regionSeg",
|
|
820
|
+
"regionSegBtn": "_72qoAq_regionSegBtn",
|
|
821
|
+
"regionSegOn": "_72qoAq_regionSegOn",
|
|
574
822
|
"searchGroup": "_72qoAq_searchGroup",
|
|
575
823
|
"seg": "_72qoAq_seg",
|
|
576
824
|
"segOn": "_72qoAq_segOn",
|
|
@@ -594,8 +842,14 @@ var market_module_default = {
|
|
|
594
842
|
"switchOn": "_72qoAq_switchOn",
|
|
595
843
|
"switchThumb": "_72qoAq_switchThumb",
|
|
596
844
|
"tag": "_72qoAq_tag",
|
|
845
|
+
"tagRow": "_72qoAq_tagRow",
|
|
597
846
|
"title": "_72qoAq_title",
|
|
598
847
|
"titleRow": "_72qoAq_titleRow",
|
|
848
|
+
"unmanagedAdopt": "_72qoAq_unmanagedAdopt",
|
|
849
|
+
"unmanagedChip": "_72qoAq_unmanagedChip",
|
|
850
|
+
"unmanagedChipName": "_72qoAq_unmanagedChipName",
|
|
851
|
+
"unmanagedLabel": "_72qoAq_unmanagedLabel",
|
|
852
|
+
"unmanagedRow": "_72qoAq_unmanagedRow",
|
|
599
853
|
"version": "_72qoAq_version",
|
|
600
854
|
"warnLine": "_72qoAq_warnLine"
|
|
601
855
|
};
|
|
@@ -604,8 +858,11 @@ var market_module_default = {
|
|
|
604
858
|
/** A source tab with trailing edit and delete controls. */
|
|
605
859
|
/** A source chip with a trailing delete control (deletion confirms at the section level). */
|
|
606
860
|
function SourceTab(props) {
|
|
607
|
-
const { t, active = false, label, onSelect, onDelete, onEdit } = props;
|
|
608
|
-
return (0, react.createElement)("div", {
|
|
861
|
+
const { t, active = false, label, title, onSelect, onDelete, onEdit } = props;
|
|
862
|
+
return (0, react.createElement)("div", {
|
|
863
|
+
className: active ? market_module_default.srcTabOn : market_module_default.srcTab,
|
|
864
|
+
title
|
|
865
|
+
}, (0, react.createElement)("button", {
|
|
609
866
|
type: "button",
|
|
610
867
|
className: market_module_default.srcTabMain,
|
|
611
868
|
onClick: onSelect
|
|
@@ -632,11 +889,19 @@ function SourceTab(props) {
|
|
|
632
889
|
/** Source editor modal for adding or editing a catalog source. */
|
|
633
890
|
function SourceEditorModal(props) {
|
|
634
891
|
const { t, editor } = props;
|
|
635
|
-
const [
|
|
892
|
+
const [kind, setKind] = (0, react.useState)(editor.mode === "edit" ? editor.source.kind === "archive" ? "archive" : editor.source.local === true ? "local" : "git" : "git");
|
|
636
893
|
const [url, setUrl] = (0, react.useState)(editor.mode === "edit" ? editor.source.url : "");
|
|
637
894
|
const [branch, setBranch] = (0, react.useState)(editor.mode === "edit" ? editor.source.branch ?? "" : "");
|
|
895
|
+
const [sha256, setSha256] = (0, react.useState)("");
|
|
638
896
|
const id = editor.mode === "edit" ? editor.source.id : "";
|
|
639
897
|
const title = editor.mode === "edit" ? t("editSourceTitle") : t("addSourceTitle");
|
|
898
|
+
const urlPlaceholder = kind === "local" ? t("sourceUrlLocalPh") : kind === "archive" ? t("sourceUrlArchivePh") : t("sourceUrlPh");
|
|
899
|
+
const urlHint = kind === "local" ? t("urlLocalHint") : kind === "archive" ? t("urlArchiveHint") : t("urlGitHint");
|
|
900
|
+
const segment = (value, label) => (0, react.createElement)("button", {
|
|
901
|
+
type: "button",
|
|
902
|
+
className: kind === value ? market_module_default.segOn : market_module_default.seg,
|
|
903
|
+
onClick: () => setKind(value)
|
|
904
|
+
}, label);
|
|
640
905
|
return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
641
906
|
open: true,
|
|
642
907
|
onClose: props.onClose,
|
|
@@ -654,26 +919,27 @@ function SourceEditorModal(props) {
|
|
|
654
919
|
variant: "primary",
|
|
655
920
|
disabled: props.busy,
|
|
656
921
|
onClick: () => {
|
|
657
|
-
props.onSave(
|
|
922
|
+
props.onSave({
|
|
923
|
+
url: url.trim(),
|
|
924
|
+
branch: branch.trim(),
|
|
925
|
+
kind,
|
|
926
|
+
sha256: sha256.trim()
|
|
927
|
+
});
|
|
658
928
|
}
|
|
659
929
|
}, t("save"))),
|
|
660
|
-
children: (0, react.createElement)("div", { className: market_module_default.editorForm }, (0, react.createElement)("div", { className: market_module_default.modeRow }, (0, react.createElement)("
|
|
661
|
-
|
|
662
|
-
className: local ? market_module_default.seg : market_module_default.segOn,
|
|
663
|
-
onClick: () => setLocal(false)
|
|
664
|
-
}, t("sourceModeGit")), (0, react.createElement)("button", {
|
|
665
|
-
type: "button",
|
|
666
|
-
className: local ? market_module_default.segOn : market_module_default.seg,
|
|
667
|
-
onClick: () => setLocal(true)
|
|
668
|
-
}, 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, {
|
|
669
|
-
placeholder: local ? t("sourceUrlLocalPh") : t("sourceUrlPh"),
|
|
930
|
+
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, {
|
|
931
|
+
placeholder: urlPlaceholder,
|
|
670
932
|
value: url,
|
|
671
933
|
onChange: (event) => setUrl(event.target.value)
|
|
672
|
-
}), (0, react.createElement)("span", { className: market_module_default.fieldHint },
|
|
934
|
+
}), (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, {
|
|
673
935
|
placeholder: t("branchPh"),
|
|
674
936
|
value: branch,
|
|
675
937
|
onChange: (event) => setBranch(event.target.value)
|
|
676
|
-
}), (0, react.createElement)("span", { className: market_module_default.fieldHint }, t("branchHint")))
|
|
938
|
+
}), (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, {
|
|
939
|
+
placeholder: t("sha256Ph"),
|
|
940
|
+
value: sha256,
|
|
941
|
+
onChange: (event) => setSha256(event.target.value)
|
|
942
|
+
}), (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}`)))
|
|
677
943
|
});
|
|
678
944
|
}
|
|
679
945
|
//#endregion
|
|
@@ -700,6 +966,10 @@ const SURFACE_TAGS = [
|
|
|
700
966
|
{
|
|
701
967
|
key: "agents",
|
|
702
968
|
labelKey: "surfaceAgents"
|
|
969
|
+
},
|
|
970
|
+
{
|
|
971
|
+
key: "lsp",
|
|
972
|
+
labelKey: "surfaceLsp"
|
|
703
973
|
}
|
|
704
974
|
];
|
|
705
975
|
function InstallConfirmModal(props) {
|
|
@@ -725,7 +995,7 @@ function InstallConfirmModal(props) {
|
|
|
725
995
|
props.onConfirm();
|
|
726
996
|
}
|
|
727
997
|
}, t("installConfirmAction"))),
|
|
728
|
-
children: (0, react.createElement)("div", { className: market_module_default.installConfirmBody }, (0, react.createElement)("div", { className: market_module_default.installConfirmSuite }, `${state.suite.sourceId} / ${state.suite.name}`), state.suite.version === void 0 ? null : (0, react.createElement)("div", { className: market_module_default.installConfirmMeta }, `${t("version")}: v${state.suite.version}`), tags.length === 0 ? (0, react.createElement)("div", { className: market_module_default.installConfirmMeta }, t("installConfirmNoSurfaces")) : (0, react.createElement)("div", { className: market_module_default.installConfirmTags }, tags.map((tag) => (0, react.createElement)("span", {
|
|
998
|
+
children: (0, react.createElement)("div", { className: market_module_default.installConfirmBody }, (0, react.createElement)("div", { className: market_module_default.installConfirmSuite }, `${state.suite.sourceId} / ${state.suite.name}`), state.suite.version === void 0 ? null : (0, react.createElement)("div", { className: market_module_default.installConfirmMeta }, `${t("version")}: v${state.suite.version}`), state.lockCommit === void 0 ? null : (0, react.createElement)("div", { className: market_module_default.installConfirmCommit }, `${t("installConfirmSource")}: ${state.lockCommit.slice(0, 12)}`), state.lockCommit === void 0 && state.localSource === true ? (0, react.createElement)("div", { className: market_module_default.installConfirmCommit }, `${t("installConfirmSource")}: ${t("installConfirmLocalTree")}`) : null, tags.length === 0 ? (0, react.createElement)("div", { className: market_module_default.installConfirmMeta }, t("installConfirmNoSurfaces")) : (0, react.createElement)("div", { className: market_module_default.installConfirmTags }, tags.map((tag) => (0, react.createElement)("span", {
|
|
729
999
|
key: tag.key,
|
|
730
1000
|
className: market_module_default.tag
|
|
731
1001
|
}, `${t(tag.labelKey)} ${surfaces[tag.key]}`))), executable ? (0, react.createElement)("div", { className: market_module_default.installConfirmWarn }, t("installConfirmExecutable")) : null)
|
|
@@ -733,7 +1003,7 @@ function InstallConfirmModal(props) {
|
|
|
733
1003
|
}
|
|
734
1004
|
//#endregion
|
|
735
1005
|
//#region src/client/ui/ToggleSwitch.tsx
|
|
736
|
-
/** Shared
|
|
1006
|
+
/** Shared switch control (ON = primary button fill, like every host toggle). */
|
|
737
1007
|
/** A green/gray switch control for suite enable state. */
|
|
738
1008
|
function ToggleSwitch(props) {
|
|
739
1009
|
return (0, react.createElement)("button", {
|
|
@@ -764,19 +1034,46 @@ function SuiteCard(props) {
|
|
|
764
1034
|
].filter(([, count]) => count > 0);
|
|
765
1035
|
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");
|
|
766
1036
|
const isRemote = suite.remoteUrl !== void 0;
|
|
1037
|
+
const hasTagRow = tags.length > 0 || suite.errors.length > 0 || (suite.mcpErrors?.length ?? 0) > 0;
|
|
767
1038
|
const stop = (callback) => (event) => {
|
|
768
1039
|
event.stopPropagation();
|
|
769
1040
|
callback();
|
|
770
1041
|
};
|
|
1042
|
+
const accent = suite.installed ? suite.enabled ? market_module_default.cardOn : market_module_default.cardMuted : void 0;
|
|
771
1043
|
return (0, react.createElement)("article", {
|
|
772
|
-
className: market_module_default.card,
|
|
1044
|
+
className: accent ? `${market_module_default.card} ${accent}` : market_module_default.card,
|
|
773
1045
|
onClick: props.onOpen
|
|
774
|
-
}, (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 ?
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
1046
|
+
}, (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 ? [
|
|
1047
|
+
(0, react.createElement)("button", {
|
|
1048
|
+
key: "refresh",
|
|
1049
|
+
type: "button",
|
|
1050
|
+
className: market_module_default.iconBtn,
|
|
1051
|
+
title: t("refresh"),
|
|
1052
|
+
disabled: busy,
|
|
1053
|
+
onClick: stop(props.onRefresh)
|
|
1054
|
+
}, (0, react.createElement)("svg", {
|
|
1055
|
+
viewBox: "0 0 24 24",
|
|
1056
|
+
"aria-hidden": "true"
|
|
1057
|
+
}, (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" }))),
|
|
1058
|
+
(0, react.createElement)("button", {
|
|
1059
|
+
key: "uninstall",
|
|
1060
|
+
type: "button",
|
|
1061
|
+
className: `${market_module_default.iconBtn} ${market_module_default.iconBtnDanger}`,
|
|
1062
|
+
title: t("uninstall"),
|
|
1063
|
+
disabled: busy,
|
|
1064
|
+
onClick: stop(props.onUninstall)
|
|
1065
|
+
}, (0, react.createElement)("svg", {
|
|
1066
|
+
viewBox: "0 0 24 24",
|
|
1067
|
+
"aria-hidden": "true"
|
|
1068
|
+
}, (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" }))),
|
|
1069
|
+
(0, react.createElement)(ToggleSwitch, {
|
|
1070
|
+
key: "toggle",
|
|
1071
|
+
on: suite.enabled,
|
|
1072
|
+
disabled: busy,
|
|
1073
|
+
title: suite.enabled ? t("disable") : t("enable"),
|
|
1074
|
+
onChange: props.onToggle
|
|
1075
|
+
})
|
|
1076
|
+
] : isRemote ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
780
1077
|
variant: "primary",
|
|
781
1078
|
size: "sm",
|
|
782
1079
|
disabled: busy,
|
|
@@ -787,19 +1084,7 @@ function SuiteCard(props) {
|
|
|
787
1084
|
size: "sm",
|
|
788
1085
|
disabled: busy,
|
|
789
1086
|
onClick: stop(props.onInstall)
|
|
790
|
-
}, t("install")), suite.
|
|
791
|
-
variant: "ghost",
|
|
792
|
-
size: "sm",
|
|
793
|
-
title: t("refresh"),
|
|
794
|
-
disabled: busy,
|
|
795
|
-
onClick: stop(props.onRefresh)
|
|
796
|
-
}, "↻") : null, suite.installed ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
797
|
-
variant: "ghost",
|
|
798
|
-
size: "sm",
|
|
799
|
-
title: t("uninstall"),
|
|
800
|
-
disabled: busy,
|
|
801
|
-
onClick: stop(props.onUninstall)
|
|
802
|
-
}, "🗑") : 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", {
|
|
1087
|
+
}, 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", {
|
|
803
1088
|
key: label,
|
|
804
1089
|
className: market_module_default.tag
|
|
805
1090
|
}, `${label} ${count}`)), suite.errors.length === 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
@@ -808,7 +1093,7 @@ function SuiteCard(props) {
|
|
|
808
1093
|
}), (suite.mcpErrors?.length ?? 0) === 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
809
1094
|
label: suite.mcpErrors.slice(0, 8).join(t("sourceErrorSeparator")),
|
|
810
1095
|
children: (0, react.createElement)("span", { className: market_module_default.warnLine }, `⚠ ${t("mcpSection")} ${suite.mcpErrors.length}`)
|
|
811
|
-
})));
|
|
1096
|
+
})) : null);
|
|
812
1097
|
}
|
|
813
1098
|
//#endregion
|
|
814
1099
|
//#region src/client/ui/StatusIcon.tsx
|
|
@@ -853,6 +1138,148 @@ var ErrorBoundary = class extends react.Component {
|
|
|
853
1138
|
}
|
|
854
1139
|
};
|
|
855
1140
|
//#endregion
|
|
1141
|
+
//#region src/client/credentials.ts
|
|
1142
|
+
/** Read one value-free credential view; secret values never enter the browser state. */
|
|
1143
|
+
async function describeCredential(api, ref) {
|
|
1144
|
+
if (api === void 0) return void 0;
|
|
1145
|
+
const response = await api.describe({ refs: [ref] });
|
|
1146
|
+
if (response.result?.ok !== true) throw new Error(response.result?.error?.message ?? "credential lookup failed");
|
|
1147
|
+
return response.result.value?.credentials?.[ref];
|
|
1148
|
+
}
|
|
1149
|
+
async function setCredential(api, ref, value) {
|
|
1150
|
+
const response = await api.set({
|
|
1151
|
+
ref,
|
|
1152
|
+
value
|
|
1153
|
+
});
|
|
1154
|
+
if (response.result?.ok !== true) throw new Error(response.result?.error?.message ?? "credential save failed");
|
|
1155
|
+
}
|
|
1156
|
+
async function unsetCredential(api, ref) {
|
|
1157
|
+
const response = await api.unset({ ref });
|
|
1158
|
+
if (response.result?.ok !== true) throw new Error(response.result?.error?.message ?? "credential removal failed");
|
|
1159
|
+
}
|
|
1160
|
+
//#endregion
|
|
1161
|
+
//#region src/client/mcp-credential.module.css
|
|
1162
|
+
var mcp_credential_module_default = {
|
|
1163
|
+
"actions": "G2mDja_actions",
|
|
1164
|
+
"controls": "G2mDja_controls",
|
|
1165
|
+
"editor": "G2mDja_editor",
|
|
1166
|
+
"error": "G2mDja_error",
|
|
1167
|
+
"factMiss": "G2mDja_factMiss",
|
|
1168
|
+
"factOk": "G2mDja_factOk",
|
|
1169
|
+
"facts": "G2mDja_facts",
|
|
1170
|
+
"form": "G2mDja_form",
|
|
1171
|
+
"head": "G2mDja_head",
|
|
1172
|
+
"input": "G2mDja_input",
|
|
1173
|
+
"note": "G2mDja_note",
|
|
1174
|
+
"ref": "G2mDja_ref",
|
|
1175
|
+
"row": "G2mDja_row"
|
|
1176
|
+
};
|
|
1177
|
+
//#endregion
|
|
1178
|
+
//#region src/client/McpCredentialEditor.tsx
|
|
1179
|
+
/**
|
|
1180
|
+
* Write-only credential editor for MCP `${ENV_NAME}` references.
|
|
1181
|
+
*
|
|
1182
|
+
* Read facts (configured / source / writable) come from the value-free
|
|
1183
|
+
* credentials wire; a typed value crosses the wire exactly once, inside
|
|
1184
|
+
* `credentials.set`, and never re-enters component state. Read-only
|
|
1185
|
+
* launch-environment credentials render guidance instead of a form that could
|
|
1186
|
+
* only fake success.
|
|
1187
|
+
*/
|
|
1188
|
+
function McpCredentialEditor(props) {
|
|
1189
|
+
const { t, api, refs } = props;
|
|
1190
|
+
const [views, setViews] = (0, react.useState)({});
|
|
1191
|
+
const [drafts, setDrafts] = (0, react.useState)({});
|
|
1192
|
+
const [busy, setBusy] = (0, react.useState)(void 0);
|
|
1193
|
+
const [error, setError] = (0, react.useState)(void 0);
|
|
1194
|
+
const refKey = refs.join("|");
|
|
1195
|
+
(0, react.useEffect)(() => {
|
|
1196
|
+
let cancelled = false;
|
|
1197
|
+
setViews({});
|
|
1198
|
+
setError(void 0);
|
|
1199
|
+
if (api === void 0 || refs.length === 0) return () => {
|
|
1200
|
+
cancelled = true;
|
|
1201
|
+
};
|
|
1202
|
+
Promise.all(refs.map(async (ref) => [ref, await describeCredential(api, ref)])).then((entries) => {
|
|
1203
|
+
if (cancelled) return;
|
|
1204
|
+
setViews(Object.fromEntries(entries.flatMap(([ref, view]) => view === void 0 ? [] : [[ref, view]])));
|
|
1205
|
+
}).catch((reason) => {
|
|
1206
|
+
if (!cancelled) setError(reason instanceof Error ? reason.message : String(reason));
|
|
1207
|
+
});
|
|
1208
|
+
return () => {
|
|
1209
|
+
cancelled = true;
|
|
1210
|
+
};
|
|
1211
|
+
}, [api, refKey]);
|
|
1212
|
+
if (refs.length === 0) return null;
|
|
1213
|
+
const refresh = async (ref) => {
|
|
1214
|
+
if (api === void 0) return;
|
|
1215
|
+
const view = await describeCredential(api, ref);
|
|
1216
|
+
if (view !== void 0) setViews((current) => ({
|
|
1217
|
+
...current,
|
|
1218
|
+
[ref]: view
|
|
1219
|
+
}));
|
|
1220
|
+
};
|
|
1221
|
+
const save = async (ref) => {
|
|
1222
|
+
const value = drafts[ref]?.trim();
|
|
1223
|
+
if (api === void 0 || value === void 0 || value === "") return;
|
|
1224
|
+
setBusy(ref);
|
|
1225
|
+
setError(void 0);
|
|
1226
|
+
try {
|
|
1227
|
+
await setCredential(api, ref, value);
|
|
1228
|
+
setDrafts((current) => ({
|
|
1229
|
+
...current,
|
|
1230
|
+
[ref]: ""
|
|
1231
|
+
}));
|
|
1232
|
+
await refresh(ref);
|
|
1233
|
+
} catch (reason) {
|
|
1234
|
+
setError(reason instanceof Error ? reason.message : String(reason));
|
|
1235
|
+
} finally {
|
|
1236
|
+
setBusy(void 0);
|
|
1237
|
+
}
|
|
1238
|
+
};
|
|
1239
|
+
const unset = async (ref) => {
|
|
1240
|
+
if (api === void 0) return;
|
|
1241
|
+
setBusy(ref);
|
|
1242
|
+
setError(void 0);
|
|
1243
|
+
try {
|
|
1244
|
+
await unsetCredential(api, ref);
|
|
1245
|
+
await refresh(ref);
|
|
1246
|
+
} catch (reason) {
|
|
1247
|
+
setError(reason instanceof Error ? reason.message : String(reason));
|
|
1248
|
+
} finally {
|
|
1249
|
+
setBusy(void 0);
|
|
1250
|
+
}
|
|
1251
|
+
};
|
|
1252
|
+
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) => {
|
|
1253
|
+
const view = views[ref];
|
|
1254
|
+
const refBusy = busy === ref;
|
|
1255
|
+
return (0, react.createElement)("div", {
|
|
1256
|
+
key: ref,
|
|
1257
|
+
className: mcp_credential_module_default.row
|
|
1258
|
+
}, (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", {
|
|
1259
|
+
className: mcp_credential_module_default.input,
|
|
1260
|
+
type: "password",
|
|
1261
|
+
autoComplete: "new-password",
|
|
1262
|
+
value: drafts[ref] ?? "",
|
|
1263
|
+
placeholder: t("mcpCredentialPlaceholder"),
|
|
1264
|
+
disabled: refBusy,
|
|
1265
|
+
onChange: (event) => setDrafts((current) => ({
|
|
1266
|
+
...current,
|
|
1267
|
+
[ref]: event.target.value
|
|
1268
|
+
}))
|
|
1269
|
+
}), (0, react.createElement)("div", { className: mcp_credential_module_default.actions }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1270
|
+
variant: "primary",
|
|
1271
|
+
size: "sm",
|
|
1272
|
+
disabled: refBusy || (drafts[ref]?.trim() ?? "") === "",
|
|
1273
|
+
onClick: () => void save(ref)
|
|
1274
|
+
}, t("mcpCredentialSave")), view.configured ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1275
|
+
variant: "ghost",
|
|
1276
|
+
size: "sm",
|
|
1277
|
+
disabled: refBusy,
|
|
1278
|
+
onClick: () => void unset(ref)
|
|
1279
|
+
}, t("mcpCredentialUnset")) : null)) : (0, react.createElement)("div", { className: mcp_credential_module_default.note }, t("mcpCredentialReadOnly"))));
|
|
1280
|
+
}));
|
|
1281
|
+
}
|
|
1282
|
+
//#endregion
|
|
856
1283
|
//#region src/client/features/suite-detail/suite-detail-resource.ts
|
|
857
1284
|
/** Create a request guard for one detail modal instance. */
|
|
858
1285
|
function createLatestRequestGuard() {
|
|
@@ -881,9 +1308,17 @@ const SURFACE_TOGGLE_ROWS = [
|
|
|
881
1308
|
["mcp", "surfaceMcp"],
|
|
882
1309
|
["hooks", "surfaceHooks"],
|
|
883
1310
|
["commands", "surfaceCommands"],
|
|
884
|
-
["agents", "surfaceAgents"]
|
|
1311
|
+
["agents", "surfaceAgents"],
|
|
1312
|
+
["lsp", "surfaceLsp"]
|
|
885
1313
|
];
|
|
886
|
-
function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
|
|
1314
|
+
function SuiteDetailModal({ t, credentials, sourceId, suiteId, onClose }) {
|
|
1315
|
+
const markdownLabels = (0, react.useMemo)(() => ({
|
|
1316
|
+
code: {
|
|
1317
|
+
copyLabel: t("mdCodeCopy"),
|
|
1318
|
+
copiedLabel: t("mdCodeCopied")
|
|
1319
|
+
},
|
|
1320
|
+
footnotes: t("mdFootnotes")
|
|
1321
|
+
}), [t]);
|
|
887
1322
|
const [detail, setDetail] = (0, react.useState)(void 0);
|
|
888
1323
|
const [error, setError] = (0, react.useState)(void 0);
|
|
889
1324
|
const [openSkill, setOpenSkill] = (0, react.useState)(void 0);
|
|
@@ -1003,7 +1438,10 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
|
|
|
1003
1438
|
onClick: () => {
|
|
1004
1439
|
toggleSkill(skill.name);
|
|
1005
1440
|
}
|
|
1006
|
-
}, (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, {
|
|
1441
|
+
}, (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, {
|
|
1442
|
+
text: skillText ?? "",
|
|
1443
|
+
labels: markdownLabels
|
|
1444
|
+
}))))), (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", {
|
|
1007
1445
|
className: market_module_default.warnLine,
|
|
1008
1446
|
style: { margin: "0 0 6px" }
|
|
1009
1447
|
}, `⚠ ${detail.mcpErrors.join(t("sourceErrorSeparator"))}`), detail.mcpServers.length === 0 ? (0, react.createElement)("div", { className: market_module_default.sidebarEmpty }, "—") : detail.mcpServers.map((server) => {
|
|
@@ -1017,7 +1455,11 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
|
|
|
1017
1455
|
type: "button",
|
|
1018
1456
|
className: openMcp === server.key ? market_module_default.detailItemOpen : market_module_default.detailItemRow,
|
|
1019
1457
|
onClick: () => toggleMcp(server.key)
|
|
1020
|
-
}, (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)(
|
|
1458
|
+
}, (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, {
|
|
1459
|
+
t,
|
|
1460
|
+
api: credentials,
|
|
1461
|
+
refs: server.credentialRefs ?? []
|
|
1462
|
+
}) : null, detail.installed && detail.surfaceToggles?.mcp !== false ? (0, react.createElement)(McpOverrideEditor, {
|
|
1021
1463
|
t,
|
|
1022
1464
|
serverKey: server.key,
|
|
1023
1465
|
transport: server.type,
|
|
@@ -1033,7 +1475,10 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
|
|
|
1033
1475
|
description: command.description,
|
|
1034
1476
|
open: openPreview === `c:${command.name}`,
|
|
1035
1477
|
onToggle: () => setOpenPreview(openPreview === `c:${command.name}` ? void 0 : `c:${command.name}`),
|
|
1036
|
-
children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
1478
|
+
children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
1479
|
+
text: command.content,
|
|
1480
|
+
labels: markdownLabels
|
|
1481
|
+
})
|
|
1037
1482
|
}))), (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, {
|
|
1038
1483
|
key: `a:${agent.name}`,
|
|
1039
1484
|
t,
|
|
@@ -1041,7 +1486,10 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
|
|
|
1041
1486
|
description: agent.description,
|
|
1042
1487
|
open: openPreview === `a:${agent.name}`,
|
|
1043
1488
|
onToggle: () => setOpenPreview(openPreview === `a:${agent.name}` ? void 0 : `a:${agent.name}`),
|
|
1044
|
-
children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
1489
|
+
children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
1490
|
+
text: agent.content,
|
|
1491
|
+
labels: markdownLabels
|
|
1492
|
+
})
|
|
1045
1493
|
}))), (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, {
|
|
1046
1494
|
key: `h:${index}`,
|
|
1047
1495
|
t,
|
|
@@ -1050,14 +1498,22 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
|
|
|
1050
1498
|
open: openPreview === `h:${index}`,
|
|
1051
1499
|
onToggle: () => setOpenPreview(openPreview === `h:${index}` ? void 0 : `h:${index}`),
|
|
1052
1500
|
children: (0, react.createElement)("pre", { className: market_module_default.mono }, JSON.stringify(hook, null, 2))
|
|
1053
|
-
}))), (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((
|
|
1501
|
+
}))), (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, {
|
|
1502
|
+
key: `l:${server.key}`,
|
|
1503
|
+
t,
|
|
1504
|
+
name: server.key,
|
|
1505
|
+
description: lspSummary(server),
|
|
1506
|
+
open: openPreview === `l:${server.key}`,
|
|
1507
|
+
onToggle: () => setOpenPreview(openPreview === `l:${server.key}` ? void 0 : `l:${server.key}`),
|
|
1508
|
+
children: (0, react.createElement)("pre", { className: market_module_default.mono }, JSON.stringify(server, null, 2))
|
|
1509
|
+
})), ...detail.lsp.raw.map((entry) => (0, react.createElement)(PreviewRow, {
|
|
1054
1510
|
key: `l:${entry.name}`,
|
|
1055
1511
|
t,
|
|
1056
1512
|
name: entry.name,
|
|
1057
1513
|
open: openPreview === `l:${entry.name}`,
|
|
1058
1514
|
onToggle: () => setOpenPreview(openPreview === `l:${entry.name}` ? void 0 : `l:${entry.name}`),
|
|
1059
1515
|
children: (0, react.createElement)("pre", { className: market_module_default.mono }, entry.content)
|
|
1060
|
-
}))), 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", {
|
|
1516
|
+
}))]), 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", {
|
|
1061
1517
|
key: index,
|
|
1062
1518
|
className: market_module_default.warnLine
|
|
1063
1519
|
}, entry))))
|
|
@@ -1068,6 +1524,10 @@ function mcpSummary(server) {
|
|
|
1068
1524
|
if (server.type === "stdio") return server.command ?? server.type;
|
|
1069
1525
|
return server.url ?? server.type;
|
|
1070
1526
|
}
|
|
1527
|
+
/** One-line summary of a declared LSP server: command plus mapped extension list. */
|
|
1528
|
+
function lspSummary(server) {
|
|
1529
|
+
return [server.command, Object.keys(server.extensions).join(" ")].join(" · ");
|
|
1530
|
+
}
|
|
1071
1531
|
/** Parse `KEY=VALUE` lines into a record; blank and comment lines are skipped. */
|
|
1072
1532
|
function parseKvLines(text) {
|
|
1073
1533
|
const result = {};
|
|
@@ -1080,10 +1540,11 @@ function parseKvLines(text) {
|
|
|
1080
1540
|
}
|
|
1081
1541
|
return Object.keys(result).length > 0 ? result : void 0;
|
|
1082
1542
|
}
|
|
1083
|
-
/** Format a record back into sorted `KEY=VALUE` lines
|
|
1543
|
+
/** Format a record back into sorted `KEY=VALUE` lines without exposing literal secrets. */
|
|
1544
|
+
const SENSITIVE_KEY = /(authorization|token|secret|password|credential|api[-_]?key)/i;
|
|
1084
1545
|
function formatKvLines(map) {
|
|
1085
1546
|
if (map === void 0) return "";
|
|
1086
|
-
return Object.keys(map).sort().map((key) => `${key}=${map[key]}`).join("\n");
|
|
1547
|
+
return Object.keys(map).filter((key) => !SENSITIVE_KEY.test(key) || map[key]?.includes("${")).sort().map((key) => `${key}=${map[key]}`).join("\n");
|
|
1087
1548
|
}
|
|
1088
1549
|
/**
|
|
1089
1550
|
* Per-server MCP override editor: enable/disable plus connection-input
|
|
@@ -1214,8 +1675,8 @@ function SearchFilterToolbar(props) {
|
|
|
1214
1675
|
key: filter.id,
|
|
1215
1676
|
type: "button",
|
|
1216
1677
|
className: filter.active ? SearchFilterToolbar_module_default.filterOn : SearchFilterToolbar_module_default.filter,
|
|
1217
|
-
title: `${filter.label} ${filter.count}`,
|
|
1218
|
-
"aria-label": `${filter.label} ${filter.count}`,
|
|
1678
|
+
title: filter.hint ?? `${filter.label} ${filter.count}`,
|
|
1679
|
+
"aria-label": filter.hint ?? `${filter.label} ${filter.count}`,
|
|
1219
1680
|
onClick: filter.onSelect
|
|
1220
1681
|
}, 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", {
|
|
1221
1682
|
type: "button",
|
|
@@ -1272,6 +1733,7 @@ function ViewIcon({ mode }) {
|
|
|
1272
1733
|
/** Host step keys -> translation keys, resolved against the active t(). */
|
|
1273
1734
|
const PROGRESS_STEP_LABELS = {
|
|
1274
1735
|
cloning: "progressCloning",
|
|
1736
|
+
downloading: "progressDownloading",
|
|
1275
1737
|
reading: "progressReading"
|
|
1276
1738
|
};
|
|
1277
1739
|
function progressStepLabel(t, step) {
|
|
@@ -1282,7 +1744,7 @@ function progressStepLabel(t, step) {
|
|
|
1282
1744
|
function interpolate(text, params) {
|
|
1283
1745
|
return text.replace(/\{(\w+)\}/g, (match, key) => key in params ? String(params[key]) : match);
|
|
1284
1746
|
}
|
|
1285
|
-
function MarketSection({ t, mode = "settings" }) {
|
|
1747
|
+
function MarketSection({ t, credentials, mode = "settings" }) {
|
|
1286
1748
|
const [overview, setOverview] = (0, react.useState)(() => loadOverview().initial);
|
|
1287
1749
|
const [loading, setLoading] = (0, react.useState)(() => loadOverview().revalidating);
|
|
1288
1750
|
const [search, setSearch] = (0, react.useState)("");
|
|
@@ -1363,6 +1825,10 @@ function MarketSection({ t, mode = "settings" }) {
|
|
|
1363
1825
|
category
|
|
1364
1826
|
]);
|
|
1365
1827
|
const selectedSource = category === "all" ? void 0 : overview.sources.find((source) => source.id === category);
|
|
1828
|
+
const adoptSource = (0, react.useCallback)(async (id) => {
|
|
1829
|
+
await action(`s:adopt:${id}`, "sources/adopt", { id });
|
|
1830
|
+
}, [action]);
|
|
1831
|
+
const unmanaged = overview.unmanaged ?? [];
|
|
1366
1832
|
return (0, react.createElement)(ErrorBoundary, {
|
|
1367
1833
|
fallback: (error) => (0, react.createElement)("div", { className: market_module_default.empty }, `${t("actionFail")}: ${error.message}`),
|
|
1368
1834
|
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, {
|
|
@@ -1383,21 +1849,39 @@ function MarketSection({ t, mode = "settings" }) {
|
|
|
1383
1849
|
active: category === "all",
|
|
1384
1850
|
label: `${t("tabAll")} ${overview.totals.all}`,
|
|
1385
1851
|
onSelect: () => setCategory("all")
|
|
1386
|
-
}), ...[...overview.sources].sort((a, b) => a.id.localeCompare(b.id)).map((source) =>
|
|
1387
|
-
|
|
1388
|
-
t,
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1852
|
+
}), ...[...overview.sources].sort((a, b) => a.id.localeCompare(b.id)).map((source) => {
|
|
1853
|
+
const notes = source.scanNotes ?? [];
|
|
1854
|
+
const noteHint = notes.length === 0 ? void 0 : `${t("scanNotes")}: ${notes.slice(0, 8).join(t("sourceErrorSeparator"))}`;
|
|
1855
|
+
const kindBadge = source.local === true ? t("sourceLocal") : source.kind === "archive" ? t("sourceArchive") : source.adopted === true ? t("sourceAdopted") : void 0;
|
|
1856
|
+
return (0, react.createElement)(SourceTab, {
|
|
1857
|
+
key: source.id,
|
|
1858
|
+
t,
|
|
1859
|
+
active: category === source.id,
|
|
1860
|
+
label: `${source.id}${kindBadge === void 0 ? "" : ` · ${kindBadge}`} ${source.suiteIds.length}${source.cloned === false || notes.length > 0 ? " ⚠" : ""}`,
|
|
1861
|
+
title: noteHint,
|
|
1862
|
+
onSelect: () => setCategory(source.id),
|
|
1863
|
+
onDelete: () => setConfirm({
|
|
1864
|
+
kind: "removeSource",
|
|
1865
|
+
sourceId: source.id
|
|
1866
|
+
}),
|
|
1867
|
+
onEdit: selectedSource?.id === source.id ? () => setEditor({
|
|
1868
|
+
mode: "edit",
|
|
1869
|
+
source
|
|
1870
|
+
}) : void 0
|
|
1871
|
+
});
|
|
1872
|
+
}))), 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", {
|
|
1873
|
+
key: entry.id,
|
|
1874
|
+
className: market_module_default.unmanagedChip,
|
|
1875
|
+
title: entry.url ?? t("unmanagedNoRemote")
|
|
1876
|
+
}, (0, react.createElement)("span", { className: market_module_default.unmanagedChipName }, entry.id), (0, react.createElement)("button", {
|
|
1877
|
+
type: "button",
|
|
1878
|
+
className: market_module_default.unmanagedAdopt,
|
|
1879
|
+
disabled: busy !== void 0,
|
|
1880
|
+
title: t("unmanagedAdopt"),
|
|
1881
|
+
onClick: () => {
|
|
1882
|
+
adoptSource(entry.id);
|
|
1883
|
+
}
|
|
1884
|
+
}, "+")))), (0, react.createElement)(SearchFilterToolbar, {
|
|
1401
1885
|
search,
|
|
1402
1886
|
searchLabel: t("searchPh"),
|
|
1403
1887
|
searchPlaceholder: t("searchPh"),
|
|
@@ -1442,7 +1926,12 @@ function MarketSection({ t, mode = "settings" }) {
|
|
|
1442
1926
|
suiteId: suite.suiteId
|
|
1443
1927
|
}),
|
|
1444
1928
|
onInstall: () => {
|
|
1445
|
-
|
|
1929
|
+
const source = overview.sources.find((entry) => entry.id === suite.sourceId);
|
|
1930
|
+
setInstallConfirm({
|
|
1931
|
+
suite,
|
|
1932
|
+
...source?.lockCommit === void 0 ? {} : { lockCommit: source.lockCommit },
|
|
1933
|
+
...source?.local === true ? { localSource: true } : {}
|
|
1934
|
+
});
|
|
1446
1935
|
},
|
|
1447
1936
|
onAddSource: () => {
|
|
1448
1937
|
if (suite.remoteUrl !== void 0) action(`a:${suite.suiteId}`, "sources/add", { url: suite.remoteUrl });
|
|
@@ -1492,6 +1981,7 @@ function MarketSection({ t, mode = "settings" }) {
|
|
|
1492
1981
|
}, t("confirmDelete")))
|
|
1493
1982
|
}), detail === void 0 ? null : (0, react.createElement)(SuiteDetailModal, {
|
|
1494
1983
|
t,
|
|
1984
|
+
credentials,
|
|
1495
1985
|
sourceId: detail.sourceId,
|
|
1496
1986
|
suiteId: detail.suiteId,
|
|
1497
1987
|
onClose: () => setDetail(void 0)
|
|
@@ -1501,13 +1991,15 @@ function MarketSection({ t, mode = "settings" }) {
|
|
|
1501
1991
|
busy: busy !== void 0,
|
|
1502
1992
|
progress,
|
|
1503
1993
|
onClose: () => setEditor(void 0),
|
|
1504
|
-
onSave: async (url, branch,
|
|
1994
|
+
onSave: async ({ url, branch, kind, sha256 }) => {
|
|
1505
1995
|
const key = editor.mode === "edit" ? `s:edit:${editor.source.id}` : `s:add:${url}`;
|
|
1506
1996
|
const body = {
|
|
1507
1997
|
url,
|
|
1508
|
-
|
|
1509
|
-
|
|
1998
|
+
local: kind === "local",
|
|
1999
|
+
kind
|
|
1510
2000
|
};
|
|
2001
|
+
if (branch !== "" && kind === "git") body["branch"] = branch;
|
|
2002
|
+
if (sha256 !== "" && kind === "archive") body["sha256"] = sha256;
|
|
1511
2003
|
if (editor.mode === "add") {
|
|
1512
2004
|
setBusy(key);
|
|
1513
2005
|
setProgress({
|
|
@@ -1566,16 +2058,30 @@ function deriveMcpStatusViewModel(payload, filter, search) {
|
|
|
1566
2058
|
plugin: 0,
|
|
1567
2059
|
direct: 0
|
|
1568
2060
|
};
|
|
1569
|
-
|
|
1570
|
-
|
|
2061
|
+
const visibleTotals = {
|
|
2062
|
+
all: 0,
|
|
2063
|
+
connected: 0,
|
|
2064
|
+
degraded: 0,
|
|
2065
|
+
failed: 0,
|
|
2066
|
+
needsCredentials: 0,
|
|
2067
|
+
orphaned: 0,
|
|
2068
|
+
disabled: 0,
|
|
2069
|
+
foreign: 0
|
|
2070
|
+
};
|
|
1571
2071
|
const filtered = [];
|
|
1572
2072
|
const needle = search.trim().toLowerCase();
|
|
1573
2073
|
for (const item of searchable) {
|
|
1574
2074
|
const entry = item.entry;
|
|
1575
2075
|
filterCounts.all++;
|
|
1576
2076
|
filterCounts[entry.kind]++;
|
|
1577
|
-
|
|
1578
|
-
if (entry.state === "
|
|
2077
|
+
visibleTotals.all++;
|
|
2078
|
+
if (entry.state === "connected") visibleTotals.connected++;
|
|
2079
|
+
if (entry.state === "degraded") visibleTotals.degraded++;
|
|
2080
|
+
if (entry.state === "failed") visibleTotals.failed++;
|
|
2081
|
+
if (entry.state === "needs-credentials") visibleTotals.needsCredentials++;
|
|
2082
|
+
if (entry.state === "orphaned") visibleTotals.orphaned++;
|
|
2083
|
+
if (entry.state === "disabled") visibleTotals.disabled++;
|
|
2084
|
+
if (entry.state === "foreign") visibleTotals.foreign++;
|
|
1579
2085
|
if (filter !== "all" && entry.kind !== filter) continue;
|
|
1580
2086
|
if (needle !== "" && !item.haystack.includes(needle)) continue;
|
|
1581
2087
|
filtered.push(entry);
|
|
@@ -1584,11 +2090,7 @@ function deriveMcpStatusViewModel(payload, filter, search) {
|
|
|
1584
2090
|
activeEntries,
|
|
1585
2091
|
filtered,
|
|
1586
2092
|
filterCounts,
|
|
1587
|
-
visibleTotals
|
|
1588
|
-
all: activeEntries.length,
|
|
1589
|
-
connected,
|
|
1590
|
-
failed
|
|
1591
|
-
}
|
|
2093
|
+
visibleTotals
|
|
1592
2094
|
};
|
|
1593
2095
|
}
|
|
1594
2096
|
function searchableFor(payload) {
|
|
@@ -1596,7 +2098,7 @@ function searchableFor(payload) {
|
|
|
1596
2098
|
if (cached !== void 0) return cached;
|
|
1597
2099
|
const searchable = payload.entries.filter((entry) => entry.state !== "disabled").map((entry) => ({
|
|
1598
2100
|
entry,
|
|
1599
|
-
haystack: `${entry.name} ${entry.source ?? ""} ${entry.endpoint ?? ""} ${entry.transport}`.toLowerCase()
|
|
2101
|
+
haystack: `${entry.name} ${entry.source ?? ""} ${entry.endpoint ?? ""} ${entry.transport} ${entry.reason ?? ""} ${(entry.credentialRefs ?? []).join(" ")}`.toLowerCase()
|
|
1600
2102
|
}));
|
|
1601
2103
|
searchableCache.set(payload, searchable);
|
|
1602
2104
|
return searchable;
|
|
@@ -1606,15 +2108,35 @@ function searchableFor(payload) {
|
|
|
1606
2108
|
var mcp_status_module_default = {
|
|
1607
2109
|
"boundary": "AUWlZW_boundary",
|
|
1608
2110
|
"card": "AUWlZW_card",
|
|
1609
|
-
"
|
|
2111
|
+
"cardBody": "AUWlZW_cardBody",
|
|
2112
|
+
"cardConflict": "AUWlZW_cardConflict",
|
|
2113
|
+
"cardConnected": "AUWlZW_cardConnected",
|
|
2114
|
+
"cardDegraded": "AUWlZW_cardDegraded",
|
|
2115
|
+
"cardDisabled": "AUWlZW_cardDisabled",
|
|
2116
|
+
"cardFailed": "AUWlZW_cardFailed",
|
|
2117
|
+
"cardForeign": "AUWlZW_cardForeign",
|
|
2118
|
+
"cardHostMissing": "AUWlZW_cardHostMissing",
|
|
2119
|
+
"cardMounted": "AUWlZW_cardMounted",
|
|
2120
|
+
"cardNeedsCredentials": "AUWlZW_cardNeedsCredentials",
|
|
2121
|
+
"cardOrphaned": "AUWlZW_cardOrphaned",
|
|
1610
2122
|
"cardTop": "AUWlZW_cardTop",
|
|
1611
2123
|
"chevron": "AUWlZW_chevron",
|
|
2124
|
+
"chipblocked": "AUWlZW_chipblocked",
|
|
2125
|
+
"chipdegraded": "AUWlZW_chipdegraded",
|
|
2126
|
+
"chipdisabled": "AUWlZW_chipdisabled",
|
|
2127
|
+
"chipfailed": "AUWlZW_chipfailed",
|
|
2128
|
+
"chipmounted": "AUWlZW_chipmounted",
|
|
2129
|
+
"chipneedsCredentials": "AUWlZW_chipneedsCredentials",
|
|
2130
|
+
"chiporphaned": "AUWlZW_chiporphaned",
|
|
1612
2131
|
"config": "AUWlZW_config",
|
|
1613
2132
|
"detail": "AUWlZW_detail",
|
|
1614
2133
|
"detailBody": "AUWlZW_detailBody",
|
|
1615
2134
|
"detailDialog": "AUWlZW_detailDialog",
|
|
1616
2135
|
"detailEmpty": "AUWlZW_detailEmpty",
|
|
2136
|
+
"detailEndpoint": "AUWlZW_detailEndpoint",
|
|
1617
2137
|
"detailHead": "AUWlZW_detailHead",
|
|
2138
|
+
"detailHero": "AUWlZW_detailHero",
|
|
2139
|
+
"detailHeroText": "AUWlZW_detailHeroText",
|
|
1618
2140
|
"detailMeta": "AUWlZW_detailMeta",
|
|
1619
2141
|
"detailSection": "AUWlZW_detailSection",
|
|
1620
2142
|
"detailState": "AUWlZW_detailState",
|
|
@@ -1622,49 +2144,85 @@ var mcp_status_module_default = {
|
|
|
1622
2144
|
"detailStatedegraded": "AUWlZW_detailStatedegraded",
|
|
1623
2145
|
"detailStatedisabled": "AUWlZW_detailStatedisabled",
|
|
1624
2146
|
"detailStatefailed": "AUWlZW_detailStatefailed",
|
|
2147
|
+
"detailStateneeds-credentials": "AUWlZW_detailStateneeds-credentials",
|
|
2148
|
+
"detailStateorphaned": "AUWlZW_detailStateorphaned",
|
|
1625
2149
|
"empty": "AUWlZW_empty",
|
|
1626
2150
|
"endpoint": "AUWlZW_endpoint",
|
|
1627
2151
|
"error": "AUWlZW_error",
|
|
1628
2152
|
"errorSummary": "AUWlZW_errorSummary",
|
|
2153
|
+
"extArrow": "AUWlZW_extArrow",
|
|
2154
|
+
"extLanguage": "AUWlZW_extLanguage",
|
|
2155
|
+
"extName": "AUWlZW_extName",
|
|
2156
|
+
"extRow": "AUWlZW_extRow",
|
|
1629
2157
|
"grid": "AUWlZW_grid",
|
|
1630
2158
|
"header": "AUWlZW_header",
|
|
1631
2159
|
"headerActions": "AUWlZW_headerActions",
|
|
1632
2160
|
"list": "AUWlZW_list",
|
|
1633
|
-
"
|
|
2161
|
+
"lspStartingPulse": "AUWlZW_lspStartingPulse",
|
|
2162
|
+
"mcp-retry-spin": "AUWlZW_mcp-retry-spin",
|
|
1634
2163
|
"modalFooter": "AUWlZW_modalFooter",
|
|
1635
2164
|
"name": "AUWlZW_name",
|
|
2165
|
+
"observedAt": "AUWlZW_observedAt",
|
|
1636
2166
|
"reason": "AUWlZW_reason",
|
|
2167
|
+
"reasonBox": "AUWlZW_reasonBox",
|
|
2168
|
+
"reasonLabel": "AUWlZW_reasonLabel",
|
|
2169
|
+
"reasonRaw": "AUWlZW_reasonRaw",
|
|
2170
|
+
"reasonText": "AUWlZW_reasonText",
|
|
2171
|
+
"retryEchoFailure": "AUWlZW_retryEchoFailure",
|
|
2172
|
+
"retryEchoSuccess": "AUWlZW_retryEchoSuccess",
|
|
2173
|
+
"retrySpinner": "AUWlZW_retrySpinner",
|
|
2174
|
+
"retryStack": "AUWlZW_retryStack",
|
|
1637
2175
|
"service": "AUWlZW_service",
|
|
1638
2176
|
"sourceDirect": "AUWlZW_sourceDirect",
|
|
1639
2177
|
"sourcePlugin": "AUWlZW_sourcePlugin",
|
|
2178
|
+
"spinning": "AUWlZW_spinning",
|
|
1640
2179
|
"state": "AUWlZW_state",
|
|
2180
|
+
"stateconflict": "AUWlZW_stateconflict",
|
|
1641
2181
|
"stateconnected": "AUWlZW_stateconnected",
|
|
1642
2182
|
"statedegraded": "AUWlZW_statedegraded",
|
|
1643
2183
|
"statedisabled": "AUWlZW_statedisabled",
|
|
1644
2184
|
"statefailed": "AUWlZW_statefailed",
|
|
2185
|
+
"statehost-missing": "AUWlZW_statehost-missing",
|
|
2186
|
+
"statemounted": "AUWlZW_statemounted",
|
|
2187
|
+
"stateneeds-credentials": "AUWlZW_stateneeds-credentials",
|
|
2188
|
+
"stateorphaned": "AUWlZW_stateorphaned",
|
|
2189
|
+
"statePill": "AUWlZW_statePill",
|
|
2190
|
+
"statusconflict": "AUWlZW_statusconflict",
|
|
1645
2191
|
"statusconnected": "AUWlZW_statusconnected",
|
|
1646
2192
|
"statusdegraded": "AUWlZW_statusdegraded",
|
|
1647
2193
|
"statusdisabled": "AUWlZW_statusdisabled",
|
|
1648
2194
|
"statusDot": "AUWlZW_statusDot",
|
|
1649
2195
|
"statusfailed": "AUWlZW_statusfailed",
|
|
2196
|
+
"statusforeign": "AUWlZW_statusforeign",
|
|
2197
|
+
"statushost-missing": "AUWlZW_statushost-missing",
|
|
2198
|
+
"statusmounted": "AUWlZW_statusmounted",
|
|
2199
|
+
"statusneeds-credentials": "AUWlZW_statusneeds-credentials",
|
|
2200
|
+
"statusorphaned": "AUWlZW_statusorphaned",
|
|
2201
|
+
"statusstarting": "AUWlZW_statusstarting",
|
|
1650
2202
|
"subtitle": "AUWlZW_subtitle",
|
|
1651
2203
|
"summary": "AUWlZW_summary",
|
|
2204
|
+
"summaryAllGood": "AUWlZW_summaryAllGood",
|
|
2205
|
+
"summaryBar": "AUWlZW_summaryBar",
|
|
2206
|
+
"summaryChip": "AUWlZW_summaryChip",
|
|
2207
|
+
"summaryCount": "AUWlZW_summaryCount",
|
|
1652
2208
|
"summaryDotGreen": "AUWlZW_summaryDotGreen",
|
|
2209
|
+
"summaryDotInfo": "AUWlZW_summaryDotInfo",
|
|
1653
2210
|
"summaryDotRed": "AUWlZW_summaryDotRed",
|
|
2211
|
+
"summaryDotWarn": "AUWlZW_summaryDotWarn",
|
|
2212
|
+
"summaryLabel": "AUWlZW_summaryLabel",
|
|
1654
2213
|
"surface": "AUWlZW_surface",
|
|
1655
2214
|
"title": "AUWlZW_title",
|
|
1656
2215
|
"tool": "AUWlZW_tool",
|
|
1657
2216
|
"toolbar": "AUWlZW_toolbar",
|
|
1658
2217
|
"toolCount": "AUWlZW_toolCount",
|
|
1659
2218
|
"toolDescription": "AUWlZW_toolDescription",
|
|
1660
|
-
"toolIndex": "AUWlZW_toolIndex",
|
|
1661
2219
|
"toolList": "AUWlZW_toolList",
|
|
1662
2220
|
"toolName": "AUWlZW_toolName",
|
|
1663
2221
|
"transport": "AUWlZW_transport"
|
|
1664
2222
|
};
|
|
1665
2223
|
//#endregion
|
|
1666
2224
|
//#region src/client/McpStatusPanel.tsx
|
|
1667
|
-
const EMPTY_STATUS = {
|
|
2225
|
+
const EMPTY_STATUS$1 = {
|
|
1668
2226
|
entries: [],
|
|
1669
2227
|
observedAt: "",
|
|
1670
2228
|
totals: {
|
|
@@ -1672,19 +2230,41 @@ const EMPTY_STATUS = {
|
|
|
1672
2230
|
connected: 0,
|
|
1673
2231
|
degraded: 0,
|
|
1674
2232
|
failed: 0,
|
|
1675
|
-
|
|
2233
|
+
needsCredentials: 0,
|
|
2234
|
+
orphaned: 0,
|
|
2235
|
+
disabled: 0,
|
|
2236
|
+
foreign: 0
|
|
1676
2237
|
},
|
|
1677
2238
|
directObservationOnly: true
|
|
1678
2239
|
};
|
|
1679
|
-
/** DSH-native MCP inventory
|
|
1680
|
-
function McpStatusPanel({ t }) {
|
|
1681
|
-
const [payload, setPayload] = (0, react.useState)(EMPTY_STATUS);
|
|
2240
|
+
/** DSH-native MCP inventory with a per-state overview and per-service detail. */
|
|
2241
|
+
function McpStatusPanel({ t, credentials }) {
|
|
2242
|
+
const [payload, setPayload] = (0, react.useState)(EMPTY_STATUS$1);
|
|
1682
2243
|
const [loading, setLoading] = (0, react.useState)(true);
|
|
1683
2244
|
const [error, setError] = (0, react.useState)(void 0);
|
|
1684
2245
|
const [filter, setFilter] = (0, react.useState)("all");
|
|
1685
2246
|
const [search, setSearch] = (0, react.useState)("");
|
|
1686
2247
|
const [view, setView] = (0, react.useState)("grid");
|
|
1687
2248
|
const [selected, setSelected] = (0, react.useState)(void 0);
|
|
2249
|
+
const retry = (entryId) => {
|
|
2250
|
+
return retryMcpMounts().then(async () => {
|
|
2251
|
+
const refreshed = await fetchMcpStatus().catch(() => void 0);
|
|
2252
|
+
if (refreshed !== void 0) setPayload(refreshed);
|
|
2253
|
+
return refreshed?.entries.some((entry) => entry.id === entryId && entry.state === "connected") === true;
|
|
2254
|
+
}).catch(async (caught) => {
|
|
2255
|
+
setError(caught instanceof Error ? caught.message : String(caught));
|
|
2256
|
+
const refreshed = await fetchMcpStatus().catch(() => void 0);
|
|
2257
|
+
if (refreshed !== void 0) setPayload(refreshed);
|
|
2258
|
+
return refreshed?.entries.some((entry) => entry.id === entryId && entry.state === "connected") === true;
|
|
2259
|
+
}).finally(() => setLoading(false));
|
|
2260
|
+
};
|
|
2261
|
+
const reauthorize = (serverName) => {
|
|
2262
|
+
return reauthorizeMcpServer(serverName).then(() => retryMcpMounts()).then(async () => {
|
|
2263
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
2264
|
+
const refreshed = await fetchMcpStatus().catch(() => void 0);
|
|
2265
|
+
if (refreshed !== void 0) setPayload(refreshed);
|
|
2266
|
+
});
|
|
2267
|
+
};
|
|
1688
2268
|
const refresh = () => {
|
|
1689
2269
|
setLoading(true);
|
|
1690
2270
|
setError(void 0);
|
|
@@ -1696,16 +2276,18 @@ function McpStatusPanel({ t }) {
|
|
|
1696
2276
|
refresh();
|
|
1697
2277
|
}, []);
|
|
1698
2278
|
const { activeEntries, filtered, filterCounts, visibleTotals } = deriveMcpStatusViewModel(payload, filter, search);
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
title: `${visibleTotals.failed} ${t("mcpFailed")}`
|
|
1702
|
-
}, (0, react.createElement)("span", { className: mcp_status_module_default.summaryDotRed }), visibleTotals.failed) : null, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2279
|
+
const allHealthy = activeEntries.length > 0 && visibleTotals.connected === activeEntries.length;
|
|
2280
|
+
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, {
|
|
1703
2281
|
variant: "ghost",
|
|
1704
2282
|
size: "sm",
|
|
1705
2283
|
onClick: refresh,
|
|
1706
2284
|
disabled: loading,
|
|
1707
2285
|
title: t("refresh")
|
|
1708
|
-
}, "
|
|
2286
|
+
}, `↻ ${t("refresh")}`))), activeEntries.length === 0 || allHealthy || loading ? null : (0, react.createElement)(StatusSummaryBar, {
|
|
2287
|
+
t,
|
|
2288
|
+
totals: visibleTotals,
|
|
2289
|
+
observedAt: payload.observedAt
|
|
2290
|
+
}), (0, react.createElement)(SearchFilterToolbar, {
|
|
1709
2291
|
className: mcp_status_module_default.toolbar,
|
|
1710
2292
|
search,
|
|
1711
2293
|
searchLabel: t("mcpSearch"),
|
|
@@ -1721,7 +2303,8 @@ function McpStatusPanel({ t }) {
|
|
|
1721
2303
|
count: filterCounts[kind],
|
|
1722
2304
|
icon: (0, react.createElement)(McpFilterIcon, { kind }),
|
|
1723
2305
|
active: filter === kind,
|
|
1724
|
-
onSelect: () => setFilter(kind)
|
|
2306
|
+
onSelect: () => setFilter(kind),
|
|
2307
|
+
hint: mcpFilterHint(t, kind)
|
|
1725
2308
|
})),
|
|
1726
2309
|
view,
|
|
1727
2310
|
gridLabel: t("grid"),
|
|
@@ -1739,31 +2322,94 @@ function McpStatusPanel({ t }) {
|
|
|
1739
2322
|
}))), selected === void 0 ? null : (0, react.createElement)(McpDetailModal, {
|
|
1740
2323
|
entry: selected,
|
|
1741
2324
|
t,
|
|
1742
|
-
|
|
2325
|
+
credentials,
|
|
2326
|
+
onClose: () => setSelected(void 0),
|
|
2327
|
+
onRetry: retry,
|
|
2328
|
+
onReauthorize: reauthorize
|
|
1743
2329
|
}));
|
|
1744
2330
|
}
|
|
2331
|
+
/**
|
|
2332
|
+
* One chip per non-healthy state, shown only when that state is non-zero.
|
|
2333
|
+
*
|
|
2334
|
+
* The chips are ordered by severity so the first one the eye lands on is the
|
|
2335
|
+
* state that most needs attention, and the whole bar collapses to a single
|
|
2336
|
+
* "all connected" confirmation when nothing is wrong.
|
|
2337
|
+
*/
|
|
2338
|
+
function StatusSummaryBar({ t, totals, observedAt }) {
|
|
2339
|
+
const chips = [
|
|
2340
|
+
{
|
|
2341
|
+
key: "orphaned",
|
|
2342
|
+
count: totals.orphaned,
|
|
2343
|
+
label: t("mcpOrphaned")
|
|
2344
|
+
},
|
|
2345
|
+
{
|
|
2346
|
+
key: "failed",
|
|
2347
|
+
count: totals.failed,
|
|
2348
|
+
label: t("mcpFailed")
|
|
2349
|
+
},
|
|
2350
|
+
{
|
|
2351
|
+
key: "needsCredentials",
|
|
2352
|
+
count: totals.needsCredentials,
|
|
2353
|
+
label: t("mcpNeedsCredentials")
|
|
2354
|
+
},
|
|
2355
|
+
{
|
|
2356
|
+
key: "degraded",
|
|
2357
|
+
count: totals.degraded,
|
|
2358
|
+
label: t("mcpDegraded")
|
|
2359
|
+
},
|
|
2360
|
+
{
|
|
2361
|
+
key: "foreign",
|
|
2362
|
+
count: totals.foreign,
|
|
2363
|
+
label: t("mcpForeign")
|
|
2364
|
+
},
|
|
2365
|
+
{
|
|
2366
|
+
key: "disabled",
|
|
2367
|
+
count: totals.disabled,
|
|
2368
|
+
label: t("mcpDisabled")
|
|
2369
|
+
}
|
|
2370
|
+
].filter((chip) => chip.count > 0);
|
|
2371
|
+
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", {
|
|
2372
|
+
key: chip.key,
|
|
2373
|
+
className: `${mcp_status_module_default.summaryChip} ${mcp_status_module_default[`chip${chip.key}`]}`,
|
|
2374
|
+
title: `${chip.count} ${chip.label}`
|
|
2375
|
+
}, (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)));
|
|
2376
|
+
}
|
|
2377
|
+
function dotTone(key) {
|
|
2378
|
+
if (key === "foreign") return "Info";
|
|
2379
|
+
if (key === "degraded" || key === "needsCredentials") return "Warn";
|
|
2380
|
+
return "Red";
|
|
2381
|
+
}
|
|
2382
|
+
function formatObservedAt$1(iso) {
|
|
2383
|
+
const date = new Date(iso);
|
|
2384
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
2385
|
+
return date.toLocaleTimeString();
|
|
2386
|
+
}
|
|
1745
2387
|
function McpCard({ entry, t, onClick }) {
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
onClick
|
|
1750
|
-
|
|
2388
|
+
const interactive = {
|
|
2389
|
+
role: "button",
|
|
2390
|
+
tabIndex: 0,
|
|
2391
|
+
onClick,
|
|
2392
|
+
onKeyDown: (event) => {
|
|
2393
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
2394
|
+
event.preventDefault();
|
|
2395
|
+
onClick();
|
|
2396
|
+
}
|
|
2397
|
+
};
|
|
2398
|
+
return (0, react.createElement)("div", {
|
|
2399
|
+
className: `${mcp_status_module_default.card} ${mcp_status_module_default[`card${stateClass(entry.state)}`]}`,
|
|
2400
|
+
...interactive
|
|
2401
|
+
}, (0, react.createElement)("div", { className: mcp_status_module_default.cardBody }, (0, react.createElement)("div", { className: mcp_status_module_default.cardTop }, (0, react.createElement)("span", {
|
|
1751
2402
|
className: `${mcp_status_module_default.statusDot} ${mcp_status_module_default[`status${entry.state}`]}`,
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
}), (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, {
|
|
1755
|
-
kind: entry.kind,
|
|
1756
|
-
label: entry.kind === "plugin" ? entry.source ?? "—" : t("mcpDirect"),
|
|
1757
|
-
t
|
|
1758
|
-
}), (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));
|
|
2403
|
+
"aria-hidden": true
|
|
2404
|
+
}), (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"))));
|
|
1759
2405
|
}
|
|
1760
|
-
function
|
|
1761
|
-
return
|
|
2406
|
+
function stateClass(state) {
|
|
2407
|
+
return state.split("-").map((part, index) => index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)).join("").replace(/^./, (char) => char.toUpperCase());
|
|
1762
2408
|
}
|
|
1763
2409
|
function McpSourceIcon({ kind }) {
|
|
1764
2410
|
const common = {
|
|
1765
|
-
width:
|
|
1766
|
-
height:
|
|
2411
|
+
width: 14,
|
|
2412
|
+
height: 14,
|
|
1767
2413
|
viewBox: "0 0 16 16",
|
|
1768
2414
|
fill: "none",
|
|
1769
2415
|
"aria-hidden": true
|
|
@@ -1785,7 +2431,27 @@ function McpFilterIcon({ kind }) {
|
|
|
1785
2431
|
"aria-hidden": true
|
|
1786
2432
|
}, (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" }));
|
|
1787
2433
|
}
|
|
1788
|
-
|
|
2434
|
+
/**
|
|
2435
|
+
* The detail dialog owns every action and every long text: state, reason,
|
|
2436
|
+
* credentials, config, tools, and the retry control with its in-place result
|
|
2437
|
+
* echo. The state pill is dropped entirely — the dot and the reason box carry
|
|
2438
|
+
* that information without a second red stamp.
|
|
2439
|
+
*/
|
|
2440
|
+
function McpDetailModal({ entry, t, credentials, onClose, onRetry, onReauthorize }) {
|
|
2441
|
+
const [retrying, setRetrying] = (0, react.useState)(false);
|
|
2442
|
+
const [retryOutcome, setRetryOutcome] = (0, react.useState)(void 0);
|
|
2443
|
+
const [reauthorizing, setReauthorizing] = (0, react.useState)(false);
|
|
2444
|
+
const [reauthOutcome, setReauthOutcome] = (0, react.useState)(void 0);
|
|
2445
|
+
const retry = () => {
|
|
2446
|
+
setRetrying(true);
|
|
2447
|
+
setRetryOutcome(void 0);
|
|
2448
|
+
onRetry(entry.id).then((success) => setRetryOutcome(success ? "success" : "failure")).catch(() => setRetryOutcome("failure")).finally(() => setRetrying(false));
|
|
2449
|
+
};
|
|
2450
|
+
const reauthorize = () => {
|
|
2451
|
+
setReauthorizing(true);
|
|
2452
|
+
setReauthOutcome(void 0);
|
|
2453
|
+
onReauthorize(entry.name).then(() => setReauthOutcome("success")).catch(() => setReauthOutcome("failure")).finally(() => setReauthorizing(false));
|
|
2454
|
+
};
|
|
1789
2455
|
return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
1790
2456
|
open: true,
|
|
1791
2457
|
onClose,
|
|
@@ -1794,18 +2460,47 @@ function McpDetailModal({ entry, t, onClose }) {
|
|
|
1794
2460
|
closeLabel: t("cancel"),
|
|
1795
2461
|
className: mcp_status_module_default.detailDialog,
|
|
1796
2462
|
contentClassName: mcp_status_module_default.detailBody,
|
|
1797
|
-
footer: (0, react.createElement)("div", { className: mcp_status_module_default.modalFooter }, (0, react.createElement)(
|
|
2463
|
+
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", {
|
|
2464
|
+
className: mcp_status_module_default.retryEchoSuccess,
|
|
2465
|
+
role: "status"
|
|
2466
|
+
}, `✓ ${t("mcpRetrySuccess")}`) : retryOutcome === "failure" ? (0, react.createElement)("span", {
|
|
2467
|
+
className: mcp_status_module_default.retryEchoFailure,
|
|
2468
|
+
role: "alert"
|
|
2469
|
+
}, `✕ ${t("mcpRetryFailure")}`) : null, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2470
|
+
variant: "ghost",
|
|
2471
|
+
size: "sm",
|
|
2472
|
+
disabled: retrying,
|
|
2473
|
+
onClick: retry
|
|
2474
|
+
}, (0, react.createElement)("span", {
|
|
2475
|
+
className: retrying ? `${mcp_status_module_default.retrySpinner} ${mcp_status_module_default.spinning}` : mcp_status_module_default.retrySpinner,
|
|
2476
|
+
"aria-hidden": true
|
|
2477
|
+
}, "↻"), retrying ? t("mcpRetrying") : t("mcpRetry"))), entry.kind === "plugin" ? (0, react.createElement)("span", { className: mcp_status_module_default.retryStack }, reauthOutcome === "success" ? (0, react.createElement)("span", {
|
|
2478
|
+
className: mcp_status_module_default.retryEchoSuccess,
|
|
2479
|
+
role: "status"
|
|
2480
|
+
}, `✓ ${t("mcpReauthSuccess")}`) : reauthOutcome === "failure" ? (0, react.createElement)("span", {
|
|
2481
|
+
className: mcp_status_module_default.retryEchoFailure,
|
|
2482
|
+
role: "alert"
|
|
2483
|
+
}, `✕ ${t("mcpReauthFailure")}`) : null, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2484
|
+
variant: "ghost",
|
|
2485
|
+
size: "sm",
|
|
2486
|
+
disabled: reauthorizing,
|
|
2487
|
+
title: entry.state === "failed" ? t("mcpConnectHint") : t("mcpReauthHint"),
|
|
2488
|
+
onClick: reauthorize
|
|
2489
|
+
}, reauthorizing ? t("mcpReauthorizing") : entry.state === "failed" ? t("mcpConnect") : t("mcpReauthorize"))) : null, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1798
2490
|
variant: "ghost",
|
|
1799
2491
|
onClick: onClose
|
|
1800
2492
|
}, t("cancel"))),
|
|
1801
|
-
children: (0, react.createElement)("div", { className: mcp_status_module_default.detail }, (0, react.createElement)("div", { className: mcp_status_module_default.
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
2493
|
+
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", {
|
|
2494
|
+
className: `${mcp_status_module_default.statusDot} ${mcp_status_module_default[`status${entry.state}`]}`,
|
|
2495
|
+
"aria-hidden": true
|
|
2496
|
+
}), (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 }, 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, {
|
|
2497
|
+
t,
|
|
2498
|
+
api: credentials,
|
|
2499
|
+
refs: entry.credentialRefs
|
|
2500
|
+
}), (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", {
|
|
1806
2501
|
key: tool.name,
|
|
1807
2502
|
className: mcp_status_module_default.tool
|
|
1808
|
-
}, (0, react.createElement)("span", { className: mcp_status_module_default.
|
|
2503
|
+
}, (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))))))
|
|
1809
2504
|
});
|
|
1810
2505
|
}
|
|
1811
2506
|
function filterLabel(t, kind) {
|
|
@@ -1813,11 +2508,448 @@ function filterLabel(t, kind) {
|
|
|
1813
2508
|
if (kind === "direct") return t("mcpDirect");
|
|
1814
2509
|
return t("mcpAll");
|
|
1815
2510
|
}
|
|
2511
|
+
/** Hover/aria explanation for each MCP filter tab. */
|
|
2512
|
+
function mcpFilterHint(t, kind) {
|
|
2513
|
+
if (kind === "plugin") return t("mcpFilterPluginHint");
|
|
2514
|
+
if (kind === "direct") return t("mcpFilterDirectHint");
|
|
2515
|
+
return t("mcpFilterAllHint");
|
|
2516
|
+
}
|
|
2517
|
+
//#endregion
|
|
2518
|
+
//#region src/client/LspStatusPanel.tsx
|
|
2519
|
+
/**
|
|
2520
|
+
* LSP status panel: declared language servers of enabled suites with their
|
|
2521
|
+
* mount state. Rows come from the declaration-and-diagnostic model — the DSH
|
|
2522
|
+
* `ctx.lsp` seam has no provider snapshot, so "mounted" means the mount
|
|
2523
|
+
* registration succeeded, not that a process probe ran.
|
|
2524
|
+
*
|
|
2525
|
+
* Visual language mirrors McpStatusPanel: the same shared SearchFilterToolbar,
|
|
2526
|
+
* the same summary chips, cards, and state pills from mcp-status.module.css.
|
|
2527
|
+
* Cards stay lean (state dot + name + command + one state pill); the source
|
|
2528
|
+
* suite and the full extension map live in the detail dialog.
|
|
2529
|
+
*/
|
|
2530
|
+
const EMPTY_STATUS = {
|
|
2531
|
+
entries: [],
|
|
2532
|
+
observedAt: "",
|
|
2533
|
+
totals: {
|
|
2534
|
+
all: 0,
|
|
2535
|
+
mounted: 0,
|
|
2536
|
+
failed: 0,
|
|
2537
|
+
blocked: 0,
|
|
2538
|
+
disabled: 0
|
|
2539
|
+
},
|
|
2540
|
+
hostMissing: true
|
|
2541
|
+
};
|
|
2542
|
+
const FILTER_KEYS = [
|
|
2543
|
+
"all",
|
|
2544
|
+
"plugin",
|
|
2545
|
+
"direct",
|
|
2546
|
+
"blocked"
|
|
2547
|
+
];
|
|
2548
|
+
const FILTER_LABEL_KEYS = {
|
|
2549
|
+
all: "lspAll",
|
|
2550
|
+
plugin: "lspPlugin",
|
|
2551
|
+
direct: "lspDirect",
|
|
2552
|
+
blocked: "lspBlocked"
|
|
2553
|
+
};
|
|
2554
|
+
/** Tooltip text per filter: the counts alone do not explain the grouping. */
|
|
2555
|
+
const FILTER_HINT_KEYS = {
|
|
2556
|
+
all: "lspFilterAllHint",
|
|
2557
|
+
plugin: "lspFilterPluginHint",
|
|
2558
|
+
direct: "lspFilterDirectHint",
|
|
2559
|
+
blocked: "lspFilterBlockedHint"
|
|
2560
|
+
};
|
|
2561
|
+
function matches(entry, filter) {
|
|
2562
|
+
if (filter === "all") return true;
|
|
2563
|
+
if (filter === "plugin" || filter === "direct") return entry.kind === filter;
|
|
2564
|
+
return entry.state === "host-missing" || entry.state === "conflict" || entry.state === "failed";
|
|
2565
|
+
}
|
|
2566
|
+
function severity(entry) {
|
|
2567
|
+
if (entry.state === "failed") return 0;
|
|
2568
|
+
if (entry.state === "conflict") return 1;
|
|
2569
|
+
if (entry.state === "host-missing") return 2;
|
|
2570
|
+
if (entry.state === "starting") return 3;
|
|
2571
|
+
if (entry.state === "disabled") return 4;
|
|
2572
|
+
return 5;
|
|
2573
|
+
}
|
|
2574
|
+
/** Language-server inventory with per-state overview and per-server detail. */
|
|
2575
|
+
function LspStatusPanel({ t }) {
|
|
2576
|
+
const [payload, setPayload] = (0, react.useState)(EMPTY_STATUS);
|
|
2577
|
+
const [loading, setLoading] = (0, react.useState)(true);
|
|
2578
|
+
const [error, setError] = (0, react.useState)(void 0);
|
|
2579
|
+
const [filter, setFilter] = (0, react.useState)("all");
|
|
2580
|
+
const [search, setSearch] = (0, react.useState)("");
|
|
2581
|
+
const [view, setView] = (0, react.useState)("grid");
|
|
2582
|
+
const [selected, setSelected] = (0, react.useState)(void 0);
|
|
2583
|
+
const [editorOpen, setEditorOpen] = (0, react.useState)(false);
|
|
2584
|
+
const refresh = () => {
|
|
2585
|
+
setLoading(true);
|
|
2586
|
+
setError(void 0);
|
|
2587
|
+
fetchLspStatus().then(setPayload).catch((caught) => {
|
|
2588
|
+
setError(caught instanceof Error ? caught.message : String(caught));
|
|
2589
|
+
}).finally(() => setLoading(false));
|
|
2590
|
+
};
|
|
2591
|
+
(0, react.useEffect)(() => {
|
|
2592
|
+
refresh();
|
|
2593
|
+
}, []);
|
|
2594
|
+
const anyStarting = payload.entries.some((entry) => entry.state === "starting");
|
|
2595
|
+
(0, react.useEffect)(() => {
|
|
2596
|
+
if (!anyStarting) return;
|
|
2597
|
+
let cancelled = false;
|
|
2598
|
+
let attempts = 0;
|
|
2599
|
+
const timer = setInterval(() => {
|
|
2600
|
+
attempts += 1;
|
|
2601
|
+
if (cancelled || attempts > 20) {
|
|
2602
|
+
clearInterval(timer);
|
|
2603
|
+
return;
|
|
2604
|
+
}
|
|
2605
|
+
fetchLspStatus().then((value) => {
|
|
2606
|
+
if (!cancelled) setPayload(value);
|
|
2607
|
+
}).catch(() => {});
|
|
2608
|
+
}, 1e3);
|
|
2609
|
+
return () => {
|
|
2610
|
+
cancelled = true;
|
|
2611
|
+
clearInterval(timer);
|
|
2612
|
+
};
|
|
2613
|
+
}, [anyStarting]);
|
|
2614
|
+
const needle = search.trim().toLowerCase();
|
|
2615
|
+
const counts = FILTER_KEYS.reduce((acc, key) => {
|
|
2616
|
+
acc[key] = payload.entries.filter((entry) => matches(entry, key)).length;
|
|
2617
|
+
return acc;
|
|
2618
|
+
}, {});
|
|
2619
|
+
const visible = payload.entries.filter((entry) => matches(entry, filter)).filter((entry) => needle === "" || `${entry.serverKey} ${entry.suiteName} ${entry.command}`.toLowerCase().includes(needle));
|
|
2620
|
+
const settled = payload.entries.filter((entry) => entry.state !== "starting");
|
|
2621
|
+
const allHealthy = settled.length > 0 && settled.every((entry) => entry.state === "mounted");
|
|
2622
|
+
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, {
|
|
2623
|
+
variant: "ghost",
|
|
2624
|
+
size: "sm",
|
|
2625
|
+
onClick: () => setEditorOpen(true),
|
|
2626
|
+
disabled: loading,
|
|
2627
|
+
title: t("lspConfigure")
|
|
2628
|
+
}, t("lspConfigure")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2629
|
+
variant: "ghost",
|
|
2630
|
+
size: "sm",
|
|
2631
|
+
onClick: refresh,
|
|
2632
|
+
disabled: loading,
|
|
2633
|
+
title: t("refresh")
|
|
2634
|
+
}, `↻ ${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", {
|
|
2635
|
+
className: `${mcp_status_module_default.summaryChip} ${mcp_status_module_default.chipblocked}`,
|
|
2636
|
+
title: t("lspHostMissing")
|
|
2637
|
+
}, t("lspHostMissingShort")) : [
|
|
2638
|
+
{
|
|
2639
|
+
key: "failed",
|
|
2640
|
+
count: payload.totals.failed,
|
|
2641
|
+
label: t("lspFailed")
|
|
2642
|
+
},
|
|
2643
|
+
{
|
|
2644
|
+
key: "blocked",
|
|
2645
|
+
count: payload.totals.blocked,
|
|
2646
|
+
label: t("lspBlocked")
|
|
2647
|
+
},
|
|
2648
|
+
{
|
|
2649
|
+
key: "disabled",
|
|
2650
|
+
count: payload.totals.disabled,
|
|
2651
|
+
label: t("lspDisabled")
|
|
2652
|
+
}
|
|
2653
|
+
].filter((chip) => chip.count > 0).map((chip) => (0, react.createElement)("span", {
|
|
2654
|
+
key: chip.key,
|
|
2655
|
+
className: `${mcp_status_module_default.summaryChip} ${mcp_status_module_default[`chip${chip.key}`]}`,
|
|
2656
|
+
title: `${chip.count} ${chip.label}`
|
|
2657
|
+
}, (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, {
|
|
2658
|
+
className: mcp_status_module_default.toolbar,
|
|
2659
|
+
search,
|
|
2660
|
+
searchLabel: t("lspSearch"),
|
|
2661
|
+
searchPlaceholder: t("lspSearch"),
|
|
2662
|
+
onSearchChange: setSearch,
|
|
2663
|
+
filters: FILTER_KEYS.map((key) => ({
|
|
2664
|
+
id: key,
|
|
2665
|
+
label: t(FILTER_LABEL_KEYS[key]),
|
|
2666
|
+
count: counts[key] ?? 0,
|
|
2667
|
+
icon: (0, react.createElement)(LspFilterIcon, { k: key }),
|
|
2668
|
+
active: filter === key,
|
|
2669
|
+
onSelect: () => setFilter(key),
|
|
2670
|
+
hint: FILTER_HINT_KEYS[key] === void 0 ? void 0 : t(FILTER_HINT_KEYS[key])
|
|
2671
|
+
})),
|
|
2672
|
+
view,
|
|
2673
|
+
gridLabel: t("grid"),
|
|
2674
|
+
listLabel: t("list"),
|
|
2675
|
+
onViewChange: (nextView) => setView(nextView)
|
|
2676
|
+
}), error !== void 0 ? (0, react.createElement)("div", { className: mcp_status_module_default.error }, error, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2677
|
+
variant: "ghost",
|
|
2678
|
+
size: "sm",
|
|
2679
|
+
onClick: refresh
|
|
2680
|
+
}, 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, {
|
|
2681
|
+
key: entry.id,
|
|
2682
|
+
entry,
|
|
2683
|
+
t,
|
|
2684
|
+
onOpen: () => setSelected(entry)
|
|
2685
|
+
}))), selected === void 0 ? null : (0, react.createElement)(LspDetailModal, {
|
|
2686
|
+
entry: selected,
|
|
2687
|
+
t,
|
|
2688
|
+
onClose: () => setSelected(void 0)
|
|
2689
|
+
}), editorOpen ? (0, react.createElement)(LspConfigEditor, {
|
|
2690
|
+
t,
|
|
2691
|
+
onClose: () => setEditorOpen(false),
|
|
2692
|
+
onSaved: () => {
|
|
2693
|
+
setEditorOpen(false);
|
|
2694
|
+
refresh();
|
|
2695
|
+
}
|
|
2696
|
+
}) : null);
|
|
2697
|
+
}
|
|
2698
|
+
/**
|
|
2699
|
+
* Direct LSP configuration editor: one JSON document shaped like Claude
|
|
2700
|
+
* Code's `lspServers` table. The host validates with the same fail-closed
|
|
2701
|
+
* rules as suite declarations and mounts direct servers on the next
|
|
2702
|
+
* reconcile pass.
|
|
2703
|
+
*/
|
|
2704
|
+
function LspConfigEditor({ t, onClose, onSaved }) {
|
|
2705
|
+
const [text, setText] = (0, react.useState)(void 0);
|
|
2706
|
+
const [busy, setBusy] = (0, react.useState)(false);
|
|
2707
|
+
const [error, setError] = (0, react.useState)(void 0);
|
|
2708
|
+
(0, react.useEffect)(() => {
|
|
2709
|
+
let cancelled = false;
|
|
2710
|
+
fetchLspServers().then((servers) => {
|
|
2711
|
+
if (cancelled) return;
|
|
2712
|
+
setText(JSON.stringify({ lspServers: servers }, null, 2));
|
|
2713
|
+
}).catch((reason) => {
|
|
2714
|
+
if (cancelled) setError(reason instanceof Error ? reason.message : String(reason));
|
|
2715
|
+
});
|
|
2716
|
+
return () => {
|
|
2717
|
+
cancelled = true;
|
|
2718
|
+
};
|
|
2719
|
+
}, []);
|
|
2720
|
+
const save = async () => {
|
|
2721
|
+
setBusy(true);
|
|
2722
|
+
setError(void 0);
|
|
2723
|
+
try {
|
|
2724
|
+
await saveLspServers(JSON.parse(text ?? ""));
|
|
2725
|
+
onSaved();
|
|
2726
|
+
} catch (reason) {
|
|
2727
|
+
setError(reason instanceof Error ? reason.message : String(reason));
|
|
2728
|
+
} finally {
|
|
2729
|
+
setBusy(false);
|
|
2730
|
+
}
|
|
2731
|
+
};
|
|
2732
|
+
return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
2733
|
+
open: true,
|
|
2734
|
+
onClose,
|
|
2735
|
+
title: t("lspConfigure"),
|
|
2736
|
+
description: t("lspConfigureHint"),
|
|
2737
|
+
closeLabel: t("cancel"),
|
|
2738
|
+
className: mcp_status_module_default.detailDialog,
|
|
2739
|
+
contentClassName: mcp_status_module_default.detailBody,
|
|
2740
|
+
footer: (0, react.createElement)("div", { className: mcp_status_module_default.modalFooter }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2741
|
+
variant: "ghost",
|
|
2742
|
+
onClick: onClose
|
|
2743
|
+
}, t("cancel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2744
|
+
variant: "primary",
|
|
2745
|
+
disabled: busy || text === void 0,
|
|
2746
|
+
onClick: () => {
|
|
2747
|
+
save();
|
|
2748
|
+
}
|
|
2749
|
+
}, t("lspSave"))),
|
|
2750
|
+
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", {
|
|
2751
|
+
className: mcp_status_module_default.config,
|
|
2752
|
+
rows: 16,
|
|
2753
|
+
spellcheck: false,
|
|
2754
|
+
value: text,
|
|
2755
|
+
onChange: (event) => setText(event.target.value)
|
|
2756
|
+
}))
|
|
2757
|
+
});
|
|
2758
|
+
}
|
|
2759
|
+
/** Lean row: state dot, server key, command. The card accent + status dot
|
|
2760
|
+
* carry the state; no redundant pill for the healthy case. Kind badge shows
|
|
2761
|
+
* where the declaration comes from (suite vs user configuration). */
|
|
2762
|
+
function LspRow({ entry, t, onOpen }) {
|
|
2763
|
+
const interactive = {
|
|
2764
|
+
role: "button",
|
|
2765
|
+
tabIndex: 0,
|
|
2766
|
+
onClick: onOpen,
|
|
2767
|
+
onKeyDown: (event) => {
|
|
2768
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
2769
|
+
event.preventDefault();
|
|
2770
|
+
onOpen();
|
|
2771
|
+
}
|
|
2772
|
+
};
|
|
2773
|
+
const showPill = entry.state !== "mounted";
|
|
2774
|
+
return (0, react.createElement)("div", {
|
|
2775
|
+
className: `${mcp_status_module_default.card} ${mcp_status_module_default[`card${accentClass(entry.state)}`]}`,
|
|
2776
|
+
...interactive
|
|
2777
|
+
}, (0, react.createElement)("div", { className: mcp_status_module_default.cardBody }, (0, react.createElement)("div", { className: mcp_status_module_default.cardTop }, (0, react.createElement)("span", {
|
|
2778
|
+
className: `${mcp_status_module_default.statusDot} ${mcp_status_module_default[`status${dotClass(entry.state)}`]}`,
|
|
2779
|
+
"aria-hidden": true
|
|
2780
|
+
}), (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(" "))));
|
|
2781
|
+
}
|
|
2782
|
+
function LspDetailModal({ entry, t, onClose }) {
|
|
2783
|
+
const extensions = Object.entries(entry.extensions);
|
|
2784
|
+
return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
2785
|
+
open: true,
|
|
2786
|
+
onClose,
|
|
2787
|
+
title: entry.serverKey,
|
|
2788
|
+
description: t("lspDetailSubtitle"),
|
|
2789
|
+
closeLabel: t("cancel"),
|
|
2790
|
+
className: mcp_status_module_default.detailDialog,
|
|
2791
|
+
contentClassName: mcp_status_module_default.detailBody,
|
|
2792
|
+
footer: (0, react.createElement)("div", { className: mcp_status_module_default.modalFooter }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2793
|
+
variant: "ghost",
|
|
2794
|
+
onClick: onClose
|
|
2795
|
+
}, t("cancel"))),
|
|
2796
|
+
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", {
|
|
2797
|
+
className: `${mcp_status_module_default.statusDot} ${mcp_status_module_default[`status${dotClass(entry.state)}`]}`,
|
|
2798
|
+
"aria-hidden": true
|
|
2799
|
+
}), (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", {
|
|
2800
|
+
key: ext,
|
|
2801
|
+
className: mcp_status_module_default.extRow
|
|
2802
|
+
}, (0, react.createElement)("span", { className: mcp_status_module_default.extName }, ext), (0, react.createElement)("span", {
|
|
2803
|
+
className: mcp_status_module_default.extArrow,
|
|
2804
|
+
"aria-hidden": true
|
|
2805
|
+
}, "→"), (0, react.createElement)("span", { className: mcp_status_module_default.extLanguage }, languageId))))))
|
|
2806
|
+
});
|
|
2807
|
+
}
|
|
2808
|
+
/** Filter icons mirroring McpFilterIcon's language: shared glyph shapes for
|
|
2809
|
+
* all/plugin/direct so the two panels read as one system, plus a warning
|
|
2810
|
+
* triangle for the blocked state. */
|
|
2811
|
+
function LspFilterIcon({ k }) {
|
|
2812
|
+
const common = {
|
|
2813
|
+
width: 16,
|
|
2814
|
+
height: 16,
|
|
2815
|
+
viewBox: "0 0 16 16",
|
|
2816
|
+
fill: "none",
|
|
2817
|
+
"aria-hidden": true
|
|
2818
|
+
};
|
|
2819
|
+
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" }));
|
|
2820
|
+
if (k === "direct") return (0, react.createElement)("svg", common, (0, react.createElement)("circle", {
|
|
2821
|
+
cx: 8,
|
|
2822
|
+
cy: 5,
|
|
2823
|
+
r: 2.2
|
|
2824
|
+
}), (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" }));
|
|
2825
|
+
if (k === "blocked") return (0, react.createElement)("svg", common, (0, react.createElement)("path", {
|
|
2826
|
+
d: "M8 2.5 14 13H2L8 2.5Z",
|
|
2827
|
+
stroke: "currentColor",
|
|
2828
|
+
strokeLinejoin: "round"
|
|
2829
|
+
}), (0, react.createElement)("path", {
|
|
2830
|
+
d: "M8 6.5v3M8 11.2v.3",
|
|
2831
|
+
stroke: "currentColor",
|
|
2832
|
+
strokeLinecap: "round"
|
|
2833
|
+
}));
|
|
2834
|
+
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" }));
|
|
2835
|
+
}
|
|
2836
|
+
/** The card-accent CSS suffix; host-missing uses the warn palette. */
|
|
2837
|
+
function accentClass(state) {
|
|
2838
|
+
if (state === "mounted") return "Mounted";
|
|
2839
|
+
if (state === "host-missing") return "HostMissing";
|
|
2840
|
+
if (state === "conflict") return "Conflict";
|
|
2841
|
+
if (state === "failed") return "Failed";
|
|
2842
|
+
return "Disabled";
|
|
2843
|
+
}
|
|
2844
|
+
/** The status-dot CSS suffix (lowercase state names in the stylesheet). */
|
|
2845
|
+
function dotClass(state) {
|
|
2846
|
+
return state === "host-missing" ? "host-missing" : state;
|
|
2847
|
+
}
|
|
2848
|
+
/** The state-pill CSS suffix; conflict borrows the failed palette and
|
|
2849
|
+
* starting borrows the warn palette. */
|
|
2850
|
+
function pillClass(state) {
|
|
2851
|
+
if (state === "conflict") return "failed";
|
|
2852
|
+
if (state === "starting") return "host-missing";
|
|
2853
|
+
return state;
|
|
2854
|
+
}
|
|
1816
2855
|
function stateLabel(t, state) {
|
|
1817
|
-
if (state === "
|
|
1818
|
-
if (state === "
|
|
1819
|
-
if (state === "
|
|
1820
|
-
return t("
|
|
2856
|
+
if (state === "mounted") return t("lspMounted");
|
|
2857
|
+
if (state === "starting") return t("lspStarting");
|
|
2858
|
+
if (state === "host-missing") return t("lspHostMissingShort");
|
|
2859
|
+
if (state === "failed") return t("lspFailed");
|
|
2860
|
+
if (state === "conflict") return t("lspConflict");
|
|
2861
|
+
return t("lspDisabled");
|
|
2862
|
+
}
|
|
2863
|
+
function formatObservedAt(iso) {
|
|
2864
|
+
const date = new Date(iso);
|
|
2865
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
2866
|
+
return date.toLocaleTimeString();
|
|
2867
|
+
}
|
|
2868
|
+
//#endregion
|
|
2869
|
+
//#region src/client/McpPluginCard.tsx
|
|
2870
|
+
/**
|
|
2871
|
+
* The Agent Plugins Market card on the host's 插件配置 (plugin configuration)
|
|
2872
|
+
* tab: the market feature's configuration entry, named after the market
|
|
2873
|
+
* itself. Disclosed inside is the MCP enhancement switch — ON (default)
|
|
2874
|
+
* mounts suite MCP servers through the market's built-in bridge (OAuth
|
|
2875
|
+
* authorization, SSE, browser-leg hold); OFF falls back to the host's
|
|
2876
|
+
* `dsh-mcp-client` compatibility client.
|
|
2877
|
+
*
|
|
2878
|
+
* The switch state is the market's host settings namespace (bound by the
|
|
2879
|
+
* client entry), so a flip persists through the host settings document and
|
|
2880
|
+
* the node half's namespace watcher remounts the servers. The host client
|
|
2881
|
+
* version probe rides the market's own API.
|
|
2882
|
+
*/
|
|
2883
|
+
/** The host's disclosure chevron, matching the native cards' glyph exactly. */
|
|
2884
|
+
const chevronIcon = _deepseek_ai_dsh_client_ui_primitives["IconChevronDownOutline14"];
|
|
2885
|
+
function McpPluginCard({ t, scope, probe }) {
|
|
2886
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
2887
|
+
const [, setTick] = (0, react.useState)(0);
|
|
2888
|
+
const [probeInfo, setProbeInfo] = (0, react.useState)(void 0);
|
|
2889
|
+
const [busy, setBusy] = (0, react.useState)(false);
|
|
2890
|
+
const [error, setError] = (0, react.useState)(void 0);
|
|
2891
|
+
(0, react.useEffect)(() => scope.subscribe(() => setTick((tick) => tick + 1)), [scope]);
|
|
2892
|
+
const refreshProbe = (0, react.useCallback)(async () => {
|
|
2893
|
+
try {
|
|
2894
|
+
setProbeInfo(await probe());
|
|
2895
|
+
} catch {}
|
|
2896
|
+
}, [probe]);
|
|
2897
|
+
(0, react.useEffect)(() => {
|
|
2898
|
+
refreshProbe();
|
|
2899
|
+
}, [refreshProbe]);
|
|
2900
|
+
const enhanced = scope.enhanced();
|
|
2901
|
+
const writable = scope.writable();
|
|
2902
|
+
const regionSetting = scope.region();
|
|
2903
|
+
const effectiveRegion = probeInfo?.downloadRegion.effective ?? (regionSetting === "china" ? "china" : "global");
|
|
2904
|
+
const hostUsable = probeInfo?.hostClient.available === true;
|
|
2905
|
+
const onToggle = () => {
|
|
2906
|
+
if (busy || !writable) return;
|
|
2907
|
+
const next = !enhanced;
|
|
2908
|
+
if (!next && !hostUsable) {
|
|
2909
|
+
setError(t("mcpBackendHostMissing"));
|
|
2910
|
+
return;
|
|
2911
|
+
}
|
|
2912
|
+
setBusy(true);
|
|
2913
|
+
setError(void 0);
|
|
2914
|
+
scope.setEnhanced(next).then(() => {
|
|
2915
|
+
setBusy(false);
|
|
2916
|
+
}).catch((cause) => {
|
|
2917
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
2918
|
+
setBusy(false);
|
|
2919
|
+
});
|
|
2920
|
+
};
|
|
2921
|
+
return (0, react.createElement)("div", {
|
|
2922
|
+
className: open ? `${market_module_default.pluginCard} ${market_module_default.pluginCardOpen}` : market_module_default.pluginCard,
|
|
2923
|
+
"data-busy": busy ? "true" : void 0
|
|
2924
|
+
}, (0, react.createElement)("button", {
|
|
2925
|
+
type: "button",
|
|
2926
|
+
className: market_module_default.pluginCardHeader,
|
|
2927
|
+
"aria-expanded": open,
|
|
2928
|
+
onClick: () => {
|
|
2929
|
+
setOpen((current) => !current);
|
|
2930
|
+
}
|
|
2931
|
+
}, (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, {
|
|
2932
|
+
on: enhanced,
|
|
2933
|
+
disabled: busy || !writable,
|
|
2934
|
+
title: writable ? void 0 : t("mcpCardReadonly"),
|
|
2935
|
+
onChange: onToggle
|
|
2936
|
+
})), 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", {
|
|
2937
|
+
key: region,
|
|
2938
|
+
type: "button",
|
|
2939
|
+
disabled: busy || !writable,
|
|
2940
|
+
className: effectiveRegion === region ? market_module_default.regionSegOn : market_module_default.regionSegBtn,
|
|
2941
|
+
onClick: () => {
|
|
2942
|
+
if (regionSetting === region) return;
|
|
2943
|
+
setBusy(true);
|
|
2944
|
+
setError(void 0);
|
|
2945
|
+
scope.setRegion(region).then(() => {
|
|
2946
|
+
setBusy(false);
|
|
2947
|
+
}).catch((cause) => {
|
|
2948
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
2949
|
+
setBusy(false);
|
|
2950
|
+
});
|
|
2951
|
+
}
|
|
2952
|
+
}, region === "global" ? t("regionGlobal") : t("regionChina")))))) : null);
|
|
1821
2953
|
}
|
|
1822
2954
|
//#endregion
|
|
1823
2955
|
//#region src/client/page-mode-selection.ts
|
|
@@ -1893,6 +3025,7 @@ function mountLegacyPageMode(options) {
|
|
|
1893
3025
|
if (root === void 0) return;
|
|
1894
3026
|
root.render((0, react.createElement)(MarketSection, {
|
|
1895
3027
|
t: options.t,
|
|
3028
|
+
credentials: options.credentials,
|
|
1896
3029
|
mode: "page"
|
|
1897
3030
|
}));
|
|
1898
3031
|
};
|
|
@@ -2034,8 +3167,11 @@ function createEntry(onClick) {
|
|
|
2034
3167
|
*/
|
|
2035
3168
|
const NS = "dsh-agent-plugins-market";
|
|
2036
3169
|
const name = "dsh-agent-plugins-market";
|
|
2037
|
-
const inject = [
|
|
2038
|
-
|
|
3170
|
+
const inject = [
|
|
3171
|
+
"slots",
|
|
3172
|
+
"locale",
|
|
3173
|
+
"connection"
|
|
3174
|
+
];
|
|
2039
3175
|
const REQUIRED_PRIMITIVES = [
|
|
2040
3176
|
"Button",
|
|
2041
3177
|
"Input",
|
|
@@ -2043,6 +3179,12 @@ const REQUIRED_PRIMITIVES = [
|
|
|
2043
3179
|
"Toast",
|
|
2044
3180
|
"Tooltip"
|
|
2045
3181
|
];
|
|
3182
|
+
/**
|
|
3183
|
+
* Register the MCP enhancement card into the host's shared 插件配置 tab
|
|
3184
|
+
* (`settings.plugin.item`), the same seat dshmarket uses. Called through
|
|
3185
|
+
* `ctx.inject(['settingsScope'])` at apply time; a host without the
|
|
3186
|
+
* settingsScope service simply skips the card.
|
|
3187
|
+
*/
|
|
2046
3188
|
/** Detect host primitives that predate the exports this UI relies on. */
|
|
2047
3189
|
function missingPrimitives(module, required = REQUIRED_PRIMITIVES) {
|
|
2048
3190
|
return required.filter((name) => module[name] === void 0);
|
|
@@ -2053,6 +3195,7 @@ function apply(ctx) {
|
|
|
2053
3195
|
en
|
|
2054
3196
|
}), "dsh-agent-plugins: dictionaries");
|
|
2055
3197
|
const t = ctx.locale.bind(NS);
|
|
3198
|
+
const credentials = ctx.connection.api.credentials;
|
|
2056
3199
|
const gaps = missingPrimitives(_deepseek_ai_dsh_client_ui_primitives);
|
|
2057
3200
|
if (gaps.length > 0) {
|
|
2058
3201
|
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)`);
|
|
@@ -2061,9 +3204,37 @@ function apply(ctx) {
|
|
|
2061
3204
|
let settingsSurfaceAvailable = false;
|
|
2062
3205
|
ctx.effect(() => mountLegacyPageMode({
|
|
2063
3206
|
t,
|
|
3207
|
+
credentials,
|
|
2064
3208
|
isSettingsSurfaceAvailable: () => settingsSurfaceAvailable,
|
|
2065
3209
|
subscribeLocale: ctx.locale.subscribe === void 0 ? void 0 : (listener) => ctx.locale.subscribe(listener)
|
|
2066
3210
|
}), "dsh-agent-plugins-market: legacy page mode");
|
|
3211
|
+
ctx.inject?.(["settingsScope"], (scoped) => {
|
|
3212
|
+
const service = scoped.settingsScope;
|
|
3213
|
+
const slots = scoped.slots;
|
|
3214
|
+
if (service === void 0 || slots === void 0) return;
|
|
3215
|
+
const tCard = ctx.locale.bind(NS);
|
|
3216
|
+
const scope = service.bind({ namespace: NS });
|
|
3217
|
+
slots.inject("settings.plugin.item", () => slots.register({
|
|
3218
|
+
name: "settings.plugin.item",
|
|
3219
|
+
key: NS,
|
|
3220
|
+
locale: NS,
|
|
3221
|
+
inject: () => ({ t: tCard })
|
|
3222
|
+
}, () => (0, react.createElement)(McpPluginCard, {
|
|
3223
|
+
t: (key) => tCard(key),
|
|
3224
|
+
scope: {
|
|
3225
|
+
enhanced: () => scope.getSnapshot().value?.mcpEnhanced !== false,
|
|
3226
|
+
writable: () => scope.getSnapshot().writable,
|
|
3227
|
+
subscribe: (listener) => scope.subscribe(listener),
|
|
3228
|
+
setEnhanced: (next) => scope.set("mcpEnhanced", next),
|
|
3229
|
+
region: () => {
|
|
3230
|
+
const value = scope.getSnapshot().value?.downloadRegion;
|
|
3231
|
+
return value === "global" || value === "china" ? value : "auto";
|
|
3232
|
+
},
|
|
3233
|
+
setRegion: (next) => scope.set("downloadRegion", next)
|
|
3234
|
+
},
|
|
3235
|
+
probe: () => fetchMcpBackend()
|
|
3236
|
+
})));
|
|
3237
|
+
});
|
|
2067
3238
|
ctx.slots.inject("settings.section", () => {
|
|
2068
3239
|
settingsSurfaceAvailable = true;
|
|
2069
3240
|
notifyPageModeSurfaceChange();
|
|
@@ -2076,6 +3247,7 @@ function apply(ctx) {
|
|
|
2076
3247
|
inject: () => ({ t })
|
|
2077
3248
|
}, () => (0, react.createElement)(MarketSection, {
|
|
2078
3249
|
t,
|
|
3250
|
+
credentials,
|
|
2079
3251
|
mode: "settings"
|
|
2080
3252
|
}));
|
|
2081
3253
|
const mcpDispose = ctx.slots.register({
|
|
@@ -2085,11 +3257,23 @@ function apply(ctx) {
|
|
|
2085
3257
|
label: () => t("mcpStatusNav"),
|
|
2086
3258
|
locale: NS,
|
|
2087
3259
|
inject: () => ({ t })
|
|
2088
|
-
}, () => (0, react.createElement)(McpStatusPanel, {
|
|
3260
|
+
}, () => (0, react.createElement)(McpStatusPanel, {
|
|
3261
|
+
t,
|
|
3262
|
+
credentials
|
|
3263
|
+
}));
|
|
3264
|
+
const lspDispose = ctx.slots.register({
|
|
3265
|
+
name: "settings.section",
|
|
3266
|
+
id: "lsp-status",
|
|
3267
|
+
order: 47,
|
|
3268
|
+
label: () => t("lspStatusNav"),
|
|
3269
|
+
locale: NS,
|
|
3270
|
+
inject: () => ({ t })
|
|
3271
|
+
}, () => (0, react.createElement)(LspStatusPanel, { t }));
|
|
2089
3272
|
return () => {
|
|
2090
3273
|
settingsSurfaceAvailable = false;
|
|
2091
3274
|
notifyPageModeSurfaceChange();
|
|
2092
3275
|
if (typeof mcpDispose === "function") mcpDispose();
|
|
3276
|
+
if (typeof lspDispose === "function") lspDispose();
|
|
2093
3277
|
if (typeof marketDispose === "function") marketDispose();
|
|
2094
3278
|
};
|
|
2095
3279
|
});
|