dsh-agent-plugins-market 0.5.3 → 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.
Files changed (86) hide show
  1. package/README.md +29 -3
  2. package/README.zh.md +29 -3
  3. package/client/client.js +1378 -202
  4. package/client/client.js.map +1 -1
  5. package/lib/application/catalog.js +537 -71
  6. package/lib/application/details.js +39 -12
  7. package/lib/catalog/archive.js +341 -0
  8. package/lib/catalog/git.js +85 -12
  9. package/lib/catalog/legacy-root-migration.js +51 -0
  10. package/lib/catalog/lsp-spec.js +87 -0
  11. package/lib/catalog/manifests.js +84 -32
  12. package/lib/catalog/paths.js +65 -7
  13. package/lib/catalog/scan-pipeline.js +50 -0
  14. package/lib/catalog/scan-resolvers.js +402 -0
  15. package/lib/catalog/source-catalog.js +22 -8
  16. package/lib/catalog/suite-scanner.js +5 -176
  17. package/lib/catalog/surfaces.js +80 -30
  18. package/lib/contracts/lsp-status.js +2 -0
  19. package/lib/contracts/market.js +8 -1
  20. package/lib/index.js +118 -13
  21. package/lib/model/state.js +14 -1
  22. package/lib/model/types.js +21 -2
  23. package/lib/routes.js +88 -6
  24. package/lib/runtime/commands-mounts.js +6 -2
  25. package/lib/runtime/hooks-mounts.js +9 -6
  26. package/lib/runtime/lsp-direct-config.js +44 -0
  27. package/lib/runtime/lsp-mounts.js +236 -0
  28. package/lib/runtime/lsp-status.js +96 -0
  29. package/lib/runtime/mcp-backend.js +60 -0
  30. package/lib/runtime/mcp-client/bridge.js +126 -0
  31. package/lib/runtime/mcp-client/config.js +42 -0
  32. package/lib/runtime/mcp-client/connection.js +380 -0
  33. package/lib/runtime/mcp-client/host-seams.js +88 -0
  34. package/lib/runtime/mcp-client/json-schema-subset.js +181 -0
  35. package/lib/runtime/mcp-client/oauth.js +379 -0
  36. package/lib/runtime/mcp-client/tools.js +432 -0
  37. package/lib/runtime/mcp-client/transport.js +103 -0
  38. package/lib/runtime/mcp-config.js +196 -54
  39. package/lib/runtime/mcp-credentials.js +20 -0
  40. package/lib/runtime/mcp-mounts.js +237 -27
  41. package/lib/runtime/mcp-overrides.js +64 -6
  42. package/lib/runtime/mcp-redaction.js +92 -0
  43. package/lib/runtime/mcp-status.js +76 -32
  44. package/lib/runtime/reconciler.js +35 -1
  45. package/lib/runtime/regions.js +56 -0
  46. package/lib/types/application/catalog.d.ts +191 -14
  47. package/lib/types/application/details.d.ts +1 -6
  48. package/lib/types/application/queries.d.ts +28 -1
  49. package/lib/types/catalog/archive.d.ts +48 -0
  50. package/lib/types/catalog/git.d.ts +27 -3
  51. package/lib/types/catalog/legacy-root-migration.d.ts +14 -0
  52. package/lib/types/catalog/lsp-spec.d.ts +14 -0
  53. package/lib/types/catalog/manifests.d.ts +16 -1
  54. package/lib/types/catalog/paths.d.ts +23 -2
  55. package/lib/types/catalog/scan-pipeline.d.ts +76 -0
  56. package/lib/types/catalog/scan-resolvers.d.ts +81 -0
  57. package/lib/types/catalog/source-catalog.d.ts +5 -0
  58. package/lib/types/catalog/suite-scanner.d.ts +14 -7
  59. package/lib/types/catalog/surfaces.d.ts +3 -3
  60. package/lib/types/contracts/lsp-status.d.ts +53 -0
  61. package/lib/types/contracts/market.d.ts +55 -1
  62. package/lib/types/contracts/mcp-status.d.ts +14 -2
  63. package/lib/types/index.d.ts +24 -8
  64. package/lib/types/model/types.d.ts +52 -3
  65. package/lib/types/runtime/lsp-direct-config.d.ts +12 -0
  66. package/lib/types/runtime/lsp-mounts.d.ts +89 -0
  67. package/lib/types/runtime/lsp-status.d.ts +30 -0
  68. package/lib/types/runtime/mcp-backend.d.ts +49 -0
  69. package/lib/types/runtime/mcp-client/bridge.d.ts +37 -0
  70. package/lib/types/runtime/mcp-client/config.d.ts +123 -0
  71. package/lib/types/runtime/mcp-client/connection.d.ts +82 -0
  72. package/lib/types/runtime/mcp-client/host-seams.d.ts +89 -0
  73. package/lib/types/runtime/mcp-client/json-schema-subset.d.ts +58 -0
  74. package/lib/types/runtime/mcp-client/oauth.d.ts +121 -0
  75. package/lib/types/runtime/mcp-client/tools.d.ts +136 -0
  76. package/lib/types/runtime/mcp-client/transport.d.ts +36 -0
  77. package/lib/types/runtime/mcp-config.d.ts +29 -12
  78. package/lib/types/runtime/mcp-credentials.d.ts +9 -0
  79. package/lib/types/runtime/mcp-mounts.d.ts +56 -6
  80. package/lib/types/runtime/mcp-overrides.d.ts +23 -4
  81. package/lib/types/runtime/mcp-redaction.d.ts +7 -0
  82. package/lib/types/runtime/mcp-status.d.ts +4 -2
  83. package/lib/types/runtime/reconciler.d.ts +22 -4
  84. package/lib/types/runtime/regions.d.ts +37 -0
  85. package/package.json +15 -11
  86. package/schemas/1.0.0/mcp.schema.json +22 -0
