dsh-agent-plugins-market 0.4.5 → 0.5.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 (61) hide show
  1. package/README.md +20 -14
  2. package/README.zh.md +20 -14
  3. package/client/client.js +1117 -360
  4. package/client/client.js.map +1 -1
  5. package/lib/application/catalog.js +447 -0
  6. package/lib/application/details.js +136 -0
  7. package/lib/application/queries.js +1 -0
  8. package/lib/{discovery → catalog}/manifests.js +20 -12
  9. package/lib/{paths.js → catalog/paths.js} +5 -1
  10. package/lib/{skills-parse.js → catalog/skills-parse.js} +7 -4
  11. package/lib/catalog/source-catalog.js +38 -0
  12. package/lib/{discovery.js → catalog/suite-scanner.js} +29 -85
  13. package/lib/{discovery → catalog}/surfaces.js +9 -11
  14. package/lib/{validate.js → catalog/validate.js} +3 -3
  15. package/lib/context.js +11 -13
  16. package/lib/contracts/market.js +27 -0
  17. package/lib/contracts/mcp-status.js +2 -0
  18. package/lib/index.js +33 -46
  19. package/lib/{state.js → model/state.js} +2 -2
  20. package/lib/routes.js +23 -20
  21. package/lib/{commands-mounts.js → runtime/commands-mounts.js} +10 -11
  22. package/lib/{hooks-mounts.js → runtime/hooks-mounts.js} +1 -1
  23. package/lib/{mcp-config.js → runtime/mcp-config.js} +7 -4
  24. package/lib/runtime/mcp-status.js +114 -0
  25. package/lib/runtime/reconciler.js +46 -0
  26. package/lib/{skills-provider.js → runtime/skills-provider.js} +26 -23
  27. package/lib/runtime/tool-registry-observer.js +35 -0
  28. package/lib/types/application/catalog.d.ts +113 -0
  29. package/lib/types/application/details.d.ts +12 -0
  30. package/lib/types/application/queries.d.ts +33 -0
  31. package/lib/types/{discovery → catalog}/manifests.d.ts +1 -1
  32. package/lib/types/catalog/source-catalog.d.ts +3 -0
  33. package/lib/types/catalog/suite-scanner.d.ts +9 -0
  34. package/lib/types/{discovery → catalog}/surfaces.d.ts +1 -1
  35. package/lib/types/{validate.d.ts → catalog/validate.d.ts} +1 -1
  36. package/lib/types/context.d.ts +2 -2
  37. package/lib/types/contracts/market.d.ts +153 -0
  38. package/lib/types/contracts/mcp-status.d.ts +38 -0
  39. package/lib/types/index.d.ts +1 -1
  40. package/lib/types/{types.d.ts → model/types.d.ts} +2 -42
  41. package/lib/types/routes.d.ts +2 -2
  42. package/lib/types/{commands-mounts.d.ts → runtime/commands-mounts.d.ts} +1 -1
  43. package/lib/types/{hooks-mounts.d.ts → runtime/hooks-mounts.d.ts} +1 -1
  44. package/lib/types/{mcp-config.d.ts → runtime/mcp-config.d.ts} +1 -1
  45. package/lib/types/{mcp-mounts.d.ts → runtime/mcp-mounts.d.ts} +1 -1
  46. package/lib/types/runtime/mcp-status.d.ts +13 -0
  47. package/lib/types/runtime/reconciler.d.ts +33 -0
  48. package/lib/types/{skills-provider.d.ts → runtime/skills-provider.d.ts} +3 -3
  49. package/lib/types/runtime/tool-registry-observer.d.ts +14 -0
  50. package/package.json +34 -19
  51. package/schemas/README.md +2 -5
  52. package/lib/manager.js +0 -570
  53. package/lib/types/discovery.d.ts +0 -16
  54. package/lib/types/manager.d.ts +0 -118
  55. /package/lib/{git.js → catalog/git.js} +0 -0
  56. /package/lib/{types.js → model/types.js} +0 -0
  57. /package/lib/{mcp-mounts.js → runtime/mcp-mounts.js} +0 -0
  58. /package/lib/types/{git.d.ts → catalog/git.d.ts} +0 -0
  59. /package/lib/types/{paths.d.ts → catalog/paths.d.ts} +0 -0
  60. /package/lib/types/{skills-parse.d.ts → catalog/skills-parse.d.ts} +0 -0
  61. /package/lib/types/{state.d.ts → model/state.d.ts} +0 -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=".qMtKNa_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: 14px;\n display: flex;\n}\n\n.qMtKNa_header {\n flex-direction: column;\n flex-shrink: 0;\n gap: 8px;\n display: flex;\n}\n\n.qMtKNa_titleRow {\n align-items: center;\n gap: 12px;\n display: flex;\n}\n\n.qMtKNa_title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n}\n\n.qMtKNa_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.qMtKNa_spacer {\n flex: 1;\n}\n\n.qMtKNa_tabGap {\n flex-shrink: 0;\n width: 16px;\n}\n\n.qMtKNa_searchGroup {\n align-items: center;\n gap: 2px;\n display: flex;\n}\n\n.qMtKNa_searchWrap, .qMtKNa_searchInput {\n align-items: center;\n display: flex;\n}\n\n.qMtKNa_searchInput input {\n width: 240px;\n font-size: 12px;\n line-height: 20px;\n}\n\n.qMtKNa_tabRow {\n border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n justify-content: flex-end;\n align-items: flex-end;\n gap: 2px;\n display: flex;\n}\n\n.qMtKNa_tab, .qMtKNa_tabOn {\n font: inherit;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n white-space: nowrap;\n background: none;\n border: none;\n border-bottom: 2px solid #0000;\n padding: 7px 12px;\n font-size: 13px;\n}\n\n.qMtKNa_tabOn {\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.qMtKNa_viewSwitch {\n font: inherit;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n white-space: nowrap;\n background: none;\n border: none;\n border-bottom: 2px solid #0000;\n padding: 7px 12px;\n font-size: 13px;\n}\n\n.qMtKNa_viewSwitch:hover {\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n.qMtKNa_body {\n flex: 1;\n align-items: flex-start;\n gap: 20px;\n min-height: 0;\n display: flex;\n}\n\n.qMtKNa_sourceTabsRow {\n padding: 0;\n display: block;\n}\n\n.qMtKNa_sourceTabsScroll {\n grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));\n gap: 6px;\n display: grid;\n}\n\n.qMtKNa_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.qMtKNa_srcTabEdit:hover {\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n.qMtKNa_srcTabOn .qMtKNa_srcTabEdit {\n color: #ffffffd9;\n}\n\n.qMtKNa_srcTabOn .qMtKNa_srcTabEdit:hover {\n color: #fff;\n}\n\n.qMtKNa_srcTab, .qMtKNa_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.qMtKNa_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.qMtKNa_srcTabMain:hover {\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n.qMtKNa_srcTabOn {\n background: var(--dsw-alias-brand-primary, #4f6ef7);\n border-color: var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n.qMtKNa_srcTabOn .qMtKNa_srcTabMain {\n color: #fff;\n font-weight: 600;\n}\n\n.qMtKNa_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.qMtKNa_srcTabDel:hover {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.qMtKNa_srcTabOn .qMtKNa_srcTabDel {\n color: #ffffffd9;\n}\n\n.qMtKNa_srcTabOn .qMtKNa_srcTabDel:hover {\n color: #fff;\n}\n\n.qMtKNa_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.qMtKNa_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.qMtKNa_list .qMtKNa_card {\n flex-flow: wrap;\n align-items: center;\n gap: 8px 14px;\n}\n\n.qMtKNa_list .qMtKNa_cardTop {\n flex: none;\n}\n\n.qMtKNa_list .qMtKNa_cardDesc {\n -webkit-line-clamp: 1;\n flex: 1;\n min-width: 200px;\n min-height: 0;\n}\n\n.qMtKNa_list .qMtKNa_cardActions {\n flex: none;\n}\n\n.qMtKNa_list .qMtKNa_meta {\n flex-basis: 100%;\n}\n\n.qMtKNa_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.qMtKNa_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.qMtKNa_cardTop {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.qMtKNa_cardTitle {\n flex: 1;\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.qMtKNa_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.qMtKNa_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.qMtKNa_cardActions {\n flex-shrink: 0;\n align-items: center;\n gap: 4px;\n display: flex;\n}\n\n.qMtKNa_switchOn, .qMtKNa_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.qMtKNa_switchOn {\n background: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.qMtKNa_switchOff {\n background: var(--dsw-alias-state-neutral, #d1d5db);\n}\n\n.qMtKNa_switchOn:disabled, .qMtKNa_switchOff:disabled {\n opacity: .6;\n cursor: default;\n}\n\n.qMtKNa_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.qMtKNa_switchOn .qMtKNa_switchThumb {\n left: 19px;\n}\n\n.qMtKNa_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.qMtKNa_meta {\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n.qMtKNa_src {\n color: var(--dsw-alias-label-secondary, #9ca3af);\n font-size: 12px;\n text-decoration: none;\n}\n\n.qMtKNa_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.qMtKNa_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.qMtKNa_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.qMtKNa_modalFooter {\n justify-content: flex-end;\n gap: 8px;\n width: 100%;\n display: flex;\n}\n\n.qMtKNa_modalFooterLeft {\n gap: 8px;\n margin-right: auto;\n display: flex;\n}\n\n.qMtKNa_editorDialog {\n width: min(500px, 92vw);\n}\n\n.qMtKNa_editorForm {\n flex-direction: column;\n gap: 14px;\n min-width: 0;\n display: flex;\n}\n\n.qMtKNa_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.qMtKNa_seg, .qMtKNa_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.qMtKNa_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.qMtKNa_fieldGroup {\n flex-direction: column;\n gap: 5px;\n display: flex;\n}\n\n.qMtKNa_fieldLabel {\n color: var(--dsw-alias-label-secondary, #6b7280);\n font-size: 12px;\n font-weight: 600;\n}\n\n.qMtKNa_fieldHint {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 12px;\n line-height: 16px;\n}\n\n.qMtKNa_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.qMtKNa_staticIdValue {\n color: var(--dsw-alias-label-primary, #1f2328);\n font-size: 13px;\n font-weight: 600;\n}\n\n.qMtKNa_detailDialog {\n width: min(800px, 94vw);\n}\n\n.qMtKNa_detailBody {\n flex-direction: column;\n gap: 14px;\n max-height: 78vh;\n display: flex;\n overflow-y: auto;\n}\n\n.qMtKNa_detailSections {\n flex-direction: column;\n gap: 14px;\n display: flex;\n}\n\n.qMtKNa_detailSection {\n flex-direction: column;\n gap: 6px;\n display: flex;\n}\n\n.qMtKNa_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.qMtKNa_detailGrid {\n grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n gap: 6px 14px;\n display: grid;\n}\n\n.qMtKNa_detailCell {\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n display: flex;\n}\n\n.qMtKNa_detailKey {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 12px;\n}\n\n.qMtKNa_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.qMtKNa_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.qMtKNa_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.qMtKNa_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.qMtKNa_detailItemRow, .qMtKNa_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.qMtKNa_detailItemRow:hover {\n background: var(--dsw-alias-bg-hover, #0000000d);\n}\n\n.qMtKNa_detailItemOpen {\n background: var(--dsw-alias-bg-selected, #4f6ef714);\n}\n\n.qMtKNa_detailItemName {\n flex-shrink: 0;\n font-size: 13px;\n font-weight: 600;\n}\n\n.qMtKNa_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.qMtKNa_detailChevron {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n flex-shrink: 0;\n}\n\n.qMtKNa_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.qMtKNa_progress, .qMtKNa_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.qMtKNa_progressError {\n border-color: var(--dsw-alias-danger, #e5484d);\n color: var(--dsw-alias-danger, #e5484d);\n}\n\n.qMtKNa_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 qMtKNa_dshApmSpin;\n}\n\n@keyframes qMtKNa_dshApmSpin {\n to {\n transform: rotate(360deg);\n }\n}\n\n.qMtKNa_progressFail {\n flex-shrink: 0;\n font-size: 13px;\n}\n\n.qMtKNa_progressText {\n overflow-wrap: anywhere;\n min-width: 0;\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 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_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.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);}})();
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  //#region \0rolldown/runtime.js
8
8
  var __create = Object.create;
@@ -29,7 +29,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
29
29
  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
+ let react_dom_client = require("react-dom/client");
32
33
  //#region src/client/locales.ts