package/client/client.js CHANGED
@@ -2,7 +2,7 @@ window.__ModuleLoader__.load({ id: "dsh-agent-plugins-market", factory: (require
2
2
 
3
3
  var module = { exports: {} };
4
4
  var exports = module.exports;
5
- (function(){if(typeof document!=="undefined"){var s=document.createElement("style");s.setAttribute("data-dsh-client","dsh-agent-plugins-market");s.textContent="._72qoAq_market {\n min-width: 0;\n height: 100%;\n min-height: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n gap: 24px;\n display: flex;\n}\n\n._72qoAq_pageMode {\n width: 100%;\n min-width: 0;\n}\n\n._72qoAq_marketControls {\n flex-direction: column;\n gap: 8px;\n min-height: 0;\n display: flex;\n}\n\n._72qoAq_mcpSurface {\n flex: 1;\n min-height: 0;\n display: flex;\n}\n\n._72qoAq_surfaceSwitch {\n border: 1px solid var(--dsw-alias-border-l2, #d4dce8);\n background: var(--dsw-alias-bg-layer-1, #fff);\n height: 26px;\n color: var(--dsw-alias-brand-primary, #4966f5);\n cursor: pointer;\n border-radius: 7px;\n flex: none;\n align-self: center;\n padding: 0 10px;\n font-size: 11px;\n}\n\n._72qoAq_surfaceSwitch:hover {\n background: var(--dsw-alias-bg-selected, #edf1ff);\n}\n\nhtml[data-dsh-agent-plugins-market-page] [data-pane=\"conversation\"], html[data-dsh-agent-plugins-market-page] [class*=\"centerCol\"] {\n position: relative;\n}\n\n._72qoAq_pageView {\n z-index: 60;\n background: var(--dsw-alias-bg-base, #f7f8fa);\n min-width: 0;\n min-height: 0;\n padding: 20px 24px;\n display: none;\n position: absolute;\n inset: 0;\n overflow: hidden;\n}\n\nhtml[data-dsh-agent-plugins-market-page] ._72qoAq_pageView {\n display: flex;\n}\n\nhtml[data-dsh-agent-plugins-market-page] [data-pane=\"conversation\"] > :not([data-dsh-agent-plugins-market-page-view]), html[data-dsh-agent-plugins-market-page] [class*=\"centerCol\"] > :not([data-dsh-agent-plugins-market-page-view]) {\n display: none !important;\n}\n\n._72qoAq_pageEntry {\n width: 100%;\n min-height: 32px;\n color: var(--dsw-alias-label-primary, #1f2328);\n cursor: pointer;\n font: inherit;\n text-align: left;\n background: none;\n border: none;\n border-radius: 8px;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n font-size: 13px;\n line-height: 20px;\n display: flex;\n}\n\n._72qoAq_pageEntry:hover {\n background: var(--dsw-alias-bg-hover, #0000000d);\n}\n\n._72qoAq_pageEntry:active {\n background: var(--dsw-alias-bg-active, #00000014);\n}\n\n._72qoAq_pageEntry svg {\n color: var(--dsw-alias-label-secondary, #6b7280);\n flex-shrink: 0;\n}\n\n._72qoAq_pageEntry span {\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n overflow: hidden;\n}\n\n[data-dsh-frame][data-sidebar-collapsed] ._72qoAq_pageEntry {\n justify-content: center;\n padding-inline: 0;\n}\n\n[data-dsh-frame][data-sidebar-collapsed] ._72qoAq_pageEntry span {\n display: none;\n}\n\n._72qoAq_pageEntry:focus-visible, ._72qoAq_srcTabMain:focus-visible, ._72qoAq_srcTabEdit:focus-visible, ._72qoAq_srcTabDel:focus-visible, ._72qoAq_seg:focus-visible, ._72qoAq_segOn:focus-visible, ._72qoAq_detailItemRow:focus-visible, ._72qoAq_detailItemOpen:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 2px;\n}\n\n._72qoAq_header {\n flex-direction: column;\n flex-shrink: 0;\n gap: 8px;\n display: flex;\n}\n\n._72qoAq_titleRow {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n._72qoAq_title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n}\n\n._72qoAq_sub {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n align-items: center;\n gap: 8px;\n min-width: 0;\n margin: 0;\n font-size: 13px;\n line-height: 20px;\n display: flex;\n overflow: hidden;\n}\n\n._72qoAq_spacer {\n flex: 1;\n}\n\n._72qoAq_searchGroup {\n align-items: center;\n gap: 2px;\n display: flex;\n}\n\n._72qoAq_body {\n flex: 1;\n align-items: flex-start;\n gap: 20px;\n min-height: 0;\n display: flex;\n}\n\n._72qoAq_sourceTabsRow {\n padding: 0;\n display: block;\n}\n\n._72qoAq_sourceTabsScroll {\n grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));\n gap: 4px;\n display: grid;\n}\n\n._72qoAq_srcTabEdit {\n font: inherit;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n background: none;\n border: none;\n flex-shrink: 0;\n padding: 2px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_srcTabEdit:hover {\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n._72qoAq_srcTabOn ._72qoAq_srcTabEdit, ._72qoAq_srcTabOn ._72qoAq_srcTabEdit:hover {\n color: var(--dsw-alias-label-primary-foreground, #fff);\n}\n\n._72qoAq_srcTab, ._72qoAq_srcTabOn {\n border: 1px solid var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-bg-layer-1, #fff);\n border-radius: 999px;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 24px;\n display: inline-flex;\n overflow: hidden;\n}\n\n._72qoAq_srcTabMain {\n font: inherit;\n color: var(--dsw-alias-label-primary, #1f2328);\n cursor: pointer;\n white-space: nowrap;\n text-overflow: ellipsis;\n background: none;\n border: none;\n flex: 1;\n min-width: 0;\n padding: 2px 2px 2px 10px;\n font-size: 12px;\n line-height: 18px;\n overflow: hidden;\n}\n\n._72qoAq_srcTabMain:hover {\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n._72qoAq_srcTabOn {\n background: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);\n border-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);\n}\n\n._72qoAq_srcTabOn ._72qoAq_srcTabMain {\n color: var(--dsw-alias-label-primary-foreground, #fff);\n font-weight: 600;\n}\n\n._72qoAq_srcTabDel {\n font: inherit;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n background: none;\n border: none;\n flex-shrink: 0;\n padding: 2px 8px 2px 2px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_srcTabDel:hover {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n._72qoAq_srcTabOn ._72qoAq_srcTabDel, ._72qoAq_srcTabOn ._72qoAq_srcTabDel:hover {\n color: var(--dsw-alias-label-primary-foreground, #fff);\n}\n\n._72qoAq_grid {\n scrollbar-gutter: stable;\n flex: 1;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n align-content: start;\n gap: 12px;\n min-width: 0;\n min-height: 0;\n padding-right: 4px;\n display: grid;\n overflow-y: auto;\n}\n\n._72qoAq_list {\n scrollbar-gutter: stable;\n flex-direction: column;\n flex: 1;\n gap: 8px;\n min-width: 0;\n min-height: 0;\n padding-right: 4px;\n display: flex;\n overflow-y: auto;\n}\n\n._72qoAq_list ._72qoAq_card {\n flex-flow: wrap;\n align-items: center;\n gap: 8px 14px;\n}\n\n._72qoAq_list ._72qoAq_cardTop {\n flex: none;\n}\n\n._72qoAq_list ._72qoAq_cardDesc {\n -webkit-line-clamp: 1;\n flex: 1;\n min-width: 200px;\n min-height: 0;\n}\n\n._72qoAq_list ._72qoAq_cardActions {\n flex: none;\n}\n\n._72qoAq_list ._72qoAq_meta {\n flex-basis: 100%;\n}\n\n._72qoAq_empty {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-align: center;\n grid-column: 1 / -1;\n padding: 48px 0;\n font-size: 13px;\n}\n\n._72qoAq_card {\n background: var(--dsw-alias-bg-layer-1, #fff);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 12px;\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n padding: 12px 14px;\n display: flex;\n}\n\n._72qoAq_cardTop {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n._72qoAq_cardTitle {\n flex: 1;\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_cardName {\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n font-weight: 600;\n line-height: 22px;\n overflow: hidden;\n}\n\n._72qoAq_version {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-variant-numeric: tabular-nums;\n flex-shrink: 0;\n font-size: 12px;\n line-height: 20px;\n}\n\n._72qoAq_cardActions {\n flex-shrink: 0;\n align-items: center;\n gap: 4px;\n display: flex;\n}\n\n._72qoAq_switchOn, ._72qoAq_switchOff {\n cursor: pointer;\n border: none;\n border-radius: 999px;\n flex-shrink: 0;\n width: 38px;\n height: 22px;\n padding: 0;\n transition: background-color .15s;\n position: relative;\n}\n\n._72qoAq_switchOn {\n background: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n._72qoAq_switchOff {\n background: var(--dsw-alias-state-neutral, #d1d5db);\n}\n\n._72qoAq_switchOn:disabled, ._72qoAq_switchOff:disabled {\n opacity: .6;\n cursor: default;\n}\n\n._72qoAq_switchThumb {\n pointer-events: none;\n background: #fff;\n border-radius: 50%;\n width: 16px;\n height: 16px;\n transition: left .15s;\n position: absolute;\n top: 3px;\n left: 3px;\n box-shadow: 0 1px 2px #0003;\n}\n\n._72qoAq_switchOn ._72qoAq_switchThumb {\n left: 19px;\n}\n\n._72qoAq_desc {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n min-height: 36px;\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n display: -webkit-box;\n overflow: hidden;\n}\n\n._72qoAq_meta {\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n._72qoAq_src {\n color: var(--dsw-alias-label-secondary, #9ca3af);\n font-size: 12px;\n text-decoration: none;\n}\n\n._72qoAq_tag {\n border: 1px solid var(--dsw-alias-border-l3, #d9dde3);\n color: var(--dsw-alias-label-secondary, #6b7280);\n border-radius: 4px;\n flex-shrink: 0;\n padding: 1px 6px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_okState {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n white-space: nowrap;\n font-size: 12px;\n font-weight: 600;\n}\n\n._72qoAq_warnLine {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n cursor: help;\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n}\n\n._72qoAq_modalFooter {\n justify-content: flex-end;\n gap: 8px;\n width: 100%;\n display: flex;\n}\n\n._72qoAq_modalFooterLeft {\n gap: 8px;\n margin-right: auto;\n display: flex;\n}\n\n._72qoAq_editorDialog {\n width: min(500px, 92vw);\n}\n\n._72qoAq_installConfirmBody {\n flex-direction: column;\n gap: 10px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_installConfirmSuite {\n color: var(--dsw-alias-label-primary, #111827);\n font-weight: 600;\n}\n\n._72qoAq_installConfirmMeta {\n color: var(--dsw-alias-label-secondary, #4b5563);\n font-size: 12px;\n}\n\n._72qoAq_installConfirmCommit {\n color: var(--dsw-alias-label-secondary, #4b5563);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12px;\n}\n\n._72qoAq_installConfirmTags {\n flex-wrap: wrap;\n gap: 6px;\n display: flex;\n}\n\n._72qoAq_installConfirmWarn {\n color: var(--dsw-alias-danger, #b45309);\n border: 1px solid var(--dsw-alias-danger, #b45309);\n border-radius: 8px;\n padding: 8px 10px;\n font-size: 12px;\n}\n\n._72qoAq_editorForm {\n flex-direction: column;\n gap: 14px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_modeRow {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n background: var(--dsw-alias-bg-layer-2, #f3f4f6);\n border-radius: 10px;\n align-self: flex-start;\n gap: 6px;\n padding: 3px;\n display: flex;\n}\n\n._72qoAq_seg, ._72qoAq_segOn {\n font: inherit;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 8px;\n padding: 5px 14px;\n font-size: 13px;\n line-height: 20px;\n}\n\n._72qoAq_segOn {\n background: var(--dsw-alias-bg-layer-1, #fff);\n color: var(--dsw-alias-label-primary, #1f2328);\n font-weight: 600;\n box-shadow: 0 1px 2px #00000014;\n}\n\n._72qoAq_fieldGroup {\n flex-direction: column;\n gap: 5px;\n display: flex;\n}\n\n._72qoAq_fieldLabel {\n color: var(--dsw-alias-label-secondary, #6b7280);\n font-size: 12px;\n font-weight: 600;\n}\n\n._72qoAq_fieldHint {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 12px;\n line-height: 16px;\n}\n\n._72qoAq_staticId {\n border: 1px dashed var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-bg-layer-2, #f3f4f6);\n border-radius: 8px;\n align-items: center;\n gap: 8px;\n padding: 7px 10px;\n display: flex;\n}\n\n._72qoAq_staticIdValue {\n color: var(--dsw-alias-label-primary, #1f2328);\n font-size: 13px;\n font-weight: 600;\n}\n\n._72qoAq_detailDialog {\n width: min(800px, 94vw);\n}\n\n._72qoAq_detailBody {\n flex-direction: column;\n gap: 14px;\n max-height: 78vh;\n display: flex;\n overflow-y: auto;\n}\n\n._72qoAq_detailSections {\n flex-direction: column;\n gap: 14px;\n display: flex;\n}\n\n._72qoAq_detailSection {\n flex-direction: column;\n gap: 6px;\n display: flex;\n}\n\n._72qoAq_detailHead {\n color: var(--dsw-alias-label-secondary, #6b7280);\n border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n margin: 0;\n padding-bottom: 4px;\n font-size: 13px;\n font-weight: 600;\n}\n\n._72qoAq_detailGrid {\n grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n gap: 6px 14px;\n display: grid;\n}\n\n._72qoAq_detailCell {\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_detailKey {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 12px;\n}\n\n._72qoAq_detailValue {\n color: var(--dsw-alias-label-primary, #1f2328);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n overflow: hidden;\n}\n\n._72qoAq_detailDesc {\n color: var(--dsw-alias-label-secondary, #6b7280);\n margin: 4px 0 0;\n font-size: 13px;\n line-height: 20px;\n}\n\n._72qoAq_mono {\n word-break: break-all;\n white-space: pre-wrap;\n color: var(--dsw-alias-label-primary, #1f2328);\n margin: 0;\n font-family: ui-monospace, Menlo, Consolas, monospace;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_detailItem {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 8px;\n flex-direction: column;\n display: flex;\n overflow: hidden;\n}\n\n._72qoAq_detailItemRow, ._72qoAq_detailItemOpen {\n width: 100%;\n font: inherit;\n text-align: left;\n cursor: pointer;\n color: var(--dsw-alias-label-primary, #1f2328);\n background: none;\n border: none;\n align-items: center;\n gap: 8px;\n padding: 7px 10px;\n display: flex;\n}\n\n._72qoAq_detailItemRow:hover {\n background: var(--dsw-alias-bg-hover, #0000000d);\n}\n\n._72qoAq_detailItemOpen {\n background: var(--dsw-alias-bg-selected, #4f6ef714);\n}\n\n._72qoAq_detailItemName {\n flex-shrink: 0;\n font-size: 13px;\n font-weight: 600;\n}\n\n._72qoAq_detailItemDesc {\n min-width: 0;\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n font-size: 12px;\n overflow: hidden;\n}\n\n._72qoAq_detailChevron {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n flex-shrink: 0;\n}\n\n._72qoAq_skillContent {\n border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n max-height: 320px;\n color: var(--dsw-alias-label-primary, #1f2328);\n padding: 10px 12px;\n font-size: 13px;\n line-height: 20px;\n overflow-y: auto;\n}\n\n._72qoAq_progress, ._72qoAq_progressError {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n background: var(--dsw-alias-bg-layer-2, #7f7f7f0f);\n color: var(--dsw-alias-label-primary, #1f2328);\n border-radius: 8px;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n font-size: 13px;\n line-height: 20px;\n display: flex;\n}\n\n._72qoAq_progressError {\n border-color: var(--dsw-alias-danger, #e5484d);\n color: var(--dsw-alias-danger, #e5484d);\n}\n\n._72qoAq_progressSpin {\n border: 2px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-top-color: var(--dsw-alias-brand-primary, #4f6ef7);\n border-radius: 50%;\n flex-shrink: 0;\n width: 14px;\n height: 14px;\n animation: .8s linear infinite _72qoAq_dshApmSpin;\n}\n\n@keyframes _72qoAq_dshApmSpin {\n to {\n transform: rotate(360deg);\n }\n}\n\n._72qoAq_progressFail {\n flex-shrink: 0;\n font-size: 13px;\n}\n\n._72qoAq_progressText {\n overflow-wrap: anywhere;\n min-width: 0;\n}\n\n@media (width <= 720px) {\n ._72qoAq_pageView {\n padding: 14px;\n }\n\n ._72qoAq_titleRow {\n flex-wrap: wrap;\n }\n\n ._72qoAq_title {\n flex: 1 0 auto;\n }\n\n ._72qoAq_sub {\n white-space: normal;\n flex: 1 0 100%;\n order: 3;\n }\n\n ._72qoAq_searchGroup {\n flex: 1 0 100%;\n order: 4;\n }\n\n ._72qoAq_sourceTabsScroll {\n scrollbar-width: thin;\n padding-bottom: 2px;\n display: flex;\n overflow-x: auto;\n }\n\n ._72qoAq_srcTab, ._72qoAq_srcTabOn {\n flex: none;\n width: auto;\n min-width: 128px;\n }\n\n ._72qoAq_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n ._72qoAq_list ._72qoAq_cardTop, ._72qoAq_list ._72qoAq_cardActions {\n max-width: 100%;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._72qoAq_progressSpin, ._72qoAq_switchOn, ._72qoAq_switchOff, ._72qoAq_switchThumb {\n transition: none;\n animation: none;\n }\n}\n\n._72qoAq_surfaceToggles {\n flex-wrap: wrap;\n align-items: center;\n gap: 4px 14px;\n display: flex;\n}\n\n._72qoAq_surfaceToggle {\n color: var(--dsw-alias-text-2, #5a6070);\n cursor: pointer;\n user-select: none;\n align-items: center;\n gap: 5px;\n font-size: 12px;\n display: inline-flex;\n}\n\n._72qoAq_surfaceToggle input[type=\"checkbox\"] {\n accent-color: var(--dsw-alias-accent, #4b6bfb);\n margin: 0;\n}\n\n._72qoAq_mcpOverrideForm {\n border: 1px solid var(--dsw-alias-border, #d8dbe2);\n border-radius: 8px;\n flex-direction: column;\n gap: 8px;\n margin: 0 0 10px;\n padding: 10px;\n display: flex;\n}\n\n._72qoAq_mcpOverrideCheck {\n cursor: pointer;\n user-select: none;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n display: inline-flex;\n}\n\n._72qoAq_mcpOverrideInput {\n box-sizing: border-box;\n width: 100%;\n padding: 6px 8px;\n font-size: 12px;\n}\n\n._72qoAq_mcpOverrideArea {\n box-sizing: border-box;\n resize: vertical;\n width: 100%;\n padding: 6px 8px;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12px;\n}\n\n._72qoAq_mcpOverrideActions {\n gap: 8px;\n display: flex;\n}\n.vavGuW_toolbar {\n grid-template-columns: minmax(0, 1fr) 12px auto auto auto 8px auto;\n align-items: flex-end;\n gap: 0;\n min-width: 0;\n display: grid;\n}\n\n.vavGuW_filterGap, .vavGuW_viewGap {\n min-width: 0;\n}\n\n.vavGuW_search {\n box-sizing: border-box;\n align-items: center;\n width: 100%;\n min-width: 0;\n height: 36px;\n display: flex;\n}\n\n.vavGuW_search input {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n height: 36px;\n min-height: 36px;\n max-height: 36px;\n padding-top: 0;\n padding-bottom: 0;\n font-size: 12px;\n line-height: 20px;\n}\n\n.vavGuW_filter, .vavGuW_filterOn {\n min-width: 54px;\n height: 36px;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n font: inherit;\n white-space: nowrap;\n background: none;\n border: none;\n border-bottom: 2px solid #0000;\n justify-content: center;\n align-items: center;\n gap: 5px;\n padding: 7px 9px;\n font-size: 13px;\n display: inline-flex;\n}\n\n.vavGuW_filterOn {\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n border-bottom-color: var(--dsw-alias-brand-primary, #4f6ef7);\n font-weight: 600;\n}\n\n.vavGuW_filter svg, .vavGuW_filterOn svg, .vavGuW_viewSwitch svg {\n stroke: currentColor;\n stroke-width: 1.5px;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n.vavGuW_filterCount {\n font-variant-numeric: tabular-nums;\n}\n\n.vavGuW_viewSwitch {\n width: 34px;\n height: 36px;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n background: none;\n border: none;\n border-bottom: 2px solid #0000;\n justify-content: center;\n align-items: center;\n display: inline-flex;\n}\n\n.vavGuW_viewSwitch:hover {\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n.vavGuW_viewSwitch:focus-visible, .vavGuW_filter:focus-visible, .vavGuW_filterOn:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 2px;\n}\n\n@media (width <= 760px) {\n .vavGuW_toolbar {\n grid-template-columns: auto auto auto 8px auto;\n justify-content: end;\n overflow-x: auto;\n }\n\n .vavGuW_search {\n grid-column: 1 / -1;\n }\n\n .vavGuW_filterGap {\n display: none;\n }\n}\n.AUWlZW_surface {\n height: 100%;\n min-height: 0;\n max-height: 100%;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n.AUWlZW_header {\n flex: none;\n align-items: center;\n gap: 8px;\n padding: 4px 0 8px;\n display: flex;\n}\n\n.AUWlZW_title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n}\n\n.AUWlZW_subtitle {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n margin: 2px 0 0;\n font-size: 13px;\n line-height: 20px;\n}\n\n.AUWlZW_headerActions {\n align-items: center;\n gap: 8px;\n margin-left: auto;\n display: flex;\n}\n\n.AUWlZW_summary {\n color: var(--dsw-alias-label-secondary, #667085);\n white-space: nowrap;\n align-items: center;\n gap: 7px;\n font-size: 12px;\n display: inline-flex;\n}\n\n.AUWlZW_errorSummary {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n font-variant-numeric: tabular-nums;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n display: inline-flex;\n}\n\n.AUWlZW_summaryDotGreen, .AUWlZW_summaryDotRed {\n border-radius: 50%;\n width: 7px;\n height: 7px;\n}\n\n.AUWlZW_summaryDotGreen {\n background: var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_summaryDotRed {\n background: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_toolbar {\n flex: none;\n margin-bottom: 24px;\n}\n\n.AUWlZW_grid {\n scrollbar-gutter: stable;\n flex: 1;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n align-content: start;\n gap: 12px;\n min-width: 0;\n min-height: 0;\n padding-right: 4px;\n display: grid;\n overflow-y: auto;\n}\n\n.AUWlZW_list {\n scrollbar-gutter: stable;\n flex-direction: column;\n flex: 1;\n gap: 8px;\n min-width: 0;\n min-height: 0;\n padding-right: 4px;\n display: flex;\n overflow-y: auto;\n}\n\n.AUWlZW_list .AUWlZW_card {\n flex-flow: wrap;\n align-items: center;\n gap: 8px 14px;\n}\n\n.AUWlZW_list .AUWlZW_cardTop {\n flex: 0 260px;\n}\n\n.AUWlZW_list .AUWlZW_endpoint {\n -webkit-line-clamp: 1;\n flex: 200px;\n min-height: 0;\n}\n\n.AUWlZW_list .AUWlZW_meta {\n flex: 0 auto;\n}\n\n.AUWlZW_list .AUWlZW_cardReason {\n flex-basis: 100%;\n}\n\n.AUWlZW_card {\n min-width: 0;\n min-height: 0;\n color: inherit;\n background: var(--dsw-alias-bg-layer-1, #fff);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n cursor: pointer;\n font: inherit;\n text-align: left;\n border-radius: 12px;\n flex-direction: column;\n gap: 8px;\n padding: 12px 14px;\n display: flex;\n}\n\n.AUWlZW_card:hover {\n border-color: var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-bg-hover, #00000009);\n}\n\n.AUWlZW_card:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 2px;\n}\n\n.AUWlZW_cardTop {\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.AUWlZW_statusDot {\n background: var(--dsw-alias-state-success-primary, #16a34a);\n border-radius: 50%;\n flex: none;\n width: 7px;\n height: 7px;\n}\n\n.AUWlZW_statusconnected {\n background: var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_statusdegraded {\n background: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_statusfailed {\n background: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_statusdisabled {\n background: var(--dsw-alias-label-tertiary, #98a2b3);\n}\n\n.AUWlZW_service {\n flex: 1;\n min-width: 0;\n}\n\n.AUWlZW_name {\n color: var(--dsw-alias-label-primary, #1f2328);\n text-overflow: ellipsis;\n white-space: nowrap;\n font: 600 13px / 22px ui-monospace, Menlo, Consolas, monospace;\n display: block;\n overflow: hidden;\n}\n\n.AUWlZW_endpoint {\n min-height: 36px;\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n -webkit-line-clamp: 2;\n overflow-wrap: anywhere;\n -webkit-box-orient: vertical;\n margin: 0;\n font: 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n display: -webkit-box;\n overflow: hidden;\n}\n\n.AUWlZW_meta {\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n.AUWlZW_sourcePlugin, .AUWlZW_sourceDirect, .AUWlZW_transport, .AUWlZW_toolCount {\n min-width: 0;\n max-width: 100%;\n color: var(--dsw-alias-label-secondary, #6b7280);\n border: 1px solid var(--dsw-alias-border-l3, #d9dde3);\n text-overflow: ellipsis;\n white-space: nowrap;\n border-radius: 4px;\n align-items: center;\n gap: 5px;\n padding: 1px 6px;\n font-size: 12px;\n line-height: 18px;\n display: inline-flex;\n}\n\n.AUWlZW_sourcePlugin svg, .AUWlZW_sourceDirect svg {\n color: currentColor;\n stroke: currentColor;\n stroke-width: 1.35px;\n stroke-linecap: round;\n stroke-linejoin: round;\n flex: none;\n width: 14px;\n height: 14px;\n}\n\n.AUWlZW_transport {\n font-family: ui-monospace, Menlo, Consolas, monospace;\n}\n\n.AUWlZW_toolCount {\n color: var(--dsw-alias-label-primary, #1f2328);\n flex: none;\n font-weight: 600;\n}\n\n.AUWlZW_cardReason {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n overflow-wrap: anywhere;\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n}\n\n.AUWlZW_state, .AUWlZW_detailState {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n white-space: nowrap;\n align-items: center;\n gap: 5px;\n font-size: 11px;\n display: inline-flex;\n}\n\n.AUWlZW_state:before, .AUWlZW_detailState:before {\n content: \"\";\n background: currentColor;\n border-radius: 50%;\n width: 6px;\n height: 6px;\n}\n\n.AUWlZW_stateconnected, .AUWlZW_detailStateconnected {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_statedegraded, .AUWlZW_detailStatedegraded {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_statefailed, .AUWlZW_detailStatefailed {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_statedisabled, .AUWlZW_detailStatedisabled {\n color: var(--dsw-alias-label-tertiary, #98a2b3);\n}\n\n.AUWlZW_chevron {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 18px;\n}\n\n.AUWlZW_empty, .AUWlZW_detailEmpty {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-align: center;\n padding: 24px;\n font-size: 12px;\n}\n\n.AUWlZW_error {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n align-items: center;\n gap: 8px;\n margin: 16px 0;\n font-size: 12px;\n display: flex;\n}\n\n.AUWlZW_boundary {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border-left: 2px solid var(--dsw-alias-border-l3, #d9dde3);\n margin: 10px 0 0;\n padding: 9px 10px;\n font-size: 11px;\n line-height: 17px;\n}\n\n.AUWlZW_detailDialog {\n width: min(720px, 94vw);\n}\n\n.AUWlZW_detailBody {\n max-height: 72vh;\n overflow-y: auto;\n}\n\n.AUWlZW_modalFooter {\n justify-content: flex-end;\n width: 100%;\n display: flex;\n}\n\n.AUWlZW_detail {\n flex-direction: column;\n gap: 16px;\n display: flex;\n}\n\n.AUWlZW_detailMeta {\n flex-wrap: wrap;\n gap: 6px;\n display: flex;\n}\n\n.AUWlZW_reason {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-bg-error, #dc26260f);\n border-left: 2px solid;\n padding: 9px 10px;\n font-size: 11px;\n line-height: 16px;\n}\n\n.AUWlZW_detailSection {\n flex-direction: column;\n gap: 7px;\n display: flex;\n}\n\n.AUWlZW_detailHead {\n color: var(--dsw-alias-label-secondary, #667085);\n border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n margin: 0;\n padding-bottom: 5px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.AUWlZW_config {\n max-height: 220px;\n color: var(--dsw-alias-label-primary, #344054);\n background: var(--dsw-alias-bg-layer-2, #f6f8fc);\n border: 1px solid var(--dsw-alias-border-l1, #e2e7ef);\n white-space: pre-wrap;\n word-break: break-word;\n border-radius: 7px;\n margin: 0;\n padding: 10px;\n font: 11px / 17px ui-monospace, Menlo, Consolas, monospace;\n overflow: auto;\n}\n\n.AUWlZW_toolList {\n flex-direction: column;\n display: flex;\n}\n\n.AUWlZW_tool {\n border-bottom: 1px solid var(--dsw-alias-border-l1, #eef1f5);\n grid-template-columns: 26px minmax(120px, auto) minmax(0, 1fr);\n align-items: center;\n gap: 8px;\n padding: 7px 0;\n display: grid;\n}\n\n.AUWlZW_tool:last-child {\n border-bottom: none;\n}\n\n.AUWlZW_toolIndex {\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n font: 10px / 16px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.AUWlZW_toolName {\n color: var(--dsw-alias-label-primary, #1f2328);\n text-overflow: ellipsis;\n white-space: nowrap;\n font: 11px / 16px ui-monospace, Menlo, Consolas, monospace;\n overflow: hidden;\n}\n\n.AUWlZW_toolDescription {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 10px;\n overflow: hidden;\n}\n\n@media (width <= 760px) {\n .AUWlZW_header, .AUWlZW_toolbar {\n padding-left: 0;\n padding-right: 0;\n }\n\n .AUWlZW_header {\n flex-direction: column;\n }\n\n .AUWlZW_headerActions {\n justify-content: space-between;\n width: 100%;\n margin-left: 0;\n }\n\n .AUWlZW_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .AUWlZW_list .AUWlZW_cardTop, .AUWlZW_list .AUWlZW_meta {\n max-width: 100%;\n }\n\n .AUWlZW_tool {\n grid-template-columns: 26px minmax(0, 1fr);\n }\n\n .AUWlZW_toolDescription {\n display: none;\n }\n}\n";document.head.appendChild(s);}})();
5
+ (function(){if(typeof document!=="undefined"){var s=document.createElement("style");s.setAttribute("data-dsh-client","dsh-agent-plugins-market");s.textContent="._72qoAq_market {\n min-width: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n gap: 24px;\n display: flex;\n}\n\n._72qoAq_pageMode {\n width: 100%;\n min-width: 0;\n height: 100%;\n min-height: 0;\n}\n\n._72qoAq_marketControls {\n flex-direction: column;\n gap: 8px;\n min-height: 0;\n display: flex;\n}\n\n._72qoAq_mcpSurface {\n flex: 1;\n min-height: 0;\n display: flex;\n}\n\n._72qoAq_surfaceSwitch {\n border: 1px solid var(--dsw-alias-border-l2, #d4dce8);\n background: var(--dsw-alias-bg-layer-1, #fff);\n height: 26px;\n color: var(--dsw-alias-brand-primary, #4966f5);\n cursor: pointer;\n border-radius: 7px;\n flex: none;\n align-self: center;\n padding: 0 10px;\n font-size: 11px;\n}\n\n._72qoAq_surfaceSwitch:hover {\n background: var(--dsw-alias-state-business-tertiary, #e4edfd);\n}\n\nhtml[data-dsh-agent-plugins-market-page] [data-pane=\"conversation\"], html[data-dsh-agent-plugins-market-page] [class*=\"centerCol\"] {\n position: relative;\n}\n\n._72qoAq_pageView {\n z-index: 60;\n background: var(--dsw-alias-bg-base, #f7f8fa);\n min-width: 0;\n min-height: 0;\n padding: 20px 24px;\n display: none;\n position: absolute;\n inset: 0;\n overflow: hidden;\n}\n\nhtml[data-dsh-agent-plugins-market-page] ._72qoAq_pageView {\n display: flex;\n}\n\nhtml[data-dsh-agent-plugins-market-page] [data-pane=\"conversation\"] > :not([data-dsh-agent-plugins-market-page-view]), html[data-dsh-agent-plugins-market-page] [class*=\"centerCol\"] > :not([data-dsh-agent-plugins-market-page-view]) {\n display: none !important;\n}\n\n._72qoAq_pageEntry {\n width: 100%;\n min-height: 32px;\n color: var(--dsw-alias-label-primary, #1f2328);\n cursor: pointer;\n font: inherit;\n text-align: left;\n background: none;\n border: none;\n border-radius: 8px;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n font-size: 13px;\n line-height: 20px;\n display: flex;\n}\n\n._72qoAq_pageEntry:hover {\n background: var(--dsw-alias-interactive-bg-hover, #2631480f);\n}\n\n._72qoAq_pageEntry:active {\n background: var(--dsw-alias-interactive-bg-active, #2631481a);\n}\n\n._72qoAq_pageEntry svg {\n color: var(--dsw-alias-label-secondary, #6b7280);\n flex-shrink: 0;\n}\n\n._72qoAq_pageEntry span {\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n overflow: hidden;\n}\n\n[data-dsh-frame][data-sidebar-collapsed] ._72qoAq_pageEntry {\n justify-content: center;\n padding-inline: 0;\n}\n\n[data-dsh-frame][data-sidebar-collapsed] ._72qoAq_pageEntry span {\n display: none;\n}\n\n._72qoAq_pageEntry:focus-visible, ._72qoAq_srcTabMain:focus-visible, ._72qoAq_srcTabEdit:focus-visible, ._72qoAq_srcTabDel:focus-visible, ._72qoAq_seg:focus-visible, ._72qoAq_segOn:focus-visible, ._72qoAq_detailItemRow:focus-visible, ._72qoAq_detailItemOpen:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 2px;\n}\n\n._72qoAq_header {\n flex-direction: column;\n flex-shrink: 0;\n gap: 8px;\n display: flex;\n}\n\n._72qoAq_titleRow {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n._72qoAq_title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n}\n\n._72qoAq_sub {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n align-items: center;\n gap: 8px;\n min-width: 0;\n margin: 0;\n font-size: 13px;\n line-height: 20px;\n display: flex;\n overflow: hidden;\n}\n\n._72qoAq_spacer {\n flex: 1;\n}\n\n._72qoAq_searchGroup {\n align-items: center;\n gap: 2px;\n display: flex;\n}\n\n._72qoAq_body {\n flex: 1;\n align-items: flex-start;\n gap: 20px;\n min-height: 0;\n display: flex;\n}\n\n._72qoAq_sourceTabsRow {\n padding: 0;\n display: block;\n}\n\n._72qoAq_sourceTabsScroll {\n grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));\n gap: 4px;\n display: grid;\n}\n\n._72qoAq_unmanagedRow {\n color: var(--dsw-alias-label-secondary, #57606a);\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n margin-top: 6px;\n font-size: 12px;\n display: flex;\n}\n\n._72qoAq_unmanagedLabel {\n flex-shrink: 0;\n}\n\n._72qoAq_unmanagedChip {\n border: 1px dashed var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-bg-layer-1, #fff);\n border-radius: 999px;\n align-items: center;\n gap: 2px;\n max-width: 220px;\n height: 22px;\n padding: 0 4px 0 8px;\n display: inline-flex;\n}\n\n._72qoAq_unmanagedChipName {\n white-space: nowrap;\n text-overflow: ellipsis;\n font-size: 12px;\n overflow: hidden;\n}\n\n._72qoAq_unmanagedAdopt {\n font: inherit;\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n cursor: pointer;\n background: none;\n border: none;\n flex-shrink: 0;\n padding: 0 4px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_unmanagedAdopt:disabled {\n cursor: default;\n opacity: .5;\n}\n\n._72qoAq_srcTabEdit {\n font: inherit;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n background: none;\n border: none;\n flex-shrink: 0;\n padding: 2px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_srcTabEdit:hover {\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n._72qoAq_srcTabOn ._72qoAq_srcTabEdit, ._72qoAq_srcTabOn ._72qoAq_srcTabEdit:hover {\n color: var(--dsw-alias-label-primary-foreground, #fff);\n}\n\n._72qoAq_srcTab, ._72qoAq_srcTabOn {\n border: 1px solid var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-bg-layer-1, #fff);\n border-radius: 999px;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 24px;\n display: inline-flex;\n overflow: hidden;\n}\n\n._72qoAq_srcTabMain {\n font: inherit;\n color: var(--dsw-alias-label-primary, #1f2328);\n cursor: pointer;\n white-space: nowrap;\n text-overflow: ellipsis;\n background: none;\n border: none;\n flex: 1;\n min-width: 0;\n padding: 2px 2px 2px 10px;\n font-size: 12px;\n line-height: 18px;\n overflow: hidden;\n}\n\n._72qoAq_srcTabMain:hover {\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n._72qoAq_srcTabOn {\n background: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);\n border-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);\n}\n\n._72qoAq_srcTabOn ._72qoAq_srcTabMain {\n color: var(--dsw-alias-label-primary-foreground, #fff);\n font-weight: 600;\n}\n\n._72qoAq_srcTabDel {\n font: inherit;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n background: none;\n border: none;\n flex-shrink: 0;\n padding: 2px 8px 2px 2px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_srcTabDel:hover {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n._72qoAq_srcTabOn ._72qoAq_srcTabDel, ._72qoAq_srcTabOn ._72qoAq_srcTabDel:hover {\n color: var(--dsw-alias-label-primary-foreground, #fff);\n}\n\n._72qoAq_grid {\n flex: 1;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n align-content: start;\n gap: 12px;\n min-width: 0;\n min-height: 0;\n display: grid;\n}\n\n._72qoAq_pageMode ._72qoAq_grid {\n scrollbar-gutter: stable;\n padding-right: 4px;\n overflow-y: auto;\n}\n\n._72qoAq_list {\n flex-direction: column;\n flex: 1;\n gap: 8px;\n min-width: 0;\n min-height: 0;\n display: flex;\n}\n\n._72qoAq_pageMode ._72qoAq_list {\n scrollbar-gutter: stable;\n padding-right: 4px;\n overflow-y: auto;\n}\n\n._72qoAq_list ._72qoAq_card {\n flex-flow: wrap;\n align-items: center;\n gap: 8px 14px;\n}\n\n._72qoAq_list ._72qoAq_cardTop {\n flex: none;\n}\n\n._72qoAq_list ._72qoAq_cardDesc {\n flex: 1;\n min-width: 200px;\n min-height: 0;\n max-height: 18px;\n overflow: hidden;\n}\n\n._72qoAq_list ._72qoAq_cardActions {\n flex: none;\n}\n\n._72qoAq_list ._72qoAq_meta, ._72qoAq_list ._72qoAq_tagRow {\n flex-basis: 100%;\n}\n\n._72qoAq_empty {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-align: center;\n grid-column: 1 / -1;\n padding: 48px 0;\n font-size: 13px;\n}\n\n._72qoAq_card {\n background: var(--dsw-alias-bg-layer-1, #fff);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n cursor: pointer;\n border-radius: 12px;\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n padding: 12px 14px;\n transition: border-color .15s, background .15s, box-shadow .15s;\n display: flex;\n}\n\n._72qoAq_card:hover {\n border-color: var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-interactive-bg-hover, #2631480f);\n box-shadow: 0 1px 4px #1018280f;\n}\n\n._72qoAq_cardOn {\n border-left: 3px solid var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n._72qoAq_cardMuted {\n border-left: 3px solid var(--dsw-alias-label-tertiary, #98a2b3);\n}\n\n._72qoAq_cardTop {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n._72qoAq_cardTitle {\n flex: 1;\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_cardName {\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n font-weight: 600;\n line-height: 22px;\n overflow: hidden;\n}\n\n._72qoAq_version {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-variant-numeric: tabular-nums;\n flex-shrink: 0;\n font-size: 12px;\n line-height: 20px;\n}\n\n._72qoAq_cardActions {\n flex-shrink: 0;\n align-items: center;\n gap: 4px;\n display: flex;\n}\n\n._72qoAq_iconBtn {\n cursor: pointer;\n width: 26px;\n height: 26px;\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n background: none;\n border: none;\n border-radius: 999px;\n justify-content: center;\n align-items: center;\n padding: 0;\n transition: background .15s, color .15s;\n display: inline-flex;\n}\n\n._72qoAq_iconBtn svg {\n fill: none;\n stroke: currentColor;\n stroke-width: 1.8px;\n stroke-linecap: round;\n stroke-linejoin: round;\n width: 15px;\n height: 15px;\n}\n\n._72qoAq_iconBtn:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, #2631480f);\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n._72qoAq_iconBtn:active:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-active, #2631481a);\n}\n\n._72qoAq_iconBtn:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 1px;\n}\n\n._72qoAq_iconBtn:disabled {\n cursor: default;\n opacity: .4;\n}\n\n._72qoAq_iconBtnDanger:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n color: var(--dsw-alias-state-error-primary, #ec1313);\n}\n\n._72qoAq_switchOn, ._72qoAq_switchOff {\n cursor: pointer;\n border: none;\n border-radius: 999px;\n flex-shrink: 0;\n width: 38px;\n height: 22px;\n padding: 0;\n transition: background-color .15s;\n position: relative;\n}\n\n._72qoAq_switchOn {\n background: var(--dsw-alias-button-primary-fill, var(--dsw-alias-brand-primary, #4f6ef7));\n}\n\n._72qoAq_switchOff {\n background: var(--dsw-alias-label-dimmed, #e1e5ee);\n}\n\n._72qoAq_switchOn:disabled, ._72qoAq_switchOff:disabled {\n opacity: .6;\n cursor: default;\n}\n\n._72qoAq_switchThumb {\n pointer-events: none;\n background: #fff;\n border-radius: 50%;\n width: 16px;\n height: 16px;\n transition: left .15s;\n position: absolute;\n top: 3px;\n left: 3px;\n box-shadow: 0 1px 2px #0003;\n}\n\n._72qoAq_switchOn ._72qoAq_switchThumb {\n left: 19px;\n}\n\n._72qoAq_desc {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n max-height: 36px;\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n overflow: hidden;\n}\n\n._72qoAq_meta, ._72qoAq_tagRow {\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n._72qoAq_src {\n color: var(--dsw-alias-label-secondary, #9ca3af);\n font-size: 12px;\n text-decoration: none;\n}\n\n._72qoAq_tag {\n border: 1px solid var(--dsw-alias-border-l3, #d9dde3);\n color: var(--dsw-alias-label-secondary, #6b7280);\n border-radius: 4px;\n flex-shrink: 0;\n padding: 1px 6px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_okState {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n white-space: nowrap;\n font-size: 12px;\n font-weight: 600;\n}\n\n._72qoAq_warnLine {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n cursor: help;\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n}\n\n._72qoAq_modalFooter {\n justify-content: flex-end;\n gap: 8px;\n width: 100%;\n display: flex;\n}\n\n._72qoAq_modalFooterLeft {\n gap: 8px;\n margin-right: auto;\n display: flex;\n}\n\n._72qoAq_editorDialog {\n width: min(500px, 92vw);\n}\n\n._72qoAq_installConfirmBody {\n flex-direction: column;\n gap: 10px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_installConfirmSuite {\n color: var(--dsw-alias-label-primary, #111827);\n font-weight: 600;\n}\n\n._72qoAq_installConfirmMeta {\n color: var(--dsw-alias-label-secondary, #4b5563);\n font-size: 12px;\n}\n\n._72qoAq_installConfirmCommit {\n color: var(--dsw-alias-label-secondary, #4b5563);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12px;\n}\n\n._72qoAq_installConfirmTags {\n flex-wrap: wrap;\n gap: 6px;\n display: flex;\n}\n\n._72qoAq_installConfirmWarn {\n color: var(--dsw-alias-state-warn-label, #dd8629);\n border: 1px solid var(--dsw-alias-state-warn-label, #dd8629);\n border-radius: 8px;\n padding: 8px 10px;\n font-size: 12px;\n}\n\n._72qoAq_editorForm {\n flex-direction: column;\n gap: 14px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_modeRow {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n background: var(--dsw-alias-bg-layer-2, #f3f4f6);\n border-radius: 10px;\n align-self: flex-start;\n gap: 6px;\n padding: 3px;\n display: flex;\n}\n\n._72qoAq_seg, ._72qoAq_segOn {\n font: inherit;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 8px;\n padding: 5px 14px;\n font-size: 13px;\n line-height: 20px;\n}\n\n._72qoAq_segOn {\n background: var(--dsw-alias-bg-layer-1, #fff);\n color: var(--dsw-alias-label-primary, #1f2328);\n font-weight: 600;\n box-shadow: 0 1px 2px #00000014;\n}\n\n._72qoAq_fieldGroup {\n flex-direction: column;\n gap: 5px;\n display: flex;\n}\n\n._72qoAq_fieldLabel {\n color: var(--dsw-alias-label-secondary, #6b7280);\n font-size: 12px;\n font-weight: 600;\n}\n\n._72qoAq_fieldHint {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 12px;\n line-height: 16px;\n}\n\n._72qoAq_staticId {\n border: 1px dashed var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-bg-layer-2, #f3f4f6);\n border-radius: 8px;\n align-items: center;\n gap: 8px;\n padding: 7px 10px;\n display: flex;\n}\n\n._72qoAq_staticIdValue {\n color: var(--dsw-alias-label-primary, #1f2328);\n font-size: 13px;\n font-weight: 600;\n}\n\n._72qoAq_detailDialog {\n width: min(800px, 94vw);\n}\n\n._72qoAq_detailBody {\n flex-direction: column;\n gap: 14px;\n max-height: 78vh;\n display: flex;\n overflow-y: auto;\n}\n\n._72qoAq_detailSections {\n flex-direction: column;\n gap: 14px;\n display: flex;\n}\n\n._72qoAq_detailSection {\n flex-direction: column;\n gap: 6px;\n display: flex;\n}\n\n._72qoAq_detailHead {\n color: var(--dsw-alias-label-secondary, #6b7280);\n border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n margin: 0;\n padding-bottom: 4px;\n font-size: 13px;\n font-weight: 600;\n}\n\n._72qoAq_detailGrid {\n grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n gap: 6px 14px;\n display: grid;\n}\n\n._72qoAq_detailCell {\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_detailKey {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 12px;\n}\n\n._72qoAq_detailValue {\n color: var(--dsw-alias-label-primary, #1f2328);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n overflow: hidden;\n}\n\n._72qoAq_detailDesc {\n color: var(--dsw-alias-label-secondary, #6b7280);\n margin: 4px 0 0;\n font-size: 13px;\n line-height: 20px;\n}\n\n._72qoAq_mono {\n word-break: break-all;\n white-space: pre-wrap;\n color: var(--dsw-alias-label-primary, #1f2328);\n margin: 0;\n font-family: ui-monospace, Menlo, Consolas, monospace;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_detailItem {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 8px;\n flex-direction: column;\n display: flex;\n overflow: hidden;\n}\n\n._72qoAq_detailItemRow, ._72qoAq_detailItemOpen {\n width: 100%;\n font: inherit;\n text-align: left;\n cursor: pointer;\n color: var(--dsw-alias-label-primary, #1f2328);\n background: none;\n border: none;\n align-items: center;\n gap: 8px;\n padding: 7px 10px;\n display: flex;\n}\n\n._72qoAq_detailItemRow:hover {\n background: var(--dsw-alias-interactive-bg-hover, #2631480f);\n}\n\n._72qoAq_detailItemOpen {\n background: var(--dsw-alias-state-business-tertiary, #e4edfd);\n}\n\n._72qoAq_detailItemName {\n flex-shrink: 0;\n font-size: 13px;\n font-weight: 600;\n}\n\n._72qoAq_detailItemDesc {\n min-width: 0;\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n font-size: 12px;\n overflow: hidden;\n}\n\n._72qoAq_detailChevron {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n flex-shrink: 0;\n}\n\n._72qoAq_skillContent {\n border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n max-height: 320px;\n color: var(--dsw-alias-label-primary, #1f2328);\n padding: 10px 12px;\n font-size: 13px;\n line-height: 20px;\n overflow-y: auto;\n}\n\n._72qoAq_progress, ._72qoAq_progressError {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n background: var(--dsw-alias-bg-layer-2, #7f7f7f0f);\n color: var(--dsw-alias-label-primary, #1f2328);\n border-radius: 8px;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n font-size: 13px;\n line-height: 20px;\n display: flex;\n}\n\n._72qoAq_progressError {\n border-color: var(--dsw-alias-state-error-primary, #ec1313);\n color: var(--dsw-alias-state-error-primary, #ec1313);\n}\n\n._72qoAq_progressSpin {\n border: 2px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-top-color: var(--dsw-alias-brand-primary, #4f6ef7);\n border-radius: 50%;\n flex-shrink: 0;\n width: 14px;\n height: 14px;\n animation: .8s linear infinite _72qoAq_dshApmSpin;\n}\n\n@keyframes _72qoAq_dshApmSpin {\n to {\n transform: rotate(360deg);\n }\n}\n\n._72qoAq_progressFail {\n flex-shrink: 0;\n font-size: 13px;\n}\n\n._72qoAq_progressText {\n overflow-wrap: anywhere;\n min-width: 0;\n}\n\n@media (width <= 720px) {\n ._72qoAq_pageView {\n padding: 14px;\n }\n\n ._72qoAq_titleRow {\n flex-wrap: wrap;\n }\n\n ._72qoAq_title {\n flex: 1 0 auto;\n }\n\n ._72qoAq_sub {\n white-space: normal;\n flex: 1 0 100%;\n order: 3;\n }\n\n ._72qoAq_searchGroup {\n flex: 1 0 100%;\n order: 4;\n }\n\n ._72qoAq_sourceTabsScroll {\n scrollbar-width: thin;\n padding-bottom: 2px;\n display: flex;\n overflow-x: auto;\n }\n\n ._72qoAq_srcTab, ._72qoAq_srcTabOn {\n flex: none;\n width: auto;\n min-width: 128px;\n }\n\n ._72qoAq_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n ._72qoAq_list ._72qoAq_cardTop, ._72qoAq_list ._72qoAq_cardActions {\n max-width: 100%;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._72qoAq_progressSpin, ._72qoAq_switchOn, ._72qoAq_switchOff, ._72qoAq_switchThumb {\n transition: none;\n animation: none;\n }\n}\n\n._72qoAq_surfaceToggles {\n flex-wrap: wrap;\n align-items: center;\n gap: 4px 14px;\n display: flex;\n}\n\n._72qoAq_surfaceToggle {\n color: var(--dsw-alias-label-secondary, #61666b);\n cursor: pointer;\n user-select: none;\n align-items: center;\n gap: 5px;\n font-size: 12px;\n display: inline-flex;\n}\n\n._72qoAq_surfaceToggle input[type=\"checkbox\"] {\n accent-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);\n margin: 0;\n}\n\n._72qoAq_mcpOverrideForm, ._72qoAq_mcpCredentialForm {\n border: 1px solid var(--dsw-alias-border-l2, #0000001a);\n border-radius: 8px;\n flex-direction: column;\n gap: 8px;\n margin: 0 0 10px;\n padding: 10px;\n display: flex;\n}\n\n._72qoAq_mcpCredentialRow {\n flex-direction: column;\n gap: 5px;\n display: flex;\n}\n\n._72qoAq_mcpCredentialControls, ._72qoAq_mcpCredentialEditor {\n flex-direction: column;\n gap: 6px;\n display: flex;\n}\n\n._72qoAq_mcpOverrideCheck {\n cursor: pointer;\n user-select: none;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n display: inline-flex;\n}\n\n._72qoAq_mcpOverrideInput {\n box-sizing: border-box;\n width: 100%;\n padding: 6px 8px;\n font-size: 12px;\n}\n\n._72qoAq_mcpOverrideArea {\n box-sizing: border-box;\n resize: vertical;\n width: 100%;\n padding: 6px 8px;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12px;\n}\n\n._72qoAq_mcpOverrideActions {\n gap: 8px;\n display: flex;\n}\n\n._72qoAq_backendBlock {\n border: 1px solid var(--dsw-alias-border-l2, #0000001a);\n opacity: 1;\n border-radius: 10px;\n flex-direction: column;\n gap: 6px;\n padding: 12px 14px;\n display: flex;\n}\n\n._72qoAq_backendBlock[data-busy=\"true\"] {\n opacity: .6;\n pointer-events: none;\n}\n\n._72qoAq_backendRow {\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n display: flex;\n}\n\n._72qoAq_backendTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n}\n\n._72qoAq_backendCurrent {\n margin: 0;\n font-size: 12px;\n font-weight: 500;\n}\n\n._72qoAq_backendHint {\n opacity: .7;\n margin: 0;\n font-size: 11px;\n}\n\n._72qoAq_backendVersion {\n opacity: .55;\n margin: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n}\n\n._72qoAq_pluginCard {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n background: var(--dsw-alias-bg-layer-3, #fff);\n border-radius: 12px;\n list-style: none;\n transition: border-color .16s, background .16s;\n}\n\n._72qoAq_pluginCard:hover {\n border-color: var(--dsw-alias-label-dimmed, #c8ccd4);\n}\n\n._72qoAq_pluginCardOpen {\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border-color: var(--dsw-alias-label-dimmed, #c8ccd4);\n}\n\n._72qoAq_pluginCard[data-busy=\"true\"] {\n opacity: .6;\n pointer-events: none;\n}\n\n._72qoAq_pluginCardHeader {\n appearance: none;\n width: 100%;\n font: inherit;\n color: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n border-radius: 12px;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n display: flex;\n}\n\n._72qoAq_pluginCardHeader:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: -2px;\n}\n\n._72qoAq_pluginCardBody {\n border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n flex-direction: column;\n gap: 8px;\n margin: 0 16px;\n padding: 4px 0 8px;\n display: flex;\n}\n\n._72qoAq_pluginCardRow {\n justify-content: space-between;\n align-items: center;\n gap: 16px;\n padding: 8px 0 4px;\n display: flex;\n}\n\n._72qoAq_pluginCardText {\n flex-direction: column;\n flex: 1;\n gap: 4px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_pluginCardTitle {\n color: var(--dsw-alias-label-primary, #1f2328);\n font-size: 15px;\n font-weight: 600;\n line-height: 1.4;\n}\n\n._72qoAq_pluginCardDesc {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 13px;\n line-height: 1.5;\n}\n\n._72qoAq_pluginCardRowLabel {\n font-size: 13px;\n font-weight: 500;\n line-height: 20px;\n}\n\n._72qoAq_pluginCardError {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n}\n\n._72qoAq_pluginChevron {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n flex: none;\n transition: transform .16s;\n display: inline-flex;\n}\n\n._72qoAq_pluginChevronOpen {\n transform: rotate(180deg);\n}\n\n._72qoAq_regionSeg {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 8px;\n flex: none;\n gap: 2px;\n padding: 2px;\n display: inline-flex;\n}\n\n._72qoAq_regionSegBtn {\n appearance: none;\n font: inherit;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 6px;\n padding: 3px 10px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_regionSegOn {\n appearance: none;\n font: inherit;\n cursor: pointer;\n background: var(--dsw-alias-bg-layer-2, #eef0f4);\n color: var(--dsw-alias-label-primary, #1f2328);\n border: none;\n border-radius: 6px;\n padding: 3px 10px;\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n}\n\n._72qoAq_regionSegBtn:disabled, ._72qoAq_regionSegOn:disabled {\n cursor: default;\n opacity: .5;\n}\n.G2mDja_form {\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 10px;\n flex-direction: column;\n gap: 10px;\n padding: 12px 14px;\n display: flex;\n}\n\n.G2mDja_head {\n color: var(--dsw-alias-label-secondary, #667085);\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n}\n\n.G2mDja_error {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n overflow-wrap: anywhere;\n border-radius: 8px;\n padding: 8px 10px;\n font-size: 12px;\n line-height: 18px;\n}\n\n.G2mDja_row {\n border-top: 1px solid var(--dsw-alias-border-l1, #eef1f5);\n flex-direction: column;\n gap: 6px;\n min-width: 0;\n padding-top: 8px;\n display: flex;\n}\n\n.G2mDja_ref {\n color: var(--dsw-alias-label-primary, #1f2328);\n font: 600 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.G2mDja_controls {\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.G2mDja_facts {\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n.G2mDja_factOk, .G2mDja_factMiss {\n border-radius: 999px;\n padding: 1px 8px;\n font-size: 11px;\n line-height: 17px;\n}\n\n.G2mDja_factOk {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n background: var(--dsw-alias-state-success-tertiary, #e6faed);\n}\n\n.G2mDja_factMiss {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n background: var(--dsw-alias-state-warn-tertiary, #fef5e7);\n}\n\n.G2mDja_note {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 11px;\n line-height: 17px;\n}\n\n.G2mDja_editor {\n flex-direction: column;\n gap: 8px;\n display: flex;\n}\n\n.G2mDja_input {\n box-sizing: border-box;\n width: 100%;\n color: var(--dsw-alias-label-primary, #1f2328);\n background: var(--dsw-alias-bg-layer-1, #fff);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 8px;\n padding: 7px 10px;\n font-size: 12px;\n}\n\n.G2mDja_input:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 1px;\n}\n\n.G2mDja_actions {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n.vavGuW_toolbar {\n align-items: flex-end;\n gap: 6px;\n min-width: 0;\n display: flex;\n}\n\n.vavGuW_filterGap, .vavGuW_viewGap {\n flex: 1 0 12px;\n min-width: 0;\n}\n\n.vavGuW_search {\n box-sizing: border-box;\n flex: 240px;\n align-items: center;\n min-width: 0;\n height: 36px;\n display: flex;\n}\n\n.vavGuW_search input {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n height: 36px;\n min-height: 36px;\n max-height: 36px;\n padding-top: 0;\n padding-bottom: 0;\n font-size: 12px;\n line-height: 20px;\n}\n\n.vavGuW_filter, .vavGuW_filterOn {\n min-width: 54px;\n height: 36px;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n font: inherit;\n white-space: nowrap;\n background: none;\n border: none;\n border-bottom: 2px solid #0000;\n flex: none;\n justify-content: center;\n align-items: center;\n gap: 5px;\n padding: 7px 9px;\n font-size: 13px;\n display: inline-flex;\n}\n\n.vavGuW_filterOn {\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n border-bottom-color: var(--dsw-alias-brand-primary, #4f6ef7);\n font-weight: 600;\n}\n\n.vavGuW_filter svg, .vavGuW_filterOn svg, .vavGuW_viewSwitch svg {\n stroke: currentColor;\n stroke-width: 1.5px;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n.vavGuW_filterCount {\n font-variant-numeric: tabular-nums;\n}\n\n.vavGuW_viewSwitch {\n width: 34px;\n height: 36px;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n background: none;\n border: none;\n border-bottom: 2px solid #0000;\n flex: none;\n justify-content: center;\n align-items: center;\n display: inline-flex;\n}\n\n.vavGuW_viewSwitch:hover {\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n.vavGuW_viewSwitch:focus-visible, .vavGuW_filter:focus-visible, .vavGuW_filterOn:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 2px;\n}\n\n@media (width <= 760px) {\n .vavGuW_toolbar {\n flex-wrap: wrap;\n justify-content: flex-end;\n }\n\n .vavGuW_search {\n flex-basis: 100%;\n }\n\n .vavGuW_filterGap {\n display: none;\n }\n}\n.AUWlZW_surface {\n min-width: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n display: flex;\n}\n\n.AUWlZW_header {\n flex: none;\n align-items: center;\n gap: 8px;\n padding: 4px 0 8px;\n display: flex;\n}\n\n.AUWlZW_title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n}\n\n.AUWlZW_subtitle {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n margin: 2px 0 0;\n font-size: 13px;\n line-height: 20px;\n}\n\n.AUWlZW_headerActions {\n align-items: center;\n gap: 8px;\n margin-left: auto;\n display: flex;\n}\n\n.AUWlZW_summary {\n color: var(--dsw-alias-label-secondary, #667085);\n white-space: nowrap;\n align-items: center;\n gap: 7px;\n font-size: 12px;\n display: inline-flex;\n}\n\n.AUWlZW_errorSummary {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n font-variant-numeric: tabular-nums;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n display: inline-flex;\n}\n\n.AUWlZW_summaryBar {\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 10px;\n flex-wrap: wrap;\n flex: none;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n display: flex;\n}\n\n.AUWlZW_summaryChip {\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n border-radius: 999px;\n align-items: center;\n gap: 6px;\n padding: 3px 10px;\n font-size: 12px;\n line-height: 18px;\n display: inline-flex;\n}\n\n.AUWlZW_chiporphaned, .AUWlZW_chipfailed {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n}\n\n.AUWlZW_chipneedsCredentials, .AUWlZW_chipdegraded {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n background: var(--dsw-alias-state-warn-tertiary, #fef5e7);\n}\n\n.AUWlZW_chipdisabled {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n background: var(--dsw-alias-bg-layer-1, #fff);\n}\n\n.AUWlZW_summaryAllGood {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n align-items: center;\n gap: 7px;\n font-size: 12px;\n display: inline-flex;\n}\n\n.AUWlZW_summaryCount {\n font-weight: 700;\n}\n\n.AUWlZW_summaryLabel {\n color: inherit;\n}\n\n.AUWlZW_observedAt {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n white-space: nowrap;\n margin-left: auto;\n font-size: 11px;\n}\n\n.AUWlZW_summaryDotGreen, .AUWlZW_summaryDotRed {\n border-radius: 50%;\n width: 7px;\n height: 7px;\n}\n\n.AUWlZW_summaryDotGreen {\n background: var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_summaryDotRed {\n background: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_summaryDotWarn {\n background: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_summaryDotInfo {\n background: var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n.AUWlZW_toolbar {\n flex: none;\n margin-bottom: 24px;\n}\n\n.AUWlZW_grid {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n align-content: start;\n gap: 12px;\n min-width: 0;\n display: grid;\n}\n\n.AUWlZW_list {\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.AUWlZW_list .AUWlZW_card {\n flex-flow: wrap;\n align-items: center;\n gap: 8px 14px;\n}\n\n.AUWlZW_list .AUWlZW_cardTop {\n flex: 0 260px;\n}\n\n.AUWlZW_list .AUWlZW_endpoint {\n flex: 200px;\n max-height: 18px;\n}\n\n.AUWlZW_card {\n min-width: 0;\n min-height: 0;\n color: inherit;\n background: var(--dsw-alias-bg-layer-1, #fff);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n cursor: pointer;\n font: inherit;\n text-align: left;\n user-select: none;\n border-radius: 12px;\n flex-direction: column;\n transition: border-color .15s, background .15s, box-shadow .15s;\n display: flex;\n}\n\n.AUWlZW_card:hover {\n border-color: var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-interactive-bg-hover, #2631480f);\n box-shadow: 0 1px 4px #1018280f;\n}\n\n.AUWlZW_cardBody {\n flex-direction: column;\n flex: 1;\n gap: 8px;\n min-width: 0;\n padding: 12px 14px 10px;\n display: flex;\n}\n\n.AUWlZW_card:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 2px;\n}\n\n.AUWlZW_cardTop {\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.AUWlZW_statusDot {\n background: var(--dsw-alias-state-success-primary, #16a34a);\n border-radius: 50%;\n flex: none;\n width: 7px;\n height: 7px;\n}\n\n.AUWlZW_statusconnected {\n background: var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_statusdegraded {\n background: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_statusfailed {\n background: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_statusneeds-credentials {\n background: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_statusorphaned {\n background: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_statusdisabled {\n background: var(--dsw-alias-label-tertiary, #98a2b3);\n}\n\n.AUWlZW_service {\n flex: 1;\n min-width: 0;\n}\n\n.AUWlZW_name {\n color: var(--dsw-alias-label-primary, #1f2328);\n text-overflow: ellipsis;\n white-space: nowrap;\n font: 600 13px / 22px ui-monospace, Menlo, Consolas, monospace;\n display: block;\n overflow: hidden;\n}\n\n.AUWlZW_endpoint {\n max-height: 36px;\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n overflow-wrap: anywhere;\n margin: 0;\n font: 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n overflow: hidden;\n}\n\n.AUWlZW_sourcePlugin, .AUWlZW_sourceDirect, .AUWlZW_transport, .AUWlZW_toolCount {\n min-width: 0;\n max-width: 100%;\n color: var(--dsw-alias-label-secondary, #6b7280);\n border: 1px solid var(--dsw-alias-border-l3, #d9dde3);\n text-overflow: ellipsis;\n white-space: nowrap;\n border-radius: 4px;\n align-items: center;\n gap: 5px;\n padding: 1px 6px;\n font-size: 12px;\n line-height: 18px;\n display: inline-flex;\n overflow: hidden;\n}\n\n.AUWlZW_sourcePlugin svg, .AUWlZW_sourceDirect svg {\n color: currentColor;\n stroke: currentColor;\n stroke-width: 1.35px;\n stroke-linecap: round;\n stroke-linejoin: round;\n flex: none;\n width: 14px;\n height: 14px;\n}\n\n.AUWlZW_transport {\n font-family: ui-monospace, Menlo, Consolas, monospace;\n}\n\n.AUWlZW_toolCount {\n color: var(--dsw-alias-label-primary, #1f2328);\n flex: none;\n font-weight: 600;\n}\n\n.AUWlZW_reasonLabel {\n opacity: .85;\n flex: none;\n font-weight: 600;\n}\n\n.AUWlZW_statePill {\n white-space: nowrap;\n border-radius: 999px;\n align-items: center;\n gap: 5px;\n padding: 1px 8px;\n font-size: 11px;\n font-weight: 600;\n line-height: 17px;\n display: inline-flex;\n}\n\n.AUWlZW_statePill:before {\n content: \"\";\n background: currentColor;\n border-radius: 50%;\n width: 6px;\n height: 6px;\n}\n\n.AUWlZW_stateconnected {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n background: var(--dsw-alias-state-success-tertiary, #e6faed);\n}\n\n.AUWlZW_statedegraded, .AUWlZW_stateneeds-credentials {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n background: var(--dsw-alias-state-warn-tertiary, #fef5e7);\n}\n\n.AUWlZW_statefailed, .AUWlZW_stateorphaned {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n}\n\n.AUWlZW_statedisabled {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n}\n\n.AUWlZW_cardConnected {\n border-left: 3px solid var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_cardDegraded, .AUWlZW_cardNeedsCredentials {\n border-left: 3px solid var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_cardFailed, .AUWlZW_cardOrphaned {\n border-left: 3px solid var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_cardDisabled {\n border-left: 3px solid var(--dsw-alias-label-tertiary, #98a2b3);\n}\n\n.AUWlZW_state, .AUWlZW_detailState {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n white-space: nowrap;\n align-items: center;\n gap: 5px;\n font-size: 11px;\n display: inline-flex;\n}\n\n.AUWlZW_state:before, .AUWlZW_detailState:before {\n content: \"\";\n background: currentColor;\n border-radius: 50%;\n width: 6px;\n height: 6px;\n}\n\n.AUWlZW_stateconnected, .AUWlZW_detailStateconnected {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_statedegraded, .AUWlZW_detailStatedegraded {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_statefailed, .AUWlZW_detailStatefailed {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_stateneeds-credentials, .AUWlZW_detailStateneeds-credentials {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_stateorphaned, .AUWlZW_detailStateorphaned {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_statedisabled, .AUWlZW_detailStatedisabled {\n color: var(--dsw-alias-label-tertiary, #98a2b3);\n}\n\n.AUWlZW_chevron {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 18px;\n}\n\n.AUWlZW_empty, .AUWlZW_detailEmpty {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-align: center;\n padding: 24px;\n font-size: 12px;\n}\n\n.AUWlZW_error {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n align-items: center;\n gap: 8px;\n margin: 16px 0;\n font-size: 12px;\n display: flex;\n}\n\n.AUWlZW_boundary {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border-left: 2px solid var(--dsw-alias-border-l3, #d9dde3);\n margin: 10px 0 0;\n padding: 9px 10px;\n font-size: 11px;\n line-height: 17px;\n}\n\n.AUWlZW_detailDialog {\n width: min(720px, 94vw);\n}\n\n.AUWlZW_detailBody {\n max-height: 72vh;\n overflow-y: auto;\n}\n\n.AUWlZW_modalFooter {\n justify-content: flex-end;\n width: 100%;\n display: flex;\n}\n\n.AUWlZW_detail {\n flex-direction: column;\n gap: 16px;\n display: flex;\n}\n\n.AUWlZW_detailMeta {\n flex-wrap: wrap;\n gap: 6px;\n display: flex;\n}\n\n.AUWlZW_detailHero {\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 10px;\n align-items: center;\n gap: 10px;\n padding: 12px 14px;\n display: flex;\n}\n\n.AUWlZW_detailHeroText {\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n display: flex;\n}\n\n.AUWlZW_detailEndpoint {\n color: var(--dsw-alias-label-secondary, #667085);\n overflow-wrap: anywhere;\n margin: 0;\n font: 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.AUWlZW_reason {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n border-left: 2px solid;\n padding: 9px 10px;\n font-size: 11px;\n line-height: 16px;\n}\n\n.AUWlZW_reasonBox {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n border-radius: 8px;\n flex-direction: column;\n gap: 4px;\n padding: 10px 12px;\n display: flex;\n}\n\n.AUWlZW_reasonText {\n overflow-wrap: anywhere;\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n}\n\n.AUWlZW_detailSection {\n flex-direction: column;\n gap: 7px;\n display: flex;\n}\n\n.AUWlZW_detailHead {\n color: var(--dsw-alias-label-secondary, #667085);\n border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n margin: 0;\n padding-bottom: 5px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.AUWlZW_config {\n max-height: 220px;\n color: var(--dsw-alias-label-primary, #344054);\n background: var(--dsw-alias-bg-layer-2, #f6f8fc);\n border: 1px solid var(--dsw-alias-border-l1, #e2e7ef);\n white-space: pre-wrap;\n word-break: break-word;\n border-radius: 7px;\n margin: 0;\n padding: 10px;\n font: 11px / 17px ui-monospace, Menlo, Consolas, monospace;\n overflow: auto;\n}\n\n.AUWlZW_toolList {\n flex-direction: column;\n display: flex;\n}\n\n.AUWlZW_tool {\n border-bottom: 1px solid var(--dsw-alias-border-l1, #eef1f5);\n grid-template-columns: minmax(140px, max-content) minmax(0, 1fr);\n align-items: center;\n gap: 12px;\n padding: 7px 0;\n display: grid;\n}\n\n.AUWlZW_tool:last-child {\n border-bottom: none;\n}\n\n.AUWlZW_toolName {\n color: var(--dsw-alias-label-primary, #1f2328);\n text-overflow: ellipsis;\n white-space: nowrap;\n font: 11px / 16px ui-monospace, Menlo, Consolas, monospace;\n overflow: hidden;\n}\n\n.AUWlZW_toolDescription {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 10px;\n overflow: hidden;\n}\n\n@media (width <= 760px) {\n .AUWlZW_header, .AUWlZW_toolbar {\n padding-left: 0;\n padding-right: 0;\n }\n\n .AUWlZW_header {\n flex-direction: column;\n }\n\n .AUWlZW_headerActions {\n justify-content: space-between;\n width: 100%;\n margin-left: 0;\n }\n\n .AUWlZW_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .AUWlZW_list .AUWlZW_cardTop {\n max-width: 100%;\n }\n\n .AUWlZW_tool {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .AUWlZW_toolDescription {\n display: none;\n }\n\n .AUWlZW_summaryBar {\n gap: 6px;\n padding: 8px 10px;\n }\n\n .AUWlZW_observedAt {\n flex-basis: 100%;\n margin-left: 0;\n }\n}\n\n.AUWlZW_statemounted {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n background: var(--dsw-alias-state-success-tertiary, #e6faed);\n}\n\n.AUWlZW_statehost-missing {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n background: var(--dsw-alias-state-warn-tertiary, #fef5e7);\n}\n\n.AUWlZW_stateconflict {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n}\n\n.AUWlZW_statusmounted {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_statushost-missing {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_statusconflict {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_cardMounted {\n border-left: 3px solid var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_cardHostMissing {\n border-left: 3px solid var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n.AUWlZW_cardConflict {\n border-left: 3px solid var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_chipmounted {\n background: var(--dsw-alias-state-success-tertiary, #e6faed);\n}\n\n.AUWlZW_chipblocked {\n background: var(--dsw-alias-state-warn-tertiary, #fef5e7);\n}\n\n.AUWlZW_summaryBar + .AUWlZW_toolbar, .AUWlZW_toolbar, .AUWlZW_header + .AUWlZW_summaryBar {\n margin-top: 12px;\n}\n\n.AUWlZW_list .AUWlZW_card {\n min-height: 0;\n padding: 2px 0;\n}\n\n.AUWlZW_list .AUWlZW_cardBody {\n flex-flow: row;\n align-items: center;\n gap: 12px;\n padding: 8px 14px;\n}\n\n.AUWlZW_list .AUWlZW_cardTop {\n flex: 0 300px;\n min-width: 0;\n}\n\n.AUWlZW_list .AUWlZW_endpoint {\n white-space: nowrap;\n text-overflow: ellipsis;\n flex: 240px;\n max-height: 22px;\n overflow: hidden;\n}\n\n.AUWlZW_extRow {\n border-bottom: 1px solid var(--dsw-alias-border-l1, #eef1f5);\n grid-template-columns: minmax(64px, auto) 20px minmax(0, 1fr);\n align-items: center;\n gap: 10px;\n padding: 7px 0;\n display: grid;\n}\n\n.AUWlZW_extRow:last-child {\n border-bottom: none;\n}\n\n.AUWlZW_extName {\n color: var(--dsw-alias-label-primary, #1f2328);\n font: 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.AUWlZW_extArrow {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n}\n\n.AUWlZW_extLanguage {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n font: 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n overflow: hidden;\n}\n\n.AUWlZW_retryStack {\n align-items: center;\n gap: 10px;\n margin-right: 4px;\n display: inline-flex;\n}\n\n.AUWlZW_retrySpinner {\n font-size: 13px;\n line-height: 1;\n display: inline-flex;\n}\n\n.AUWlZW_spinning {\n animation: .9s linear infinite AUWlZW_mcp-retry-spin;\n}\n\n@keyframes AUWlZW_mcp-retry-spin {\n from {\n transform: rotate(0);\n }\n\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .AUWlZW_spinning {\n animation: none;\n }\n}\n\n.AUWlZW_retryEchoSuccess, .AUWlZW_retryEchoFailure {\n white-space: nowrap;\n font-size: 12px;\n line-height: 18px;\n}\n\n.AUWlZW_retryEchoSuccess {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n}\n\n.AUWlZW_retryEchoFailure {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.AUWlZW_statusstarting {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n animation: 1.2s ease-in-out infinite AUWlZW_lspStartingPulse;\n}\n\n@keyframes AUWlZW_lspStartingPulse {\n 50% {\n opacity: .35;\n }\n}\n\n.AUWlZW_statusforeign {\n background: var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n.AUWlZW_cardForeign {\n border-left: 3px solid var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n.AUWlZW_reasonRaw {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n word-break: break-all;\n margin: 6px 0 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n line-height: 1.5;\n}\n";document.head.appendChild(s);}})();
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  //#region \0rolldown/runtime.js
8
8
  var __create = Object.create;
@@ -30,6 +30,120 @@ let react = require("react");
30
30
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
31
31
  _deepseek_ai_dsh_client_ui_primitives = __toESM(_deepseek_ai_dsh_client_ui_primitives, 1);
32
32
  let react_dom_client = require("react-dom/client");
33
+ //#region src/contracts/market.ts
34
+ /** Browser-safe market wire records and route constants shared by host and client. */
35
+ /** Prefix for all Agent Plugins Market HTTP routes. */
36
+ const MARKET_API_PREFIX = "/api/agent-plugins/";
37
+ /** Fixed Agent Plugins Market HTTP routes. */
38
+ const MARKET_ROUTES = {
39
+ overview: `${MARKET_API_PREFIX}overview`,
40
+ mcpStatus: `${MARKET_API_PREFIX}mcp-status`,
41
+ lspStatus: `${MARKET_API_PREFIX}lsp-status`,
42
+ lspServers: `${MARKET_API_PREFIX}lsp-servers`,
43
+ progress: `${MARKET_API_PREFIX}progress`,
44
+ config: `${MARKET_API_PREFIX}config`,
45
+ suite: `${MARKET_API_PREFIX}suite`,
46
+ skill: `${MARKET_API_PREFIX}skill`,
47
+ addSource: `${MARKET_API_PREFIX}sources/add`,
48
+ updateSource: `${MARKET_API_PREFIX}sources/update`,
49
+ adoptSource: `${MARKET_API_PREFIX}sources/adopt`,
50
+ removeSource: `${MARKET_API_PREFIX}sources/remove`,
51
+ refreshSource: `${MARKET_API_PREFIX}sources/refresh`,
52
+ install: `${MARKET_API_PREFIX}install`,
53
+ uninstall: `${MARKET_API_PREFIX}uninstall`,
54
+ setEnabled: `${MARKET_API_PREFIX}set-enabled`,
55
+ setSurface: `${MARKET_API_PREFIX}set-surface`,
56
+ mcpOverrides: `${MARKET_API_PREFIX}mcp-overrides`,
57
+ setMcpOverride: `${MARKET_API_PREFIX}set-mcp-override`,
58
+ mcpRetry: `${MARKET_API_PREFIX}mcp-retry`,
59
+ mcpReauthorize: `${MARKET_API_PREFIX}mcp-reauthorize`,
60
+ mcpBackend: `${MARKET_API_PREFIX}mcp-backend`,
61
+ setMcpBackend: `${MARKET_API_PREFIX}set-mcp-backend`
62
+ };
63
+ /** Build a suite-detail URL without duplicating route or query encoding logic. */
64
+ function suiteRoute(sourceId, suiteId) {
65
+ return `${MARKET_ROUTES.suite}?sourceId=${encodeURIComponent(sourceId)}&suiteId=${encodeURIComponent(suiteId)}`;
66
+ }
67
+ /** Build a skill-content URL without duplicating route or query encoding logic. */
68
+ function skillRoute(sourceId, suiteId, skill) {
69
+ return `${MARKET_ROUTES.skill}?sourceId=${encodeURIComponent(sourceId)}&suiteId=${encodeURIComponent(suiteId)}&skill=${encodeURIComponent(skill)}`;
70
+ }
71
+ //#endregion
72
+ //#region src/client/api.ts
73
+ /** Typed fetch helpers over the host's `/api/agent-plugins/*` routes. */
74
+ async function fetchOverview() {
75
+ const response = await fetch(MARKET_ROUTES.overview, { credentials: "same-origin" });
76
+ if (!response.ok) throw new Error(`overview failed: ${response.status}`);
77
+ return response.json();
78
+ }
79
+ async function fetchSourceProgress() {
80
+ const response = await fetch(MARKET_ROUTES.progress, { credentials: "same-origin" });
81
+ if (!response.ok) throw new Error(`progress failed: ${response.status}`);
82
+ return response.json();
83
+ }
84
+ async function fetchSuiteDetail(sourceId, suiteId) {
85
+ const response = await fetch(suiteRoute(sourceId, suiteId), { credentials: "same-origin" });
86
+ if (!response.ok) throw new Error(`suite detail failed: ${response.status}`);
87
+ return response.json();
88
+ }
89
+ async function fetchMcpStatus() {
90
+ const response = await fetch(MARKET_ROUTES.mcpStatus, { credentials: "same-origin" });
91
+ if (!response.ok) throw new Error(`MCP status failed: ${response.status}`);
92
+ return response.json();
93
+ }
94
+ async function fetchLspStatus() {
95
+ const response = await fetch(MARKET_ROUTES.lspStatus, { credentials: "same-origin" });
96
+ if (!response.ok) throw new Error(`LSP status failed: ${response.status}`);
97
+ return response.json();
98
+ }
99
+ /** The user's direct LSP server table (normalized specs). */
100
+ async function fetchLspServers() {
101
+ const response = await fetch(MARKET_ROUTES.lspServers, { credentials: "same-origin" });
102
+ if (!response.ok) throw new Error(`LSP servers failed: ${response.status}`);
103
+ return (await response.json()).lspServers ?? {};
104
+ }
105
+ /** Validate and persist the user's direct LSP server table. */
106
+ async function saveLspServers(lspServers) {
107
+ const response = await fetch(MARKET_ROUTES.lspServers, {
108
+ method: "POST",
109
+ credentials: "same-origin",
110
+ headers: { "content-type": "application/json" },
111
+ body: JSON.stringify({ lspServers })
112
+ });
113
+ const body = await response.json();
114
+ if (!response.ok || body.ok === false) throw new Error(body.error ?? `LSP servers save failed: ${response.status}`);
115
+ return body.lspServers ?? {};
116
+ }
117
+ async function fetchSkillContent(sourceId, suiteId, skill) {
118
+ const response = await fetch(skillRoute(sourceId, suiteId, skill), { credentials: "same-origin" });
119
+ if (!response.ok) throw new Error(`skill content failed: ${response.status}`);
120
+ return response.json();
121
+ }
122
+ /** Re-run the host MCP reconcile: retries failed mounts, clears residual tools. */
123
+ async function retryMcpMounts() {
124
+ await postAction("mcp-retry", {});
125
+ }
126
+ /** Drop one server's OAuth grant so its next mount re-runs browser authorization. */
127
+ async function reauthorizeMcpServer(serverName) {
128
+ await postAction("mcp-reauthorize", { serverName });
129
+ }
130
+ async function fetchMcpBackend() {
131
+ const response = await fetch(MARKET_ROUTES.mcpBackend, { credentials: "same-origin" });
132
+ if (!response.ok) throw new Error(`mcp backend failed: ${response.status}`);
133
+ return response.json();
134
+ }
135
+ async function postAction(path, body) {
136
+ const response = await fetch(`${MARKET_API_PREFIX}${path}`, {
137
+ method: "POST",
138
+ credentials: "same-origin",
139
+ headers: { "content-type": "application/json" },
140
+ body: JSON.stringify(body)
141
+ });
142
+ const payload = await response.json();
143
+ if (!response.ok || payload.ok !== true) throw new Error(payload.error ?? `request failed: ${response.status}`);
144
+ return payload;
145
+ }
146
+ //#endregion
33
147
  //#region src/client/locales.ts
34
148
  /** Chinese is the source-of-truth key set; English is checked against it below. */
35
149
  const zh = {
@@ -44,10 +158,18 @@ const zh = {
44
158
  sourceIdPh: "源 id(小写字母数字)",
45
159
  sourceUrlPh: "git 仓库地址",
46
160
  sourceUrlLocalPh: "本地仓库路径(绝对路径或 ~/…)",
161
+ sourceUrlArchivePh: "压缩包地址(.zip / .tar.gz)",
47
162
  sourceModeGit: "远程 git",
163
+ sourceModeArchive: "压缩包",
48
164
  sourceModeLocal: "本地目录",
49
165
  branchPh: "分支(可选)",
50
166
  sourceLocal: "本地",
167
+ sourceArchive: "压缩包",
168
+ sourceAdopted: "已收编",
169
+ sha256Ph: "SHA-256(可选,64 位十六进制)",
170
+ unmanagedTitle: "检测到未登记的本地仓库:",
171
+ unmanagedAdopt: "收编为源(只登记,不克隆不删除)",
172
+ unmanagedNoRemote: "非 git 目录:将以本地目录形式登记",
51
173
  editSource: "编辑当前源",
52
174
  editSourceTitle: "编辑仓库源",
53
175
  addSourceTitle: "新增仓库源",
@@ -70,7 +192,7 @@ const zh = {
70
192
  disabledLabel: "已停用",
71
193
  notInstalledLabel: "未安装",
72
194
  surfaceTogglesSection: "运行时注入开关",
73
- surfaceTogglesHint: "按能力面控制注入:关闭后立即卸载对应注入(技能 / MCP / Hooks / 命令 / 子代理)",
195
+ surfaceTogglesHint: "按能力面控制注入:关闭后立即卸载对应注入(技能 / MCP / Hooks / 命令 / 子代理 / LSP)",
74
196
  mcpOverrideEdit: "编辑覆盖",
75
197
  mcpOverrideSave: "保存覆盖",
76
198
  mcpOverrideReset: "重置为源配置",
@@ -89,11 +211,14 @@ const zh = {
89
211
  editorHint: "仓库源提供 Agent Plugins。本地目录直接读取(实时反映工作树);git 源克隆到 ~/.dsh/agent-plugins/.sources/<id>。",
90
212
  idHint: "小写字母/数字/连字符,全局唯一",
91
213
  urlGitHint: "git 仓库地址,例如 https://github.com/org/repo.git",
214
+ urlArchiveHint: "HTTPS 压缩包地址,例如 https://example.com/plugin.zip;下载后解压为源目录",
92
215
  urlLocalHint: "绝对路径或 ~/…,直接读取本地目录(不克隆、移除源时不会删除)",
93
216
  branchHint: "可选;不填则跟踪默认分支",
217
+ sha256Hint: "可选;填写后校验下载内容的 SHA-256,不匹配即拒绝安装",
94
218
  idFixed: "id 不可修改(源标识全局唯一)",
95
219
  progressStarting: "正在提交…",
96
220
  progressCloning: "正在克隆仓库(git clone),可能需要几十秒…",
221
+ progressDownloading: "正在下载并解压压缩包,可能需要几十秒…",
97
222
  progressReading: "正在读取插件清单…",
98
223
  idAutoLabel: "源 ID(自动生成)",
99
224
  idAutoHint: "自动从插件清单名或仓库名解析,无需填写",
@@ -146,6 +271,7 @@ const zh = {
146
271
  sourceNotCloned: "未克隆",
147
272
  sourceCloned: "已克隆",
148
273
  errors: "校验问题",
274
+ scanNotes: "扫描提示",
149
275
  sourceErrorSeparator: ";",
150
276
  viewMode: "视图模式",
151
277
  grid: "网格",
@@ -157,6 +283,10 @@ const zh = {
157
283
  countInstalled: "已装 {n}",
158
284
  countEnabled: "启用 {n}",
159
285
  mcpStatusNav: "MCP 服务",
286
+ lspStatusNav: "LSP 服务",
287
+ lspSearch: "搜索 LSP 服务",
288
+ lspAllMounted: "全部已挂载",
289
+ lspDirect: "直接安装",
160
290
  mcpStatusTitle: "MCP 服务",
161
291
  mcpStatusSubtitle: "连接状态、来源和工具清单",
162
292
  mcpSearch: "搜索 MCP 名称、来源或地址…",
@@ -167,9 +297,48 @@ const zh = {
167
297
  mcpSource: "来源",
168
298
  mcpTransport: "传输",
169
299
  mcpTools: "工具",
300
+ mcpTool: "工具",
301
+ mcpAllConnected: "全部已连接",
302
+ mcpReasonLabel: "原因",
303
+ mcpRetryNote: "已自动重试多次仍失败。点击「重试」立即重连,或在插件市场中检查该服务的配置。",
304
+ mcpRetrying: "正在重连…",
305
+ mcpRetrySuccess: "重连成功,服务已恢复",
306
+ mcpRetryFailure: "重连失败,请检查原因说明",
307
+ mcpReauthorize: "重新授权",
308
+ mcpConnect: "连接",
309
+ mcpReauthorizing: "等待浏览器授权…",
310
+ marketCardDesc: "Agent Plugins 市场套件的安装、启用与运行时行为配置。",
311
+ mcpCardTitle: "MCP 增强模式",
312
+ mcpCardDescOn: "已开启:支持 OAuth 授权、SSE、授权保持等功能。",
313
+ mcpCardDescOff: "已关闭:使用宿主 dsh-mcp-client。",
314
+ mcpCardReadonly: "当前环境设置文档只读,无法切换。",
315
+ mcpForeign: "已由其他客户端挂载",
316
+ mcpForeignHint: "该服务器已通过其他途径(原生配置或另一插件)挂载了同名 MCP,市场已跳过以避免重复挂载。如需由市场接管,请先停用另一来源的该服务器;若确认是残留挂载,重启宿主即可清除。",
317
+ regionLabel: "下载区域",
318
+ regionHint: "中国大陆走镜像线路,仅影响下载线路。",
319
+ regionGlobal: "全球",
320
+ regionChina: "中国大陆",
321
+ mcpBackendHostMissing: "宿主 dsh-mcp-client 在当前环境不可用,无法切换到兼容模式。",
322
+ mcpReauthHint: "删除已保存的授权令牌并重新走浏览器授权——用于权限范围选少了的场景。点击后请在弹出的页面完成登录。",
323
+ mcpConnectHint: "删除旧的授权记录并重新发起浏览器登录。点击后请在弹出的页面完成授权,服务会自动连接。",
324
+ mcpReauthSuccess: "已清除旧授权,请在弹出的浏览器页面重新登录",
325
+ mcpReauthFailure: "重新授权失败,请稍后重试",
326
+ mcpZeroTools: "该服务已连接,但未声明任何工具。",
170
327
  mcpConnected: "已连接",
171
328
  mcpDegraded: "降级",
172
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: "删除凭据",
173
342
  mcpDisabled: "未启用",
174
343
  mcpObservedEndpoint: "当前工具表观测",
175
344
  mcpServiceDetail: "服务详情",
@@ -180,7 +349,38 @@ const zh = {
180
349
  mcpDirectConfigUnavailable: "宿主未提供直接安装 MCP 的配置记录",
181
350
  mcpDirectBoundary: "直接安装 MCP 仅显示当前工具表中可观测的服务;宿主未提供配置与连接状态 API。",
182
351
  mcpBackToMarket: "返回市场",
183
- 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: "脚注"
184
384
  };
185
385
  const en = {
186
386
  nav: "Agent Plugins Market",
@@ -194,10 +394,18 @@ const en = {
194
394
  sourceIdPh: "source id (lowercase alnum)",
195
395
  sourceUrlPh: "git repository URL",
196
396
  sourceUrlLocalPh: "local repository path (absolute or ~/…)",
397
+ sourceUrlArchivePh: "archive URL (.zip / .tar.gz)",
197
398
  sourceModeGit: "remote git",
399
+ sourceModeArchive: "archive",
198
400
  sourceModeLocal: "local dir",
199
401
  branchPh: "branch (optional)",
200
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",
201
409
  editSource: "Edit source",
202
410
  editSourceTitle: "Edit source",
203
411
  addSourceTitle: "Add source",
@@ -220,7 +428,7 @@ const en = {
220
428
  disabledLabel: "disabled",
221
429
  notInstalledLabel: "not installed",
222
430
  surfaceTogglesSection: "Runtime injection toggles",
223
- 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)",
224
432
  mcpOverrideEdit: "Edit override",
225
433
  mcpOverrideSave: "Save override",
226
434
  mcpOverrideReset: "Reset to source config",
@@ -239,11 +447,14 @@ const en = {
239
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>.",
240
448
  idHint: "lowercase letters / digits / hyphens, globally unique",
241
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",
242
451
  urlLocalHint: "absolute path or ~/…, read in place (never cloned, never deleted on removal)",
243
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",
244
454
  idFixed: "id is fixed (the source identifier is globally unique)",
245
455
  progressStarting: "Submitting…",
246
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…",
247
458
  progressReading: "Reading plugin manifests…",
248
459
  idAutoLabel: "Source ID (auto)",
249
460
  idAutoHint: "Derived from the suite or repo name — no need to type it",
@@ -296,6 +507,7 @@ const en = {
296
507
  sourceNotCloned: "not cloned",
297
508
  sourceCloned: "cloned",
298
509
  errors: "validation issues",
510
+ scanNotes: "scan notes",
299
511
  sourceErrorSeparator: "; ",
300
512
  viewMode: "View mode",
301
513
  grid: "grid",
@@ -307,6 +519,10 @@ const en = {
307
519
  countInstalled: "{n} installed",
308
520
  countEnabled: "{n} enabled",
309
521
  mcpStatusNav: "MCP services",
522
+ lspStatusNav: "LSP servers",
523
+ lspSearch: "Search LSP servers",
524
+ lspAllMounted: "All mounted",
525
+ lspDirect: "Direct",
310
526
  mcpStatusTitle: "MCP services",
311
527
  mcpStatusSubtitle: "Connection state, sources, and tools",
312
528
  mcpSearch: "Search MCP names, sources, or endpoints…",
@@ -317,9 +533,48 @@ const en = {
317
533
  mcpSource: "Source",
318
534
  mcpTransport: "Transport",
319
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.",
320
563
  mcpConnected: "connected",
321
564
  mcpDegraded: "degraded",
322
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",
323
578
  mcpDisabled: "disabled",
324
579
  mcpObservedEndpoint: "observed from tool registry",
325
580
  mcpServiceDetail: "Service detail",
@@ -330,79 +585,39 @@ const en = {
330
585
  mcpDirectConfigUnavailable: "The host does not expose direct-MCP configuration",
331
586
  mcpDirectBoundary: "Direct MCP entries only show services observed in the current tool registry; the host exposes no config or connection-status API.",
332
587
  mcpBackToMarket: "Back to market",
333
- mcpRetry: "Retry"
334
- };
335
- //#endregion
336
- //#region src/contracts/market.ts
337
- /** Browser-safe market wire records and route constants shared by host and client. */
338
- /** Prefix for all Agent Plugins Market HTTP routes. */
339
- const MARKET_API_PREFIX = "/api/agent-plugins/";
340
- /** Fixed Agent Plugins Market HTTP routes. */
341
- const MARKET_ROUTES = {
342
- overview: `${MARKET_API_PREFIX}overview`,
343
- mcpStatus: `${MARKET_API_PREFIX}mcp-status`,
344
- progress: `${MARKET_API_PREFIX}progress`,
345
- config: `${MARKET_API_PREFIX}config`,
346
- suite: `${MARKET_API_PREFIX}suite`,
347
- skill: `${MARKET_API_PREFIX}skill`,
348
- addSource: `${MARKET_API_PREFIX}sources/add`,
349
- updateSource: `${MARKET_API_PREFIX}sources/update`,
350
- removeSource: `${MARKET_API_PREFIX}sources/remove`,
351
- refreshSource: `${MARKET_API_PREFIX}sources/refresh`,
352
- install: `${MARKET_API_PREFIX}install`,
353
- uninstall: `${MARKET_API_PREFIX}uninstall`,
354
- setEnabled: `${MARKET_API_PREFIX}set-enabled`,
355
- setSurface: `${MARKET_API_PREFIX}set-surface`,
356
- mcpOverrides: `${MARKET_API_PREFIX}mcp-overrides`,
357
- setMcpOverride: `${MARKET_API_PREFIX}set-mcp-override`
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"
358
620
  };
359
- /** Build a suite-detail URL without duplicating route or query encoding logic. */
360
- function suiteRoute(sourceId, suiteId) {
361
- return `${MARKET_ROUTES.suite}?sourceId=${encodeURIComponent(sourceId)}&suiteId=${encodeURIComponent(suiteId)}`;
362
- }
363
- /** Build a skill-content URL without duplicating route or query encoding logic. */
364
- function skillRoute(sourceId, suiteId, skill) {
365
- return `${MARKET_ROUTES.skill}?sourceId=${encodeURIComponent(sourceId)}&suiteId=${encodeURIComponent(suiteId)}&skill=${encodeURIComponent(skill)}`;
366
- }
367
- //#endregion
368
- //#region src/client/api.ts
369
- /** Typed fetch helpers over the host's `/api/agent-plugins/*` routes. */
370
- async function fetchOverview() {
371
- const response = await fetch(MARKET_ROUTES.overview, { credentials: "same-origin" });
372
- if (!response.ok) throw new Error(`overview failed: ${response.status}`);
373
- return response.json();
374
- }
375
- async function fetchSourceProgress() {
376
- const response = await fetch(MARKET_ROUTES.progress, { credentials: "same-origin" });
377
- if (!response.ok) throw new Error(`progress failed: ${response.status}`);
378
- return response.json();
379
- }
380
- async function fetchSuiteDetail(sourceId, suiteId) {
381
- const response = await fetch(suiteRoute(sourceId, suiteId), { credentials: "same-origin" });
382
- if (!response.ok) throw new Error(`suite detail failed: ${response.status}`);
383
- return response.json();
384
- }
385
- async function fetchMcpStatus() {
386
- const response = await fetch(MARKET_ROUTES.mcpStatus, { credentials: "same-origin" });
387
- if (!response.ok) throw new Error(`MCP status failed: ${response.status}`);
388
- return response.json();
389
- }
390
- async function fetchSkillContent(sourceId, suiteId, skill) {
391
- const response = await fetch(skillRoute(sourceId, suiteId, skill), { credentials: "same-origin" });
392
- if (!response.ok) throw new Error(`skill content failed: ${response.status}`);
393
- return response.json();
394
- }
395
- async function postAction(path, body) {
396
- const response = await fetch(`${MARKET_API_PREFIX}${path}`, {
397
- method: "POST",
398
- credentials: "same-origin",
399
- headers: { "content-type": "application/json" },
400
- body: JSON.stringify(body)
401
- });
402
- const payload = await response.json();
403
- if (!response.ok || payload.ok !== true) throw new Error(payload.error ?? `request failed: ${response.status}`);
404
- return payload;
405
- }
406
621
  //#endregion
407
622
  //#region src/client/features/market/market-resource.ts
408
623
  /** Market overview cache, invalidation, and source-progress resource helpers. */
@@ -417,7 +632,8 @@ const EMPTY_OVERVIEW = {
417
632
  roots: {
418
633
  user: "",
419
634
  data: ""
420
- }
635
+ },
636
+ unmanaged: []
421
637
  };
422
638
  let cachedOverview;
423
639
  let inflightOverview;
@@ -512,11 +728,19 @@ function searchableFor$1(overview) {
512
728
  //#endregion
513
729
  //#region src/client/market.module.css
514
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",
515
737
  "body": "_72qoAq_body",
516
738
  "card": "_72qoAq_card",
517
739
  "cardActions": "_72qoAq_cardActions",
518
740
  "cardDesc": "_72qoAq_cardDesc",
741
+ "cardMuted": "_72qoAq_cardMuted",
519
742
  "cardName": "_72qoAq_cardName",
743
+ "cardOn": "_72qoAq_cardOn",
520
744
  "cardTitle": "_72qoAq_cardTitle",
521
745
  "cardTop": "_72qoAq_cardTop",
522
746
  "desc": "_72qoAq_desc",
@@ -545,6 +769,8 @@ var market_module_default = {
545
769
  "fieldLabel": "_72qoAq_fieldLabel",
546
770
  "grid": "_72qoAq_grid",
547
771
  "header": "_72qoAq_header",
772
+ "iconBtn": "_72qoAq_iconBtn",
773
+ "iconBtnDanger": "_72qoAq_iconBtnDanger",
548
774
  "installConfirmBody": "_72qoAq_installConfirmBody",
549
775
  "installConfirmCommit": "_72qoAq_installConfirmCommit",
550
776
  "installConfirmMeta": "_72qoAq_installConfirmMeta",
@@ -554,6 +780,10 @@ var market_module_default = {
554
780
  "list": "_72qoAq_list",
555
781
  "market": "_72qoAq_market",
556
782
  "marketControls": "_72qoAq_marketControls",
783
+ "mcpCredentialControls": "_72qoAq_mcpCredentialControls",
784
+ "mcpCredentialEditor": "_72qoAq_mcpCredentialEditor",
785
+ "mcpCredentialForm": "_72qoAq_mcpCredentialForm",
786
+ "mcpCredentialRow": "_72qoAq_mcpCredentialRow",
557
787
  "mcpOverrideActions": "_72qoAq_mcpOverrideActions",
558
788
  "mcpOverrideArea": "_72qoAq_mcpOverrideArea",
559
789
  "mcpOverrideCheck": "_72qoAq_mcpOverrideCheck",
@@ -569,11 +799,26 @@ var market_module_default = {
569
799
  "pageEntry": "_72qoAq_pageEntry",
570
800
  "pageMode": "_72qoAq_pageMode",
571
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",
572
814
  "progress": "_72qoAq_progress",
573
815
  "progressError": "_72qoAq_progressError",
574
816
  "progressFail": "_72qoAq_progressFail",
575
817
  "progressSpin": "_72qoAq_progressSpin",
576
818
  "progressText": "_72qoAq_progressText",
819
+ "regionSeg": "_72qoAq_regionSeg",
820
+ "regionSegBtn": "_72qoAq_regionSegBtn",
821
+ "regionSegOn": "_72qoAq_regionSegOn",
577
822
  "searchGroup": "_72qoAq_searchGroup",
578
823
  "seg": "_72qoAq_seg",
579
824
  "segOn": "_72qoAq_segOn",
@@ -597,8 +842,14 @@ var market_module_default = {
597
842
  "switchOn": "_72qoAq_switchOn",
598
843
  "switchThumb": "_72qoAq_switchThumb",
599
844
  "tag": "_72qoAq_tag",
845
+ "tagRow": "_72qoAq_tagRow",
600
846
  "title": "_72qoAq_title",
601
847
  "titleRow": "_72qoAq_titleRow",
848
+ "unmanagedAdopt": "_72qoAq_unmanagedAdopt",
849
+ "unmanagedChip": "_72qoAq_unmanagedChip",
850
+ "unmanagedChipName": "_72qoAq_unmanagedChipName",
851
+ "unmanagedLabel": "_72qoAq_unmanagedLabel",
852
+ "unmanagedRow": "_72qoAq_unmanagedRow",
602
853
  "version": "_72qoAq_version",
603
854
  "warnLine": "_72qoAq_warnLine"
604
855
  };
@@ -607,8 +858,11 @@ var market_module_default = {
607
858
  /** A source tab with trailing edit and delete controls. */
608
859
  /** A source chip with a trailing delete control (deletion confirms at the section level). */
609
860
  function SourceTab(props) {
610
- const { t, active = false, label, onSelect, onDelete, onEdit } = props;
611
- return (0, react.createElement)("div", { className: active ? market_module_default.srcTabOn : market_module_default.srcTab }, (0, react.createElement)("button", {
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", {
612
866
  type: "button",
613
867
  className: market_module_default.srcTabMain,
614
868
  onClick: onSelect
@@ -635,11 +889,19 @@ function SourceTab(props) {
635
889
  /** Source editor modal for adding or editing a catalog source. */
636
890
  function SourceEditorModal(props) {
637
891
  const { t, editor } = props;
638
- const [local, setLocal] = (0, react.useState)(editor.mode === "edit" && editor.source.local === true);
892
+ const [kind, setKind] = (0, react.useState)(editor.mode === "edit" ? editor.source.kind === "archive" ? "archive" : editor.source.local === true ? "local" : "git" : "git");
639
893
  const [url, setUrl] = (0, react.useState)(editor.mode === "edit" ? editor.source.url : "");
640
894
  const [branch, setBranch] = (0, react.useState)(editor.mode === "edit" ? editor.source.branch ?? "" : "");
895
+ const [sha256, setSha256] = (0, react.useState)("");
641
896
  const id = editor.mode === "edit" ? editor.source.id : "";
642
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);
643
905
  return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
644
906
  open: true,
645
907
  onClose: props.onClose,
@@ -657,26 +919,27 @@ function SourceEditorModal(props) {
657
919
  variant: "primary",
658
920
  disabled: props.busy,
659
921
  onClick: () => {
660
- props.onSave(url.trim(), branch.trim(), local);
922
+ props.onSave({
923
+ url: url.trim(),
924
+ branch: branch.trim(),
925
+ kind,
926
+ sha256: sha256.trim()
927
+ });
661
928
  }
662
929
  }, t("save"))),
663
- children: (0, react.createElement)("div", { className: market_module_default.editorForm }, (0, react.createElement)("div", { className: market_module_default.modeRow }, (0, react.createElement)("button", {
664
- type: "button",
665
- className: local ? market_module_default.seg : market_module_default.segOn,
666
- onClick: () => setLocal(false)
667
- }, t("sourceModeGit")), (0, react.createElement)("button", {
668
- type: "button",
669
- className: local ? market_module_default.segOn : market_module_default.seg,
670
- onClick: () => setLocal(true)
671
- }, t("sourceModeLocal"))), editor.mode === "edit" ? (0, react.createElement)("div", { className: market_module_default.fieldGroup }, (0, react.createElement)("label", { className: market_module_default.fieldLabel }, t("sourceIdPh")), (0, react.createElement)("div", { className: market_module_default.staticId }, (0, react.createElement)("span", { className: market_module_default.staticIdValue }, id), (0, react.createElement)("span", { className: market_module_default.fieldHint }, t("idFixed")))) : null, (0, react.createElement)("div", { className: market_module_default.fieldGroup }, (0, react.createElement)("label", { className: market_module_default.fieldLabel }, local ? t("sourceUrlLocalPh") : t("sourceUrlPh")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Input, {
672
- placeholder: local ? t("sourceUrlLocalPh") : t("sourceUrlPh"),
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,
673
932
  value: url,
674
933
  onChange: (event) => setUrl(event.target.value)
675
- }), (0, react.createElement)("span", { className: market_module_default.fieldHint }, local ? t("urlLocalHint") : t("urlGitHint"))), local ? null : (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, {
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, {
676
935
  placeholder: t("branchPh"),
677
936
  value: branch,
678
937
  onChange: (event) => setBranch(event.target.value)
679
- }), (0, react.createElement)("span", { className: market_module_default.fieldHint }, t("branchHint"))), 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}`)))
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}`)))
680
943
  });
681
944
  }
682
945
  //#endregion
@@ -703,6 +966,10 @@ const SURFACE_TAGS = [
703
966
  {
704
967
  key: "agents",
705
968
  labelKey: "surfaceAgents"
969
+ },
970
+ {
971
+ key: "lsp",
972
+ labelKey: "surfaceLsp"
706
973
  }
707
974
  ];
708
975
  function InstallConfirmModal(props) {
@@ -736,7 +1003,7 @@ function InstallConfirmModal(props) {
736
1003
  }
737
1004
  //#endregion
738
1005
  //#region src/client/ui/ToggleSwitch.tsx
739
- /** Shared green/gray switch control used by suite cards. */
1006
+ /** Shared switch control (ON = primary button fill, like every host toggle). */
740
1007
  /** A green/gray switch control for suite enable state. */
741
1008
  function ToggleSwitch(props) {
742
1009
  return (0, react.createElement)("button", {
@@ -767,19 +1034,46 @@ function SuiteCard(props) {
767
1034
  ].filter(([, count]) => count > 0);
768
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");
769
1036
  const isRemote = suite.remoteUrl !== void 0;
1037
+ const hasTagRow = tags.length > 0 || suite.errors.length > 0 || (suite.mcpErrors?.length ?? 0) > 0;
770
1038
  const stop = (callback) => (event) => {
771
1039
  event.stopPropagation();
772
1040
  callback();
773
1041
  };
1042
+ const accent = suite.installed ? suite.enabled ? market_module_default.cardOn : market_module_default.cardMuted : void 0;
774
1043
  return (0, react.createElement)("article", {
775
- className: market_module_default.card,
1044
+ className: accent ? `${market_module_default.card} ${accent}` : market_module_default.card,
776
1045
  onClick: props.onOpen
777
- }, (0, react.createElement)("div", { className: market_module_default.cardTop }, (0, react.createElement)("div", { className: market_module_default.cardTitle }, (0, react.createElement)("span", { className: market_module_default.cardName }, suite.name), suite.version === void 0 ? null : (0, react.createElement)("span", { className: market_module_default.version }, `v${suite.version}`)), (0, react.createElement)("div", { className: market_module_default.cardActions }, suite.installed ? (0, react.createElement)(ToggleSwitch, {
778
- on: suite.enabled,
779
- disabled: busy,
780
- title: suite.enabled ? t("disable") : t("enable"),
781
- onChange: props.onToggle
782
- }) : isRemote ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
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, {
783
1077
  variant: "primary",
784
1078
  size: "sm",
785
1079
  disabled: busy,
@@ -790,19 +1084,7 @@ function SuiteCard(props) {
790
1084
  size: "sm",
791
1085
  disabled: busy,
792
1086
  onClick: stop(props.onInstall)
793
- }, t("install")), suite.installed ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
794
- variant: "ghost",
795
- size: "sm",
796
- title: t("refresh"),
797
- disabled: busy,
798
- onClick: stop(props.onRefresh)
799
- }, "↻") : null, suite.installed ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
800
- variant: "ghost",
801
- size: "sm",
802
- title: t("uninstall"),
803
- disabled: busy,
804
- onClick: stop(props.onUninstall)
805
- }, "🗑") : null)), (0, react.createElement)("p", { className: market_module_default.desc }, suite.description ?? ""), (0, react.createElement)("div", { className: market_module_default.meta }, (0, react.createElement)("span", { className: market_module_default.src }, `${suite.sourceId} · ${isRemote ? t("remoteRef") : suite.dimension === "user" ? t("dimensionUser") : t("dimensionProject")}`), (0, react.createElement)("span", { className: market_module_default.tag }, layoutLabel), suite.installed ? (0, react.createElement)("span", { className: suite.enabled ? market_module_default.okState : market_module_default.tag }, suite.enabled ? `✓ ${t("installedBadge")}` : t("installedBadge")) : null, ...tags.map(([label, count]) => (0, react.createElement)("span", {
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", {
806
1088
  key: label,
807
1089
  className: market_module_default.tag
808
1090
  }, `${label} ${count}`)), suite.errors.length === 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
@@ -811,7 +1093,7 @@ function SuiteCard(props) {
811
1093
  }), (suite.mcpErrors?.length ?? 0) === 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
812
1094
  label: suite.mcpErrors.slice(0, 8).join(t("sourceErrorSeparator")),
813
1095
  children: (0, react.createElement)("span", { className: market_module_default.warnLine }, `⚠ ${t("mcpSection")} ${suite.mcpErrors.length}`)
814
- })));
1096
+ })) : null);
815
1097
  }
816
1098
  //#endregion
817
1099
  //#region src/client/ui/StatusIcon.tsx
@@ -856,6 +1138,148 @@ var ErrorBoundary = class extends react.Component {
856
1138
  }
857
1139
  };
858
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
859
1283
  //#region src/client/features/suite-detail/suite-detail-resource.ts
860
1284
  /** Create a request guard for one detail modal instance. */
861
1285
  function createLatestRequestGuard() {
@@ -884,9 +1308,17 @@ const SURFACE_TOGGLE_ROWS = [
884
1308
  ["mcp", "surfaceMcp"],
885
1309
  ["hooks", "surfaceHooks"],
886
1310
  ["commands", "surfaceCommands"],
887
- ["agents", "surfaceAgents"]
1311
+ ["agents", "surfaceAgents"],
1312
+ ["lsp", "surfaceLsp"]
888
1313
  ];
889
- 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]);
890
1322
  const [detail, setDetail] = (0, react.useState)(void 0);
891
1323
  const [error, setError] = (0, react.useState)(void 0);
892
1324
  const [openSkill, setOpenSkill] = (0, react.useState)(void 0);
@@ -1006,7 +1438,10 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
1006
1438
  onClick: () => {
1007
1439
  toggleSkill(skill.name);
1008
1440
  }
1009
- }, (0, react.createElement)("span", { className: market_module_default.detailItemName }, skill.name), (0, react.createElement)("span", { className: market_module_default.detailItemDesc }, skill.description), (0, react.createElement)("span", { className: market_module_default.detailChevron }, openSkill === skill.name ? "▾" : "▸")), openSkill !== skill.name ? null : (0, react.createElement)("div", { className: market_module_default.skillContent }, skillLoading ? t("loading") : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, { text: skillText ?? "" }))))), (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", {
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", {
1010
1445
  className: market_module_default.warnLine,
1011
1446
  style: { margin: "0 0 6px" }
1012
1447
  }, `⚠ ${detail.mcpErrors.join(t("sourceErrorSeparator"))}`), detail.mcpServers.length === 0 ? (0, react.createElement)("div", { className: market_module_default.sidebarEmpty }, "—") : detail.mcpServers.map((server) => {
@@ -1020,7 +1455,11 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
1020
1455
  type: "button",
1021
1456
  className: openMcp === server.key ? market_module_default.detailItemOpen : market_module_default.detailItemRow,
1022
1457
  onClick: () => toggleMcp(server.key)
1023
- }, (0, react.createElement)("span", { className: market_module_default.detailItemName }, server.key), (0, react.createElement)("span", { className: market_module_default.detailItemDesc }, `${mcpSummary(server)}${disabled ? ` · ${t("mcpOverrideDisabledBadge")}` : overridden ? ` · ${t("mcpOverriddenBadge")}` : ""}`), (0, react.createElement)("span", { className: market_module_default.detailChevron }, openMcp === server.key ? "▾" : "▸")), openMcp === server.key ? (0, react.createElement)("div", { className: market_module_default.skillContent }, detail.installed && detail.surfaceToggles?.mcp !== false ? (0, react.createElement)(McpOverrideEditor, {
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, {
1024
1463
  t,
1025
1464
  serverKey: server.key,
1026
1465
  transport: server.type,
@@ -1036,7 +1475,10 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
1036
1475
  description: command.description,
1037
1476
  open: openPreview === `c:${command.name}`,
1038
1477
  onToggle: () => setOpenPreview(openPreview === `c:${command.name}` ? void 0 : `c:${command.name}`),
1039
- children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, { text: command.content })
1478
+ children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
1479
+ text: command.content,
1480
+ labels: markdownLabels
1481
+ })
1040
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, {
1041
1483
  key: `a:${agent.name}`,
1042
1484
  t,
@@ -1044,7 +1486,10 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
1044
1486
  description: agent.description,
1045
1487
  open: openPreview === `a:${agent.name}`,
1046
1488
  onToggle: () => setOpenPreview(openPreview === `a:${agent.name}` ? void 0 : `a:${agent.name}`),
1047
- children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, { text: agent.content })
1489
+ children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
1490
+ text: agent.content,
1491
+ labels: markdownLabels
1492
+ })
1048
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, {
1049
1494
  key: `h:${index}`,
1050
1495
  t,
@@ -1053,14 +1498,22 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
1053
1498
  open: openPreview === `h:${index}`,
1054
1499
  onToggle: () => setOpenPreview(openPreview === `h:${index}` ? void 0 : `h:${index}`),
1055
1500
  children: (0, react.createElement)("pre", { className: market_module_default.mono }, JSON.stringify(hook, null, 2))
1056
- }))), (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, `${t("lspSection")} (${detail.lsp.length})`), detail.lsp.length === 0 ? (0, react.createElement)("div", { className: market_module_default.sidebarEmpty }, "—") : detail.lsp.map((entry) => (0, react.createElement)(PreviewRow, {
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, {
1057
1510
  key: `l:${entry.name}`,
1058
1511
  t,
1059
1512
  name: entry.name,
1060
1513
  open: openPreview === `l:${entry.name}`,
1061
1514
  onToggle: () => setOpenPreview(openPreview === `l:${entry.name}` ? void 0 : `l:${entry.name}`),
1062
1515
  children: (0, react.createElement)("pre", { className: market_module_default.mono }, entry.content)
1063
- }))), detail.errors.length === 0 ? null : (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, `${t("errors")} (${detail.errors.length})`), detail.errors.map((entry, index) => (0, react.createElement)("div", {
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", {
1064
1517
  key: index,
1065
1518
  className: market_module_default.warnLine
1066
1519
  }, entry))))
@@ -1071,6 +1524,10 @@ function mcpSummary(server) {
1071
1524
  if (server.type === "stdio") return server.command ?? server.type;
1072
1525
  return server.url ?? server.type;
1073
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
+ }
1074
1531
  /** Parse `KEY=VALUE` lines into a record; blank and comment lines are skipped. */
1075
1532
  function parseKvLines(text) {
1076
1533
  const result = {};
@@ -1083,10 +1540,11 @@ function parseKvLines(text) {
1083
1540
  }
1084
1541
  return Object.keys(result).length > 0 ? result : void 0;
1085
1542
  }
1086
- /** Format a record back into sorted `KEY=VALUE` lines for editing. */
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;
1087
1545
  function formatKvLines(map) {
1088
1546
  if (map === void 0) return "";
1089
- 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");
1090
1548
  }
1091
1549
  /**
1092
1550
  * Per-server MCP override editor: enable/disable plus connection-input
@@ -1217,8 +1675,8 @@ function SearchFilterToolbar(props) {
1217
1675
  key: filter.id,
1218
1676
  type: "button",
1219
1677
  className: filter.active ? SearchFilterToolbar_module_default.filterOn : SearchFilterToolbar_module_default.filter,
1220
- title: `${filter.label} ${filter.count}`,
1221
- "aria-label": `${filter.label} ${filter.count}`,
1678
+ title: filter.hint ?? `${filter.label} ${filter.count}`,
1679
+ "aria-label": filter.hint ?? `${filter.label} ${filter.count}`,
1222
1680
  onClick: filter.onSelect
1223
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", {
1224
1682
  type: "button",
@@ -1275,6 +1733,7 @@ function ViewIcon({ mode }) {
1275
1733
  /** Host step keys -> translation keys, resolved against the active t(). */