34
+ /** Chinese is the source-of-truth key set; English is checked against it below. */
33
35
  const zh = {
34
36
  nav: "Agent Plugins 市场",
35
37
  subtitle: "发现与安装 Agent Plugins(agent-plugins.org 便携包)",
@@ -92,7 +94,7 @@ const zh = {
92
94
  uninstall: "卸载",
93
95
  uninstallConfirmTitle: "卸载 Agent Plugins",
94
96
  uninstallConfirmDesc: "将从已安装列表移除该 Agent Plugins,其技能与 MCP 工具随即停止注入。仓库源克隆保留。",
95
- removeSourceConfirmTitle: "移除仓库源",
97
+ removeSourceConfirmTitle: "移除仓库源「{sourceId}」",
96
98
  removeSourceConfirmDesc: "将删除该源的本地克隆与全部安装记录。",
97
99
  enable: "启用",
98
100
  disable: "禁用",
@@ -123,6 +125,8 @@ const zh = {
123
125
  sourceNotCloned: "未克隆",
124
126
  sourceCloned: "已克隆",
125
127
  errors: "校验问题",
128
+ sourceErrorSeparator: ";",
129
+ viewMode: "视图模式",
126
130
  grid: "网格",
127
131
  list: "列表",
128
132
  openSettings: "在设置中打开",
@@ -130,7 +134,32 @@ const zh = {
130
134
  dataLabel: "Agent Plugins 数据目录",
131
135
  countAll: "共 {n} 个 Agent Plugins",
132
136
  countInstalled: "已装 {n}",
133
- countEnabled: "启用 {n}"
137
+ countEnabled: "启用 {n}",
138
+ mcpStatusNav: "MCP 服务",
139
+ mcpStatusTitle: "MCP 服务",
140
+ mcpStatusSubtitle: "连接状态、来源和工具清单",
141
+ mcpSearch: "搜索 MCP 名称、来源或地址…",
142
+ mcpAll: "全部",
143
+ mcpPlugin: "Plugin",
144
+ mcpDirect: "直接安装",
145
+ mcpService: "服务",
146
+ mcpSource: "来源",
147
+ mcpTransport: "传输",
148
+ mcpTools: "工具",
149
+ mcpConnected: "已连接",
150
+ mcpDegraded: "降级",
151
+ mcpFailed: "失败",
152
+ mcpDisabled: "未启用",
153
+ mcpObservedEndpoint: "当前工具表观测",
154
+ mcpServiceDetail: "服务详情",
155
+ mcpConfig: "连接配置",
156
+ mcpSelectHint: "选择一个 MCP 服务查看配置与工具",
157
+ mcpEmpty: "没有匹配的 MCP 服务",
158
+ mcpNoTools: "当前没有已注册工具",
159
+ mcpDirectConfigUnavailable: "宿主未提供直接安装 MCP 的配置记录",
160
+ mcpDirectBoundary: "直接安装 MCP 仅显示当前工具表中可观测的服务;宿主未提供配置与连接状态 API。",
161
+ mcpBackToMarket: "返回市场",
162
+ mcpRetry: "重试"
134
163
  };
135
164
  const en = {
136
165
  nav: "Agent Plugins Market",
@@ -194,7 +223,7 @@ const en = {
194
223
  uninstall: "Uninstall",
195
224
  uninstallConfirmTitle: "Uninstall suite",
196
225
  uninstallConfirmDesc: "Removes the suite from the installed list; its skills and MCP tools stop injecting. The source clone stays.",
197
- removeSourceConfirmTitle: "Remove source",
226
+ removeSourceConfirmTitle: "Remove source “{sourceId}”",
198
227
  removeSourceConfirmDesc: "Deletes the local clone and all install records of this source.",
199
228
  enable: "Enable",
200
229
  disable: "Disable",
@@ -225,6 +254,8 @@ const en = {
225
254
  sourceNotCloned: "not cloned",
226
255
  sourceCloned: "cloned",
227
256
  errors: "validation issues",
257
+ sourceErrorSeparator: "; ",
258
+ viewMode: "View mode",
228
259
  grid: "grid",
229
260
  list: "list",
230
261
  openSettings: "Open in settings",
@@ -232,32 +263,92 @@ const en = {
232
263
  dataLabel: "Suite data root",
233
264
  countAll: "{n} suites",
234
265
  countInstalled: "{n} installed",
235
- countEnabled: "{n} enabled"
266
+ countEnabled: "{n} enabled",
267
+ mcpStatusNav: "MCP services",
268
+ mcpStatusTitle: "MCP services",
269
+ mcpStatusSubtitle: "Connection state, sources, and tools",
270
+ mcpSearch: "Search MCP names, sources, or endpoints…",
271
+ mcpAll: "All",
272
+ mcpPlugin: "Plugin",
273
+ mcpDirect: "Direct",
274
+ mcpService: "Service",
275
+ mcpSource: "Source",
276
+ mcpTransport: "Transport",
277
+ mcpTools: "tools",
278
+ mcpConnected: "connected",
279
+ mcpDegraded: "degraded",
280
+ mcpFailed: "failed",
281
+ mcpDisabled: "disabled",
282
+ mcpObservedEndpoint: "observed from tool registry",
283
+ mcpServiceDetail: "Service detail",
284
+ mcpConfig: "Connection config",
285
+ mcpSelectHint: "Select an MCP service to inspect config and tools",
286
+ mcpEmpty: "No matching MCP services",
287
+ mcpNoTools: "No registered tools",
288
+ mcpDirectConfigUnavailable: "The host does not expose direct-MCP configuration",
289
+ mcpDirectBoundary: "Direct MCP entries only show services observed in the current tool registry; the host exposes no config or connection-status API.",
290
+ mcpBackToMarket: "Back to market",
291
+ mcpRetry: "Retry"
236
292
  };
237
293
  //#endregion
294
+ //#region src/contracts/market.ts
295
+ /** Browser-safe market wire records and route constants shared by host and client. */
296
+ /** Prefix for all Agent Plugins Market HTTP routes. */
297
+ const MARKET_API_PREFIX = "/api/agent-plugins/";
298
+ /** Fixed Agent Plugins Market HTTP routes. */
299
+ const MARKET_ROUTES = {
300
+ overview: `${MARKET_API_PREFIX}overview`,
301
+ mcpStatus: `${MARKET_API_PREFIX}mcp-status`,
302
+ progress: `${MARKET_API_PREFIX}progress`,
303
+ config: `${MARKET_API_PREFIX}config`,
304
+ suite: `${MARKET_API_PREFIX}suite`,
305
+ skill: `${MARKET_API_PREFIX}skill`,
306
+ addSource: `${MARKET_API_PREFIX}sources/add`,
307
+ updateSource: `${MARKET_API_PREFIX}sources/update`,
308
+ removeSource: `${MARKET_API_PREFIX}sources/remove`,
309
+ refreshSource: `${MARKET_API_PREFIX}sources/refresh`,
310
+ install: `${MARKET_API_PREFIX}install`,
311
+ uninstall: `${MARKET_API_PREFIX}uninstall`,
312
+ setEnabled: `${MARKET_API_PREFIX}set-enabled`
313
+ };
314
+ /** Build a suite-detail URL without duplicating route or query encoding logic. */
315
+ function suiteRoute(sourceId, suiteId) {
316
+ return `${MARKET_ROUTES.suite}?sourceId=${encodeURIComponent(sourceId)}&suiteId=${encodeURIComponent(suiteId)}`;
317
+ }
318
+ /** Build a skill-content URL without duplicating route or query encoding logic. */
319
+ function skillRoute(sourceId, suiteId, skill) {
320
+ return `${MARKET_ROUTES.skill}?sourceId=${encodeURIComponent(sourceId)}&suiteId=${encodeURIComponent(suiteId)}&skill=${encodeURIComponent(skill)}`;
321
+ }
322
+ //#endregion
238
323
  //#region src/client/api.ts
324
+ /** Typed fetch helpers over the host's `/api/agent-plugins/*` routes. */
239
325
  async function fetchOverview() {
240
- const response = await fetch("/api/agent-plugins/overview", { credentials: "same-origin" });
326
+ const response = await fetch(MARKET_ROUTES.overview, { credentials: "same-origin" });
241
327
  if (!response.ok) throw new Error(`overview failed: ${response.status}`);
242
328
  return response.json();
243
329
  }
244
330
  async function fetchSourceProgress() {
245
- const response = await fetch("/api/agent-plugins/progress", { credentials: "same-origin" });
331
+ const response = await fetch(MARKET_ROUTES.progress, { credentials: "same-origin" });
246
332
  if (!response.ok) throw new Error(`progress failed: ${response.status}`);
247
333
  return response.json();
248
334
  }
249
335
  async function fetchSuiteDetail(sourceId, suiteId) {
250
- const response = await fetch(`/api/agent-plugins/suite?sourceId=${encodeURIComponent(sourceId)}&suiteId=${encodeURIComponent(suiteId)}`, { credentials: "same-origin" });
336
+ const response = await fetch(suiteRoute(sourceId, suiteId), { credentials: "same-origin" });
251
337
  if (!response.ok) throw new Error(`suite detail failed: ${response.status}`);
252
338
  return response.json();
253
339
  }
340
+ async function fetchMcpStatus() {
341
+ const response = await fetch(MARKET_ROUTES.mcpStatus, { credentials: "same-origin" });
342
+ if (!response.ok) throw new Error(`MCP status failed: ${response.status}`);
343
+ return response.json();
344
+ }
254
345
  async function fetchSkillContent(sourceId, suiteId, skill) {
255
- const response = await fetch(`/api/agent-plugins/skill?sourceId=${encodeURIComponent(sourceId)}&suiteId=${encodeURIComponent(suiteId)}&skill=${encodeURIComponent(skill)}`, { credentials: "same-origin" });
346
+ const response = await fetch(skillRoute(sourceId, suiteId, skill), { credentials: "same-origin" });
256
347
  if (!response.ok) throw new Error(`skill content failed: ${response.status}`);
257
348
  return response.json();
258
349
  }
259
350
  async function postAction(path, body) {
260
- const response = await fetch(`/api/agent-plugins/${path}`, {
351
+ const response = await fetch(`${MARKET_API_PREFIX}${path}`, {
261
352
  method: "POST",
262
353
  credentials: "same-origin",
263
354
  headers: { "content-type": "application/json" },
@@ -268,6 +359,368 @@ async function postAction(path, body) {
268
359
  return payload;
269
360
  }
270
361
  //#endregion
362
+ //#region src/client/features/market/market-resource.ts
363
+ /** Market overview cache, invalidation, and source-progress resource helpers. */
364
+ const EMPTY_OVERVIEW = {
365
+ sources: [],
366
+ suites: [],
367
+ totals: {
368
+ all: 0,
369
+ installed: 0,
370
+ enabled: 0
371
+ },
372
+ roots: {
373
+ user: "",
374
+ data: ""
375
+ }
376
+ };
377
+ let cachedOverview;
378
+ let inflightOverview;
379
+ /** Load the last overview immediately and revalidate one shared request. */
380
+ function loadOverview() {
381
+ const initial = cachedOverview ?? EMPTY_OVERVIEW;
382
+ if (inflightOverview === void 0) inflightOverview = fetchOverview().then((data) => {
383
+ cachedOverview = data;
384
+ return data;
385
+ }).finally(() => {
386
+ inflightOverview = void 0;
387
+ });
388
+ return {
389
+ initial,
390
+ revalidating: cachedOverview === void 0,
391
+ promise: inflightOverview
392
+ };
393
+ }
394
+ /** Invalidate the shared overview after a mutating action. */
395
+ function invalidateOverview() {
396
+ cachedOverview = void 0;
397
+ }
398
+ /**
399
+ * Poll source mutation progress until stopped. Poll failures remain silent
400
+ * because the add-source request is authoritative for mutation success.
401
+ */
402
+ function startSourceProgressPolling(report, resolveStep = (step) => step) {
403
+ let stopped = false;
404
+ let timer;
405
+ const tick = async () => {
406
+ if (stopped) return;
407
+ try {
408
+ const progress = await fetchSourceProgress();
409
+ if (!stopped && progress.active) report({
410
+ step: resolveStep(progress.step),
411
+ error: void 0
412
+ });
413
+ } catch {}
414
+ if (!stopped) timer = setTimeout(() => {
415
+ tick();
416
+ }, 800);
417
+ };
418
+ timer = setTimeout(() => {
419
+ tick();
420
+ }, 400);
421
+ return { stop: () => {
422
+ stopped = true;
423
+ if (timer !== void 0) clearTimeout(timer);
424
+ } };
425
+ }
426
+ //#endregion
427
+ //#region src/client/features/market/market-view-model.ts
428
+ const searchableCache$1 = /* @__PURE__ */ new WeakMap();
429
+ /** Derive visible cards and scope counts in one pass over a normalized payload. */
430
+ function deriveMarketViewModel(overview, search, filter, category) {
431
+ const searchable = searchableFor$1(overview);
432
+ const needle = search.trim().toLowerCase();
433
+ let all = 0;
434
+ let installed = 0;
435
+ let enabled = 0;
436
+ const visible = [];
437
+ for (const entry of searchable) {
438
+ const suite = entry.suite;
439
+ if (category !== "all" && suite.sourceId !== category) continue;
440
+ all++;
441
+ if (suite.installed) installed++;
442
+ if (suite.enabled) enabled++;
443
+ if (filter === "installed" && !suite.installed) continue;
444
+ if (filter === "uninstalled" && suite.installed) continue;
445
+ if (needle !== "" && !entry.haystack.includes(needle)) continue;
446
+ visible.push(suite);
447
+ }
448
+ return {
449
+ scopeTotals: {
450
+ all,
451
+ installed,
452
+ enabled
453
+ },
454
+ filtered: visible
455
+ };
456
+ }
457
+ function searchableFor$1(overview) {
458
+ const cached = searchableCache$1.get(overview);
459
+ if (cached !== void 0) return cached;
460
+ const searchable = overview.suites.map((suite) => ({
461
+ suite,
462
+ haystack: `${suite.name} ${suite.description ?? ""} ${suite.keywords.join(" ")}`.toLowerCase()
463
+ }));
464
+ searchableCache$1.set(overview, searchable);
465
+ return searchable;
466
+ }
467
+ //#endregion
468
+ //#region src/client/market.module.css
469
+ var market_module_default = {
470
+ "body": "_72qoAq_body",
471
+ "card": "_72qoAq_card",
472
+ "cardActions": "_72qoAq_cardActions",
473
+ "cardDesc": "_72qoAq_cardDesc",
474
+ "cardName": "_72qoAq_cardName",
475
+ "cardTitle": "_72qoAq_cardTitle",
476
+ "cardTop": "_72qoAq_cardTop",
477
+ "desc": "_72qoAq_desc",
478
+ "detailBody": "_72qoAq_detailBody",
479
+ "detailCell": "_72qoAq_detailCell",
480
+ "detailChevron": "_72qoAq_detailChevron",
481
+ "detailDesc": "_72qoAq_detailDesc",
482
+ "detailDialog": "_72qoAq_detailDialog",
483
+ "detailGrid": "_72qoAq_detailGrid",
484
+ "detailHead": "_72qoAq_detailHead",
485
+ "detailItem": "_72qoAq_detailItem",
486
+ "detailItemDesc": "_72qoAq_detailItemDesc",
487
+ "detailItemName": "_72qoAq_detailItemName",
488
+ "detailItemOpen": "_72qoAq_detailItemOpen",
489
+ "detailItemRow": "_72qoAq_detailItemRow",
490
+ "detailKey": "_72qoAq_detailKey",
491
+ "detailSection": "_72qoAq_detailSection",
492
+ "detailSections": "_72qoAq_detailSections",
493
+ "detailValue": "_72qoAq_detailValue",
494
+ "dshApmSpin": "_72qoAq_dshApmSpin",
495
+ "editorDialog": "_72qoAq_editorDialog",
496
+ "editorForm": "_72qoAq_editorForm",
497
+ "empty": "_72qoAq_empty",
498
+ "fieldGroup": "_72qoAq_fieldGroup",
499
+ "fieldHint": "_72qoAq_fieldHint",
500
+ "fieldLabel": "_72qoAq_fieldLabel",
501
+ "grid": "_72qoAq_grid",
502
+ "header": "_72qoAq_header",
503
+ "list": "_72qoAq_list",
504
+ "market": "_72qoAq_market",
505
+ "marketControls": "_72qoAq_marketControls",
506
+ "mcpSurface": "_72qoAq_mcpSurface",
507
+ "meta": "_72qoAq_meta",
508
+ "modalFooter": "_72qoAq_modalFooter",
509
+ "modalFooterLeft": "_72qoAq_modalFooterLeft",
510
+ "modeRow": "_72qoAq_modeRow",
511
+ "mono": "_72qoAq_mono",
512
+ "okState": "_72qoAq_okState",
513
+ "pageEntry": "_72qoAq_pageEntry",
514
+ "pageMode": "_72qoAq_pageMode",
515
+ "pageView": "_72qoAq_pageView",
516
+ "progress": "_72qoAq_progress",
517
+ "progressError": "_72qoAq_progressError",
518
+ "progressFail": "_72qoAq_progressFail",
519
+ "progressSpin": "_72qoAq_progressSpin",
520
+ "progressText": "_72qoAq_progressText",
521
+ "searchGroup": "_72qoAq_searchGroup",
522
+ "seg": "_72qoAq_seg",
523
+ "segOn": "_72qoAq_segOn",
524
+ "skillContent": "_72qoAq_skillContent",
525
+ "sourceTabsRow": "_72qoAq_sourceTabsRow",
526
+ "sourceTabsScroll": "_72qoAq_sourceTabsScroll",
527
+ "spacer": "_72qoAq_spacer",
528
+ "src": "_72qoAq_src",
529
+ "srcTab": "_72qoAq_srcTab",
530
+ "srcTabDel": "_72qoAq_srcTabDel",
531
+ "srcTabEdit": "_72qoAq_srcTabEdit",
532
+ "srcTabMain": "_72qoAq_srcTabMain",
533
+ "srcTabOn": "_72qoAq_srcTabOn",
534
+ "staticId": "_72qoAq_staticId",
535
+ "staticIdValue": "_72qoAq_staticIdValue",
536
+ "sub": "_72qoAq_sub",
537
+ "surfaceSwitch": "_72qoAq_surfaceSwitch",
538
+ "switchOff": "_72qoAq_switchOff",
539
+ "switchOn": "_72qoAq_switchOn",
540
+ "switchThumb": "_72qoAq_switchThumb",
541
+ "tag": "_72qoAq_tag",
542
+ "title": "_72qoAq_title",
543
+ "titleRow": "_72qoAq_titleRow",
544
+ "version": "_72qoAq_version",
545
+ "warnLine": "_72qoAq_warnLine"
546
+ };
547
+ //#endregion
548
+ //#region src/client/features/market/SourceTab.tsx
549
+ /** A source tab with trailing edit and delete controls. */
550
+ /** A source chip with a trailing delete control (deletion confirms at the section level). */
551
+ function SourceTab(props) {
552
+ const { t, active = false, label, onSelect, onDelete, onEdit } = props;
553
+ return (0, react.createElement)("div", { className: active ? market_module_default.srcTabOn : market_module_default.srcTab }, (0, react.createElement)("button", {
554
+ type: "button",
555
+ className: market_module_default.srcTabMain,
556
+ onClick: onSelect
557
+ }, label), onEdit === void 0 ? null : (0, react.createElement)("button", {
558
+ type: "button",
559
+ className: market_module_default.srcTabEdit,
560
+ title: t("editSource"),
561
+ onClick: (event) => {
562
+ event.stopPropagation();
563
+ onEdit();
564
+ }
565
+ }, "✎"), onDelete === void 0 ? null : (0, react.createElement)("button", {
566
+ type: "button",
567
+ className: market_module_default.srcTabDel,
568
+ title: t("remove"),
569
+ onClick: (event) => {
570
+ event.stopPropagation();
571
+ onDelete();
572
+ }
573
+ }, "×"));
574
+ }
575
+ //#endregion
576
+ //#region src/client/features/market/SourceEditorModal.tsx
577
+ /** Source editor modal for adding or editing a catalog source. */
578
+ function SourceEditorModal(props) {
579
+ const { t, editor } = props;
580
+ const [local, setLocal] = (0, react.useState)(editor.mode === "edit" && editor.source.local === true);
581
+ const [url, setUrl] = (0, react.useState)(editor.mode === "edit" ? editor.source.url : "");
582
+ const [branch, setBranch] = (0, react.useState)(editor.mode === "edit" ? editor.source.branch ?? "" : "");
583
+ const id = editor.mode === "edit" ? editor.source.id : "";
584
+ const title = editor.mode === "edit" ? t("editSourceTitle") : t("addSourceTitle");
585
+ return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
586
+ open: true,
587
+ onClose: props.onClose,
588
+ title,
589
+ description: t("editorHint"),
590
+ closeLabel: t("cancel"),
591
+ className: market_module_default.editorDialog,
592
+ footer: (0, react.createElement)("div", { className: market_module_default.modalFooter }, (0, react.createElement)("div", { className: market_module_default.modalFooterLeft }, editor.mode === "edit" ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
593
+ variant: "ghost",
594
+ onClick: () => props.onRemove(id)
595
+ }, `🗑 ${t("remove")}`) : null), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
596
+ variant: "ghost",
597
+ onClick: props.onClose
598
+ }, t("cancel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
599
+ variant: "primary",
600
+ disabled: props.busy,
601
+ onClick: () => {
602
+ props.onSave(url.trim(), branch.trim(), local);
603
+ }
604
+ }, t("save"))),
605
+ children: (0, react.createElement)("div", { className: market_module_default.editorForm }, (0, react.createElement)("div", { className: market_module_default.modeRow }, (0, react.createElement)("button", {
606
+ type: "button",
607
+ className: local ? market_module_default.seg : market_module_default.segOn,
608
+ onClick: () => setLocal(false)
609
+ }, t("sourceModeGit")), (0, react.createElement)("button", {
610
+ type: "button",
611
+ className: local ? market_module_default.segOn : market_module_default.seg,
612
+ onClick: () => setLocal(true)
613
+ }, 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, {
614
+ placeholder: local ? t("sourceUrlLocalPh") : t("sourceUrlPh"),
615
+ value: url,
616
+ onChange: (event) => setUrl(event.target.value)
617
+ }), (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, {
618
+ placeholder: t("branchPh"),
619
+ value: branch,
620
+ onChange: (event) => setBranch(event.target.value)
621
+ }), (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}`)))
622
+ });
623
+ }
624
+ //#endregion
625
+ //#region src/client/ui/ToggleSwitch.tsx
626
+ /** Shared green/gray switch control used by suite cards. */
627
+ /** A green/gray switch control for suite enable state. */
628
+ function ToggleSwitch(props) {
629
+ return (0, react.createElement)("button", {
630
+ type: "button",
631
+ role: "switch",
632
+ "aria-checked": props.on,
633
+ title: props.title,
634
+ disabled: props.disabled,
635
+ className: props.on ? market_module_default.switchOn : market_module_default.switchOff,
636
+ onClick: (event) => {
637
+ event.stopPropagation();
638
+ props.onChange();
639
+ }
640
+ }, (0, react.createElement)("span", { className: market_module_default.switchThumb }));
641
+ }
642
+ //#endregion
643
+ //#region src/client/features/market/SuiteCard.tsx
644
+ /** A suite card in the market grid/list. */
645
+ function SuiteCard(props) {
646
+ const { t, suite, busy } = props;
647
+ const tags = [
648
+ [t("surfaceSkills"), suite.surfaces.skills],
649
+ [t("surfaceMcp"), suite.surfaces.mcp],
650
+ [t("surfaceHooks"), suite.surfaces.hooks],
651
+ [t("surfaceCommands"), suite.surfaces.commands],
652
+ [t("surfaceAgents"), suite.surfaces.agents],
653
+ [t("surfaceLsp"), suite.surfaces.lsp]
654
+ ].filter(([, count]) => count > 0);
655
+ 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") : t("layoutSkills");
656
+ const isRemote = suite.remoteUrl !== void 0;
657
+ const stop = (callback) => (event) => {
658
+ event.stopPropagation();
659
+ callback();
660
+ };
661
+ return (0, react.createElement)("article", {
662
+ className: market_module_default.card,
663
+ onClick: props.onOpen
664
+ }, (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, {
665
+ on: suite.enabled,
666
+ disabled: busy,
667
+ title: suite.enabled ? t("disable") : t("enable"),
668
+ onChange: props.onToggle
669
+ }) : isRemote ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
670
+ variant: "primary",
671
+ size: "sm",
672
+ disabled: busy,
673
+ title: suite.remoteUrl,
674
+ onClick: stop(props.onAddSource)
675
+ }, t("addSource")) : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
676
+ variant: "primary",
677
+ size: "sm",
678
+ disabled: busy,
679
+ onClick: stop(props.onInstall)
680
+ }, t("install")), suite.installed ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
681
+ variant: "ghost",
682
+ size: "sm",
683
+ title: t("refresh"),
684
+ disabled: busy,
685
+ onClick: stop(props.onRefresh)
686
+ }, "↻") : null, suite.installed ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
687
+ variant: "ghost",
688
+ size: "sm",
689
+ title: t("uninstall"),
690
+ disabled: busy,
691
+ onClick: stop(props.onUninstall)
692
+ }, "🗑") : 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", {
693
+ key: label,
694
+ className: market_module_default.tag
695
+ }, `${label} ${count}`)), suite.errors.length === 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
696
+ label: suite.errors.slice(0, 8).join(t("sourceErrorSeparator")),
697
+ children: (0, react.createElement)("span", { className: market_module_default.warnLine }, `⚠ ${t("errors")} ${suite.errors.length}`)
698
+ }), (suite.mcpErrors?.length ?? 0) === 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
699
+ label: suite.mcpErrors.slice(0, 8).join(t("sourceErrorSeparator")),
700
+ children: (0, react.createElement)("span", { className: market_module_default.warnLine }, `⚠ ${t("mcpSection")} ${suite.mcpErrors.length}`)
701
+ })));
702
+ }
703
+ //#endregion
704
+ //#region src/client/ui/StatusIcon.tsx
705
+ /** Shared status icon used by market and MCP status filter tabs. */
706
+ /** An SVG status icon for the all/installed/uninstalled filter tabs. */
707
+ function StatusIcon({ kind }) {
708
+ const common = {
709
+ width: 16,
710
+ height: 16,
711
+ viewBox: "0 0 16 16",
712
+ fill: "none",
713
+ "aria-hidden": true
714
+ };
715
+ if (kind === "installed") return (0, react.createElement)("svg", common, (0, react.createElement)("circle", {
716
+ cx: 8,
717
+ cy: 8,
718
+ r: 5.5
719
+ }), (0, react.createElement)("path", { d: "m5.5 8 1.7 1.7 3.4-3.4" }));
720
+ if (kind === "uninstalled") return (0, react.createElement)("svg", common, (0, react.createElement)("path", { d: "M8 2v8m-3-3 3 3 3-3M3 13h10" }));
721
+ 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" }));
722
+ }
723
+ //#endregion
271
724
  //#region src/client/ErrorBoundary.tsx
272
725
  /**
273
726
  * Error boundary for untrusted preview content.
@@ -290,86 +743,18 @@ var ErrorBoundary = class extends react.Component {
290
743
  }
291
744
  };
292
745
  //#endregion
293
- //#region src/client/market.module.css
294
- var market_module_default = {
295
- "body": "qMtKNa_body",
296
- "card": "qMtKNa_card",
297
- "cardActions": "qMtKNa_cardActions",
298
- "cardDesc": "qMtKNa_cardDesc",
299
- "cardName": "qMtKNa_cardName",
300
- "cardTitle": "qMtKNa_cardTitle",
301
- "cardTop": "qMtKNa_cardTop",
302
- "desc": "qMtKNa_desc",
303
- "detailBody": "qMtKNa_detailBody",
304
- "detailCell": "qMtKNa_detailCell",
305
- "detailChevron": "qMtKNa_detailChevron",
306
- "detailDesc": "qMtKNa_detailDesc",
307
- "detailDialog": "qMtKNa_detailDialog",
308
- "detailGrid": "qMtKNa_detailGrid",
309
- "detailHead": "qMtKNa_detailHead",
310
- "detailItem": "qMtKNa_detailItem",
311
- "detailItemDesc": "qMtKNa_detailItemDesc",
312
- "detailItemName": "qMtKNa_detailItemName",
313
- "detailItemOpen": "qMtKNa_detailItemOpen",
314
- "detailItemRow": "qMtKNa_detailItemRow",
315
- "detailKey": "qMtKNa_detailKey",
316
- "detailSection": "qMtKNa_detailSection",
317
- "detailSections": "qMtKNa_detailSections",
318
- "detailValue": "qMtKNa_detailValue",
319
- "dshApmSpin": "qMtKNa_dshApmSpin",
320
- "editorDialog": "qMtKNa_editorDialog",
321
- "editorForm": "qMtKNa_editorForm",
322
- "empty": "qMtKNa_empty",
323
- "fieldGroup": "qMtKNa_fieldGroup",
324
- "fieldHint": "qMtKNa_fieldHint",
325
- "fieldLabel": "qMtKNa_fieldLabel",
326
- "grid": "qMtKNa_grid",
327
- "header": "qMtKNa_header",
328
- "list": "qMtKNa_list",
329
- "market": "qMtKNa_market",
330
- "meta": "qMtKNa_meta",
331
- "modalFooter": "qMtKNa_modalFooter",
332
- "modalFooterLeft": "qMtKNa_modalFooterLeft",
333
- "modeRow": "qMtKNa_modeRow",
334
- "mono": "qMtKNa_mono",
335
- "okState": "qMtKNa_okState",
336
- "progress": "qMtKNa_progress",
337
- "progressError": "qMtKNa_progressError",
338
- "progressFail": "qMtKNa_progressFail",
339
- "progressSpin": "qMtKNa_progressSpin",
340
- "progressText": "qMtKNa_progressText",
341
- "searchGroup": "qMtKNa_searchGroup",
342
- "searchInput": "qMtKNa_searchInput",
343
- "searchWrap": "qMtKNa_searchWrap",
344
- "seg": "qMtKNa_seg",
345
- "segOn": "qMtKNa_segOn",
346
- "skillContent": "qMtKNa_skillContent",
347
- "sourceTabsRow": "qMtKNa_sourceTabsRow",
348
- "sourceTabsScroll": "qMtKNa_sourceTabsScroll",
349
- "spacer": "qMtKNa_spacer",
350
- "src": "qMtKNa_src",
351
- "srcTab": "qMtKNa_srcTab",
352
- "srcTabDel": "qMtKNa_srcTabDel",
353
- "srcTabEdit": "qMtKNa_srcTabEdit",
354
- "srcTabMain": "qMtKNa_srcTabMain",
355
- "srcTabOn": "qMtKNa_srcTabOn",
356
- "staticId": "qMtKNa_staticId",
357
- "staticIdValue": "qMtKNa_staticIdValue",
358
- "sub": "qMtKNa_sub",
359
- "switchOff": "qMtKNa_switchOff",
360
- "switchOn": "qMtKNa_switchOn",
361
- "switchThumb": "qMtKNa_switchThumb",
362
- "tab": "qMtKNa_tab",
363
- "tabGap": "qMtKNa_tabGap",
364
- "tabOn": "qMtKNa_tabOn",
365
- "tabRow": "qMtKNa_tabRow",
366
- "tag": "qMtKNa_tag",
367
- "title": "qMtKNa_title",
368
- "titleRow": "qMtKNa_titleRow",
369
- "version": "qMtKNa_version",
370
- "viewSwitch": "qMtKNa_viewSwitch",
371
- "warnLine": "qMtKNa_warnLine"
372
- };
746
+ //#region src/client/features/suite-detail/suite-detail-resource.ts
747
+ /** Create a request guard for one detail modal instance. */
748
+ function createLatestRequestGuard() {
749
+ let revision = 0;
750
+ return {
751
+ next: () => ++revision,
752
+ invalidate: () => {
753
+ revision++;
754
+ },
755
+ isCurrent: (requestId) => requestId === revision
756
+ };
757
+ }
373
758
  //#endregion
374
759
  //#region src/client/SuiteDetail.tsx
375
760
  /**
@@ -386,12 +771,16 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
386
771
  const [openSkill, setOpenSkill] = (0, react.useState)(void 0);
387
772
  const [skillText, setSkillText] = (0, react.useState)(void 0);
388
773
  const [skillLoading, setSkillLoading] = (0, react.useState)(false);
774
+ const skillRequestGuard = (0, react.useRef)(createLatestRequestGuard());
389
775
  const [openMcp, setOpenMcp] = (0, react.useState)(void 0);
390
776
  const [openPreview, setOpenPreview] = (0, react.useState)(void 0);
391
777
  (0, react.useEffect)(() => {
392
778
  let cancelled = false;
779
+ skillRequestGuard.current.invalidate();
393
780
  setDetail(void 0);
394
781
  setError(void 0);
782
+ setOpenSkill(void 0);
783
+ setSkillText(void 0);
395
784
  fetchSuiteDetail(sourceId, suiteId).then((value) => {
396
785
  if (!cancelled) setDetail(value);
397
786
  }).catch((reason) => {
@@ -399,9 +788,11 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
399
788
  });
400
789
  return () => {
401
790
  cancelled = true;
791
+ skillRequestGuard.current.invalidate();
402
792
  };
403
793
  }, [sourceId, suiteId]);
404
794
  const toggleSkill = async (name) => {
795
+ const requestId = skillRequestGuard.current.next();
405
796
  if (openSkill === name) {
406
797
  setOpenSkill(void 0);
407
798
  return;
@@ -411,17 +802,17 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
411
802
  setSkillText(void 0);
412
803
  try {
413
804
  const content = await fetchSkillContent(sourceId, suiteId, name);
414
- setSkillText(content.content);
805
+ if (skillRequestGuard.current.isCurrent(requestId)) setSkillText(content.content);
415
806
  } catch (reason) {
416
- setSkillText(`⚠ ${reason instanceof Error ? reason.message : String(reason)}`);
807
+ if (skillRequestGuard.current.isCurrent(requestId)) setSkillText(`⚠ ${reason instanceof Error ? reason.message : String(reason)}`);
417
808
  } finally {
418
- setSkillLoading(false);
809
+ if (skillRequestGuard.current.isCurrent(requestId)) setSkillLoading(false);
419
810
  }
420
811
  };
421
812
  const toggleMcp = (key) => {
422
813
  setOpenMcp(openMcp === key ? void 0 : key);
423
814
  };
424
- const layoutLabel = detail === void 0 ? "" : detail.layout === "agent-plugin-v1" ? t("layoutV1") : detail.layout === "claude-code" ? t("layoutCC") : detail.layout === "codex" ? t("layoutCodex") : detail.layout === "remote" ? t("layoutRemote") : t("layoutSkills");
815
+ const layoutLabel = detail === void 0 ? "" : detail.layout === "agent-plugin-v1" ? t("layoutV1") : detail.layout === "claude-code" ? t("layoutCC") : detail.layout === "codex" ? t("layoutCodex") : detail.layout === "universal" ? t("layoutUniversal") : detail.layout === "cursor" ? t("layoutCursor") : detail.layout === "kimi" ? t("layoutKimi") : detail.layout === "remote" ? t("layoutRemote") : t("layoutSkills");
425
816
  return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
426
817
  open: true,
427
818
  onClose,
@@ -448,7 +839,7 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
448
839
  }, (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", {
449
840
  className: market_module_default.warnLine,
450
841
  style: { margin: "0 0 6px" }
451
- }, `⚠ ${detail.mcpErrors.join(";")}`), detail.mcpServers.length === 0 ? (0, react.createElement)("div", { className: market_module_default.sidebarEmpty }, "—") : detail.mcpServers.map((server) => (0, react.createElement)("div", {
842
+ }, `⚠ ${detail.mcpErrors.join(t("sourceErrorSeparator"))}`), detail.mcpServers.length === 0 ? (0, react.createElement)("div", { className: market_module_default.sidebarEmpty }, "—") : detail.mcpServers.map((server) => (0, react.createElement)("div", {
452
843
  key: server.key,
453
844
  className: market_module_default.detailItem
454
845
  }, (0, react.createElement)("button", {
@@ -498,7 +889,7 @@ function mcpSummary(server) {
498
889
  return server.url ?? server.type;
499
890
  }
500
891
  function PreviewRow(props) {
501
- const { t: _t, name, description, open, onToggle, children } = props;
892
+ const { name, description, open, onToggle, children } = props;
502
893
  return (0, react.createElement)("div", { className: market_module_default.detailItem }, (0, react.createElement)("button", {
503
894
  type: "button",
504
895
  className: open ? market_module_default.detailItemOpen : market_module_default.detailItemRow,
@@ -506,6 +897,87 @@ function PreviewRow(props) {
506
897
  }, (0, react.createElement)("span", { className: market_module_default.detailItemName }, name), description === void 0 ? null : (0, react.createElement)("span", { className: market_module_default.detailItemDesc }, description), (0, react.createElement)("span", { className: market_module_default.detailChevron }, open ? "▾" : "▸")), open ? (0, react.createElement)("div", { className: market_module_default.skillContent }, children) : null);
507
898
  }
508
899
  //#endregion
900
+ //#region src/client/SearchFilterToolbar.module.css
901
+ var SearchFilterToolbar_module_default = {
902
+ "filter": "vavGuW_filter",
903
+ "filterCount": "vavGuW_filterCount",
904
+ "filterGap": "vavGuW_filterGap",
905
+ "filterOn": "vavGuW_filterOn",
906
+ "search": "vavGuW_search",
907
+ "toolbar": "vavGuW_toolbar",
908
+ "viewGap": "vavGuW_viewGap",
909
+ "viewSwitch": "vavGuW_viewSwitch"
910
+ };
911
+ //#endregion
912
+ //#region src/client/SearchFilterToolbar.tsx
913
+ /**
914
+ * Shared search, filter, and view controls for catalog-style settings panels.
915
+ */
916
+ /**
917
+ * Render a consistent control row for searchable grid and list content.
918
+ *
919
+ * @param props - Search state, selectable filters, and view-mode state.
920
+ * @returns Search input, filter tabs, and an accessible grid/list toggle.
921
+ */
922
+ function SearchFilterToolbar(props) {
923
+ const nextView = props.view === "grid" ? "list" : "grid";
924
+ const nextViewLabel = nextView === "grid" ? props.gridLabel : props.listLabel;
925
+ return (0, react.createElement)("div", { className: props.className === void 0 ? SearchFilterToolbar_module_default.toolbar : `${SearchFilterToolbar_module_default.toolbar} ${props.className}` }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Input, {
926
+ className: SearchFilterToolbar_module_default.search,
927
+ value: props.search,
928
+ placeholder: props.searchPlaceholder,
929
+ "aria-label": props.searchLabel,
930
+ onChange: (event) => props.onSearchChange(event.target.value)
931
+ }), (0, react.createElement)("div", { className: SearchFilterToolbar_module_default.filterGap }), ...props.filters.map((filter) => (0, react.createElement)("button", {
932
+ key: filter.id,
933
+ type: "button",
934
+ className: filter.active ? SearchFilterToolbar_module_default.filterOn : SearchFilterToolbar_module_default.filter,
935
+ title: `${filter.label} ${filter.count}`,
936
+ "aria-label": `${filter.label} ${filter.count}`,
937
+ onClick: filter.onSelect
938
+ }, 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", {
939
+ type: "button",
940
+ className: SearchFilterToolbar_module_default.viewSwitch,
941
+ "aria-label": nextViewLabel,
942
+ title: nextViewLabel,
943
+ onClick: () => props.onViewChange(nextView)
944
+ }, (0, react.createElement)(ViewIcon, { mode: nextView })));
945
+ }
946
+ function ViewIcon({ mode }) {
947
+ const common = {
948
+ width: 16,
949
+ height: 16,
950
+ viewBox: "0 0 16 16",
951
+ fill: "none",
952
+ "aria-hidden": true
953
+ };
954
+ return mode === "list" ? (0, react.createElement)("svg", common, (0, react.createElement)("path", { d: "M3 4h10M3 8h10M3 12h10" })) : (0, react.createElement)("svg", common, (0, react.createElement)("rect", {
955
+ x: 2.5,
956
+ y: 2.5,
957
+ width: 4,
958
+ height: 4,
959
+ rx: .8
960
+ }), (0, react.createElement)("rect", {
961
+ x: 9.5,
962
+ y: 2.5,
963
+ width: 4,
964
+ height: 4,
965
+ rx: .8
966
+ }), (0, react.createElement)("rect", {
967
+ x: 2.5,
968
+ y: 9.5,
969
+ width: 4,
970
+ height: 4,
971
+ rx: .8
972
+ }), (0, react.createElement)("rect", {
973
+ x: 9.5,
974
+ y: 9.5,
975
+ width: 4,
976
+ height: 4,
977
+ rx: .8
978
+ }));
979
+ }
980
+ //#endregion
509
981
  //#region src/client/MarketSection.tsx
510
982
  /**
511
983
  * The Agent Plugins Market settings section.
@@ -520,73 +992,17 @@ const PROGRESS_STEP_LABELS = {
520
992
  cloning: "progressCloning",
521
993
  reading: "progressReading"
522
994
  };
523
- /**
524
- * Poll the host's source-mutation progress while an add-source request runs.
525
- * Failures of the poll itself never surface: the add request is the authority.
526
- */
527
- function startProgressPolling(report) {
528
- let stopped = false;
529
- const tick = async () => {
530
- if (stopped) return;
531
- try {
532
- const progress = await fetchSourceProgress();
533
- if (!stopped && progress.active) report({
534
- step: progressStepLabel(progress.step),
535
- error: void 0
536
- });
537
- } catch {}
538
- if (!stopped) timer = setTimeout(tick, 800);
539
- };
540
- let timer = setTimeout(tick, 400);
541
- return { stop: () => {
542
- stopped = true;
543
- clearTimeout(timer);
544
- } };
995
+ function progressStepLabel(t, step) {
996
+ const key = PROGRESS_STEP_LABELS[step];
997
+ return key === void 0 ? step : t(key);
545
998
  }
546
- function progressStepLabel(step) {
547
- return PROGRESS_STEP_LABELS[step] ?? step;
999
+ /** Keep parameterized copy compatible with hosts whose bound translator ignores params. */
1000
+ function interpolate(text, params) {
1001
+ return text.replace(/\{(\w+)\}/g, (match, key) => key in params ? String(params[key]) : match);
548
1002
  }
549
- const EMPTY_OVERVIEW = {
550
- sources: [],
551
- suites: [],
552
- totals: {
553
- all: 0,
554
- installed: 0,
555
- enabled: 0
556
- },
557
- roots: {
558
- user: "",
559
- data: ""
560
- }
561
- };
562
- /**
563
- * Session-level overview cache: the first mount paints the last snapshot
564
- * instantly (no empty-state flash on reopen), then revalidates in the
565
- * background. Every refresh overwrites the cached copy.
566
- */
567
- let cachedOverview;
568
- let inflightOverview;
569
- function loadOverview() {
570
- const initial = cachedOverview ?? EMPTY_OVERVIEW;
571
- if (inflightOverview === void 0) inflightOverview = fetchOverview().then((data) => {
572
- cachedOverview = data;
573
- return data;
574
- }).finally(() => {
575
- inflightOverview = void 0;
576
- });
577
- return {
578
- initial,
579
- revalidating: cachedOverview === void 0,
580
- promise: inflightOverview
581
- };
582
- }
583
- /** Invalidate the cached overview after any mutating action. */
584
- function dropCachedOverview() {
585
- cachedOverview = void 0;
586
- }
587
- function MarketSection({ t }) {
1003
+ function MarketSection({ t, mode = "settings" }) {
588
1004
  const [overview, setOverview] = (0, react.useState)(() => loadOverview().initial);
589
- const [loading, setLoading] = (0, react.useState)(() => cachedOverview === void 0);
1005
+ const [loading, setLoading] = (0, react.useState)(() => loadOverview().revalidating);
590
1006
  const [search, setSearch] = (0, react.useState)("");
591
1007
  const [tab, setTab] = (0, react.useState)("all");
592
1008
  const [category, setCategory] = (0, react.useState)("all");
@@ -601,7 +1017,7 @@ function MarketSection({ t }) {
601
1017
  error: void 0
602
1018
  });
603
1019
  const refresh = (0, react.useCallback)(async () => {
604
- dropCachedOverview();
1020
+ invalidateOverview();
605
1021
  try {
606
1022
  const data = await loadOverview().promise;
607
1023
  setOverview(data);
@@ -621,7 +1037,7 @@ function MarketSection({ t }) {
621
1037
  setBusy(key);
622
1038
  try {
623
1039
  await postAction(path, body);
624
- dropCachedOverview();
1040
+ invalidateOverview();
625
1041
  await refresh();
626
1042
  return true;
627
1043
  } catch (error) {
@@ -634,25 +1050,7 @@ function MarketSection({ t }) {
634
1050
  setBusy(void 0);
635
1051
  }
636
1052
  }, [refresh, t]);
637
- const scopeTotals = (0, react.useMemo)(() => {
638
- if (category === "all") return overview.totals;
639
- const scoped = overview.suites.filter((suite) => suite.sourceId === category);
640
- return {
641
- all: scoped.length,
642
- installed: scoped.filter((suite) => suite.installed).length,
643
- enabled: scoped.filter((suite) => suite.enabled).length
644
- };
645
- }, [overview, category]);
646
- const filtered = (0, react.useMemo)(() => {
647
- const needle = search.trim().toLowerCase();
648
- return overview.suites.filter((suite) => {
649
- if (category !== "all" && suite.sourceId !== category) return false;
650
- if (tab === "installed" && !suite.installed) return false;
651
- if (tab === "uninstalled" && suite.installed) return false;
652
- if (needle === "") return true;
653
- return `${suite.name} ${suite.description ?? ""} ${suite.keywords.join(" ")}`.toLowerCase().includes(needle);
654
- });
655
- }, [
1053
+ const { scopeTotals, filtered } = (0, react.useMemo)(() => deriveMarketViewModel(overview, search, tab, category), [
656
1054
  overview,
657
1055
  search,
658
1056
  tab,
@@ -684,7 +1082,7 @@ function MarketSection({ t }) {
684
1082
  const selectedSource = category === "all" ? void 0 : overview.sources.find((source) => source.id === category);
685
1083
  return (0, react.createElement)(ErrorBoundary, {
686
1084
  fallback: (error) => (0, react.createElement)("div", { className: market_module_default.empty }, `${t("actionFail")}: ${error.message}`),
687
- children: (0, react.createElement)("div", { className: 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)("p", { className: market_module_default.sub }, t("subtitle")), (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, {
1085
+ 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, {
688
1086
  variant: "ghost",
689
1087
  size: "sm",
690
1088
  title: t("addSource"),
@@ -696,12 +1094,7 @@ function MarketSection({ t }) {
696
1094
  onClick: () => {
697
1095
  action("s:refresh:all", "sources/refresh", {});
698
1096
  }
699
- }, "↻"), (0, react.createElement)("div", { className: market_module_default.searchWrap }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Input, {
700
- className: market_module_default.searchInput,
701
- placeholder: t("searchPh"),
702
- value: search,
703
- onChange: (event) => setSearch(event.target.value)
704
- })))), (0, react.createElement)("div", { className: market_module_default.sourceTabsRow }, (0, react.createElement)("div", { className: market_module_default.sourceTabsScroll }, (0, react.createElement)(SourceTab, {
1097
+ }, "↻"))), (0, react.createElement)("div", { className: market_module_default.marketControls }, (0, react.createElement)("div", { className: market_module_default.sourceTabsRow }, (0, react.createElement)("div", { className: market_module_default.sourceTabsScroll }, (0, react.createElement)(SourceTab, {
705
1098
  key: "__all__",
706
1099
  t,
707
1100
  active: category === "all",
@@ -721,26 +1114,42 @@ function MarketSection({ t }) {
721
1114
  mode: "edit",
722
1115
  source
723
1116
  }) : void 0
724
- })))), (0, react.createElement)("div", { className: market_module_default.tabRow }, (0, react.createElement)(TabButton, {
725
- t,
726
- active: tab === "all",
727
- label: `${t("tabAll")} ${scopeTotals.all}`,
728
- onClick: () => setTab("all")
729
- }), (0, react.createElement)(TabButton, {
730
- t,
731
- active: tab === "installed",
732
- label: `${t("tabInstalled")} ${scopeTotals.installed}`,
733
- onClick: () => setTab("installed")
734
- }), (0, react.createElement)(TabButton, {
735
- t,
736
- active: tab === "uninstalled",
737
- label: `${t("tabUninstalled")} ${scopeTotals.all - scopeTotals.installed}`,
738
- onClick: () => setTab("uninstalled")
739
- }), (0, react.createElement)("div", { className: market_module_default.tabGap }), (0, react.createElement)("button", {
740
- type: "button",
741
- className: market_module_default.viewSwitch,
742
- onClick: () => setView(view === "grid" ? "list" : "grid")
743
- }, view === "grid" ? t("list") : t("grid")))), (0, react.createElement)("main", { className: view === "grid" ? market_module_default.grid : market_module_default.list }, loading ? (0, react.createElement)("div", { className: market_module_default.empty }, "…") : filtered.length === 0 ? (0, react.createElement)("div", { className: market_module_default.empty }, tab === "installed" ? t("installedEmpty") : t("empty")) : filtered.map((suite) => (0, react.createElement)(SuiteCard, {
1117
+ })))), (0, react.createElement)(SearchFilterToolbar, {
1118
+ search,
1119
+ searchLabel: t("searchPh"),
1120
+ searchPlaceholder: t("searchPh"),
1121
+ onSearchChange: setSearch,
1122
+ filters: [
1123
+ {
1124
+ id: "all",
1125
+ label: t("tabAll"),
1126
+ count: scopeTotals.all,
1127
+ icon: (0, react.createElement)(StatusIcon, { kind: "all" }),
1128
+ active: tab === "all",
1129
+ onSelect: () => setTab("all")
1130
+ },
1131
+ {
1132
+ id: "installed",
1133
+ label: t("tabInstalled"),
1134
+ count: scopeTotals.installed,
1135
+ icon: (0, react.createElement)(StatusIcon, { kind: "installed" }),
1136
+ active: tab === "installed",
1137
+ onSelect: () => setTab("installed")
1138
+ },
1139
+ {
1140
+ id: "uninstalled",
1141
+ label: t("tabUninstalled"),
1142
+ count: scopeTotals.all - scopeTotals.installed,
1143
+ icon: (0, react.createElement)(StatusIcon, { kind: "uninstalled" }),
1144
+ active: tab === "uninstalled",
1145
+ onSelect: () => setTab("uninstalled")
1146
+ }
1147
+ ],
1148
+ view,
1149
+ gridLabel: t("grid"),
1150
+ listLabel: t("list"),
1151
+ onViewChange: (nextView) => setView(nextView)
1152
+ }))), (0, react.createElement)("main", { className: view === "grid" ? market_module_default.grid : market_module_default.list }, loading ? (0, react.createElement)("div", { className: market_module_default.empty }, t("loading")) : filtered.length === 0 ? (0, react.createElement)("div", { className: market_module_default.empty }, tab === "installed" ? t("installedEmpty") : t("empty")) : filtered.map((suite) => (0, react.createElement)(SuiteCard, {
744
1153
  key: `${suite.sourceId}/${suite.suiteId}`,
745
1154
  t,
746
1155
  suite,
@@ -776,7 +1185,7 @@ function MarketSection({ t }) {
776
1185
  }), confirm === void 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
777
1186
  open: true,
778
1187
  onClose: () => setConfirm(void 0),
779
- title: confirm.kind === "uninstall" ? t("uninstallConfirmTitle") : `${t("removeSourceConfirmTitle")}「${confirm.sourceId}」`,
1188
+ title: confirm.kind === "uninstall" ? t("uninstallConfirmTitle") : interpolate(t("removeSourceConfirmTitle", { sourceId: confirm.sourceId }), { sourceId: confirm.sourceId }),
780
1189
  closeLabel: t("cancel"),
781
1190
  description: confirm.kind === "uninstall" ? t("uninstallConfirmDesc") : t("removeSourceConfirmDesc"),
782
1191
  footer: (0, react.createElement)("div", { className: market_module_default.modalFooter }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
@@ -812,10 +1221,10 @@ function MarketSection({ t }) {
812
1221
  step: t("progressStarting"),
813
1222
  error: void 0
814
1223
  });
815
- const poll = startProgressPolling(setProgress);
1224
+ const poll = startSourceProgressPolling(setProgress, (step) => progressStepLabel(t, step));
816
1225
  try {
817
1226
  const derived = (await postAction("sources/add", body))["source"]?.id;
818
- dropCachedOverview();
1227
+ invalidateOverview();
819
1228
  await refresh();
820
1229
  setEditor(void 0);
821
1230
  if (derived !== void 0) setCategory(derived);
@@ -852,165 +1261,483 @@ function MarketSection({ t }) {
852
1261
  }))
853
1262
  });
854
1263
  }
855
- function TabButton({ t: _t, active, label, onClick }) {
1264
+ //#endregion
1265
+ //#region src/client/features/mcp-status/mcp-status-view-model.ts
1266
+ const searchableCache = /* @__PURE__ */ new WeakMap();
1267
+ /** Derive active rows, filter counts, and visible rows in one pass. */
1268
+ function deriveMcpStatusViewModel(payload, filter, search) {
1269
+ const searchable = searchableFor(payload);
1270
+ const activeEntries = searchable.map((item) => item.entry);
1271
+ const filterCounts = {
1272
+ all: 0,
1273
+ plugin: 0,
1274
+ direct: 0
1275
+ };
1276
+ let connected = 0;
1277
+ let failed = 0;
1278
+ const filtered = [];
1279
+ const needle = search.trim().toLowerCase();
1280
+ for (const item of searchable) {
1281
+ const entry = item.entry;
1282
+ filterCounts.all++;
1283
+ filterCounts[entry.kind]++;
1284
+ if (entry.state === "connected") connected++;
1285
+ if (entry.state === "failed") failed++;
1286
+ if (filter !== "all" && entry.kind !== filter) continue;
1287
+ if (needle !== "" && !item.haystack.includes(needle)) continue;
1288
+ filtered.push(entry);
1289
+ }
1290
+ return {
1291
+ activeEntries,
1292
+ filtered,
1293
+ filterCounts,
1294
+ visibleTotals: {
1295
+ all: activeEntries.length,
1296
+ connected,
1297
+ failed
1298
+ }
1299
+ };
1300
+ }
1301
+ function searchableFor(payload) {
1302
+ const cached = searchableCache.get(payload);
1303
+ if (cached !== void 0) return cached;
1304
+ const searchable = payload.entries.filter((entry) => entry.state !== "disabled").map((entry) => ({
1305
+ entry,
1306
+ haystack: `${entry.name} ${entry.source ?? ""} ${entry.endpoint ?? ""} ${entry.transport}`.toLowerCase()
1307
+ }));
1308
+ searchableCache.set(payload, searchable);
1309
+ return searchable;
1310
+ }
1311
+ //#endregion
1312
+ //#region src/client/mcp-status.module.css
1313
+ var mcp_status_module_default = {
1314
+ "boundary": "AUWlZW_boundary",
1315
+ "card": "AUWlZW_card",
1316
+ "cardReason": "AUWlZW_cardReason",
1317
+ "cardTop": "AUWlZW_cardTop",
1318
+ "chevron": "AUWlZW_chevron",
1319
+ "config": "AUWlZW_config",
1320
+ "detail": "AUWlZW_detail",
1321
+ "detailBody": "AUWlZW_detailBody",
1322
+ "detailDialog": "AUWlZW_detailDialog",
1323
+ "detailEmpty": "AUWlZW_detailEmpty",
1324
+ "detailHead": "AUWlZW_detailHead",
1325
+ "detailMeta": "AUWlZW_detailMeta",
1326
+ "detailSection": "AUWlZW_detailSection",
1327
+ "detailState": "AUWlZW_detailState",
1328
+ "detailStateconnected": "AUWlZW_detailStateconnected",
1329
+ "detailStatedegraded": "AUWlZW_detailStatedegraded",
1330
+ "detailStatedisabled": "AUWlZW_detailStatedisabled",
1331
+ "detailStatefailed": "AUWlZW_detailStatefailed",
1332
+ "empty": "AUWlZW_empty",
1333
+ "endpoint": "AUWlZW_endpoint",
1334
+ "error": "AUWlZW_error",
1335
+ "errorSummary": "AUWlZW_errorSummary",
1336
+ "grid": "AUWlZW_grid",
1337
+ "header": "AUWlZW_header",
1338
+ "headerActions": "AUWlZW_headerActions",
1339
+ "list": "AUWlZW_list",
1340
+ "meta": "AUWlZW_meta",
1341
+ "modalFooter": "AUWlZW_modalFooter",
1342
+ "name": "AUWlZW_name",
1343
+ "reason": "AUWlZW_reason",
1344
+ "service": "AUWlZW_service",
1345
+ "sourceDirect": "AUWlZW_sourceDirect",
1346
+ "sourcePlugin": "AUWlZW_sourcePlugin",
1347
+ "state": "AUWlZW_state",
1348
+ "stateconnected": "AUWlZW_stateconnected",
1349
+ "statedegraded": "AUWlZW_statedegraded",
1350
+ "statedisabled": "AUWlZW_statedisabled",
1351
+ "statefailed": "AUWlZW_statefailed",
1352
+ "statusconnected": "AUWlZW_statusconnected",
1353
+ "statusdegraded": "AUWlZW_statusdegraded",
1354
+ "statusdisabled": "AUWlZW_statusdisabled",
1355
+ "statusDot": "AUWlZW_statusDot",
1356
+ "statusfailed": "AUWlZW_statusfailed",
1357
+ "subtitle": "AUWlZW_subtitle",
1358
+ "summary": "AUWlZW_summary",
1359
+ "summaryDotGreen": "AUWlZW_summaryDotGreen",
1360
+ "summaryDotRed": "AUWlZW_summaryDotRed",
1361
+ "surface": "AUWlZW_surface",
1362
+ "title": "AUWlZW_title",
1363
+ "tool": "AUWlZW_tool",
1364
+ "toolbar": "AUWlZW_toolbar",
1365
+ "toolCount": "AUWlZW_toolCount",
1366
+ "toolDescription": "AUWlZW_toolDescription",
1367
+ "toolIndex": "AUWlZW_toolIndex",
1368
+ "toolList": "AUWlZW_toolList",
1369
+ "toolName": "AUWlZW_toolName",
1370
+ "transport": "AUWlZW_transport"
1371
+ };
1372
+ //#endregion
1373
+ //#region src/client/McpStatusPanel.tsx
1374
+ const EMPTY_STATUS = {
1375
+ entries: [],
1376
+ observedAt: "",
1377
+ totals: {
1378
+ all: 0,
1379
+ connected: 0,
1380
+ degraded: 0,
1381
+ failed: 0,
1382
+ disabled: 0
1383
+ },
1384
+ directObservationOnly: true
1385
+ };
1386
+ /** DSH-native MCP inventory: click a service card for a standard Modal detail. */
1387
+ function McpStatusPanel({ t }) {
1388
+ const [payload, setPayload] = (0, react.useState)(EMPTY_STATUS);
1389
+ const [loading, setLoading] = (0, react.useState)(true);
1390
+ const [error, setError] = (0, react.useState)(void 0);
1391
+ const [filter, setFilter] = (0, react.useState)("all");
1392
+ const [search, setSearch] = (0, react.useState)("");
1393
+ const [view, setView] = (0, react.useState)("grid");
1394
+ const [selected, setSelected] = (0, react.useState)(void 0);
1395
+ const refresh = () => {
1396
+ setLoading(true);
1397
+ setError(void 0);
1398
+ fetchMcpStatus().then(setPayload).catch((caught) => {
1399
+ setError(caught instanceof Error ? caught.message : String(caught));
1400
+ }).finally(() => setLoading(false));
1401
+ };
1402
+ (0, react.useEffect)(() => {
1403
+ refresh();
1404
+ }, []);
1405
+ const { activeEntries, filtered, filterCounts, visibleTotals } = deriveMcpStatusViewModel(payload, filter, search);
1406
+ 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", {
1407
+ className: mcp_status_module_default.errorSummary,
1408
+ title: `${visibleTotals.failed} ${t("mcpFailed")}`
1409
+ }, (0, react.createElement)("span", { className: mcp_status_module_default.summaryDotRed }), visibleTotals.failed) : null, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1410
+ variant: "ghost",
1411
+ size: "sm",
1412
+ onClick: refresh,
1413
+ disabled: loading,
1414
+ title: t("refresh")
1415
+ }, "↻"))), (0, react.createElement)(SearchFilterToolbar, {
1416
+ className: mcp_status_module_default.toolbar,
1417
+ search,
1418
+ searchLabel: t("mcpSearch"),
1419
+ searchPlaceholder: t("mcpSearch"),
1420
+ onSearchChange: setSearch,
1421
+ filters: [
1422
+ "all",
1423
+ "plugin",
1424
+ "direct"
1425
+ ].map((kind) => ({
1426
+ id: kind,
1427
+ label: filterLabel(t, kind),
1428
+ count: filterCounts[kind],
1429
+ icon: (0, react.createElement)(McpFilterIcon, { kind }),
1430
+ active: filter === kind,
1431
+ onSelect: () => setFilter(kind)
1432
+ })),
1433
+ view,
1434
+ gridLabel: t("grid"),
1435
+ listLabel: t("list"),
1436
+ onViewChange: (nextView) => setView(nextView)
1437
+ }), error !== void 0 ? (0, react.createElement)("div", { className: mcp_status_module_default.error }, error, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1438
+ variant: "ghost",
1439
+ size: "sm",
1440
+ onClick: refresh
1441
+ }, t("mcpRetry"))) : loading && activeEntries.length === 0 ? (0, react.createElement)("div", { className: mcp_status_module_default.empty }, t("loading")) : filtered.length === 0 ? (0, react.createElement)("div", { className: mcp_status_module_default.empty }, t("mcpEmpty")) : (0, react.createElement)("div", { className: view === "grid" ? mcp_status_module_default.grid : mcp_status_module_default.list }, filtered.map((entry) => (0, react.createElement)(McpCard, {
1442
+ key: entry.id,
1443
+ entry,
1444
+ t,
1445
+ onClick: () => setSelected(entry)
1446
+ }))), selected === void 0 ? null : (0, react.createElement)(McpDetailModal, {
1447
+ entry: selected,
1448
+ t,
1449
+ onClose: () => setSelected(void 0)
1450
+ }));
1451
+ }
1452
+ function McpCard({ entry, t, onClick }) {
856
1453
  return (0, react.createElement)("button", {
857
1454
  type: "button",
858
- className: active ? market_module_default.tabOn : market_module_default.tab,
1455
+ className: mcp_status_module_default.card,
859
1456
  onClick
860
- }, label);
1457
+ }, (0, react.createElement)("div", { className: mcp_status_module_default.cardTop }, (0, react.createElement)("span", {
1458
+ className: `${mcp_status_module_default.statusDot} ${mcp_status_module_default[`status${entry.state}`]}`,
1459
+ title: stateLabel(t, entry.state),
1460
+ "aria-label": stateLabel(t, entry.state)
1461
+ }), (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, {
1462
+ kind: entry.kind,
1463
+ label: entry.kind === "plugin" ? entry.source ?? "—" : t("mcpDirect"),
1464
+ t
1465
+ }), (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));
861
1466
  }
862
- /** A source tab with a trailing delete control (deletion confirms at the section level). */
863
- function SourceTab(props) {
864
- const { t, active = false, label, onSelect, onDelete, onEdit } = props;
865
- return (0, react.createElement)("div", { className: active ? market_module_default.srcTabOn : market_module_default.srcTab }, (0, react.createElement)("button", {
866
- type: "button",
867
- className: market_module_default.srcTabMain,
868
- onClick: onSelect
869
- }, label), onEdit === void 0 ? null : (0, react.createElement)("button", {
870
- type: "button",
871
- className: market_module_default.srcTabEdit,
872
- title: t("editSource"),
873
- onClick: (event) => {
874
- event.stopPropagation();
875
- onEdit();
876
- }
877
- }, "✎"), onDelete === void 0 ? null : (0, react.createElement)("button", {
878
- type: "button",
879
- className: market_module_default.srcTabDel,
880
- title: t("remove"),
881
- onClick: (event) => {
882
- event.stopPropagation();
883
- onDelete();
884
- }
885
- }, "×"));
1467
+ function McpSourceBadge({ kind, label, t }) {
1468
+ 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")));
886
1469
  }
887
- function SourceEditorModal(props) {
888
- const { t, editor } = props;
889
- const [local, setLocal] = (0, react.useState)(editor.mode === "edit" && editor.source.local === true);
890
- const [url, setUrl] = (0, react.useState)(editor.mode === "edit" ? editor.source.url : "");
891
- const [branch, setBranch] = (0, react.useState)(editor.mode === "edit" ? editor.source.branch ?? "" : "");
892
- const id = editor.mode === "edit" ? editor.source.id : "";
893
- const title = editor.mode === "edit" ? t("editSourceTitle") : t("addSourceTitle");
1470
+ function McpSourceIcon({ kind }) {
1471
+ const common = {
1472
+ width: 16,
1473
+ height: 16,
1474
+ viewBox: "0 0 16 16",
1475
+ fill: "none",
1476
+ "aria-hidden": true
1477
+ };
1478
+ return kind === "plugin" ? (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" })) : (0, react.createElement)("svg", common, (0, react.createElement)("circle", {
1479
+ cx: 8,
1480
+ cy: 5,
1481
+ r: 2.2
1482
+ }), (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" }));
1483
+ }
1484
+ function McpFilterIcon({ kind }) {
1485
+ if (kind === "plugin") return (0, react.createElement)(McpSourceIcon, { kind: "plugin" });
1486
+ if (kind === "direct") return (0, react.createElement)(McpSourceIcon, { kind: "direct" });
1487
+ return (0, react.createElement)("svg", {
1488
+ width: 16,
1489
+ height: 16,
1490
+ viewBox: "0 0 16 16",
1491
+ fill: "none",
1492
+ "aria-hidden": true
1493
+ }, (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" }));
1494
+ }
1495
+ function McpDetailModal({ entry, t, onClose }) {
894
1496
  return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
895
1497
  open: true,
896
- onClose: props.onClose,
897
- title,
898
- description: t("editorHint"),
1498
+ onClose,
1499
+ title: entry.name,
1500
+ description: t("mcpServiceDetail"),
899
1501
  closeLabel: t("cancel"),
900
- className: market_module_default.editorDialog,
901
- footer: (0, react.createElement)("div", { className: market_module_default.modalFooter }, (0, react.createElement)("div", { className: market_module_default.modalFooterLeft }, editor.mode === "edit" ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
902
- variant: "ghost",
903
- onClick: () => props.onRemove(id)
904
- }, `🗑 ${t("remove")}`) : null), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1502
+ className: mcp_status_module_default.detailDialog,
1503
+ contentClassName: mcp_status_module_default.detailBody,
1504
+ footer: (0, react.createElement)("div", { className: mcp_status_module_default.modalFooter }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
905
1505
  variant: "ghost",
906
- onClick: props.onClose
907
- }, t("cancel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
908
- variant: "primary",
909
- disabled: props.busy,
910
- onClick: () => {
911
- props.onSave(url.trim(), branch.trim(), local);
912
- }
913
- }, t("save"))),
914
- children: (0, react.createElement)("div", { className: market_module_default.editorForm }, (0, react.createElement)("div", { className: market_module_default.modeRow }, (0, react.createElement)("button", {
915
- type: "button",
916
- className: local ? market_module_default.seg : market_module_default.segOn,
917
- onClick: () => setLocal(false)
918
- }, t("sourceModeGit")), (0, react.createElement)("button", {
919
- type: "button",
920
- className: local ? market_module_default.segOn : market_module_default.seg,
921
- onClick: () => setLocal(true)
922
- }, 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, {
923
- placeholder: local ? t("sourceUrlLocalPh") : t("sourceUrlPh"),
924
- value: url,
925
- onChange: (event) => setUrl(event.target.value)
926
- }), (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, {
927
- placeholder: t("branchPh"),
928
- value: branch,
929
- onChange: (event) => setBranch(event.target.value)
930
- }), (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}`)))
1506
+ onClick: onClose
1507
+ }, t("cancel"))),
1508
+ 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, {
1509
+ kind: entry.kind,
1510
+ label: entry.kind === "plugin" ? entry.source ?? "—" : t("mcpDirect"),
1511
+ t
1512
+ }), (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", {
1513
+ key: tool.name,
1514
+ className: mcp_status_module_default.tool
1515
+ }, (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 ?? ""))))))
931
1516
  });