1276
1734
  const PROGRESS_STEP_LABELS = {
1277
1735
  cloning: "progressCloning",
1736
+ downloading: "progressDownloading",
1278
1737
  reading: "progressReading"
1279
1738
  };
1280
1739
  function progressStepLabel(t, step) {
@@ -1285,7 +1744,7 @@ function progressStepLabel(t, step) {
1285
1744
  function interpolate(text, params) {
1286
1745
  return text.replace(/\{(\w+)\}/g, (match, key) => key in params ? String(params[key]) : match);
1287
1746
  }
1288
- function MarketSection({ t, mode = "settings" }) {
1747
+ function MarketSection({ t, credentials, mode = "settings" }) {
1289
1748
  const [overview, setOverview] = (0, react.useState)(() => loadOverview().initial);
1290
1749
  const [loading, setLoading] = (0, react.useState)(() => loadOverview().revalidating);
1291
1750
  const [search, setSearch] = (0, react.useState)("");
@@ -1366,6 +1825,10 @@ function MarketSection({ t, mode = "settings" }) {
1366
1825
  category
1367
1826
  ]);
1368
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 ?? [];
1369
1832
  return (0, react.createElement)(ErrorBoundary, {
1370
1833
  fallback: (error) => (0, react.createElement)("div", { className: market_module_default.empty }, `${t("actionFail")}: ${error.message}`),
1371
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, {
@@ -1386,21 +1849,39 @@ function MarketSection({ t, mode = "settings" }) {
1386
1849
  active: category === "all",
1387
1850
  label: `${t("tabAll")} ${overview.totals.all}`,
1388
1851
  onSelect: () => setCategory("all")
1389
- }), ...[...overview.sources].sort((a, b) => a.id.localeCompare(b.id)).map((source) => (0, react.createElement)(SourceTab, {
1390
- key: source.id,
1391
- t,
1392
- active: category === source.id,
1393
- label: `${source.id}${source.local === true ? ` · ${t("sourceLocal")}` : ""} ${source.suiteIds.length}${source.cloned === false ? " ⚠" : ""}`,
1394
- onSelect: () => setCategory(source.id),
1395
- onDelete: () => setConfirm({
1396
- kind: "removeSource",
1397
- sourceId: source.id
1398
- }),
1399
- onEdit: selectedSource?.id === source.id ? () => setEditor({
1400
- mode: "edit",
1401
- source
1402
- }) : void 0
1403
- })))), (0, react.createElement)(SearchFilterToolbar, {
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, {
1404
1885
  search,
1405
1886
  searchLabel: t("searchPh"),
1406
1887
  searchPlaceholder: t("searchPh"),
@@ -1500,6 +1981,7 @@ function MarketSection({ t, mode = "settings" }) {
1500
1981
  }, t("confirmDelete")))
1501
1982
  }), detail === void 0 ? null : (0, react.createElement)(SuiteDetailModal, {
1502
1983
  t,
1984
+ credentials,
1503
1985
  sourceId: detail.sourceId,
1504
1986
  suiteId: detail.suiteId,
1505
1987
  onClose: () => setDetail(void 0)
@@ -1509,13 +1991,15 @@ function MarketSection({ t, mode = "settings" }) {
1509
1991
  busy: busy !== void 0,
1510
1992
  progress,
1511
1993
  onClose: () => setEditor(void 0),
1512
- onSave: async (url, branch, local) => {
1994
+ onSave: async ({ url, branch, kind, sha256 }) => {
1513
1995
  const key = editor.mode === "edit" ? `s:edit:${editor.source.id}` : `s:add:${url}`;
1514
1996
  const body = {
1515
1997
  url,
1516
- ...branch === "" ? {} : { branch },
1517
- local
1998
+ local: kind === "local",
1999
+ kind
1518
2000
  };
2001
+ if (branch !== "" && kind === "git") body["branch"] = branch;
2002
+ if (sha256 !== "" && kind === "archive") body["sha256"] = sha256;
1519
2003
  if (editor.mode === "add") {
1520
2004
  setBusy(key);
1521
2005
  setProgress({
@@ -1574,16 +2058,30 @@ function deriveMcpStatusViewModel(payload, filter, search) {
1574
2058
  plugin: 0,
1575
2059
  direct: 0
1576
2060
  };
1577
- let connected = 0;
1578
- let failed = 0;
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
+ };
1579
2071
  const filtered = [];
1580
2072
  const needle = search.trim().toLowerCase();
1581
2073
  for (const item of searchable) {
1582
2074
  const entry = item.entry;
1583
2075
  filterCounts.all++;
1584
2076
  filterCounts[entry.kind]++;
1585
- if (entry.state === "connected") connected++;
1586
- if (entry.state === "failed") failed++;
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++;
1587
2085
  if (filter !== "all" && entry.kind !== filter) continue;
1588
2086
  if (needle !== "" && !item.haystack.includes(needle)) continue;
1589
2087
  filtered.push(entry);
@@ -1592,11 +2090,7 @@ function deriveMcpStatusViewModel(payload, filter, search) {
1592
2090
  activeEntries,
1593
2091
  filtered,
1594
2092
  filterCounts,
1595
- visibleTotals: {
1596
- all: activeEntries.length,
1597
- connected,
1598
- failed
1599
- }
2093
+ visibleTotals
1600
2094
  };
1601
2095
  }
1602
2096
  function searchableFor(payload) {
@@ -1604,7 +2098,7 @@ function searchableFor(payload) {
1604
2098
  if (cached !== void 0) return cached;
1605
2099
  const searchable = payload.entries.filter((entry) => entry.state !== "disabled").map((entry) => ({
1606
2100
  entry,
1607
- 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()
1608
2102
  }));
1609
2103
  searchableCache.set(payload, searchable);
1610
2104
  return searchable;
@@ -1614,15 +2108,35 @@ function searchableFor(payload) {
1614
2108
  var mcp_status_module_default = {
1615
2109
  "boundary": "AUWlZW_boundary",
1616
2110
  "card": "AUWlZW_card",
1617
- "cardReason": "AUWlZW_cardReason",
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",
1618
2122
  "cardTop": "AUWlZW_cardTop",
1619
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",
1620
2131
  "config": "AUWlZW_config",
1621
2132
  "detail": "AUWlZW_detail",
1622
2133
  "detailBody": "AUWlZW_detailBody",
1623
2134
  "detailDialog": "AUWlZW_detailDialog",
1624
2135
  "detailEmpty": "AUWlZW_detailEmpty",
2136
+ "detailEndpoint": "AUWlZW_detailEndpoint",
1625
2137
  "detailHead": "AUWlZW_detailHead",
2138
+ "detailHero": "AUWlZW_detailHero",
2139
+ "detailHeroText": "AUWlZW_detailHeroText",
1626
2140
  "detailMeta": "AUWlZW_detailMeta",
1627
2141
  "detailSection": "AUWlZW_detailSection",
1628
2142
  "detailState": "AUWlZW_detailState",
@@ -1630,49 +2144,85 @@ var mcp_status_module_default = {
1630
2144
  "detailStatedegraded": "AUWlZW_detailStatedegraded",
1631
2145
  "detailStatedisabled": "AUWlZW_detailStatedisabled",
1632
2146
  "detailStatefailed": "AUWlZW_detailStatefailed",
2147
+ "detailStateneeds-credentials": "AUWlZW_detailStateneeds-credentials",
2148
+ "detailStateorphaned": "AUWlZW_detailStateorphaned",
1633
2149
  "empty": "AUWlZW_empty",
1634
2150
  "endpoint": "AUWlZW_endpoint",
1635
2151
  "error": "AUWlZW_error",
1636
2152
  "errorSummary": "AUWlZW_errorSummary",
2153
+ "extArrow": "AUWlZW_extArrow",
2154
+ "extLanguage": "AUWlZW_extLanguage",
2155
+ "extName": "AUWlZW_extName",
2156
+ "extRow": "AUWlZW_extRow",
1637
2157
  "grid": "AUWlZW_grid",
1638
2158
  "header": "AUWlZW_header",
1639
2159
  "headerActions": "AUWlZW_headerActions",
1640
2160
  "list": "AUWlZW_list",
1641
- "meta": "AUWlZW_meta",
2161
+ "lspStartingPulse": "AUWlZW_lspStartingPulse",
2162
+ "mcp-retry-spin": "AUWlZW_mcp-retry-spin",
1642
2163
  "modalFooter": "AUWlZW_modalFooter",
1643
2164
  "name": "AUWlZW_name",
2165
+ "observedAt": "AUWlZW_observedAt",
1644
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",
1645
2175
  "service": "AUWlZW_service",
1646
2176
  "sourceDirect": "AUWlZW_sourceDirect",
1647
2177
  "sourcePlugin": "AUWlZW_sourcePlugin",
2178
+ "spinning": "AUWlZW_spinning",
1648
2179
  "state": "AUWlZW_state",
2180
+ "stateconflict": "AUWlZW_stateconflict",
1649
2181
  "stateconnected": "AUWlZW_stateconnected",
1650
2182
  "statedegraded": "AUWlZW_statedegraded",
1651
2183
  "statedisabled": "AUWlZW_statedisabled",
1652
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",
1653
2191
  "statusconnected": "AUWlZW_statusconnected",
1654
2192
  "statusdegraded": "AUWlZW_statusdegraded",
1655
2193
  "statusdisabled": "AUWlZW_statusdisabled",
1656
2194
  "statusDot": "AUWlZW_statusDot",
1657
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",
1658
2202
  "subtitle": "AUWlZW_subtitle",
1659
2203
  "summary": "AUWlZW_summary",
2204
+ "summaryAllGood": "AUWlZW_summaryAllGood",
2205
+ "summaryBar": "AUWlZW_summaryBar",
2206
+ "summaryChip": "AUWlZW_summaryChip",
2207
+ "summaryCount": "AUWlZW_summaryCount",
1660
2208
  "summaryDotGreen": "AUWlZW_summaryDotGreen",
2209
+ "summaryDotInfo": "AUWlZW_summaryDotInfo",
1661
2210
  "summaryDotRed": "AUWlZW_summaryDotRed",
2211
+ "summaryDotWarn": "AUWlZW_summaryDotWarn",
2212
+ "summaryLabel": "AUWlZW_summaryLabel",
1662
2213
  "surface": "AUWlZW_surface",
1663
2214
  "title": "AUWlZW_title",
1664
2215
  "tool": "AUWlZW_tool",
1665
2216
  "toolbar": "AUWlZW_toolbar",
1666
2217
  "toolCount": "AUWlZW_toolCount",
1667
2218
  "toolDescription": "AUWlZW_toolDescription",
1668
- "toolIndex": "AUWlZW_toolIndex",
1669
2219
  "toolList": "AUWlZW_toolList",
1670
2220
  "toolName": "AUWlZW_toolName",
1671
2221
  "transport": "AUWlZW_transport"
1672
2222
  };
1673
2223
  //#endregion
1674
2224
  //#region src/client/McpStatusPanel.tsx
1675
- const EMPTY_STATUS = {
2225
+ const EMPTY_STATUS$1 = {
1676
2226
  entries: [],
1677
2227
  observedAt: "",
1678
2228
  totals: {
@@ -1680,19 +2230,41 @@ const EMPTY_STATUS = {
1680
2230
  connected: 0,
1681
2231
  degraded: 0,
1682
2232
  failed: 0,
1683
- disabled: 0
2233
+ needsCredentials: 0,
2234
+ orphaned: 0,
2235
+ disabled: 0,
2236
+ foreign: 0
1684
2237
  },
1685
2238
  directObservationOnly: true
1686
2239
  };
1687
- /** DSH-native MCP inventory: click a service card for a standard Modal detail. */
1688
- function McpStatusPanel({ t }) {
1689
- 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);
1690
2243
  const [loading, setLoading] = (0, react.useState)(true);
1691
2244
  const [error, setError] = (0, react.useState)(void 0);
1692
2245
  const [filter, setFilter] = (0, react.useState)("all");
1693
2246
  const [search, setSearch] = (0, react.useState)("");
1694
2247
  const [view, setView] = (0, react.useState)("grid");
1695
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
+ };
1696
2268
  const refresh = () => {
1697
2269
  setLoading(true);
1698
2270
  setError(void 0);
@@ -1704,16 +2276,18 @@ function McpStatusPanel({ t }) {
1704
2276
  refresh();
1705
2277
  }, []);
1706
2278
  const { activeEntries, filtered, filterCounts, visibleTotals } = deriveMcpStatusViewModel(payload, filter, search);
1707
- 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", {}, (0, react.createElement)("h2", { className: mcp_status_module_default.title }, t("mcpStatusTitle"))), (0, react.createElement)("div", { className: mcp_status_module_default.headerActions }, visibleTotals.failed > 0 ? (0, react.createElement)("span", {
1708
- className: mcp_status_module_default.errorSummary,
1709
- title: `${visibleTotals.failed} ${t("mcpFailed")}`
1710
- }, (0, react.createElement)("span", { className: mcp_status_module_default.summaryDotRed }), visibleTotals.failed) : null, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
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, {
1711
2281
  variant: "ghost",
1712
2282
  size: "sm",
1713
2283
  onClick: refresh,
1714
2284
  disabled: loading,
1715
2285
  title: t("refresh")
1716
- }, "↻"))), (0, react.createElement)(SearchFilterToolbar, {
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, {
1717
2291
  className: mcp_status_module_default.toolbar,
1718
2292
  search,
1719
2293
  searchLabel: t("mcpSearch"),
@@ -1729,7 +2303,8 @@ function McpStatusPanel({ t }) {
1729
2303
  count: filterCounts[kind],
1730
2304
  icon: (0, react.createElement)(McpFilterIcon, { kind }),
1731
2305
  active: filter === kind,
1732
- onSelect: () => setFilter(kind)
2306
+ onSelect: () => setFilter(kind),
2307
+ hint: mcpFilterHint(t, kind)
1733
2308
  })),
1734
2309
  view,
1735
2310
  gridLabel: t("grid"),
@@ -1747,31 +2322,94 @@ function McpStatusPanel({ t }) {
1747
2322
  }))), selected === void 0 ? null : (0, react.createElement)(McpDetailModal, {
1748
2323
  entry: selected,
1749
2324
  t,
1750
- onClose: () => setSelected(void 0)
2325
+ credentials,
2326
+ onClose: () => setSelected(void 0),
2327
+ onRetry: retry,
2328
+ onReauthorize: reauthorize
1751
2329
  }));
1752
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
+ }
1753
2387
  function McpCard({ entry, t, onClick }) {
1754
- return (0, react.createElement)("button", {
1755
- type: "button",
1756
- className: mcp_status_module_default.card,
1757
- onClick
1758
- }, (0, react.createElement)("div", { className: mcp_status_module_default.cardTop }, (0, react.createElement)("span", {
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", {
1759
2402
  className: `${mcp_status_module_default.statusDot} ${mcp_status_module_default[`status${entry.state}`]}`,
1760
- title: stateLabel(t, entry.state),
1761
- "aria-label": stateLabel(t, entry.state)
1762
- }), (0, react.createElement)("span", { className: mcp_status_module_default.service }, (0, react.createElement)("span", { className: mcp_status_module_default.name }, entry.name)), (0, react.createElement)("span", { className: mcp_status_module_default.toolCount }, `${t("mcpTools")} ${entry.tools.length}`)), (0, react.createElement)("p", { className: mcp_status_module_default.endpoint }, entry.endpoint ?? t("mcpObservedEndpoint")), (0, react.createElement)("div", { className: mcp_status_module_default.meta }, (0, react.createElement)(McpSourceBadge, {
1763
- kind: entry.kind,
1764
- label: entry.kind === "plugin" ? entry.source ?? "—" : t("mcpDirect"),
1765
- t
1766
- }), (0, react.createElement)("span", { className: mcp_status_module_default.transport }, entry.transport)), entry.reason === void 0 ? null : (0, react.createElement)("p", { className: mcp_status_module_default.cardReason }, entry.reason));
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"))));
1767
2405
  }
1768
- function McpSourceBadge({ kind, label, t }) {
1769
- return (0, react.createElement)("span", { className: kind === "plugin" ? mcp_status_module_default.sourcePlugin : mcp_status_module_default.sourceDirect }, (0, react.createElement)(McpSourceIcon, { kind }), (0, react.createElement)("span", {}, kind === "plugin" ? label : t("mcpDirect")));
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());
1770
2408
  }
1771
2409
  function McpSourceIcon({ kind }) {
1772
2410
  const common = {
1773
- width: 16,
1774
- height: 16,
2411
+ width: 14,
2412
+ height: 14,
1775
2413
  viewBox: "0 0 16 16",
1776
2414
  fill: "none",
1777
2415
  "aria-hidden": true
@@ -1793,7 +2431,27 @@ function McpFilterIcon({ kind }) {
1793
2431
  "aria-hidden": true
1794
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" }));
1795
2433
  }
1796
- function McpDetailModal({ entry, t, onClose }) {
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
+ };
1797
2455
  return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1798
2456
  open: true,
1799
2457
  onClose,
@@ -1802,18 +2460,47 @@ function McpDetailModal({ entry, t, onClose }) {
1802
2460
  closeLabel: t("cancel"),
1803
2461
  className: mcp_status_module_default.detailDialog,
1804
2462
  contentClassName: mcp_status_module_default.detailBody,
1805
- footer: (0, react.createElement)("div", { className: mcp_status_module_default.modalFooter }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
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, {
1806
2490
  variant: "ghost",
1807
2491
  onClick: onClose
1808
2492
  }, t("cancel"))),
1809
- children: (0, react.createElement)("div", { className: mcp_status_module_default.detail }, (0, react.createElement)("div", { className: mcp_status_module_default.detailMeta }, (0, react.createElement)(McpSourceBadge, {
1810
- kind: entry.kind,
1811
- label: entry.kind === "plugin" ? entry.source ?? "—" : t("mcpDirect"),
1812
- t
1813
- }), (0, react.createElement)("span", { className: mcp_status_module_default.transport }, entry.transport), (0, react.createElement)("span", { className: `${mcp_status_module_default.state} ${mcp_status_module_default[`state${entry.state}`]}` }, stateLabel(t, entry.state))), entry.reason === void 0 ? null : (0, react.createElement)("div", { className: mcp_status_module_default.reason }, entry.reason), (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 }, t("mcpNoTools")) : (0, react.createElement)("div", { className: mcp_status_module_default.toolList }, entry.tools.map((tool, index) => (0, react.createElement)("div", {
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", {
1814
2501
  key: tool.name,
1815
2502
  className: mcp_status_module_default.tool
1816
- }, (0, react.createElement)("span", { className: mcp_status_module_default.toolIndex }, String(index + 1).padStart(2, "0")), (0, react.createElement)("span", { className: mcp_status_module_default.toolName }, tool.name), (0, react.createElement)("span", { className: mcp_status_module_default.toolDescription }, tool.description ?? ""))))))
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))))))
1817
2504
  });