932
1517
  }
933
- /** A green/gray switch control for suite enable state. */
934
- function ToggleSwitch(props) {
935
- return (0, react.createElement)("button", {
936
- type: "button",
937
- role: "switch",
938
- "aria-checked": props.on,
939
- title: props.title,
940
- disabled: props.disabled,
941
- className: props.on ? market_module_default.switchOn : market_module_default.switchOff,
942
- onClick: (event) => {
943
- event.stopPropagation();
944
- props.onChange();
945
- }
946
- }, (0, react.createElement)("span", { className: market_module_default.switchThumb }));
1518
+ function filterLabel(t, kind) {
1519
+ if (kind === "plugin") return t("mcpPlugin");
1520
+ if (kind === "direct") return t("mcpDirect");
1521
+ return t("mcpAll");
947
1522
  }
948
- function SuiteCard(props) {
949
- const { t, suite, busy } = props;
950
- const tags = [
951
- [t("surfaceSkills"), suite.surfaces.skills],
952
- [t("surfaceMcp"), suite.surfaces.mcp],
953
- [t("surfaceHooks"), suite.surfaces.hooks],
954
- [t("surfaceCommands"), suite.surfaces.commands],
955
- [t("surfaceAgents"), suite.surfaces.agents],
956
- [t("surfaceLsp"), suite.surfaces.lsp]
957
- ].filter(([, count]) => count > 0);
958
- 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") : t("layoutSkills");
959
- const isRemote = suite.remoteUrl !== void 0;
960
- const stop = (callback) => (event) => {
961
- event.stopPropagation();
962
- callback();
1523
+ function stateLabel(t, state) {
1524
+ if (state === "connected") return t("mcpConnected");
1525
+ if (state === "degraded") return t("mcpDegraded");
1526
+ if (state === "failed") return t("mcpFailed");
1527
+ return t("mcpDisabled");
1528
+ }
1529
+ //#endregion
1530
+ //#region src/client/page-mode-selection.ts
1531
+ /** Pure capability decision for the legacy page-mode fallback. */
1532
+ /**
1533
+ * Use the DOM page fallback only when the host has no settings page and does
1534
+ * expose a page shell for the fallback to mount into.
1535
+ *
1536
+ * @param settingsSurfaceAvailable - whether `settings.section` is live.
1537
+ * @param pageShellAvailable - whether the sidebar/conversation shell exists.
1538
+ * @returns true when the fallback is the only available market surface.
1539
+ */
1540
+ function shouldUseLegacyPageMode(settingsSurfaceAvailable, pageShellAvailable) {
1541
+ return !settingsSurfaceAvailable && pageShellAvailable;
1542
+ }
1543
+ //#endregion
1544
+ //#region src/client/page-mode.tsx
1545
+ /**
1546
+ * Legacy Web page-mode adapter.
1547
+ *
1548
+ * Current DSH compositions expose `settings.section`; older compositions that
1549
+ * predate that slot can still host a top-level market panel through the DOM
1550
+ * shell used by the original page-mode integration. The adapter is deliberately
1551
+ * guarded by the live settings-slot state so one composition never renders two
1552
+ * market surfaces.
1553
+ */
1554
+ const ACTIVE_ATTRIBUTE = "data-dsh-agent-plugins-market-page";
1555
+ const VIEW_ATTRIBUTE = "data-dsh-agent-plugins-market-page-view";
1556
+ const ENTRY_ATTRIBUTE = "data-dsh-agent-plugins-market-entry";
1557
+ const SURFACE_EVENT = "dsh-agent-plugins-market-settings-surface";
1558
+ const PANEL_EVENT = "dsh-panel-activate";
1559
+ const PANEL_NAME = "agent-plugins-market";
1560
+ /** Notify the page adapter that the settings-slot capability changed. */
1561
+ const LEGACY_PAGE_MODE_SURFACE_EVENT = SURFACE_EVENT;
1562
+ const SIDEBAR_COLUMN_SELECTOR = "[data-pane=\"sidebar\"], [class*=\"sidebarCol\"]";
1563
+ const CONVERSATION_COLUMN_SELECTOR = "[data-pane=\"conversation\"], [class*=\"centerCol\"]";
1564
+ const SIDEBAR_CONTEXT_SELECTOR = "[class*=\"sessionRow\"], [class*=\"projectRow\"], [class*=\"searchResultRow\"], [class*=\"searchResultWorkspace\"], [class*=\"newSession\"]";
1565
+ /**
1566
+ * Mount the page-mode fallback and its sidebar entry.
1567
+ *
1568
+ * The fallback remains dormant when the settings surface is present. It also
1569
+ * remains a no-op in non-browser runtimes or shells that expose neither the
1570
+ * sidebar nor the conversation column.
1571
+ *
1572
+ * @param options - page-mode dependencies and host capability probe.
1573
+ * @returns disposer that removes the injected entry, panel, listeners, and
1574
+ * active document marker.
1575
+ */
1576
+ function mountLegacyPageMode(options) {
1577
+ if (typeof document === "undefined" || typeof MutationObserver === "undefined") return () => {};
1578
+ let stopped = false;
1579
+ let open = false;
1580
+ let root;
1581
+ let container;
1582
+ let entry;
1583
+ let entryLabel;
1584
+ let observer;
1585
+ const setActive = (next) => {
1586
+ open = next;
1587
+ if (open && !options.isSettingsSurfaceAvailable()) {
1588
+ document.documentElement.setAttribute(ACTIVE_ATTRIBUTE, "");
1589
+ document.dispatchEvent(new CustomEvent(PANEL_EVENT, { detail: PANEL_NAME }));
1590
+ } else document.documentElement.removeAttribute(ACTIVE_ATTRIBUTE);
963
1591
  };
964
- return (0, react.createElement)("article", {
965
- className: market_module_default.card,
966
- onClick: props.onOpen
967
- }, (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, {
968
- on: suite.enabled,
969
- disabled: busy,
970
- title: suite.enabled ? t("disable") : t("enable"),
971
- onChange: props.onToggle
972
- }) : isRemote ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
973
- variant: "primary",
974
- size: "sm",
975
- disabled: busy,
976
- title: suite.remoteUrl,
977
- onClick: stop(props.onAddSource)
978
- }, t("addSource")) : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
979
- variant: "primary",
980
- size: "sm",
981
- disabled: busy,
982
- onClick: stop(props.onInstall)
983
- }, t("install")), suite.installed ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
984
- variant: "ghost",
985
- size: "sm",
986
- title: t("refresh"),
987
- disabled: busy,
988
- onClick: stop(props.onRefresh)
989
- }, "↻") : null, suite.installed ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
990
- variant: "ghost",
991
- size: "sm",
992
- title: t("uninstall"),
993
- disabled: busy,
994
- onClick: stop(props.onUninstall)
995
- }, "🗑") : 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", {
996
- key: label,
997
- className: market_module_default.tag
998
- }, `${label} ${count}`)), suite.errors.length === 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
999
- label: suite.errors.slice(0, 8).join(";"),
1000
- children: (0, react.createElement)("span", { className: market_module_default.warnLine }, `⚠ ${t("errors")} ${suite.errors.length}`)
1001
- }), (suite.mcpErrors?.length ?? 0) === 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
1002
- label: suite.mcpErrors.slice(0, 8).join(";"),
1003
- children: (0, react.createElement)("span", { className: market_module_default.warnLine }, `⚠ ${t("mcpSection")} ${suite.mcpErrors.length}`)
1004
- })));
1592
+ const removeView = () => {
1593
+ setActive(false);
1594
+ root?.unmount();
1595
+ root = void 0;
1596
+ container?.remove();
1597
+ container = void 0;
1598
+ };
1599
+ const renderView = () => {
1600
+ if (root === void 0) return;
1601
+ root.render((0, react.createElement)(MarketSection, {
1602
+ t: options.t,
1603
+ mode: "page"
1604
+ }));
1605
+ };
1606
+ const updateEntryCopy = () => {
1607
+ if (entryLabel === void 0 || entry === void 0) return;
1608
+ const label = options.t("nav");
1609
+ entryLabel.textContent = label;
1610
+ entry.title = label;
1611
+ entry.setAttribute("aria-label", label);
1612
+ };
1613
+ const ensureView = () => {
1614
+ if (stopped || options.isSettingsSurfaceAvailable()) {
1615
+ removeView();
1616
+ return;
1617
+ }
1618
+ const column = conversationColumn();
1619
+ if (!shouldUseLegacyPageMode(options.isSettingsSurfaceAvailable(), column !== void 0)) {
1620
+ removeView();
1621
+ return;
1622
+ }
1623
+ if (column === void 0) return;
1624
+ if (container !== void 0 && container.isConnected) return;
1625
+ root?.unmount();
1626
+ container?.remove();
1627
+ container = document.createElement("div");
1628
+ container.setAttribute(VIEW_ATTRIBUTE, "");
1629
+ container.className = market_module_default.pageView;
1630
+ column.appendChild(container);
1631
+ root = (0, react_dom_client.createRoot)(container);
1632
+ renderView();
1633
+ };
1634
+ const ensureEntry = () => {
1635
+ if (stopped || options.isSettingsSurfaceAvailable()) {
1636
+ entry?.remove();
1637
+ return;
1638
+ }
1639
+ const rootElement = sidebarRoot();
1640
+ const anchor = rootElement === void 0 ? void 0 : newSessionButton(rootElement);
1641
+ if (rootElement === void 0 || anchor === void 0 || anchor.parentElement === null) return;
1642
+ if (entry === void 0) {
1643
+ entry = createEntry(() => {
1644
+ setActive(!open);
1645
+ ensureView();
1646
+ });
1647
+ entryLabel = entry.querySelector("[data-dsh-agent-plugins-market-label]") ?? void 0;
1648
+ updateEntryCopy();
1649
+ }
1650
+ if (entry.parentElement !== anchor.parentElement || entry.previousSibling !== anchor) anchor.insertAdjacentElement("afterend", entry);
1651
+ };
1652
+ const observeShell = () => {
1653
+ if (stopped || observer !== void 0 || options.isSettingsSurfaceAvailable()) return;
1654
+ observer = new MutationObserver(ensure);
1655
+ observer.observe(document.body ?? document.documentElement, {
1656
+ childList: true,
1657
+ subtree: true
1658
+ });
1659
+ };
1660
+ const stopObservingShell = () => {
1661
+ observer?.disconnect();
1662
+ observer = void 0;
1663
+ };
1664
+ const ensure = () => {
1665
+ if (stopped) return;
1666
+ if (options.isSettingsSurfaceAvailable()) {
1667
+ stopObservingShell();
1668
+ removeView();
1669
+ entry?.remove();
1670
+ return;
1671
+ }
1672
+ observeShell();
1673
+ ensureView();
1674
+ ensureEntry();
1675
+ };
1676
+ const onLocale = () => {
1677
+ updateEntryCopy();
1678
+ renderView();
1679
+ };
1680
+ const onSurfaceChange = () => {
1681
+ ensure();
1682
+ };
1683
+ const unsubscribeLocale = options.subscribeLocale?.(onLocale);
1684
+ const onPanelActivate = (event) => {
1685
+ if (event.detail !== PANEL_NAME && open) setActive(false);
1686
+ };
1687
+ const onSidebarContextClick = (event) => {
1688
+ if (!open) return;
1689
+ const target = event.target;
1690
+ if (!(target instanceof HTMLElement) || target.closest(SIDEBAR_CONTEXT_SELECTOR) === null) return;
1691
+ setActive(false);
1692
+ };
1693
+ document.addEventListener(PANEL_EVENT, onPanelActivate);
1694
+ document.addEventListener(SURFACE_EVENT, onSurfaceChange);
1695
+ document.addEventListener("click", onSidebarContextClick, true);
1696
+ queueMicrotask(ensure);
1697
+ return () => {
1698
+ stopped = true;
1699
+ unsubscribeLocale?.();
1700
+ document.removeEventListener(PANEL_EVENT, onPanelActivate);
1701
+ document.removeEventListener(SURFACE_EVENT, onSurfaceChange);
1702
+ document.removeEventListener("click", onSidebarContextClick, true);
1703
+ stopObservingShell();
1704
+ entry?.remove();
1705
+ removeView();
1706
+ };
1707
+ }
1708
+ function sidebarRoot() {
1709
+ const column = document.querySelector(SIDEBAR_COLUMN_SELECTOR);
1710
+ if (column === null) return void 0;
1711
+ return column.querySelector("[class*=\"logoRow\"]")?.parentElement ?? column.firstElementChild ?? void 0;
1712
+ }
1713
+ function newSessionButton(root) {
1714
+ const nested = root.querySelector("button[class*=\"newSession\"]");
1715
+ if (nested !== null) return nested;
1716
+ for (const child of root.children) if (child instanceof HTMLButtonElement) return child;
1717
+ }
1718
+ function conversationColumn() {
1719
+ return document.querySelector(CONVERSATION_COLUMN_SELECTOR) ?? void 0;
1720
+ }
1721
+ function createEntry(onClick) {
1722
+ const button = document.createElement("button");
1723
+ button.type = "button";
1724
+ button.setAttribute(ENTRY_ATTRIBUTE, "");
1725
+ button.className = market_module_default.pageEntry;
1726
+ button.innerHTML = "<svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><rect x=\"2\" y=\"2\" width=\"5\" height=\"5\" rx=\"1\"/><rect x=\"9\" y=\"2\" width=\"5\" height=\"5\" rx=\"1\"/><rect x=\"2\" y=\"9\" width=\"5\" height=\"5\" rx=\"1\"/><rect x=\"9\" y=\"9\" width=\"5\" height=\"5\" rx=\"1\"/></svg>";
1727
+ const label = document.createElement("span");
1728
+ label.dataset.dshAgentPluginsMarketLabel = "";
1729
+ button.append(label);
1730
+ button.addEventListener("click", onClick);
1731
+ return button;
1005
1732
  }
1006
1733
  //#endregion
1007
1734
  //#region src/client/index.ts
1008
1735
  /**
1009
1736
  * dsh-agent-plugins-market client: registers the Agent Plugins Market section inside the Web
1010
- * GUI's settings dialog (the same settings.section seat dshmarket uses).
1011
- * Mirrors the market's integration contract: the bundle's only externals are
1012
- * react and the injected `dsh.client.inject` module table, so it cannot reach
1013
- * packages the host does not serve.
1737
+ * GUI's settings page (the same settings.section seat dshmarket uses), with a
1738
+ * guarded legacy top-level page fallback for older shells. The bundle's
1739
+ * browser externals are React, ReactDOM, and the injected `dsh.client.inject`
1740
+ * module table, so it cannot reach packages the host does not serve.
1014
1741
  */
1015
1742
  const NS = "dsh-agent-plugins-market";
1016
1743
  const name = "dsh-agent-plugins-market";
@@ -1038,14 +1765,44 @@ function apply(ctx) {
1038
1765
  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)`);
1039
1766
  return;
1040
1767
  }
1041
- ctx.slots.inject("settings.section", () => ctx.slots.register({
1042
- name: "settings.section",
1043
- id: "agent-plugin",
1044
- order: 45,
1045
- label: () => t("nav"),
1046
- locale: NS,
1047
- inject: () => ({ t })
1048
- }, () => (0, react.createElement)(MarketSection, { t })));
1768
+ let settingsSurfaceAvailable = false;
1769
+ ctx.effect(() => mountLegacyPageMode({
1770
+ t,
1771
+ isSettingsSurfaceAvailable: () => settingsSurfaceAvailable,
1772
+ subscribeLocale: ctx.locale.subscribe === void 0 ? void 0 : (listener) => ctx.locale.subscribe(listener)
1773
+ }), "dsh-agent-plugins-market: legacy page mode");
1774
+ ctx.slots.inject("settings.section", () => {
1775
+ settingsSurfaceAvailable = true;
1776
+ notifyPageModeSurfaceChange();
1777
+ const marketDispose = ctx.slots.register({
1778
+ name: "settings.section",
1779
+ id: "agent-plugin",
1780
+ order: 45,
1781
+ label: () => t("nav"),
1782
+ locale: NS,
1783
+ inject: () => ({ t })
1784
+ }, () => (0, react.createElement)(MarketSection, {
1785
+ t,
1786
+ mode: "settings"
1787
+ }));
1788
+ const mcpDispose = ctx.slots.register({
1789
+ name: "settings.section",
1790
+ id: "mcp-status",
1791
+ order: 46,
1792
+ label: () => t("mcpStatusNav"),
1793
+ locale: NS,
1794
+ inject: () => ({ t })
1795
+ }, () => (0, react.createElement)(McpStatusPanel, { t }));
1796
+ return () => {
1797
+ settingsSurfaceAvailable = false;
1798
+ notifyPageModeSurfaceChange();
1799
+ if (typeof mcpDispose === "function") mcpDispose();
1800
+ if (typeof marketDispose === "function") marketDispose();
1801
+ };
1802
+ });
1803
+ }
1804
+ function notifyPageModeSurfaceChange() {
1805
+ if (typeof document !== "undefined") document.dispatchEvent(new Event(LEGACY_PAGE_MODE_SURFACE_EVENT));
1049
1806
  }
1050
1807
  //#endregion
1051
1808
  exports.REQUIRED_PRIMITIVES = REQUIRED_PRIMITIVES;