1818
2505
  }
1819
2506
  function filterLabel(t, kind) {
@@ -1821,11 +2508,448 @@ function filterLabel(t, kind) {
1821
2508
  if (kind === "direct") return t("mcpDirect");
1822
2509
  return t("mcpAll");
1823
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
+ }
1824
2855
  function stateLabel(t, state) {
1825
- if (state === "connected") return t("mcpConnected");
1826
- if (state === "degraded") return t("mcpDegraded");
1827
- if (state === "failed") return t("mcpFailed");
1828
- return t("mcpDisabled");
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);
1829
2953
  }
1830
2954
  //#endregion
1831
2955
  //#region src/client/page-mode-selection.ts
@@ -1901,6 +3025,7 @@ function mountLegacyPageMode(options) {
1901
3025
  if (root === void 0) return;
1902
3026
  root.render((0, react.createElement)(MarketSection, {
1903
3027
  t: options.t,
3028
+ credentials: options.credentials,
1904
3029
  mode: "page"
1905
3030
  }));
1906
3031
  };
@@ -2042,8 +3167,11 @@ function createEntry(onClick) {
2042
3167
  */
2043
3168
  const NS = "dsh-agent-plugins-market";
2044
3169
  const name = "dsh-agent-plugins-market";
2045
- const inject = ["slots", "locale"];
2046
- /** Primitives this section renders with; absent exports degrade the whole section. */
3170
+ const inject = [
3171
+ "slots",
3172
+ "locale",
3173
+ "connection"
3174
+ ];
2047
3175
  const REQUIRED_PRIMITIVES = [
2048
3176
  "Button",
2049
3177
  "Input",
@@ -2051,6 +3179,12 @@ const REQUIRED_PRIMITIVES = [
2051
3179
  "Toast",
2052
3180
  "Tooltip"
2053
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
+ */
2054
3188
  /** Detect host primitives that predate the exports this UI relies on. */
2055
3189
  function missingPrimitives(module, required = REQUIRED_PRIMITIVES) {
2056
3190
  return required.filter((name) => module[name] === void 0);
@@ -2061,6 +3195,7 @@ function apply(ctx) {
2061
3195
  en
2062
3196
  }), "dsh-agent-plugins: dictionaries");
2063
3197
  const t = ctx.locale.bind(NS);
3198
+ const credentials = ctx.connection.api.credentials;
2064
3199
  const gaps = missingPrimitives(_deepseek_ai_dsh_client_ui_primitives);
2065
3200
  if (gaps.length > 0) {
2066
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)`);
@@ -2069,9 +3204,37 @@ function apply(ctx) {
2069
3204
  let settingsSurfaceAvailable = false;
2070
3205
  ctx.effect(() => mountLegacyPageMode({
2071
3206
  t,
3207
+ credentials,
2072
3208
  isSettingsSurfaceAvailable: () => settingsSurfaceAvailable,
2073
3209
  subscribeLocale: ctx.locale.subscribe === void 0 ? void 0 : (listener) => ctx.locale.subscribe(listener)
2074
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
+ });
2075
3238
  ctx.slots.inject("settings.section", () => {
2076
3239
  settingsSurfaceAvailable = true;
2077
3240
  notifyPageModeSurfaceChange();
@@ -2084,6 +3247,7 @@ function apply(ctx) {
2084
3247
  inject: () => ({ t })
2085
3248
  }, () => (0, react.createElement)(MarketSection, {
2086
3249
  t,
3250
+ credentials,
2087
3251
  mode: "settings"
2088
3252
  }));
2089
3253
  const mcpDispose = ctx.slots.register({
@@ -2093,11 +3257,23 @@ function apply(ctx) {
2093
3257
  label: () => t("mcpStatusNav"),
2094
3258
  locale: NS,
2095
3259
  inject: () => ({ t })
2096
- }, () => (0, react.createElement)(McpStatusPanel, { t }));
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 }));
2097
3272
  return () => {
2098
3273
  settingsSurfaceAvailable = false;
2099
3274
  notifyPageModeSurfaceChange();
2100
3275
  if (typeof mcpDispose === "function") mcpDispose();
3276
+ if (typeof lspDispose === "function") lspDispose();
2101
3277
  if (typeof marketDispose === "function") marketDispose();
2102
3278
  };
2103
3279
  });