dsh-agent-plugins-market 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +39 -26
  2. package/README.zh.md +39 -26
  3. package/client/client.js +1214 -181
  4. package/client/client.js.map +1 -1
  5. package/lib/application/catalog.js +23 -4
  6. package/lib/application/install-store.js +1 -1
  7. package/lib/application/mcp-service.js +185 -30
  8. package/lib/catalog/archive.js +15 -0
  9. package/lib/catalog/component-files.js +3 -1
  10. package/lib/catalog/manifests.js +124 -13
  11. package/lib/catalog/native-project.js +1 -1
  12. package/lib/catalog/project-config.js +0 -2
  13. package/lib/catalog/project-hooks.js +12 -7
  14. package/lib/catalog/scan-resolvers.js +117 -12
  15. package/lib/catalog/surfaces.js +86 -33
  16. package/lib/catalog/validate.js +205 -54
  17. package/lib/contracts/market.js +2 -0
  18. package/lib/index.js +6 -2
  19. package/lib/model/command-names.js +14 -0
  20. package/lib/model/layouts.js +35 -0
  21. package/lib/model/preset-source.js +8 -0
  22. package/lib/routes.js +31 -2
  23. package/lib/runtime/agent-role-router.js +176 -51
  24. package/lib/runtime/commands-mounts.js +3 -2
  25. package/lib/runtime/hooks-mounts.js +7 -4
  26. package/lib/runtime/host-locale.js +6 -12
  27. package/lib/runtime/mcp-client/connection.js +3 -2
  28. package/lib/runtime/mcp-client/oauth.js +82 -14
  29. package/lib/runtime/mcp-client/tools.js +2 -1
  30. package/lib/runtime/mcp-config.js +178 -34
  31. package/lib/runtime/mcp-direct-config.js +66 -14
  32. package/lib/runtime/mcp-mounts.js +15 -3
  33. package/lib/runtime/mcp-overrides.js +131 -1
  34. package/lib/runtime/mcp-redaction.js +8 -0
  35. package/lib/runtime/mcp-status.js +21 -5
  36. package/lib/runtime/plugin-message-source.js +4 -0
  37. package/lib/runtime/project-runtime.js +10 -8
  38. package/lib/runtime/server-config.js +49 -8
  39. package/lib/runtime/subagent-catalog.js +62 -22
  40. package/lib/runtime/tool-registry-observer.js +8 -4
  41. package/lib/runtime/user-commands.js +23 -8
  42. package/lib/runtime/user-hooks.js +102 -0
  43. package/lib/runtime/user-panels.js +34 -22
  44. package/lib/runtime/user-store.js +81 -19
  45. package/lib/types/application/catalog.d.ts +10 -1
  46. package/lib/types/application/install-store.d.ts +1 -1
  47. package/lib/types/application/mcp-service.d.ts +32 -3
  48. package/lib/types/application/queries.d.ts +6 -1
  49. package/lib/types/catalog/component-files.d.ts +1 -0
  50. package/lib/types/catalog/manifests.d.ts +6 -2
  51. package/lib/types/catalog/project-hooks.d.ts +15 -2
  52. package/lib/types/catalog/surfaces.d.ts +16 -4
  53. package/lib/types/catalog/validate.d.ts +72 -11
  54. package/lib/types/contracts/market.d.ts +72 -1
  55. package/lib/types/contracts/mcp-status.d.ts +11 -0
  56. package/lib/types/model/command-names.d.ts +12 -0
  57. package/lib/types/model/layouts.d.ts +21 -0
  58. package/lib/types/model/preset-source.d.ts +18 -0
  59. package/lib/types/model/types.d.ts +39 -2
  60. package/lib/types/runtime/agent-role-router.d.ts +90 -16
  61. package/lib/types/runtime/host-locale.d.ts +1 -1
  62. package/lib/types/runtime/mcp-client/oauth.d.ts +4 -0
  63. package/lib/types/runtime/mcp-config.d.ts +75 -13
  64. package/lib/types/runtime/mcp-direct-config.d.ts +23 -5
  65. package/lib/types/runtime/mcp-overrides.d.ts +44 -0
  66. package/lib/types/runtime/mcp-redaction.d.ts +6 -0
  67. package/lib/types/runtime/plugin-message-source.d.ts +24 -0
  68. package/lib/types/runtime/server-config.d.ts +26 -1
  69. package/lib/types/runtime/subagent-catalog.d.ts +14 -2
  70. package/lib/types/runtime/tool-registry-observer.d.ts +5 -3
  71. package/lib/types/runtime/user-commands.d.ts +5 -2
  72. package/lib/types/runtime/user-hooks.d.ts +22 -0
  73. package/lib/types/runtime/user-panels.d.ts +35 -15
  74. package/lib/types/runtime/user-store.d.ts +27 -10
  75. package/package.json +39 -35
  76. package/schemas/1.0.0/mcp.schema.json +0 -22
  77. package/schemas/1.1.0/mcp.schema.json +120 -0
  78. package/schemas/1.1.0/plugin.schema.json +65 -0
  79. package/schemas/README.md +25 -19
  80. package/schemas/agent-plugins/spec.md +23 -9
  81. package/schemas/com.deepseek.harness/namespace.schema.json +42 -0
  82. package/schemas/com.deepseek.harness/spec.md +52 -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=".qUlk6a_overlay {\n z-index: 2147483647;\n box-sizing: border-box;\n background: var(--dsw-alias-bg-mask-3);\n backdrop-filter: blur(3px);\n cursor: progress;\n outline: none;\n place-items: center;\n display: grid;\n position: fixed;\n overflow: hidden;\n}\n\n.qUlk6a_overlay[data-visible=\"false\"] {\n backdrop-filter: none;\n background: none;\n}\n\n.qUlk6a_overlay[data-visible=\"true\"] {\n animation: .14s ease-out qUlk6a_busy-enter;\n}\n\n.qUlk6a_content {\n box-sizing: border-box;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n width: min(360px, 100% - 32px);\n color: var(--dsw-alias-label-primary);\n text-align: center;\n border-radius: 8px;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n padding: 24px;\n display: flex;\n}\n\n.qUlk6a_spinner {\n width: 28px;\n height: 28px;\n animation: .9s linear infinite qUlk6a_busy-spin;\n display: flex;\n}\n\n.qUlk6a_label {\n font-size: 14px;\n font-weight: 600;\n line-height: 20px;\n}\n\n.qUlk6a_hintViewport {\n width: 100%;\n min-height: 54px;\n overflow: hidden;\n}\n\n.qUlk6a_hint {\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n margin: 0;\n font-size: 13px;\n line-height: 18px;\n animation: .3s ease-out qUlk6a_busy-hint;\n}\n\n.qUlk6a_warning {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n background: var(--dsw-alias-state-warn-tertiary, #fef5e7);\n overflow-wrap: anywhere;\n border-radius: 6px;\n margin: 0;\n padding: 6px 8px;\n font-size: 12px;\n line-height: 17px;\n}\n\n@keyframes qUlk6a_busy-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n@keyframes qUlk6a_busy-enter {\n from {\n opacity: 0;\n }\n\n to {\n opacity: 1;\n }\n}\n\n@keyframes qUlk6a_busy-hint {\n from {\n opacity: 0;\n transform: translateY(14px);\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .qUlk6a_overlay, .qUlk6a_hint {\n animation: none;\n }\n\n .qUlk6a_spinner {\n animation-duration: 2.4s;\n }\n}\n._72qoAq_market {\n min-width: 0;\n min-height: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n flex: 1;\n gap: 24px;\n display: flex;\n container-type: inline-size;\n}\n\n._72qoAq_pageMode {\n width: 100%;\n min-width: 0;\n height: 100%;\n min-height: 0;\n}\n\n._72qoAq_marketControls {\n flex-direction: column;\n gap: 8px;\n min-height: 0;\n display: flex;\n}\n\nhtml[data-dsh-agent-plugins-market-page] [data-pane=\"conversation\"], html[data-dsh-agent-plugins-market-page] [class*=\"centerCol\"] {\n position: relative;\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:focus-visible, ._72qoAq_srcTabMain:focus-visible, ._72qoAq_srcTabEdit:focus-visible, ._72qoAq_srcTabDel: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_sourceTabsBox {\n min-width: 0;\n position: relative;\n}\n\n._72qoAq_sourceTabsRow {\n grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));\n gap: 4px;\n min-width: 0;\n display: grid;\n}\n\n._72qoAq_sourceTabsBoxFold {\n clip-path: inset(-6px);\n height: 52px;\n}\n\n._72qoAq_sourceTabsBoxFold:hover, ._72qoAq_sourceTabsBoxFold:has(:focus-visible) {\n clip-path: none;\n z-index: 20;\n}\n\n._72qoAq_sourceTabsBoxFold ._72qoAq_sourceTabsRow {\n box-sizing: border-box;\n background: var(--dsw-alias-bg-layer-1, #fff);\n border-radius: 10px;\n max-height: 58px;\n padding: 6px 6px 0;\n transition: max-height .16s, box-shadow .16s, padding-bottom .16s;\n position: absolute;\n inset: -6px -6px auto;\n overflow: hidden;\n -webkit-mask-image: linear-gradient(#000 78%, #0000 100%);\n mask-image: linear-gradient(#000 78%, #0000 100%);\n}\n\n._72qoAq_sourceTabsBoxFold:hover ._72qoAq_sourceTabsRow, ._72qoAq_sourceTabsBoxFold:has(:focus-visible) ._72qoAq_sourceTabsRow {\n z-index: 30;\n max-height: 420px;\n box-shadow: 0 0 0 1px var(--dsw-alias-border-l3, #d9dde3),\n 0 12px 28px #10182829;\n padding-bottom: 6px;\n -webkit-mask-image: none;\n mask-image: none;\n}\n\n._72qoAq_sourceTabsBoxFold._72qoAq_sourceTabsBoxPicked:hover, ._72qoAq_sourceTabsBoxFold._72qoAq_sourceTabsBoxPicked:has(:focus-visible) {\n clip-path: inset(-6px);\n}\n\n._72qoAq_sourceTabsBoxFold._72qoAq_sourceTabsBoxPicked:hover ._72qoAq_sourceTabsRow, ._72qoAq_sourceTabsBoxFold._72qoAq_sourceTabsBoxPicked:has(:focus-visible) ._72qoAq_sourceTabsRow {\n max-height: 58px;\n box-shadow: none;\n padding-bottom: 0;\n -webkit-mask-image: linear-gradient(#000 78%, #0000 100%);\n mask-image: linear-gradient(#000 78%, #0000 100%);\n}\n\n._72qoAq_unmanagedRow {\n color: var(--dsw-alias-label-secondary, #57606a);\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n margin-top: 6px;\n font-size: 12px;\n display: flex;\n}\n\n._72qoAq_unmanagedLabel {\n flex-shrink: 0;\n}\n\n._72qoAq_unmanagedChip {\n border: 1px dashed var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-bg-layer-1, #fff);\n border-radius: 999px;\n align-items: center;\n gap: 2px;\n max-width: 220px;\n height: 22px;\n padding: 0 4px 0 8px;\n display: inline-flex;\n}\n\n._72qoAq_unmanagedChipName {\n white-space: nowrap;\n text-overflow: ellipsis;\n font-size: 12px;\n overflow: hidden;\n}\n\n._72qoAq_unmanagedAdopt {\n font: inherit;\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n cursor: pointer;\n background: none;\n border: none;\n flex-shrink: 0;\n padding: 0 4px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_unmanagedAdopt:disabled {\n cursor: default;\n opacity: .5;\n}\n\n._72qoAq_srcTabEdit {\n font: inherit;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n background: none;\n border: none;\n flex-shrink: 0;\n margin-left: 4px;\n padding: 0 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: auto;\n max-width: 100%;\n height: 24px;\n padding: 0 10px;\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: 0;\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, #0f1115);\n border-color: var(--dsw-alias-brand-primary, #0f1115);\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 margin-left: 4px;\n padding: 0 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, ._72qoAq_list ._72qoAq_cardActions {\n flex: none;\n}\n\n._72qoAq_list ._72qoAq_meta, ._72qoAq_list ._72qoAq_tagRow {\n flex-basis: 100%;\n}\n\n._72qoAq_empty {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-align: center;\n grid-column: 1 / -1;\n padding: 48px 0;\n font-size: 13px;\n}\n\n._72qoAq_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_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_confirmCheck {\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: row;\n align-items: center;\n gap: 8px;\n font-size: 12px;\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(640px, 92vw);\n}\n\n._72qoAq_installConfirmBody {\n flex-direction: column;\n gap: 10px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_installConfirmSuite {\n color: var(--dsw-alias-label-primary, #111827);\n font-weight: 600;\n}\n\n._72qoAq_installConfirmMeta {\n color: var(--dsw-alias-label-secondary, #4b5563);\n font-size: 12px;\n}\n\n._72qoAq_installConfirmCommit {\n color: var(--dsw-alias-label-secondary, #4b5563);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12px;\n}\n\n._72qoAq_installConfirmTags {\n flex-wrap: wrap;\n gap: 6px;\n display: flex;\n}\n\n._72qoAq_installConfirmWarn {\n color: var(--dsw-alias-state-warn-label, #dd8629);\n border: 1px solid var(--dsw-alias-state-warn-label, #dd8629);\n border-radius: 8px;\n padding: 8px 10px;\n font-size: 12px;\n}\n\n._72qoAq_progress, ._72qoAq_progressError {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n background: var(--dsw-alias-bg-layer-2, #7f7f7f0f);\n color: var(--dsw-alias-label-primary, #1f2328);\n border-radius: 8px;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n font-size: 13px;\n line-height: 20px;\n display: flex;\n}\n\n._72qoAq_progressError {\n border-color: var(--dsw-alias-state-error-primary, #ec1313);\n color: var(--dsw-alias-state-error-primary, #ec1313);\n}\n\n._72qoAq_progressSpin {\n border: 2px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-top-color: var(--dsw-alias-brand-primary, #4f6ef7);\n border-radius: 50%;\n flex-shrink: 0;\n width: 14px;\n height: 14px;\n animation: .8s linear infinite _72qoAq_dshApmSpin;\n}\n\n@keyframes _72qoAq_dshApmSpin {\n to {\n transform: rotate(360deg);\n }\n}\n\n._72qoAq_progressFail {\n flex-shrink: 0;\n font-size: 13px;\n}\n\n._72qoAq_progressText {\n overflow-wrap: anywhere;\n min-width: 0;\n}\n\n@media (width <= 720px) {\n ._72qoAq_pageView {\n padding: 14px;\n }\n\n ._72qoAq_sourceTabsRow {\n grid-template-columns: repeat(auto-fill, minmax(102px, 1fr));\n }\n\n ._72qoAq_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n ._72qoAq_list ._72qoAq_cardTop, ._72qoAq_list ._72qoAq_cardActions {\n max-width: 100%;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._72qoAq_progressSpin, ._72qoAq_switchOn, ._72qoAq_switchOff, ._72qoAq_switchThumb {\n transition: none;\n animation: none;\n }\n}\n\n._72qoAq_surfaceToggles {\n flex-wrap: wrap;\n align-items: center;\n gap: 4px 14px;\n display: flex;\n}\n\n._72qoAq_surfaceToggle {\n color: var(--dsw-alias-label-secondary, #61666b);\n cursor: pointer;\n user-select: none;\n align-items: center;\n gap: 5px;\n font-size: 12px;\n display: inline-flex;\n}\n\n._72qoAq_surfaceToggle input[type=\"checkbox\"] {\n accent-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);\n margin: 0;\n}\n\n._72qoAq_pluginCard {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n background: var(--dsw-alias-bg-layer-3, #fff);\n border-radius: 12px;\n list-style: none;\n transition: border-color .16s, background .16s;\n container: _72qoAq_market-config / inline-size;\n}\n\n._72qoAq_pluginCard:hover {\n border-color: var(--dsw-alias-label-dimmed, #c8ccd4);\n}\n\n._72qoAq_pluginCardOpen {\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border-color: var(--dsw-alias-label-dimmed, #c8ccd4);\n}\n\n._72qoAq_pluginCard[data-busy=\"true\"] {\n opacity: .6;\n pointer-events: none;\n}\n\n._72qoAq_pluginCardHeader {\n appearance: none;\n width: 100%;\n font: inherit;\n color: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n border-radius: 12px;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n display: flex;\n}\n\n._72qoAq_pluginCardHeader:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: -2px;\n}\n\n._72qoAq_pluginCardBody {\n border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n flex-direction: column;\n gap: 8px;\n margin: 0 16px;\n padding: 4px 0 8px;\n display: flex;\n}\n\n._72qoAq_pluginCardRow {\n justify-content: space-between;\n align-items: center;\n gap: 16px;\n padding: 8px 0 4px;\n display: flex;\n}\n\n._72qoAq_pluginCardText {\n flex-direction: column;\n flex: 1;\n gap: 4px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_pluginCardTitle {\n color: var(--dsw-alias-label-primary, #1f2328);\n font-size: 15px;\n font-weight: 600;\n line-height: 1.4;\n}\n\n._72qoAq_pluginCardDesc {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 13px;\n line-height: 1.5;\n}\n\n._72qoAq_pluginCardRowLabel {\n font-size: 13px;\n font-weight: 500;\n line-height: 20px;\n}\n\n@container _72qoAq_market-config (width <= 320px) {\n ._72qoAq_pluginCardRow {\n flex-direction: column;\n align-items: flex-start;\n gap: 8px;\n }\n\n ._72qoAq_pluginCardText {\n overflow-wrap: anywhere;\n width: 100%;\n }\n\n ._72qoAq_regionSeg {\n flex-wrap: wrap;\n max-width: 100%;\n }\n}\n\n._72qoAq_pluginCardError {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n}\n\n._72qoAq_pluginFieldHead {\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n._72qoAq_pluginFieldBadges {\n align-items: center;\n gap: 6px;\n display: inline-flex;\n}\n\n._72qoAq_pluginFieldReset {\n appearance: none;\n font: inherit;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n text-underline-offset: 2px;\n background: none;\n border: 0;\n padding: 0;\n font-size: 12px;\n line-height: 18px;\n text-decoration: underline;\n}\n\n._72qoAq_pluginFieldReset:disabled {\n cursor: default;\n opacity: .5;\n}\n\n._72qoAq_pluginCardReadonly {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n}\n\n._72qoAq_pluginCardFooter {\n border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n margin-top: 4px;\n padding-top: 8px;\n display: flex;\n}\n\n._72qoAq_pluginCardFooter ._72qoAq_pluginCardError {\n margin-right: auto;\n}\n\n._72qoAq_pluginCardDiscard, ._72qoAq_pluginCardSave {\n appearance: none;\n font: inherit;\n cursor: pointer;\n border-radius: 8px;\n padding: 4px 12px;\n font-size: 13px;\n line-height: 20px;\n}\n\n._72qoAq_pluginCardDiscard {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n color: var(--dsw-alias-label-primary, #1f2328);\n background: none;\n}\n\n._72qoAq_pluginCardDiscard:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, #0000000a);\n}\n\n._72qoAq_pluginCardSave {\n background: var(--dsw-alias-button-primary-fill);\n color: var(--dsw-alias-label-primary-foreground);\n border: 1px solid #0000;\n}\n\n._72qoAq_pluginCardSave:hover:not(:disabled) {\n background: var(--dsw-alias-button-primary-hover);\n}\n\n._72qoAq_pluginCardDiscard:disabled, ._72qoAq_pluginCardSave:disabled {\n cursor: default;\n opacity: .5;\n}\n\n._72qoAq_pluginChevron {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n flex: none;\n transition: transform .16s;\n display: inline-flex;\n}\n\n._72qoAq_pluginChevronOpen {\n transform: rotate(180deg);\n}\n\n._72qoAq_regionSeg {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 8px;\n flex: none;\n gap: 2px;\n padding: 2px;\n display: inline-flex;\n}\n\n._72qoAq_regionSegBtn {\n appearance: none;\n font: inherit;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 6px;\n padding: 3px 10px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_regionSegOn {\n appearance: none;\n font: inherit;\n cursor: pointer;\n background: var(--dsw-alias-bg-layer-2, #eef0f4);\n color: var(--dsw-alias-label-primary, #1f2328);\n border: none;\n border-radius: 6px;\n padding: 3px 10px;\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n}\n\n._72qoAq_regionSegEffective {\n appearance: none;\n font: inherit;\n cursor: pointer;\n color: var(--dsw-alias-label-primary, #1f2328);\n background: none;\n border: none;\n border-radius: 6px;\n padding: 3px 10px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_regionSegBtn:disabled, ._72qoAq_regionSegOn:disabled {\n cursor: default;\n opacity: .5;\n}\n._5JDFMW_field {\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n display: flex;\n}\n\n._5JDFMW_field > label, ._5JDFMW_field > span, ._5JDFMW_field > ._5JDFMW_rowHead > span {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n font-weight: 600;\n}\n\n._5JDFMW_field input, ._5JDFMW_field select, ._5JDFMW_field textarea {\n box-sizing: border-box;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n width: 100%;\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n border-radius: 8px;\n padding: 7px 9px;\n font-size: 12px;\n}\n\n._5JDFMW_field textarea {\n resize: vertical;\n min-height: 240px;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n line-height: 19px;\n}\n\n._5JDFMW_jsonArea {\n min-height: 220px;\n}\n\n._5JDFMW_field input:focus-visible, ._5JDFMW_field select:focus-visible, ._5JDFMW_field textarea:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n._5JDFMW_hint {\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n font-weight: 400;\n line-height: 16px;\n}\n\n._5JDFMW_form {\n flex-direction: column;\n gap: 14px;\n min-width: 0;\n display: flex;\n}\n\n._5JDFMW_formGrid {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 12px;\n display: grid;\n}\n\n._5JDFMW_full {\n grid-column: 1 / -1;\n}\n\n._5JDFMW_seg {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n flex: none;\n gap: 2px;\n padding: 2px;\n display: inline-flex;\n}\n\n._5JDFMW_seg button {\n height: 24px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n background: none;\n border: none;\n border-radius: 6px;\n padding: 0 10px;\n font-size: 12px;\n}\n\n._5JDFMW_seg button:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._5JDFMW_seg button[aria-pressed=\"true\"] {\n background: var(--dsw-alias-interactive-bg-active);\n color: var(--dsw-alias-label-primary);\n font-weight: 600;\n}\n\n._5JDFMW_seg button:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n}\n\n._5JDFMW_readonly {\n border: 1px dashed var(--dsw-alias-border-l3);\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n border-radius: 8px;\n padding: 7px 9px;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n}\n\n._5JDFMW_rows {\n flex-direction: column;\n gap: 6px;\n min-width: 0;\n display: flex;\n}\n\n._5JDFMW_row {\n align-items: center;\n gap: 6px;\n min-width: 0;\n display: flex;\n}\n\n._5JDFMW_row input {\n flex: auto;\n width: 0;\n min-width: 0;\n}\n\n._5JDFMW_rowKey {\n flex: 0 0 34%;\n}\n\n._5JDFMW_rowKeyNarrow {\n flex: 0 0 26%;\n}\n\n._5JDFMW_rowActions {\n flex: none;\n align-items: center;\n gap: 2px;\n display: flex;\n}\n\n._5JDFMW_iconBtn {\n width: 24px;\n height: 24px;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 6px;\n justify-content: center;\n align-items: center;\n padding: 0;\n display: inline-flex;\n}\n\n._5JDFMW_iconBtn:hover {\n background: var(--dsw-alias-interactive-bg-hover-danger);\n color: var(--dsw-alias-state-error-primary);\n}\n\n._5JDFMW_rowHead {\n justify-content: space-between;\n align-items: center;\n gap: 8px;\n min-height: 24px;\n display: flex;\n}\n\n._5JDFMW_addIcon {\n width: 24px;\n height: 24px;\n color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 6px;\n justify-content: center;\n align-items: center;\n padding: 0;\n display: inline-flex;\n}\n\n._5JDFMW_addIcon:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._5JDFMW_addIcon:disabled {\n cursor: default;\n opacity: .4;\n}\n\n._5JDFMW_addIcon svg {\n fill: none;\n stroke: currentColor;\n stroke-width: 1.5px;\n stroke-linecap: round;\n stroke-linejoin: round;\n display: block;\n}\n\n._5JDFMW_inlineCheck {\n color: var(--dsw-alias-label-primary);\n align-items: center;\n gap: 8px;\n font-size: 12px;\n display: inline-flex;\n}\n\n._5JDFMW_fieldset {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 12px;\n min-width: 0;\n margin: 0;\n padding: 2px 12px 12px;\n display: grid;\n}\n\n._5JDFMW_fieldset legend {\n color: var(--dsw-alias-label-secondary);\n padding: 0 4px;\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n}\n\n._5JDFMW_fieldset > ._5JDFMW_hint, ._5JDFMW_fieldset > ._5JDFMW_full {\n grid-column: 1 / -1;\n}\n\n._5JDFMW_previewBox {\n border: 1px solid var(--dsw-alias-border-l2);\n box-sizing: border-box;\n border-radius: 8px;\n min-height: 300px;\n padding: 12px 14px;\n overflow-y: auto;\n}\n\n._5JDFMW_footer {\n flex: 1;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n._5JDFMW_footerHint {\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n}\n\n._5JDFMW_grow {\n flex: auto;\n}\n\n._5JDFMW_footerError {\n color: var(--dsw-alias-state-error-primary);\n font-size: 12px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._5JDFMW_seg button, ._5JDFMW_addIcon, ._5JDFMW_iconBtn {\n transition: none;\n }\n}\n\n@container (width <= 700px) {\n ._5JDFMW_formGrid, ._5JDFMW_fieldset {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n.IgyjIq_card[data-resource-state] {\n box-sizing: border-box;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n min-width: 0;\n max-width: 100%;\n color: var(--dsw-alias-label-primary);\n box-shadow: none;\n cursor: pointer;\n border-left-width: 3px;\n border-radius: 10px;\n gap: 4px 10px;\n padding: 11px 12px 11px 13px;\n transition: border-color .14s, background .14s;\n display: grid;\n position: relative;\n overflow: hidden;\n}\n\n.IgyjIq_card[data-resource-state=\"active\"] {\n border-left-color: var(--dsw-alias-state-success-primary);\n}\n\n.IgyjIq_card[data-resource-state=\"disabled\"] {\n border-left-color: var(--dsw-alias-label-tertiary);\n}\n\n.IgyjIq_card[data-resource-state=\"warning\"] {\n border-left-color: var(--dsw-alias-state-warn-primary);\n}\n\n.IgyjIq_card[data-resource-state=\"error\"] {\n border-left-color: var(--dsw-alias-state-error-primary);\n}\n\n.IgyjIq_card[data-resource-state]:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state]:hover .IgyjIq_rowActions, .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state]:focus-within .IgyjIq_rowActions {\n z-index: 1;\n}\n\n.IgyjIq_collection[data-resource-view] {\n box-sizing: border-box;\n scrollbar-gutter: stable;\n align-content: start;\n align-items: stretch;\n width: 100%;\n min-width: 0;\n min-height: 0;\n overflow-y: auto;\n}\n\n.IgyjIq_collection[data-resource-view=\"grid\"] {\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n grid-auto-rows: 122px;\n gap: 10px;\n padding-right: 4px;\n display: grid;\n}\n\n.IgyjIq_collection[data-resource-view=\"list\"] {\n flex-direction: column;\n gap: 6px;\n padding-right: 4px;\n display: flex;\n}\n\n.IgyjIq_collection[data-resource-view=\"list\"] > .IgyjIq_card {\n flex-shrink: 0;\n}\n\n.IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state] {\n grid-template: \"IgyjIq_id IgyjIq_act\"\n \"IgyjIq_body IgyjIq_body\" minmax(0, 1fr)\n \"IgyjIq_foot IgyjIq_foot\"\n / minmax(0, 1fr) auto;\n}\n\n.IgyjIq_collection[data-resource-view=\"list\"] > .IgyjIq_card[data-resource-state] {\n box-sizing: border-box;\n grid-template-columns: minmax(160px, .85fr) minmax(210px, 1.05fr) minmax(0, 1.5fr) auto;\n grid-template-areas: \"IgyjIq_id IgyjIq_foot IgyjIq_body IgyjIq_act\";\n align-items: center;\n gap: 16px;\n height: 56px;\n}\n\n@container (width <= 700px) {\n .IgyjIq_collection[data-resource-view=\"grid\"] {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n grid-auto-rows: max-content;\n gap: 4px;\n }\n\n .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state] {\n grid-template: \"IgyjIq_id\"\n \"IgyjIq_body\"\n \"IgyjIq_foot\"\n / minmax(0, 1fr);\n align-content: start;\n gap: 4px;\n padding: 10px 10px 10px 13px;\n }\n\n .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state] .IgyjIq_rowId, .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state] .IgyjIq_rowBody {\n overflow: hidden;\n }\n\n .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state] .IgyjIq_rowActions {\n background: var(--dsw-alias-bg-layer-1);\n box-shadow: 0 0 6px 8px var(--dsw-alias-bg-layer-1);\n opacity: 0;\n border-radius: 16px;\n gap: 4px;\n margin-left: 0;\n padding: 4px 6px;\n transition: opacity .14s;\n position: absolute;\n top: 8px;\n bottom: auto;\n right: 8px;\n }\n\n .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state]:hover .IgyjIq_rowActions, .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state]:focus-within .IgyjIq_rowActions {\n opacity: 1;\n }\n\n .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state]:hover, .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state]:focus-within {\n background: var(--dsw-alias-bg-layer-1);\n }\n\n .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-surface=\"mcp\"] .IgyjIq_provenanceChip, .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-surface=\"lsp\"] .IgyjIq_provenanceChip {\n display: none;\n }\n\n .IgyjIq_collection[data-resource-view=\"list\"] > .IgyjIq_card[data-resource-state] {\n grid-template-columns: minmax(0, 1fr) auto;\n grid-template-areas: \"IgyjIq_id IgyjIq_act\"\n \"IgyjIq_foot IgyjIq_act\"\n \"IgyjIq_body IgyjIq_act\";\n height: auto;\n padding-block: 10px;\n }\n}\n\n@container (width <= 420px) {\n .IgyjIq_collection[data-resource-view=\"grid\"] {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n.IgyjIq_rowId {\n grid-area: IgyjIq_id;\n align-items: center;\n gap: 7px;\n min-width: 0;\n min-height: 24px;\n display: flex;\n}\n\n.IgyjIq_rowBody {\n grid-area: IgyjIq_body;\n min-width: 0;\n overflow: hidden;\n}\n\n.IgyjIq_rowFoot {\n grid-area: IgyjIq_foot;\n align-items: center;\n gap: 7px;\n min-width: 0;\n min-height: 16px;\n display: flex;\n overflow: hidden;\n}\n\n.IgyjIq_rowActions {\n border-radius: 8px;\n flex: none;\n grid-area: IgyjIq_act;\n justify-content: flex-end;\n align-items: center;\n gap: 2px;\n margin-left: auto;\n display: flex;\n position: relative;\n}\n\n.IgyjIq_name {\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n white-space: nowrap;\n font-size: 13px;\n font-weight: 600;\n line-height: 20px;\n}\n\n.IgyjIq_nameMono {\n letter-spacing: -.01em;\n font-family: ui-monospace, Menlo, Consolas, monospace;\n font-size: 12.5px;\n}\n\n.IgyjIq_version {\n color: var(--dsw-alias-label-tertiary);\n font-variant-numeric: tabular-nums;\n flex: none;\n font-size: 11px;\n}\n\n.IgyjIq_desc {\n max-height: 34px;\n color: var(--dsw-alias-label-secondary);\n margin: 0;\n font-size: 12px;\n line-height: 17px;\n overflow: hidden;\n}\n\n.IgyjIq_monoLine {\n max-height: 34px;\n color: var(--dsw-alias-label-tertiary);\n overflow-wrap: anywhere;\n margin: 0;\n font-family: ui-monospace, Menlo, Consolas, monospace;\n font-size: 11.5px;\n line-height: 17px;\n overflow: hidden;\n}\n\n.IgyjIq_provenance, .IgyjIq_path {\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 0 auto;\n font-family: ui-monospace, Menlo, Consolas, monospace;\n font-size: 11px;\n overflow: hidden;\n}\n\n.IgyjIq_count {\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n flex: none;\n font-size: 11px;\n}\n\n.IgyjIq_countValue {\n color: var(--dsw-alias-label-secondary);\n font-variant-numeric: tabular-nums;\n font-weight: 600;\n}\n\n.IgyjIq_separator {\n color: var(--dsw-alias-label-dimmed);\n flex: none;\n font-size: 11px;\n}\n\n.IgyjIq_iconBtn {\n width: 24px;\n height: 24px;\n color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 6px;\n justify-content: center;\n align-items: center;\n padding: 0;\n display: inline-flex;\n}\n\n.IgyjIq_iconBtn:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.IgyjIq_iconBtn:disabled {\n cursor: default;\n opacity: .4;\n}\n\n.IgyjIq_iconBtnDanger:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-danger);\n color: var(--dsw-alias-state-error-primary);\n}\n\n.IgyjIq_iconBtn:focus-visible, .IgyjIq_rowActions :focus-visible, .IgyjIq_card[data-resource-state]:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n}\n\n.IgyjIq_revealOnHover {\n opacity: 0;\n transition: opacity .14s;\n}\n\n.IgyjIq_card[data-resource-state]:hover .IgyjIq_revealOnHover, .IgyjIq_card[data-resource-state]:focus-within .IgyjIq_revealOnHover {\n opacity: 1;\n}\n\n.IgyjIq_collection[data-resource-view=\"list\"] .IgyjIq_desc, .IgyjIq_collection[data-resource-view=\"list\"] .IgyjIq_monoLine {\n max-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 11.5px;\n display: block;\n overflow: hidden;\n}\n\n.IgyjIq_collection[data-resource-view=\"list\"] .IgyjIq_revealOnHover {\n opacity: 1;\n}\n\n.IgyjIq_switchWrap, .IgyjIq_warnWrap {\n flex: none;\n align-items: center;\n display: inline-flex;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .IgyjIq_card[data-resource-state], .IgyjIq_revealOnHover, .IgyjIq_rowActions {\n transition: none;\n }\n}\n.sBXwgW_dialog[role=\"dialog\"] {\n box-sizing: border-box;\n max-width: calc(100vw - 48px);\n max-height: calc(100dvh - 48px);\n}\n\n.sBXwgW_dialog[role=\"dialog\"].sBXwgW_sizeSm {\n width: min(460px, 100vw - 48px);\n}\n\n.sBXwgW_dialog[role=\"dialog\"].sBXwgW_sizeMd {\n width: min(640px, 100vw - 48px);\n}\n\n.sBXwgW_dialog[role=\"dialog\"].sBXwgW_sizeLg {\n width: min(880px, 100vw - 48px);\n}\n\n.sBXwgW_body {\n overflow-wrap: anywhere;\n min-width: 0;\n min-height: 0;\n max-height: calc(100dvh - 200px);\n overflow-y: auto;\n}\n\n.sBXwgW_footer {\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n width: 100%;\n display: flex;\n}\n\n.sBXwgW_footer > :first-child {\n flex: 1;\n}\n\n.sBXwgW_footerSlot:empty {\n display: none;\n}\n\n.sBXwgW_frontmatter {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-markdown-code-block);\n color: var(--dsw-alias-label-tertiary);\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n border-radius: 8px;\n margin: 0 0 10px;\n padding: 8px 10px;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11.5px;\n line-height: 18px;\n}\n\n.sBXwgW_preview {\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 14px;\n line-height: 1.6;\n}\n\n.sBXwgW_preview pre, .sBXwgW_preview table {\n max-width: 100%;\n overflow: auto;\n}\n\n.sBXwgW_preview img {\n max-width: 100%;\n height: auto;\n}\n\n.sBXwgW_error {\n color: var(--dsw-alias-state-error-primary);\n margin: 8px 0;\n font-size: 13px;\n}\n\n.sBXwgW_pair {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 16px;\n display: grid;\n}\n\n.sBXwgW_row {\n align-items: center;\n gap: 6px;\n min-width: 0;\n display: flex;\n}\n\n.sBXwgW_row input {\n flex: 1;\n width: 0;\n}\n\n.sBXwgW_row button {\n flex: none;\n}\n\n@media (width <= 640px) {\n .sBXwgW_dialog[role=\"dialog\"] {\n width: calc(100vw - 16px);\n max-width: calc(100vw - 16px);\n max-height: calc(100dvh - 16px);\n }\n\n .sBXwgW_form {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n._9Lujra_rows {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 10px;\n flex-direction: column;\n min-width: 0;\n display: flex;\n overflow: hidden;\n}\n\n._9Lujra_group {\n flex-direction: column;\n min-width: 0;\n display: flex;\n}\n\n._9Lujra_group + ._9Lujra_group ._9Lujra_row {\n border-top: 1px solid var(--dsw-alias-border-l1);\n}\n\n._9Lujra_row {\n box-sizing: border-box;\n width: 100%;\n color: inherit;\n text-align: left;\n font: inherit;\n background: none;\n border: none;\n grid-template-columns: minmax(110px, max-content) minmax(0, 1fr) 14px;\n align-items: center;\n gap: 12px;\n padding: 9px 12px;\n display: grid;\n}\n\nbutton._9Lujra_row {\n cursor: pointer;\n}\n\n._9Lujra_row:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._9Lujra_row[aria-expanded=\"true\"] {\n background: var(--dsw-alias-state-business-tertiary);\n}\n\n._9Lujra_row:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n._9Lujra_name {\n color: var(--dsw-alias-label-primary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11.5px;\n font-weight: 600;\n overflow: hidden;\n}\n\n._9Lujra_summary {\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 11.5px;\n overflow: hidden;\n}\n\n._9Lujra_chevron {\n color: var(--dsw-alias-label-tertiary);\n justify-self: end;\n display: inline-flex;\n}\n\n._9Lujra_chevron svg {\n display: block;\n}\n\n._9Lujra_body {\n border-top: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-interactive-bg-hover);\n padding: 12px 14px;\n}\n.HJ9x7a_shell {\n min-width: 0;\n min-height: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n flex: 1;\n gap: 16px;\n display: flex;\n container-type: inline-size;\n}\n\n.HJ9x7a_header {\n flex-direction: row;\n flex: none;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n min-height: 46px;\n display: flex;\n}\n\n.HJ9x7a_headerText {\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n display: flex;\n}\n\n.HJ9x7a_title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n}\n\n.HJ9x7a_subtitle {\n color: var(--dsw-alias-label-secondary);\n margin: 0;\n font-size: 13px;\n line-height: 20px;\n}\n\n.HJ9x7a_headerActions {\n flex-direction: row;\n flex: none;\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n.HJ9x7a_body {\n scrollbar-gutter: stable;\n flex-direction: column;\n flex: 1;\n gap: 12px;\n min-height: 0;\n display: flex;\n overflow-y: auto;\n}\n\n.HJ9x7a_busyLine {\n color: var(--dsw-alias-label-secondary, #6b7280);\n flex-direction: row;\n flex: none;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n display: flex;\n}\n\n.HJ9x7a_busyLabel {\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n overflow: hidden;\n}\n\n.HJ9x7a_spinner {\n color: var(--dsw-alias-label-secondary, #6b7280);\n flex: none;\n font-size: 13px;\n display: inline-flex;\n}\n\n.HJ9x7a_spinning {\n animation: .9s linear infinite HJ9x7a_panel-spin;\n}\n\n@keyframes HJ9x7a_panel-spin {\n from {\n transform: rotate(0);\n }\n\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .HJ9x7a_spinning {\n animation-duration: 2.4s;\n }\n}\n\n.HJ9x7a_editorDialog {\n gap: 12px;\n max-width: 720px;\n}\n\n.HJ9x7a_editorDialog [class*=\"content\"] > [class*=\"body\"] {\n margin-top: 0;\n}\n\n.HJ9x7a_editorBody {\n flex-direction: column;\n gap: 12px;\n display: flex;\n}\n\n.HJ9x7a_editorFooter {\n flex-direction: row;\n flex: 1;\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.HJ9x7a_editorError {\n color: var(--dsw-alias-state-error-primary, #c81e1e);\n margin-right: auto;\n font-size: 12px;\n}\n\n.HJ9x7a_confirmCheck {\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: row;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n display: flex;\n}\n\n.HJ9x7a_empty {\n color: var(--dsw-alias-label-tertiary, #6b7280);\n text-align: center;\n padding: 24px 12px;\n font-size: 12px;\n}\n\n@container (width <= 540px) {\n .HJ9x7a_entryGrid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .HJ9x7a_entryRow {\n flex-wrap: wrap;\n }\n\n .HJ9x7a_entryActions {\n margin-left: auto;\n }\n\n .HJ9x7a_entryMain {\n flex-basis: 100%;\n }\n}\n\n.HJ9x7a_hero {\n background: var(--dsw-alias-interactive-bg-hover);\n border-radius: 10px;\n align-items: center;\n gap: 10px;\n padding: 12px 14px;\n display: flex;\n}\n\n.HJ9x7a_heroText {\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n display: flex;\n}\n\n.HJ9x7a_heroLine {\n flex-wrap: wrap;\n align-items: center;\n gap: 7px;\n display: flex;\n}\n\n.HJ9x7a_heroMono {\n overflow-wrap: anywhere;\n color: var(--dsw-alias-label-secondary);\n margin: 0;\n font: 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.HJ9x7a_block {\n margin-top: 18px;\n}\n\n.HJ9x7a_blockHead {\n color: var(--dsw-alias-label-secondary);\n letter-spacing: .04em;\n text-transform: uppercase;\n margin: 0 0 8px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.HJ9x7a_kvGrid {\n grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));\n gap: 10px 16px;\n margin: 0;\n display: grid;\n}\n\n.HJ9x7a_kvKey {\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n line-height: 16px;\n}\n\n.HJ9x7a_kvValue {\n text-overflow: ellipsis;\n white-space: nowrap;\n margin: 3px 0 0;\n font-size: 12.5px;\n line-height: 18px;\n overflow: hidden;\n}\n\n.HJ9x7a_monoBlock {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-markdown-code-block);\n color: var(--dsw-alias-label-secondary);\n border-radius: 10px;\n margin: 0;\n padding: 12px 14px;\n font: 11.5px / 18px ui-monospace, Menlo, Consolas, monospace;\n overflow-x: auto;\n}\n\n.HJ9x7a_detailProse {\n color: var(--dsw-alias-label-secondary);\n margin: 0;\n font-size: 13px;\n line-height: 21px;\n}\n\n.HJ9x7a_kvValueMono {\n font-family: ui-monospace, Menlo, Consolas, monospace;\n}\n.vavGuW_toolbar {\n flex: none;\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.vavGuW_search {\n flex: auto;\n align-items: center;\n min-width: 0;\n display: flex;\n}\n\n.vavGuW_searchInput {\n flex: auto;\n min-width: 0;\n}\n\n.vavGuW_searchInput input {\n font-size: 12px;\n line-height: 20px;\n}\n\n.vavGuW_segment {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 10px;\n flex: none;\n align-items: center;\n gap: 2px;\n padding: 3px;\n display: flex;\n}\n\n.vavGuW_count {\n color: var(--dsw-alias-label-tertiary);\n font-variant-numeric: tabular-nums;\n}\n\n.vavGuW_segment svg {\n stroke: currentColor;\n stroke-width: 1.5px;\n stroke-linecap: round;\n stroke-linejoin: round;\n display: block;\n}\n\n@container (width <= 480px) {\n .vavGuW_toolbar {\n flex-wrap: wrap;\n justify-content: flex-end;\n }\n\n .vavGuW_search {\n flex-basis: 100%;\n }\n}\n._5BoKRG_editor {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n box-sizing: border-box;\n border-radius: 8px;\n flex-direction: column;\n display: flex;\n overflow: hidden;\n}\n\n._5BoKRG_editor .cm-editor {\n flex: 1;\n min-height: 0;\n}\n\n._5BoKRG_editor .cm-scroller {\n overflow: auto;\n}\n.G2mDja_form {\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 10px;\n flex-direction: column;\n gap: 10px;\n padding: 12px 14px;\n display: flex;\n}\n\n.G2mDja_head {\n color: var(--dsw-alias-label-secondary, #667085);\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n}\n\n.G2mDja_error {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n overflow-wrap: anywhere;\n border-radius: 8px;\n padding: 8px 10px;\n font-size: 12px;\n line-height: 18px;\n}\n\n.G2mDja_row {\n border-top: 1px solid var(--dsw-alias-border-l1, #eef1f5);\n flex-direction: column;\n gap: 6px;\n min-width: 0;\n padding-top: 8px;\n display: flex;\n}\n\n.G2mDja_ref {\n color: var(--dsw-alias-label-primary, #1f2328);\n font: 600 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.G2mDja_controls {\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.G2mDja_facts {\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n.G2mDja_factOk, .G2mDja_factMiss {\n border-radius: 999px;\n padding: 1px 8px;\n font-size: 11px;\n line-height: 17px;\n}\n\n.G2mDja_factOk {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n background: var(--dsw-alias-state-success-tertiary, #e6faed);\n}\n\n.G2mDja_factMiss {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n background: var(--dsw-alias-state-warn-tertiary, #fef5e7);\n}\n\n.G2mDja_note {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 11px;\n line-height: 17px;\n}\n\n.G2mDja_editor {\n flex-direction: column;\n gap: 8px;\n display: flex;\n}\n\n.G2mDja_input {\n box-sizing: border-box;\n width: 100%;\n color: var(--dsw-alias-label-primary, #1f2328);\n background: var(--dsw-alias-bg-layer-1, #fff);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 8px;\n padding: 7px 10px;\n font-size: 12px;\n}\n\n.G2mDja_input:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 1px;\n}\n\n.G2mDja_actions {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n.HJ9x7a_shell {\n min-width: 0;\n min-height: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n flex: 1;\n gap: 16px;\n display: flex;\n container-type: inline-size;\n}\n\n.HJ9x7a_header {\n flex-direction: row;\n flex: none;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n min-height: 46px;\n display: flex;\n}\n\n.HJ9x7a_headerText {\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n display: flex;\n}\n\n.HJ9x7a_title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n}\n\n.HJ9x7a_subtitle {\n color: var(--dsw-alias-label-secondary);\n margin: 0;\n font-size: 13px;\n line-height: 20px;\n}\n\n.HJ9x7a_headerActions {\n flex-direction: row;\n flex: none;\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n.HJ9x7a_body {\n scrollbar-gutter: stable;\n flex-direction: column;\n flex: 1;\n gap: 12px;\n min-height: 0;\n display: flex;\n overflow-y: auto;\n}\n\n.HJ9x7a_busyLine {\n color: var(--dsw-alias-label-secondary, #6b7280);\n flex-direction: row;\n flex: none;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n display: flex;\n}\n\n.HJ9x7a_busyLabel {\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n overflow: hidden;\n}\n\n.HJ9x7a_spinner {\n color: var(--dsw-alias-label-secondary, #6b7280);\n flex: none;\n font-size: 13px;\n display: inline-flex;\n}\n\n.HJ9x7a_spinning {\n animation: .9s linear infinite HJ9x7a_panel-spin;\n}\n\n@keyframes HJ9x7a_panel-spin {\n from {\n transform: rotate(0);\n }\n\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .HJ9x7a_spinning {\n animation-duration: 2.4s;\n }\n}\n\n.HJ9x7a_editorDialog {\n gap: 12px;\n max-width: 720px;\n}\n\n.HJ9x7a_editorDialog [class*=\"content\"] > [class*=\"body\"] {\n margin-top: 0;\n}\n\n.HJ9x7a_editorBody {\n flex-direction: column;\n gap: 12px;\n display: flex;\n}\n\n.HJ9x7a_editorFooter {\n flex-direction: row;\n flex: 1;\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.HJ9x7a_editorError {\n color: var(--dsw-alias-state-error-primary, #c81e1e);\n margin-right: auto;\n font-size: 12px;\n}\n\n.HJ9x7a_confirmCheck {\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: row;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n display: flex;\n}\n\n.HJ9x7a_empty {\n color: var(--dsw-alias-label-tertiary, #6b7280);\n text-align: center;\n padding: 24px 12px;\n font-size: 12px;\n}\n\n@container (width <= 540px) {\n .HJ9x7a_entryGrid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .HJ9x7a_entryRow {\n flex-wrap: wrap;\n }\n\n .HJ9x7a_entryActions {\n margin-left: auto;\n }\n\n .HJ9x7a_entryMain {\n flex-basis: 100%;\n }\n}\n\n.HJ9x7a_hero {\n background: var(--dsw-alias-interactive-bg-hover);\n border-radius: 10px;\n align-items: center;\n gap: 10px;\n padding: 12px 14px;\n display: flex;\n}\n\n.HJ9x7a_heroText {\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n display: flex;\n}\n\n.HJ9x7a_heroLine {\n flex-wrap: wrap;\n align-items: center;\n gap: 7px;\n display: flex;\n}\n\n.HJ9x7a_heroMono {\n overflow-wrap: anywhere;\n color: var(--dsw-alias-label-secondary);\n margin: 0;\n font: 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.HJ9x7a_block {\n margin-top: 18px;\n}\n\n.HJ9x7a_blockHead {\n color: var(--dsw-alias-label-secondary);\n letter-spacing: .04em;\n text-transform: uppercase;\n margin: 0 0 8px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.HJ9x7a_kvGrid {\n grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));\n gap: 10px 16px;\n margin: 0;\n display: grid;\n}\n\n.HJ9x7a_kvKey {\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n line-height: 16px;\n}\n\n.HJ9x7a_kvValue {\n text-overflow: ellipsis;\n white-space: nowrap;\n margin: 3px 0 0;\n font-size: 12.5px;\n line-height: 18px;\n overflow: hidden;\n}\n\n.HJ9x7a_monoBlock {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-markdown-code-block);\n color: var(--dsw-alias-label-secondary);\n border-radius: 10px;\n margin: 0;\n padding: 12px 14px;\n font: 11.5px / 18px ui-monospace, Menlo, Consolas, monospace;\n overflow-x: auto;\n}\n\n.HJ9x7a_detailProse {\n color: var(--dsw-alias-label-secondary);\n margin: 0;\n font-size: 13px;\n line-height: 21px;\n}\n\n.HJ9x7a_kvValueMono {\n font-family: ui-monospace, Menlo, Consolas, monospace;\n}\n\n.AUWlZW_surface {\n min-width: 0;\n min-height: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n flex: 1;\n display: flex;\n}\n\n.AUWlZW_toolbar {\n flex: none;\n}\n\n@media (width <= 760px) {\n .AUWlZW_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n.AUWlZW_reasonLabel {\n opacity: .85;\n flex: none;\n font-weight: 600;\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_detailBody {\n max-height: 72vh;\n overflow-y: auto;\n}\n\n.AUWlZW_modalFooter {\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n width: 100%;\n display: flex;\n}\n\n.AUWlZW_modalFooterHint {\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n}\n\n.AUWlZW_modalFooterGrow {\n flex: auto;\n}\n\n.AUWlZW_detail {\n flex-direction: column;\n gap: 16px;\n display: flex;\n}\n\n.AUWlZW_reasonBox {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n border-radius: 8px;\n flex-direction: column;\n gap: 4px;\n padding: 10px 12px;\n display: flex;\n}\n\n.AUWlZW_reasonText {\n overflow-wrap: anywhere;\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n}\n\n.AUWlZW_toolList {\n flex-direction: column;\n display: flex;\n}\n\n.AUWlZW_tool {\n border-bottom: 1px solid var(--dsw-alias-border-l1, #eef1f5);\n grid-template-columns: minmax(140px, max-content) minmax(0, 1fr);\n align-items: center;\n gap: 12px;\n padding: 7px 0;\n display: grid;\n}\n\n.AUWlZW_tool:last-child {\n border-bottom: none;\n}\n\n.AUWlZW_toolName {\n color: var(--dsw-alias-label-primary, #1f2328);\n text-overflow: ellipsis;\n white-space: nowrap;\n font: 11px / 16px ui-monospace, Menlo, Consolas, monospace;\n overflow: hidden;\n}\n\n.AUWlZW_toolDescription {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 10px;\n overflow: hidden;\n}\n\n@media (width <= 760px) {\n .AUWlZW_toolbar {\n padding-left: 0;\n padding-right: 0;\n }\n\n .AUWlZW_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .AUWlZW_list .AUWlZW_cardTop {\n max-width: 100%;\n }\n\n .AUWlZW_tool {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .AUWlZW_toolDescription {\n display: none;\n }\n}\n\n.AUWlZW_retryEchoSuccess {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n white-space: nowrap;\n font-size: 12px;\n line-height: 18px;\n}\n\n@keyframes AUWlZW_lspStartingPulse {\n 50% {\n opacity: .35;\n }\n}\n\n.AUWlZW_reasonRaw {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n word-break: break-all;\n margin: 6px 0 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n line-height: 1.5;\n}\n\n.AUWlZW_seamBanner {\n border-left: 3px solid var(--dsw-alias-state-warn-primary, #b45309);\n background: var(--dsw-alias-state-warn-tertiary, #b4530914);\n border-radius: 8px;\n flex-direction: column;\n gap: 8px;\n margin: 0 0 12px;\n padding: 12px 14px;\n display: flex;\n}\n\n.AUWlZW_seamTitle {\n color: var(--dsw-alias-label-primary, #1f2329);\n font-size: 13px;\n font-weight: 600;\n}\n\n.AUWlZW_seamBody {\n color: var(--dsw-alias-label-secondary, #4e5969);\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n}\n\n.AUWlZW_seamPathLabel {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 11px;\n}\n\n.AUWlZW_seamPath {\n color: var(--dsw-alias-label-secondary, #4e5969);\n overflow-wrap: anywhere;\n margin: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n line-height: 16px;\n}\n\n.AUWlZW_seamOther {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n margin: 0;\n font-size: 11px;\n line-height: 16px;\n}\n\n.AUWlZW_seamDone {\n color: var(--dsw-alias-state-success-primary, #15803d);\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n}\n.l0H8fW_workspace {\n min-width: 0;\n height: 100%;\n min-height: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n flex: 1;\n gap: 12px;\n display: flex;\n}\n\n.l0H8fW_pageMode {\n box-sizing: border-box;\n padding: 4px 0;\n}\n\n.l0H8fW_tabRow {\n border-bottom: 1px solid var(--dsw-alias-border-l2, #0000001a);\n scrollbar-width: none;\n flex-direction: row;\n flex: none;\n align-items: center;\n gap: 4px;\n display: flex;\n overflow-x: auto;\n}\n\n.l0H8fW_tab, .l0H8fW_tabOn {\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-radius: 8px 8px 0 0;\n flex: none;\n padding: 7px 14px;\n font-size: 13px;\n line-height: 20px;\n position: relative;\n}\n\n.l0H8fW_tab:hover {\n background: var(--dsw-alias-interactive-bg-hover, #2631480f);\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n.l0H8fW_tabOn {\n color: var(--dsw-alias-label-primary, #1f2328);\n font-weight: 600;\n}\n\n.l0H8fW_tabOn:after {\n background: var(--dsw-alias-brand-primary);\n content: \"\";\n border-radius: 2px;\n height: 2px;\n position: absolute;\n bottom: 0;\n left: 10px;\n right: 10px;\n}\n\n.l0H8fW_tabPanel {\n flex-direction: column;\n flex: 1;\n min-height: 0;\n display: flex;\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=".qUlk6a_overlay {\n z-index: 2147483647;\n box-sizing: border-box;\n background: var(--dsw-alias-bg-mask-3);\n backdrop-filter: blur(3px);\n cursor: progress;\n outline: none;\n place-items: center;\n display: grid;\n position: fixed;\n overflow: hidden;\n}\n\n.qUlk6a_overlay[data-visible=\"false\"] {\n backdrop-filter: none;\n background: none;\n}\n\n.qUlk6a_overlay[data-visible=\"true\"] {\n animation: .14s ease-out qUlk6a_busy-enter;\n}\n\n.qUlk6a_content {\n box-sizing: border-box;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n width: min(360px, 100% - 32px);\n color: var(--dsw-alias-label-primary);\n text-align: center;\n border-radius: 8px;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n padding: 24px;\n display: flex;\n}\n\n.qUlk6a_spinner {\n width: 28px;\n height: 28px;\n animation: .9s linear infinite qUlk6a_busy-spin;\n display: flex;\n}\n\n.qUlk6a_label {\n font-size: 14px;\n font-weight: 600;\n line-height: 20px;\n}\n\n.qUlk6a_hintViewport {\n width: 100%;\n min-height: 54px;\n overflow: hidden;\n}\n\n.qUlk6a_hint {\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n margin: 0;\n font-size: 13px;\n line-height: 18px;\n animation: .3s ease-out qUlk6a_busy-hint;\n}\n\n.qUlk6a_warning {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n background: var(--dsw-alias-state-warn-tertiary, #fef5e7);\n overflow-wrap: anywhere;\n border-radius: 6px;\n margin: 0;\n padding: 6px 8px;\n font-size: 12px;\n line-height: 17px;\n}\n\n@keyframes qUlk6a_busy-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n@keyframes qUlk6a_busy-enter {\n from {\n opacity: 0;\n }\n\n to {\n opacity: 1;\n }\n}\n\n@keyframes qUlk6a_busy-hint {\n from {\n opacity: 0;\n transform: translateY(14px);\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .qUlk6a_overlay, .qUlk6a_hint {\n animation: none;\n }\n\n .qUlk6a_spinner {\n animation-duration: 2.4s;\n }\n}\n._72qoAq_market {\n min-width: 0;\n min-height: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n flex: 1;\n gap: 24px;\n display: flex;\n container-type: inline-size;\n}\n\n._72qoAq_pageMode {\n width: 100%;\n min-width: 0;\n height: 100%;\n min-height: 0;\n}\n\n._72qoAq_marketControls {\n flex-direction: column;\n gap: 8px;\n min-height: 0;\n display: flex;\n}\n\nhtml[data-dsh-agent-plugins-market-page] [data-pane=\"conversation\"], html[data-dsh-agent-plugins-market-page] [class*=\"centerCol\"] {\n position: relative;\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:focus-visible, ._72qoAq_srcTabMain:focus-visible, ._72qoAq_srcTabEdit:focus-visible, ._72qoAq_srcTabDel: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_sourceTabsBox {\n min-width: 0;\n position: relative;\n}\n\n._72qoAq_sourceTabsRow {\n grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));\n gap: 4px;\n min-width: 0;\n display: grid;\n}\n\n._72qoAq_sourceTabsBoxFold {\n clip-path: inset(-6px);\n height: 52px;\n}\n\n._72qoAq_sourceTabsBoxFold:hover, ._72qoAq_sourceTabsBoxFold:has(:focus-visible) {\n clip-path: none;\n z-index: 20;\n}\n\n._72qoAq_sourceTabsBoxFold ._72qoAq_sourceTabsRow {\n box-sizing: border-box;\n background: var(--dsw-alias-bg-layer-1, #fff);\n border-radius: 10px;\n max-height: 58px;\n padding: 6px 6px 0;\n transition: max-height .16s, box-shadow .16s, padding-bottom .16s;\n position: absolute;\n inset: -6px -6px auto;\n overflow: hidden;\n -webkit-mask-image: linear-gradient(#000 78%, #0000 100%);\n mask-image: linear-gradient(#000 78%, #0000 100%);\n}\n\n._72qoAq_sourceTabsBoxFold:hover ._72qoAq_sourceTabsRow, ._72qoAq_sourceTabsBoxFold:has(:focus-visible) ._72qoAq_sourceTabsRow {\n z-index: 30;\n max-height: 420px;\n box-shadow: 0 0 0 1px var(--dsw-alias-border-l3, #d9dde3),\n 0 12px 28px #10182829;\n padding-bottom: 6px;\n -webkit-mask-image: none;\n mask-image: none;\n}\n\n._72qoAq_sourceTabsBoxFold._72qoAq_sourceTabsBoxPicked:hover, ._72qoAq_sourceTabsBoxFold._72qoAq_sourceTabsBoxPicked:has(:focus-visible) {\n clip-path: inset(-6px);\n}\n\n._72qoAq_sourceTabsBoxFold._72qoAq_sourceTabsBoxPicked:hover ._72qoAq_sourceTabsRow, ._72qoAq_sourceTabsBoxFold._72qoAq_sourceTabsBoxPicked:has(:focus-visible) ._72qoAq_sourceTabsRow {\n max-height: 58px;\n box-shadow: none;\n padding-bottom: 0;\n -webkit-mask-image: linear-gradient(#000 78%, #0000 100%);\n mask-image: linear-gradient(#000 78%, #0000 100%);\n}\n\n._72qoAq_unmanagedRow {\n color: var(--dsw-alias-label-secondary, #57606a);\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n margin-top: 6px;\n font-size: 12px;\n display: flex;\n}\n\n._72qoAq_unmanagedLabel {\n flex-shrink: 0;\n}\n\n._72qoAq_unmanagedChip {\n border: 1px dashed var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-bg-layer-1, #fff);\n border-radius: 999px;\n align-items: center;\n gap: 2px;\n max-width: 220px;\n height: 22px;\n padding: 0 4px 0 8px;\n display: inline-flex;\n}\n\n._72qoAq_unmanagedChipName {\n white-space: nowrap;\n text-overflow: ellipsis;\n font-size: 12px;\n overflow: hidden;\n}\n\n._72qoAq_unmanagedAdopt {\n font: inherit;\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n cursor: pointer;\n background: none;\n border: none;\n flex-shrink: 0;\n padding: 0 4px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_unmanagedAdopt:disabled {\n cursor: default;\n opacity: .5;\n}\n\n._72qoAq_srcTabEdit {\n font: inherit;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n background: none;\n border: none;\n flex-shrink: 0;\n margin-left: 4px;\n padding: 0 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: auto;\n max-width: 100%;\n height: 24px;\n padding: 0 10px;\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: 0;\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, #0f1115);\n border-color: var(--dsw-alias-brand-primary, #0f1115);\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 margin-left: 4px;\n padding: 0 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, ._72qoAq_list ._72qoAq_cardActions {\n flex: none;\n}\n\n._72qoAq_list ._72qoAq_meta, ._72qoAq_list ._72qoAq_tagRow {\n flex-basis: 100%;\n}\n\n._72qoAq_empty {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-align: center;\n grid-column: 1 / -1;\n padding: 48px 0;\n font-size: 13px;\n}\n\n._72qoAq_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_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_confirmCheck {\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: row;\n align-items: center;\n gap: 8px;\n font-size: 12px;\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(640px, 92vw);\n}\n\n._72qoAq_installConfirmBody {\n flex-direction: column;\n gap: 10px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_installConfirmSuite {\n color: var(--dsw-alias-label-primary, #111827);\n font-weight: 600;\n}\n\n._72qoAq_installConfirmMeta {\n color: var(--dsw-alias-label-secondary, #4b5563);\n font-size: 12px;\n}\n\n._72qoAq_installConfirmCommit {\n color: var(--dsw-alias-label-secondary, #4b5563);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12px;\n}\n\n._72qoAq_installConfirmTags {\n flex-wrap: wrap;\n gap: 6px;\n display: flex;\n}\n\n._72qoAq_installConfirmWarn {\n color: var(--dsw-alias-state-warn-label, #dd8629);\n border: 1px solid var(--dsw-alias-state-warn-label, #dd8629);\n border-radius: 8px;\n padding: 8px 10px;\n font-size: 12px;\n}\n\n._72qoAq_progress, ._72qoAq_progressError {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n background: var(--dsw-alias-bg-layer-2, #7f7f7f0f);\n color: var(--dsw-alias-label-primary, #1f2328);\n border-radius: 8px;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n font-size: 13px;\n line-height: 20px;\n display: flex;\n}\n\n._72qoAq_progressError {\n border-color: var(--dsw-alias-state-error-primary, #ec1313);\n color: var(--dsw-alias-state-error-primary, #ec1313);\n}\n\n._72qoAq_progressSpin {\n border: 2px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-top-color: var(--dsw-alias-brand-primary, #4f6ef7);\n border-radius: 50%;\n flex-shrink: 0;\n width: 14px;\n height: 14px;\n animation: .8s linear infinite _72qoAq_dshApmSpin;\n}\n\n@keyframes _72qoAq_dshApmSpin {\n to {\n transform: rotate(360deg);\n }\n}\n\n._72qoAq_progressFail {\n flex-shrink: 0;\n font-size: 13px;\n}\n\n._72qoAq_progressText {\n overflow-wrap: anywhere;\n min-width: 0;\n}\n\n@media (width <= 720px) {\n ._72qoAq_pageView {\n padding: 14px;\n }\n\n ._72qoAq_sourceTabsRow {\n grid-template-columns: repeat(auto-fill, minmax(102px, 1fr));\n }\n\n ._72qoAq_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n ._72qoAq_list ._72qoAq_cardTop, ._72qoAq_list ._72qoAq_cardActions {\n max-width: 100%;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._72qoAq_progressSpin, ._72qoAq_switchOn, ._72qoAq_switchOff, ._72qoAq_switchThumb {\n transition: none;\n animation: none;\n }\n}\n\n._72qoAq_surfaceToggles {\n flex-wrap: wrap;\n align-items: center;\n gap: 4px 14px;\n display: flex;\n}\n\n._72qoAq_surfaceToggle {\n color: var(--dsw-alias-label-secondary, #61666b);\n cursor: pointer;\n user-select: none;\n align-items: center;\n gap: 5px;\n font-size: 12px;\n display: inline-flex;\n}\n\n._72qoAq_surfaceToggle input[type=\"checkbox\"] {\n accent-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);\n margin: 0;\n}\n\n._72qoAq_pluginCard {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n background: var(--dsw-alias-bg-layer-3, #fff);\n border-radius: 12px;\n list-style: none;\n transition: border-color .16s, background .16s;\n container: _72qoAq_market-config / inline-size;\n}\n\n._72qoAq_pluginCard:hover {\n border-color: var(--dsw-alias-label-dimmed, #c8ccd4);\n}\n\n._72qoAq_pluginCardOpen {\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border-color: var(--dsw-alias-label-dimmed, #c8ccd4);\n}\n\n._72qoAq_pluginCard[data-busy=\"true\"] {\n opacity: .6;\n pointer-events: none;\n}\n\n._72qoAq_pluginCardHeader {\n appearance: none;\n width: 100%;\n font: inherit;\n color: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n border-radius: 12px;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n display: flex;\n}\n\n._72qoAq_pluginCardHeader:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: -2px;\n}\n\n._72qoAq_pluginCardBody {\n border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n flex-direction: column;\n gap: 8px;\n margin: 0 16px;\n padding: 4px 0 8px;\n display: flex;\n}\n\n._72qoAq_pluginCardRow {\n justify-content: space-between;\n align-items: center;\n gap: 16px;\n padding: 8px 0 4px;\n display: flex;\n}\n\n._72qoAq_pluginCardText {\n flex-direction: column;\n flex: 1;\n gap: 4px;\n min-width: 0;\n display: flex;\n}\n\n._72qoAq_pluginCardTitle {\n color: var(--dsw-alias-label-primary, #1f2328);\n font-size: 15px;\n font-weight: 600;\n line-height: 1.4;\n}\n\n._72qoAq_pluginCardDesc {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 13px;\n line-height: 1.5;\n}\n\n._72qoAq_pluginCardRowLabel {\n font-size: 13px;\n font-weight: 500;\n line-height: 20px;\n}\n\n@container _72qoAq_market-config (width <= 320px) {\n ._72qoAq_pluginCardRow {\n flex-direction: column;\n align-items: flex-start;\n gap: 8px;\n }\n\n ._72qoAq_pluginCardText {\n overflow-wrap: anywhere;\n width: 100%;\n }\n\n ._72qoAq_regionSeg {\n flex-wrap: wrap;\n max-width: 100%;\n }\n}\n\n._72qoAq_pluginCardError {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n}\n\n._72qoAq_pluginFieldHead {\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n._72qoAq_pluginFieldBadges {\n align-items: center;\n gap: 6px;\n display: inline-flex;\n}\n\n._72qoAq_pluginFieldReset {\n appearance: none;\n font: inherit;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n text-underline-offset: 2px;\n background: none;\n border: 0;\n padding: 0;\n font-size: 12px;\n line-height: 18px;\n text-decoration: underline;\n}\n\n._72qoAq_pluginFieldReset:disabled {\n cursor: default;\n opacity: .5;\n}\n\n._72qoAq_pluginCardReadonly {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n}\n\n._72qoAq_pluginCardFooter {\n border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n margin-top: 4px;\n padding-top: 8px;\n display: flex;\n}\n\n._72qoAq_pluginCardFooter ._72qoAq_pluginCardError {\n margin-right: auto;\n}\n\n._72qoAq_pluginCardDiscard, ._72qoAq_pluginCardSave {\n appearance: none;\n font: inherit;\n cursor: pointer;\n border-radius: 8px;\n padding: 4px 12px;\n font-size: 13px;\n line-height: 20px;\n}\n\n._72qoAq_pluginCardDiscard {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n color: var(--dsw-alias-label-primary, #1f2328);\n background: none;\n}\n\n._72qoAq_pluginCardDiscard:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, #0000000a);\n}\n\n._72qoAq_pluginCardSave {\n background: var(--dsw-alias-button-primary-fill);\n color: var(--dsw-alias-label-primary-foreground);\n border: 1px solid #0000;\n}\n\n._72qoAq_pluginCardSave:hover:not(:disabled) {\n background: var(--dsw-alias-button-primary-hover);\n}\n\n._72qoAq_pluginCardDiscard:disabled, ._72qoAq_pluginCardSave:disabled {\n cursor: default;\n opacity: .5;\n}\n\n._72qoAq_pluginChevron {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n flex: none;\n transition: transform .16s;\n display: inline-flex;\n}\n\n._72qoAq_pluginChevronOpen {\n transform: rotate(180deg);\n}\n\n._72qoAq_regionSeg {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 8px;\n flex: none;\n gap: 2px;\n padding: 2px;\n display: inline-flex;\n}\n\n._72qoAq_regionSegBtn {\n appearance: none;\n font: inherit;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 6px;\n padding: 3px 10px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_regionSegOn {\n appearance: none;\n font: inherit;\n cursor: pointer;\n background: var(--dsw-alias-bg-layer-2, #eef0f4);\n color: var(--dsw-alias-label-primary, #1f2328);\n border: none;\n border-radius: 6px;\n padding: 3px 10px;\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n}\n\n._72qoAq_regionSegEffective {\n appearance: none;\n font: inherit;\n cursor: pointer;\n color: var(--dsw-alias-label-primary, #1f2328);\n background: none;\n border: none;\n border-radius: 6px;\n padding: 3px 10px;\n font-size: 12px;\n line-height: 18px;\n}\n\n._72qoAq_regionSegBtn:disabled, ._72qoAq_regionSegOn:disabled {\n cursor: default;\n opacity: .5;\n}\n._5JDFMW_field {\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n display: flex;\n}\n\n._5JDFMW_field > label, ._5JDFMW_field > span, ._5JDFMW_field > ._5JDFMW_rowHead > span {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n font-weight: 600;\n}\n\n._5JDFMW_field input, ._5JDFMW_field select, ._5JDFMW_field textarea {\n box-sizing: border-box;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n width: 100%;\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n border-radius: 8px;\n padding: 7px 9px;\n font-size: 12px;\n}\n\n._5JDFMW_field textarea {\n resize: vertical;\n min-height: 240px;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n line-height: 19px;\n}\n\n._5JDFMW_jsonArea {\n min-height: 220px;\n}\n\n._5JDFMW_fieldRow {\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n._5JDFMW_fieldRow > input {\n flex: auto;\n}\n\n._5JDFMW_field input:focus-visible, ._5JDFMW_field select:focus-visible, ._5JDFMW_field textarea:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n._5JDFMW_hint {\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n font-weight: 400;\n line-height: 16px;\n}\n\n._5JDFMW_required {\n color: var(--dsw-alias-state-error-primary);\n margin-left: 4px;\n font-weight: 400;\n}\n\n._5JDFMW_emptyRows {\n border: 1px dashed var(--dsw-alias-border-l3);\n width: 100%;\n color: var(--dsw-alias-label-tertiary);\n font: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border-radius: 8px;\n padding: 8px 10px;\n font-size: 11px;\n line-height: 16px;\n}\n\n._5JDFMW_emptyRows:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n\n._5JDFMW_form {\n flex-direction: column;\n gap: 10px;\n min-width: 0;\n display: flex;\n}\n\n._5JDFMW_editorBody {\n max-width: 620px;\n}\n\n._5JDFMW_formGrid {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n align-items: start;\n gap: 10px;\n display: grid;\n}\n\n._5JDFMW_full {\n grid-column: 1 / -1;\n}\n\n._5JDFMW_seg {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n flex: none;\n gap: 2px;\n padding: 2px;\n display: inline-flex;\n}\n\n._5JDFMW_seg button {\n height: 24px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n background: none;\n border: none;\n border-radius: 6px;\n padding: 0 10px;\n font-size: 12px;\n}\n\n._5JDFMW_seg button:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._5JDFMW_seg button[aria-pressed=\"true\"] {\n background: var(--dsw-alias-interactive-bg-active);\n color: var(--dsw-alias-label-primary);\n font-weight: 600;\n}\n\n._5JDFMW_seg button:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n}\n\n._5JDFMW_readonly {\n border: 1px dashed var(--dsw-alias-border-l3);\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n border-radius: 8px;\n padding: 7px 9px;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n}\n\n._5JDFMW_rows {\n flex-direction: column;\n gap: 4px;\n min-width: 0;\n display: flex;\n}\n\n._5JDFMW_row {\n align-items: center;\n gap: 6px;\n min-width: 0;\n display: flex;\n}\n\n._5JDFMW_row input {\n flex: auto;\n width: 0;\n min-width: 0;\n}\n\n._5JDFMW_rowKey {\n flex: 0 0 34%;\n}\n\n._5JDFMW_rowKeyNarrow {\n flex: 0 0 26%;\n}\n\n._5JDFMW_rowActions {\n flex: none;\n align-items: center;\n gap: 2px;\n display: flex;\n}\n\n._5JDFMW_iconBtn {\n width: 24px;\n height: 24px;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 6px;\n justify-content: center;\n align-items: center;\n padding: 0;\n display: inline-flex;\n}\n\n._5JDFMW_iconBtn:hover {\n background: var(--dsw-alias-interactive-bg-hover-danger);\n color: var(--dsw-alias-state-error-primary);\n}\n\n._5JDFMW_rowHead {\n justify-content: space-between;\n align-items: center;\n gap: 8px;\n min-height: 24px;\n display: flex;\n}\n\n._5JDFMW_addIcon {\n width: 24px;\n height: 24px;\n color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 6px;\n justify-content: center;\n align-items: center;\n padding: 0;\n display: inline-flex;\n}\n\n._5JDFMW_addIcon:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._5JDFMW_addIcon:disabled {\n cursor: default;\n opacity: .4;\n}\n\n._5JDFMW_addIcon svg {\n display: block;\n}\n\n._5JDFMW_inlineCheck {\n color: var(--dsw-alias-label-primary);\n align-items: center;\n gap: 8px;\n font-size: 12px;\n display: inline-flex;\n}\n\n._5JDFMW_fieldset {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 12px;\n min-width: 0;\n margin: 0;\n padding: 2px 12px 12px;\n display: grid;\n}\n\n._5JDFMW_fieldset legend {\n color: var(--dsw-alias-label-secondary);\n padding: 0 4px;\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n}\n\n._5JDFMW_fieldset > ._5JDFMW_hint, ._5JDFMW_fieldset > ._5JDFMW_full {\n grid-column: 1 / -1;\n}\n\n._5JDFMW_previewBox {\n border: 1px solid var(--dsw-alias-border-l2);\n box-sizing: border-box;\n border-radius: 8px;\n min-height: 300px;\n padding: 12px 14px;\n overflow-y: auto;\n}\n\n._5JDFMW_footer {\n flex: 1;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n._5JDFMW_footerHint {\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n}\n\n._5JDFMW_grow {\n flex: auto;\n}\n\n._5JDFMW_footerError {\n color: var(--dsw-alias-state-error-primary);\n font-size: 12px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._5JDFMW_seg button, ._5JDFMW_addIcon, ._5JDFMW_iconBtn {\n transition: none;\n }\n}\n\n@container (width <= 700px) {\n ._5JDFMW_formGrid, ._5JDFMW_fieldset {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n.IgyjIq_card[data-resource-state] {\n box-sizing: border-box;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n min-width: 0;\n max-width: 100%;\n color: var(--dsw-alias-label-primary);\n box-shadow: none;\n cursor: pointer;\n border-left-width: 3px;\n border-radius: 10px;\n gap: 4px 10px;\n padding: 11px 12px 11px 13px;\n transition: border-color .14s, background .14s;\n display: grid;\n position: relative;\n overflow: hidden;\n}\n\n.IgyjIq_card[data-resource-state=\"active\"] {\n border-left-color: var(--dsw-alias-state-success-primary);\n}\n\n.IgyjIq_card[data-resource-state=\"disabled\"] {\n border-left-color: var(--dsw-alias-label-tertiary);\n}\n\n.IgyjIq_card[data-resource-state=\"warning\"] {\n border-left-color: var(--dsw-alias-state-warn-primary);\n}\n\n.IgyjIq_card[data-resource-state=\"error\"] {\n border-left-color: var(--dsw-alias-state-error-primary);\n}\n\n.IgyjIq_card[data-resource-state]:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state]:hover .IgyjIq_rowActions, .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state]:focus-within .IgyjIq_rowActions {\n z-index: 1;\n}\n\n.IgyjIq_collection[data-resource-view] {\n box-sizing: border-box;\n scrollbar-gutter: stable;\n align-content: start;\n align-items: stretch;\n width: 100%;\n min-width: 0;\n min-height: 0;\n overflow-y: auto;\n}\n\n.IgyjIq_collection[data-resource-view=\"grid\"] {\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n grid-auto-rows: 122px;\n gap: 10px;\n padding-right: 4px;\n display: grid;\n}\n\n.IgyjIq_collection[data-resource-view=\"list\"] {\n flex-direction: column;\n gap: 6px;\n padding-right: 4px;\n display: flex;\n}\n\n.IgyjIq_collection[data-resource-view=\"list\"] > .IgyjIq_card {\n flex-shrink: 0;\n}\n\n.IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state] {\n grid-template: \"IgyjIq_id IgyjIq_act\"\n \"IgyjIq_body IgyjIq_body\" minmax(0, 1fr)\n \"IgyjIq_foot IgyjIq_foot\"\n / minmax(0, 1fr) auto;\n}\n\n.IgyjIq_collection[data-resource-view=\"list\"] > .IgyjIq_card[data-resource-state] {\n box-sizing: border-box;\n grid-template-columns: minmax(160px, .85fr) minmax(210px, 1.05fr) minmax(0, 1.5fr) auto;\n grid-template-areas: \"IgyjIq_id IgyjIq_foot IgyjIq_body IgyjIq_act\";\n align-items: center;\n gap: 16px;\n height: 56px;\n}\n\n@container (width <= 700px) {\n .IgyjIq_collection[data-resource-view=\"grid\"] {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n grid-auto-rows: max-content;\n gap: 4px;\n }\n\n .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state] {\n grid-template: \"IgyjIq_id\"\n \"IgyjIq_body\"\n \"IgyjIq_foot\"\n / minmax(0, 1fr);\n align-content: start;\n gap: 4px;\n padding: 10px 10px 10px 13px;\n }\n\n .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state] .IgyjIq_rowId, .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state] .IgyjIq_rowBody {\n overflow: hidden;\n }\n\n .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state] .IgyjIq_rowActions {\n background: var(--dsw-alias-bg-layer-1);\n box-shadow: 0 0 6px 8px var(--dsw-alias-bg-layer-1);\n opacity: 0;\n border-radius: 16px;\n gap: 4px;\n margin-left: 0;\n padding: 4px 6px;\n transition: opacity .14s;\n position: absolute;\n top: 8px;\n bottom: auto;\n right: 8px;\n }\n\n .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state]:hover .IgyjIq_rowActions, .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state]:focus-within .IgyjIq_rowActions {\n opacity: 1;\n }\n\n .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state]:hover, .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-state]:focus-within {\n background: var(--dsw-alias-bg-layer-1);\n }\n\n .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-surface=\"mcp\"] .IgyjIq_provenanceChip, .IgyjIq_collection[data-resource-view=\"grid\"] > .IgyjIq_card[data-resource-surface=\"lsp\"] .IgyjIq_provenanceChip {\n display: none;\n }\n\n .IgyjIq_collection[data-resource-view=\"list\"] > .IgyjIq_card[data-resource-state] {\n grid-template-columns: minmax(0, 1fr) auto;\n grid-template-areas: \"IgyjIq_id IgyjIq_act\"\n \"IgyjIq_foot IgyjIq_act\"\n \"IgyjIq_body IgyjIq_act\";\n height: auto;\n padding-block: 10px;\n }\n}\n\n@container (width <= 420px) {\n .IgyjIq_collection[data-resource-view=\"grid\"] {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n.IgyjIq_rowId {\n grid-area: IgyjIq_id;\n align-items: center;\n gap: 7px;\n min-width: 0;\n min-height: 24px;\n display: flex;\n}\n\n.IgyjIq_rowBody {\n grid-area: IgyjIq_body;\n min-width: 0;\n overflow: hidden;\n}\n\n.IgyjIq_rowFoot {\n grid-area: IgyjIq_foot;\n align-items: center;\n gap: 7px;\n min-width: 0;\n min-height: 16px;\n display: flex;\n overflow: hidden;\n}\n\n.IgyjIq_rowActions {\n border-radius: 8px;\n flex: none;\n grid-area: IgyjIq_act;\n justify-content: flex-end;\n align-items: center;\n gap: 2px;\n margin-left: auto;\n display: flex;\n position: relative;\n}\n\n.IgyjIq_name {\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n white-space: nowrap;\n font-size: 13px;\n font-weight: 600;\n line-height: 20px;\n}\n\n.IgyjIq_nameMono {\n letter-spacing: -.01em;\n font-family: ui-monospace, Menlo, Consolas, monospace;\n font-size: 12.5px;\n}\n\n.IgyjIq_version {\n color: var(--dsw-alias-label-tertiary);\n font-variant-numeric: tabular-nums;\n flex: none;\n font-size: 11px;\n}\n\n.IgyjIq_desc {\n max-height: 34px;\n color: var(--dsw-alias-label-secondary);\n margin: 0;\n font-size: 12px;\n line-height: 17px;\n overflow: hidden;\n}\n\n.IgyjIq_monoLine {\n max-height: 34px;\n color: var(--dsw-alias-label-tertiary);\n overflow-wrap: anywhere;\n margin: 0;\n font-family: ui-monospace, Menlo, Consolas, monospace;\n font-size: 11.5px;\n line-height: 17px;\n overflow: hidden;\n}\n\n.IgyjIq_provenance, .IgyjIq_path {\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 0 auto;\n font-family: ui-monospace, Menlo, Consolas, monospace;\n font-size: 11px;\n overflow: hidden;\n}\n\n.IgyjIq_count {\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n flex: none;\n font-size: 11px;\n}\n\n.IgyjIq_countValue {\n color: var(--dsw-alias-label-secondary);\n font-variant-numeric: tabular-nums;\n font-weight: 600;\n}\n\n.IgyjIq_separator {\n color: var(--dsw-alias-label-dimmed);\n flex: none;\n font-size: 11px;\n}\n\n.IgyjIq_iconBtn {\n width: 24px;\n height: 24px;\n color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 6px;\n justify-content: center;\n align-items: center;\n padding: 0;\n display: inline-flex;\n}\n\n.IgyjIq_iconBtn:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.IgyjIq_iconBtn:disabled {\n cursor: default;\n opacity: .4;\n}\n\n.IgyjIq_iconBtnDanger:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-danger);\n color: var(--dsw-alias-state-error-primary);\n}\n\n.IgyjIq_iconBtn:focus-visible, .IgyjIq_rowActions :focus-visible, .IgyjIq_card[data-resource-state]:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n}\n\n.IgyjIq_revealOnHover {\n opacity: 0;\n transition: opacity .14s;\n}\n\n.IgyjIq_card[data-resource-state]:hover .IgyjIq_revealOnHover, .IgyjIq_card[data-resource-state]:focus-within .IgyjIq_revealOnHover {\n opacity: 1;\n}\n\n.IgyjIq_collection[data-resource-view=\"list\"] .IgyjIq_desc, .IgyjIq_collection[data-resource-view=\"list\"] .IgyjIq_monoLine {\n max-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 11.5px;\n display: block;\n overflow: hidden;\n}\n\n.IgyjIq_collection[data-resource-view=\"list\"] .IgyjIq_revealOnHover {\n opacity: 1;\n}\n\n.IgyjIq_switchWrap, .IgyjIq_warnWrap {\n flex: none;\n align-items: center;\n display: inline-flex;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .IgyjIq_card[data-resource-state], .IgyjIq_revealOnHover, .IgyjIq_rowActions {\n transition: none;\n }\n}\n.sBXwgW_dialog[role=\"dialog\"] {\n box-sizing: border-box;\n max-width: calc(100vw - 48px);\n max-height: calc(100dvh - 48px);\n}\n\n.sBXwgW_dialog[role=\"dialog\"].sBXwgW_sizeSm {\n width: min(460px, 100vw - 48px);\n}\n\n.sBXwgW_dialog[role=\"dialog\"].sBXwgW_sizeMd {\n width: min(640px, 100vw - 48px);\n}\n\n.sBXwgW_dialog[role=\"dialog\"].sBXwgW_sizeLg {\n width: min(880px, 100vw - 48px);\n}\n\n.sBXwgW_body {\n overflow-wrap: anywhere;\n min-width: 0;\n min-height: 0;\n max-height: calc(100dvh - 200px);\n overflow-y: auto;\n}\n\n.sBXwgW_footer {\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n width: 100%;\n display: flex;\n}\n\n.sBXwgW_footer > :first-child {\n flex: 1;\n}\n\n.sBXwgW_footerSlot:empty {\n display: none;\n}\n\n.sBXwgW_frontmatter {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-markdown-code-block);\n color: var(--dsw-alias-label-tertiary);\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n border-radius: 8px;\n margin: 0 0 10px;\n padding: 8px 10px;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11.5px;\n line-height: 18px;\n}\n\n.sBXwgW_preview {\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 14px;\n line-height: 1.6;\n}\n\n.sBXwgW_preview pre, .sBXwgW_preview table {\n max-width: 100%;\n overflow: auto;\n}\n\n.sBXwgW_preview img {\n max-width: 100%;\n height: auto;\n}\n\n.sBXwgW_error {\n color: var(--dsw-alias-state-error-primary);\n margin: 8px 0;\n font-size: 13px;\n}\n\n.sBXwgW_pair {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 16px;\n display: grid;\n}\n\n.sBXwgW_row {\n align-items: center;\n gap: 6px;\n min-width: 0;\n display: flex;\n}\n\n.sBXwgW_row input {\n flex: 1;\n width: 0;\n}\n\n.sBXwgW_row button {\n flex: none;\n}\n\n@media (width <= 640px) {\n .sBXwgW_dialog[role=\"dialog\"] {\n width: calc(100vw - 16px);\n max-width: calc(100vw - 16px);\n max-height: calc(100dvh - 16px);\n }\n\n .sBXwgW_form {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n._9Lujra_rows {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 10px;\n flex-direction: column;\n min-width: 0;\n display: flex;\n overflow: hidden;\n}\n\n._9Lujra_group {\n flex-direction: column;\n min-width: 0;\n display: flex;\n}\n\n._9Lujra_group + ._9Lujra_group ._9Lujra_row {\n border-top: 1px solid var(--dsw-alias-border-l1);\n}\n\n._9Lujra_row {\n box-sizing: border-box;\n width: 100%;\n color: inherit;\n text-align: left;\n font: inherit;\n background: none;\n border: none;\n grid-template-columns: minmax(110px, max-content) minmax(0, 1fr) 14px;\n align-items: center;\n gap: 12px;\n padding: 9px 12px;\n display: grid;\n}\n\nbutton._9Lujra_row {\n cursor: pointer;\n}\n\n._9Lujra_row:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._9Lujra_row[aria-expanded=\"true\"] {\n background: var(--dsw-alias-state-business-tertiary);\n}\n\n._9Lujra_row:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n._9Lujra_name {\n color: var(--dsw-alias-label-primary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11.5px;\n font-weight: 600;\n overflow: hidden;\n}\n\n._9Lujra_summary {\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 11.5px;\n overflow: hidden;\n}\n\n._9Lujra_chevron {\n color: var(--dsw-alias-label-tertiary);\n justify-self: end;\n display: inline-flex;\n}\n\n._9Lujra_chevron svg {\n display: block;\n}\n\n._9Lujra_body {\n border-top: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-interactive-bg-hover);\n padding: 12px 14px;\n}\n.HJ9x7a_shell {\n min-width: 0;\n min-height: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n flex: 1;\n gap: 16px;\n display: flex;\n container-type: inline-size;\n}\n\n.HJ9x7a_header {\n flex-direction: row;\n flex: none;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n min-height: 46px;\n display: flex;\n}\n\n.HJ9x7a_headerText {\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n display: flex;\n}\n\n.HJ9x7a_title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n}\n\n.HJ9x7a_subtitle {\n color: var(--dsw-alias-label-secondary);\n margin: 0;\n font-size: 13px;\n line-height: 20px;\n}\n\n.HJ9x7a_headerActions {\n flex-direction: row;\n flex: none;\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n.HJ9x7a_body {\n scrollbar-gutter: stable;\n flex-direction: column;\n flex: 1;\n gap: 12px;\n min-height: 0;\n display: flex;\n overflow-y: auto;\n}\n\n.HJ9x7a_busyLine {\n color: var(--dsw-alias-label-secondary, #6b7280);\n flex-direction: row;\n flex: none;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n display: flex;\n}\n\n.HJ9x7a_busyLabel {\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n overflow: hidden;\n}\n\n.HJ9x7a_spinner {\n color: var(--dsw-alias-label-secondary, #6b7280);\n flex: none;\n font-size: 13px;\n display: inline-flex;\n}\n\n.HJ9x7a_spinning {\n animation: .9s linear infinite HJ9x7a_panel-spin;\n}\n\n@keyframes HJ9x7a_panel-spin {\n from {\n transform: rotate(0);\n }\n\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .HJ9x7a_spinning {\n animation-duration: 2.4s;\n }\n}\n\n.HJ9x7a_editorDialog {\n gap: 12px;\n max-width: 720px;\n}\n\n.HJ9x7a_editorDialog [class*=\"content\"] > [class*=\"body\"] {\n margin-top: 0;\n}\n\n.HJ9x7a_editorBody {\n flex-direction: column;\n gap: 12px;\n display: flex;\n}\n\n.HJ9x7a_editorFooter {\n flex-direction: row;\n flex: 1;\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.HJ9x7a_editorError {\n color: var(--dsw-alias-state-error-primary, #c81e1e);\n margin-right: auto;\n font-size: 12px;\n}\n\n.HJ9x7a_confirmCheck {\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: row;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n display: flex;\n}\n\n.HJ9x7a_empty {\n color: var(--dsw-alias-label-tertiary, #6b7280);\n text-align: center;\n padding: 24px 12px;\n font-size: 12px;\n}\n\n@container (width <= 540px) {\n .HJ9x7a_entryGrid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .HJ9x7a_entryRow {\n flex-wrap: wrap;\n }\n\n .HJ9x7a_entryActions {\n margin-left: auto;\n }\n\n .HJ9x7a_entryMain {\n flex-basis: 100%;\n }\n}\n\n.HJ9x7a_hero {\n background: var(--dsw-alias-interactive-bg-hover);\n border-radius: 10px;\n align-items: center;\n gap: 10px;\n padding: 12px 14px;\n display: flex;\n}\n\n.HJ9x7a_heroText {\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n display: flex;\n}\n\n.HJ9x7a_heroLine {\n flex-wrap: wrap;\n align-items: center;\n gap: 7px;\n display: flex;\n}\n\n.HJ9x7a_heroMono {\n overflow-wrap: anywhere;\n color: var(--dsw-alias-label-secondary);\n margin: 0;\n font: 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.HJ9x7a_block {\n margin-top: 18px;\n}\n\n.HJ9x7a_blockHead {\n color: var(--dsw-alias-label-secondary);\n letter-spacing: .04em;\n text-transform: uppercase;\n margin: 0 0 8px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.HJ9x7a_kvGrid {\n grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));\n gap: 10px 16px;\n margin: 0;\n display: grid;\n}\n\n.HJ9x7a_kvKey {\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n line-height: 16px;\n}\n\n.HJ9x7a_kvValue {\n text-overflow: ellipsis;\n white-space: nowrap;\n margin: 3px 0 0;\n font-size: 12.5px;\n line-height: 18px;\n overflow: hidden;\n}\n\n.HJ9x7a_monoBlock {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-markdown-code-block);\n color: var(--dsw-alias-label-secondary);\n border-radius: 10px;\n margin: 0;\n padding: 12px 14px;\n font: 11.5px / 18px ui-monospace, Menlo, Consolas, monospace;\n overflow-x: auto;\n}\n\n.HJ9x7a_detailProse {\n color: var(--dsw-alias-label-secondary);\n margin: 0;\n font-size: 13px;\n line-height: 21px;\n}\n\n.HJ9x7a_kvValueMono {\n font-family: ui-monospace, Menlo, Consolas, monospace;\n}\n.vavGuW_toolbar {\n flex: none;\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.vavGuW_search {\n flex: auto;\n align-items: center;\n min-width: 0;\n display: flex;\n}\n\n.vavGuW_searchInput {\n flex: auto;\n min-width: 0;\n}\n\n.vavGuW_searchInput input {\n font-size: 12px;\n line-height: 20px;\n}\n\n.vavGuW_segment {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 10px;\n flex: none;\n align-items: center;\n gap: 2px;\n padding: 3px;\n display: flex;\n}\n\n.vavGuW_count {\n color: var(--dsw-alias-label-tertiary);\n font-variant-numeric: tabular-nums;\n}\n\n.vavGuW_segment svg {\n stroke: currentColor;\n stroke-width: 1.5px;\n stroke-linecap: round;\n stroke-linejoin: round;\n display: block;\n}\n\n@container (width <= 480px) {\n .vavGuW_toolbar {\n flex-wrap: wrap;\n justify-content: flex-end;\n }\n\n .vavGuW_search {\n flex-basis: 100%;\n }\n}\n._5BoKRG_editor {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n box-sizing: border-box;\n border-radius: 8px;\n flex-direction: column;\n display: flex;\n overflow: hidden;\n}\n\n._5BoKRG_editor .cm-editor {\n flex: 1;\n min-height: 0;\n}\n\n._5BoKRG_editor .cm-scroller {\n overflow: auto;\n}\n.G2mDja_form {\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 10px;\n flex-direction: column;\n gap: 10px;\n padding: 12px 14px;\n display: flex;\n}\n\n.G2mDja_head {\n color: var(--dsw-alias-label-secondary, #667085);\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n}\n\n.G2mDja_error {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n overflow-wrap: anywhere;\n border-radius: 8px;\n padding: 8px 10px;\n font-size: 12px;\n line-height: 18px;\n}\n\n.G2mDja_row {\n border-top: 1px solid var(--dsw-alias-border-l1, #eef1f5);\n flex-direction: column;\n gap: 4px;\n min-width: 0;\n padding-top: 8px;\n display: flex;\n}\n\n.G2mDja_rowHead {\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.G2mDja_grow {\n flex: auto;\n}\n\n.G2mDja_where {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n overflow-wrap: anywhere;\n font-size: 11px;\n line-height: 17px;\n}\n\n.G2mDja_ref {\n color: var(--dsw-alias-label-primary, #1f2328);\n font: 600 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.G2mDja_controls {\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.G2mDja_facts {\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n.G2mDja_factOk, .G2mDja_factMiss {\n border-radius: 999px;\n padding: 1px 8px;\n font-size: 11px;\n line-height: 17px;\n}\n\n.G2mDja_factOk {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n background: var(--dsw-alias-state-success-tertiary, #e6faed);\n}\n\n.G2mDja_factMiss {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n background: var(--dsw-alias-state-warn-tertiary, #fef5e7);\n}\n\n.G2mDja_note {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 11px;\n line-height: 17px;\n}\n\n.G2mDja_editor {\n flex-direction: column;\n gap: 8px;\n display: flex;\n}\n\n.G2mDja_input {\n box-sizing: border-box;\n width: 100%;\n color: var(--dsw-alias-label-primary, #1f2328);\n background: var(--dsw-alias-bg-layer-1, #fff);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 8px;\n padding: 7px 10px;\n font-size: 12px;\n}\n\n.G2mDja_input:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 1px;\n}\n\n.G2mDja_actions {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n.HJ9x7a_shell {\n min-width: 0;\n min-height: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n flex: 1;\n gap: 16px;\n display: flex;\n container-type: inline-size;\n}\n\n.HJ9x7a_header {\n flex-direction: row;\n flex: none;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n min-height: 46px;\n display: flex;\n}\n\n.HJ9x7a_headerText {\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n display: flex;\n}\n\n.HJ9x7a_title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n}\n\n.HJ9x7a_subtitle {\n color: var(--dsw-alias-label-secondary);\n margin: 0;\n font-size: 13px;\n line-height: 20px;\n}\n\n.HJ9x7a_headerActions {\n flex-direction: row;\n flex: none;\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n.HJ9x7a_body {\n scrollbar-gutter: stable;\n flex-direction: column;\n flex: 1;\n gap: 12px;\n min-height: 0;\n display: flex;\n overflow-y: auto;\n}\n\n.HJ9x7a_busyLine {\n color: var(--dsw-alias-label-secondary, #6b7280);\n flex-direction: row;\n flex: none;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n display: flex;\n}\n\n.HJ9x7a_busyLabel {\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n overflow: hidden;\n}\n\n.HJ9x7a_spinner {\n color: var(--dsw-alias-label-secondary, #6b7280);\n flex: none;\n font-size: 13px;\n display: inline-flex;\n}\n\n.HJ9x7a_spinning {\n animation: .9s linear infinite HJ9x7a_panel-spin;\n}\n\n@keyframes HJ9x7a_panel-spin {\n from {\n transform: rotate(0);\n }\n\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .HJ9x7a_spinning {\n animation-duration: 2.4s;\n }\n}\n\n.HJ9x7a_editorDialog {\n gap: 12px;\n max-width: 720px;\n}\n\n.HJ9x7a_editorDialog [class*=\"content\"] > [class*=\"body\"] {\n margin-top: 0;\n}\n\n.HJ9x7a_editorBody {\n flex-direction: column;\n gap: 12px;\n display: flex;\n}\n\n.HJ9x7a_editorFooter {\n flex-direction: row;\n flex: 1;\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.HJ9x7a_editorError {\n color: var(--dsw-alias-state-error-primary, #c81e1e);\n margin-right: auto;\n font-size: 12px;\n}\n\n.HJ9x7a_confirmCheck {\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: row;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n display: flex;\n}\n\n.HJ9x7a_empty {\n color: var(--dsw-alias-label-tertiary, #6b7280);\n text-align: center;\n padding: 24px 12px;\n font-size: 12px;\n}\n\n@container (width <= 540px) {\n .HJ9x7a_entryGrid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .HJ9x7a_entryRow {\n flex-wrap: wrap;\n }\n\n .HJ9x7a_entryActions {\n margin-left: auto;\n }\n\n .HJ9x7a_entryMain {\n flex-basis: 100%;\n }\n}\n\n.HJ9x7a_hero {\n background: var(--dsw-alias-interactive-bg-hover);\n border-radius: 10px;\n align-items: center;\n gap: 10px;\n padding: 12px 14px;\n display: flex;\n}\n\n.HJ9x7a_heroText {\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n display: flex;\n}\n\n.HJ9x7a_heroLine {\n flex-wrap: wrap;\n align-items: center;\n gap: 7px;\n display: flex;\n}\n\n.HJ9x7a_heroMono {\n overflow-wrap: anywhere;\n color: var(--dsw-alias-label-secondary);\n margin: 0;\n font: 12px / 18px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.HJ9x7a_block {\n margin-top: 18px;\n}\n\n.HJ9x7a_blockHead {\n color: var(--dsw-alias-label-secondary);\n letter-spacing: .04em;\n text-transform: uppercase;\n margin: 0 0 8px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.HJ9x7a_kvGrid {\n grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));\n gap: 10px 16px;\n margin: 0;\n display: grid;\n}\n\n.HJ9x7a_kvKey {\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n line-height: 16px;\n}\n\n.HJ9x7a_kvValue {\n text-overflow: ellipsis;\n white-space: nowrap;\n margin: 3px 0 0;\n font-size: 12.5px;\n line-height: 18px;\n overflow: hidden;\n}\n\n.HJ9x7a_monoBlock {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-markdown-code-block);\n color: var(--dsw-alias-label-secondary);\n border-radius: 10px;\n margin: 0;\n padding: 12px 14px;\n font: 11.5px / 18px ui-monospace, Menlo, Consolas, monospace;\n overflow-x: auto;\n}\n\n.HJ9x7a_detailProse {\n color: var(--dsw-alias-label-secondary);\n margin: 0;\n font-size: 13px;\n line-height: 21px;\n}\n\n.HJ9x7a_kvValueMono {\n font-family: ui-monospace, Menlo, Consolas, monospace;\n}\n\n.AUWlZW_surface {\n min-width: 0;\n min-height: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n flex: 1;\n display: flex;\n}\n\n.AUWlZW_toolbar {\n flex: none;\n}\n\n@media (width <= 760px) {\n .AUWlZW_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n.AUWlZW_reasonLabel {\n opacity: .85;\n flex: none;\n font-weight: 600;\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_detailBody {\n max-height: 72vh;\n overflow-y: auto;\n}\n\n.AUWlZW_modalFooter {\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n width: 100%;\n display: flex;\n}\n\n.AUWlZW_modalFooterHint {\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n}\n\n.AUWlZW_modalFooterGrow {\n flex: auto;\n}\n\n.AUWlZW_detail {\n flex-direction: column;\n gap: 16px;\n display: flex;\n}\n\n.AUWlZW_reasonBox {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-interactive-bg-hover-danger, #ec13130d);\n border-radius: 8px;\n flex-direction: column;\n gap: 4px;\n padding: 10px 12px;\n display: flex;\n}\n\n.AUWlZW_reasonText {\n overflow-wrap: anywhere;\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n}\n\n.AUWlZW_reasonActions {\n flex-wrap: wrap;\n gap: 8px;\n margin-top: 4px;\n display: flex;\n}\n\n.AUWlZW_reasonHint {\n color: var(--dsw-alias-label-secondary, #4e5969);\n overflow-wrap: anywhere;\n margin: 2px 0 0;\n font-size: 11px;\n line-height: 16px;\n}\n\n.AUWlZW_blockHeadRow {\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n display: flex;\n}\n\n.AUWlZW_blockSub {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n margin: 0 0 6px;\n font-size: 11px;\n line-height: 16px;\n}\n\n.AUWlZW_starter, .AUWlZW_starterList {\n flex-wrap: wrap;\n gap: 8px;\n display: flex;\n}\n\n.AUWlZW_starterPaste {\n flex-direction: column;\n gap: 8px;\n display: flex;\n}\n\n.AUWlZW_pasteArea {\n box-sizing: border-box;\n width: 100%;\n min-height: 120px;\n color: var(--dsw-alias-label-primary, #1f2328);\n background: var(--dsw-alias-bg-layer-1, #fff);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n resize: vertical;\n border-radius: 8px;\n padding: 7px 9px;\n font: 12px / 19px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.AUWlZW_pasteNote {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n margin: 0;\n font-size: 11px;\n line-height: 16px;\n}\n\n.AUWlZW_pasteCheck {\n color: var(--dsw-alias-label-secondary, #4e5969);\n align-items: center;\n gap: 8px;\n font-size: 11px;\n line-height: 16px;\n display: inline-flex;\n}\n\n.AUWlZW_pasteOutcome {\n flex-direction: column;\n gap: 2px;\n display: flex;\n}\n\n.AUWlZW_pasteOutcome p {\n color: var(--dsw-alias-label-secondary, #4e5969);\n overflow-wrap: anywhere;\n margin: 0;\n font-size: 11px;\n line-height: 16px;\n}\n\n.AUWlZW_toolSearch {\n flex: 0 220px;\n min-width: 0;\n display: block;\n}\n\n.AUWlZW_toolList {\n flex-direction: column;\n display: flex;\n}\n\n.AUWlZW_tool {\n border-bottom: 1px solid var(--dsw-alias-border-l1, #eef1f5);\n grid-template-columns: minmax(140px, max-content) minmax(0, 1fr) max-content;\n align-items: center;\n gap: 12px;\n padding: 7px 0 7px 2px;\n display: grid;\n}\n\n.AUWlZW_tool:last-child {\n border-bottom: none;\n}\n\n.AUWlZW_toolIdentity {\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\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, .AUWlZW_toolNote {\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.AUWlZW_toolNameButton {\n cursor: pointer;\n text-align: left;\n background: none;\n border: none;\n padding: 0;\n}\n\n.AUWlZW_toolNameButton:hover {\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n.AUWlZW_toolParams {\n grid-column: 1 / -1;\n padding: 8px 0 2px 11px;\n}\n\n.AUWlZW_toolParamsGrid {\n grid-template-columns: minmax(120px, max-content) minmax(60px, max-content) max-content minmax(0, 1fr);\n align-items: baseline;\n gap: 6px 12px;\n display: grid;\n}\n\n.AUWlZW_toolParam {\n display: contents;\n}\n\n.AUWlZW_toolParamName {\n color: var(--dsw-alias-label-primary, #1f2328);\n font: 11px / 16px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.AUWlZW_toolParamType {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font: 10px / 16px ui-monospace, Menlo, Consolas, monospace;\n}\n\n.AUWlZW_toolParamRequired {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n font-size: 10px;\n line-height: 16px;\n}\n\n.AUWlZW_toolParamDesc {\n overflow-wrap: anywhere;\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 10px;\n line-height: 16px;\n}\n\n.AUWlZW_toolParamsEmpty {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n margin: 0;\n font-size: 10px;\n line-height: 16px;\n}\n\n.AUWlZW_toolMore {\n color: var(--dsw-alias-label-secondary, #667085);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 6px;\n align-self: flex-start;\n margin-top: 8px;\n padding: 4px 8px;\n font-size: 11px;\n line-height: 17px;\n}\n\n.AUWlZW_toolMore:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n@media (width <= 760px) {\n .AUWlZW_toolbar {\n padding-left: 0;\n padding-right: 0;\n }\n\n .AUWlZW_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .AUWlZW_list .AUWlZW_cardTop {\n max-width: 100%;\n }\n\n .AUWlZW_tool {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .AUWlZW_toolDescription {\n display: none;\n }\n}\n\n.AUWlZW_retryEchoSuccess {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n white-space: nowrap;\n font-size: 12px;\n line-height: 18px;\n}\n\n@keyframes AUWlZW_lspStartingPulse {\n 50% {\n opacity: .35;\n }\n}\n\n.AUWlZW_reasonRaw {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n word-break: break-all;\n margin: 6px 0 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n line-height: 1.5;\n}\n\n.AUWlZW_seamBanner {\n border-left: 3px solid var(--dsw-alias-state-warn-primary, #b45309);\n background: var(--dsw-alias-state-warn-tertiary, #b4530914);\n border-radius: 8px;\n flex-direction: column;\n gap: 8px;\n margin: 0 0 12px;\n padding: 12px 14px;\n display: flex;\n}\n\n.AUWlZW_seamTitle {\n color: var(--dsw-alias-label-primary, #1f2329);\n font-size: 13px;\n font-weight: 600;\n}\n\n.AUWlZW_seamBody {\n color: var(--dsw-alias-label-secondary, #4e5969);\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n}\n\n.AUWlZW_seamPathLabel {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 11px;\n}\n\n.AUWlZW_seamPath {\n color: var(--dsw-alias-label-secondary, #4e5969);\n overflow-wrap: anywhere;\n margin: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n line-height: 16px;\n}\n\n.AUWlZW_seamOther {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n margin: 0;\n font-size: 11px;\n line-height: 16px;\n}\n\n.AUWlZW_seamDone {\n color: var(--dsw-alias-state-success-primary, #15803d);\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n}\n.l0H8fW_workspace {\n min-width: 0;\n height: 100%;\n min-height: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n flex: 1;\n gap: 12px;\n display: flex;\n}\n\n.l0H8fW_pageMode {\n box-sizing: border-box;\n padding: 4px 0;\n}\n\n.l0H8fW_tabRow {\n border-bottom: 1px solid var(--dsw-alias-border-l2, #0000001a);\n scrollbar-width: none;\n flex-direction: row;\n flex: none;\n align-items: center;\n gap: 4px;\n display: flex;\n overflow-x: auto;\n}\n\n.l0H8fW_tab, .l0H8fW_tabOn {\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-radius: 8px 8px 0 0;\n flex: none;\n padding: 7px 14px;\n font-size: 13px;\n line-height: 20px;\n position: relative;\n}\n\n.l0H8fW_tab:hover {\n background: var(--dsw-alias-interactive-bg-hover, #2631480f);\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n.l0H8fW_tabOn {\n color: var(--dsw-alias-label-primary, #1f2328);\n font-weight: 600;\n}\n\n.l0H8fW_tabOn:after {\n background: var(--dsw-alias-brand-primary);\n content: \"\";\n border-radius: 2px;\n height: 2px;\n position: absolute;\n bottom: 0;\n left: 10px;\n right: 10px;\n}\n\n.l0H8fW_tabPanel {\n flex-direction: column;\n flex: 1;\n min-height: 0;\n display: flex;\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;
@@ -238,7 +238,7 @@ function ActiveOverlay$1({ target, t, visible, slow }) {
238
238
  }, visible ? (0, react.createElement)("div", { className: busy_overlay_module_default.content }, (0, react.createElement)("span", {
239
239
  className: busy_overlay_module_default.spinner,
240
240
  "aria-hidden": true
241
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconLoadingOutline16, { size: 28 })), (0, react.createElement)("strong", { className: busy_overlay_module_default.label }, t("panelWorking")), (0, react.createElement)("div", { className: busy_overlay_module_default.hintViewport }, (0, react.createElement)("p", {
241
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconLoadingOutlineMedium, { size: 28 })), (0, react.createElement)("strong", { className: busy_overlay_module_default.label }, t("panelWorking")), (0, react.createElement)("div", { className: busy_overlay_module_default.hintViewport }, (0, react.createElement)("p", {
242
242
  key: message,
243
243
  className: busy_overlay_module_default.hint
244
244
  }, hints[message])), slow ? (0, react.createElement)("p", {
@@ -303,6 +303,7 @@ const MARKET_ROUTES = {
303
303
  overview: `${MARKET_API_PREFIX}overview`,
304
304
  mcpStatus: `${MARKET_API_PREFIX}mcp-status`,
305
305
  addMcpServer: `${MARKET_API_PREFIX}mcp-servers/add`,
306
+ importMcpServers: `${MARKET_API_PREFIX}mcp-servers/import`,
306
307
  lspStatus: `${MARKET_API_PREFIX}lsp-status`,
307
308
  lspServers: `${MARKET_API_PREFIX}lsp-servers`,
308
309
  addLspServer: `${MARKET_API_PREFIX}lsp-servers/add`,
@@ -326,6 +327,7 @@ const MARKET_ROUTES = {
326
327
  mcpOverrides: `${MARKET_API_PREFIX}mcp-overrides`,
327
328
  setMcpOverride: `${MARKET_API_PREFIX}set-mcp-override`,
328
329
  setMcpServerEnabled: `${MARKET_API_PREFIX}set-mcp-server-enabled`,
330
+ setMcpServerTool: `${MARKET_API_PREFIX}set-mcp-server-tool`,
329
331
  mcpRetry: `${MARKET_API_PREFIX}mcp-retry`,
330
332
  mcpReauthorize: `${MARKET_API_PREFIX}mcp-reauthorize`,
331
333
  mcpBackend: `${MARKET_API_PREFIX}mcp-backend`,
@@ -411,7 +413,7 @@ async function postOkJson(url, body, label) {
411
413
  body: JSON.stringify(body)
412
414
  }, MUTATION_TIMEOUT_MS);
413
415
  const payload = await response.json();
414
- if (!response.ok || payload.ok !== true) throw new Error(payload.error ?? `${label}: ${response.status}`);
416
+ if (!response.ok || payload.ok !== true) throw Object.assign(new Error(payload.error ?? `${label}: ${response.status}`), { fields: payload.fields });
415
417
  return payload;
416
418
  }
417
419
  async function fetchServerConfig(kind, id) {
@@ -425,12 +427,13 @@ async function fetchServerConfig(kind, id) {
425
427
  return body;
426
428
  });
427
429
  }
428
- async function saveServerConfig(kind, id, config) {
430
+ async function saveServerConfig(kind, id, config, policy) {
429
431
  return withBusyOperation(async () => {
430
432
  await postAction("server-config/save", {
431
433
  kind,
432
434
  id,
433
- config
435
+ config,
436
+ ...policy === void 0 ? {} : { policy }
434
437
  });
435
438
  });
436
439
  }
@@ -494,6 +497,26 @@ async function addMcpServer(name, config) {
494
497
  });
495
498
  });
496
499
  }
500
+ /** Import several pasted services in one write; each entry reports its own outcome. */
501
+ async function importMcpServers(servers, overwrite) {
502
+ return withBusyOperation(async () => {
503
+ const payload = await postAction("mcp-servers/import", {
504
+ servers,
505
+ overwrite
506
+ });
507
+ return {
508
+ imported: Array.isArray(payload["imported"]) ? payload["imported"].filter((value) => typeof value === "string") : [],
509
+ skipped: Array.isArray(payload["skipped"]) ? payload["skipped"].flatMap((entry) => {
510
+ if (typeof entry !== "object" || entry === null) return [];
511
+ const { name, reason } = entry;
512
+ return typeof name === "string" && typeof reason === "string" ? [{
513
+ name,
514
+ reason
515
+ }] : [];
516
+ }) : []
517
+ };
518
+ });
519
+ }
497
520
  /** Drop one server's OAuth grant so its next mount re-runs browser authorization. */
498
521
  async function reauthorizeMcpServer(serverName) {
499
522
  return withBusyOperation(async () => {
@@ -516,6 +539,24 @@ async function setMcpServerEnabled(suiteId, serverKey, enabled) {
516
539
  });
517
540
  });
518
541
  }
542
+ /**
543
+ * Allow or deny one tool of a declared MCP server.
544
+ *
545
+ * @param suiteId - the source-qualified suite id the status row carries.
546
+ * @param serverKey - the server key inside that suite's declaration.
547
+ * @param tool - the tool's raw name inside the server's namespace.
548
+ * @param enabled - whether the tool is allowed.
549
+ */
550
+ async function setMcpServerTool(suiteId, serverKey, tool, enabled) {
551
+ return withBusyOperation(async () => {
552
+ await postAction("set-mcp-server-tool", {
553
+ suiteId,
554
+ serverKey,
555
+ tool,
556
+ enabled
557
+ });
558
+ });
559
+ }
519
560
  /** Enable or disable one declared language server by its status-row id. */
520
561
  async function setLspServerEnabled(id, enabled) {
521
562
  return withBusyOperation(async () => {
@@ -575,6 +616,7 @@ const zh = {
575
616
  serverConfigReadOnly: "此服务由宿主管理,请在原始配置中编辑。",
576
617
  lspServerName: "服务名称",
577
618
  lspAddTitle: "新建 LSP 服务",
619
+ lspEditTitle: "编辑 LSP 服务",
578
620
  detailMarkdown: "编辑 Markdown",
579
621
  detailMetadata: "元数据",
580
622
  detailForm: "表单",
@@ -597,13 +639,22 @@ const zh = {
597
639
  detailInvalidJson: "JSON 无效",
598
640
  detailUseJson: "当前字段类型无法使用表单,请在 JSON 中修正。",
599
641
  detailTransport: "传输方式",
642
+ transportHintStdio: "在本机启动一个子进程,用命令与参数配置",
643
+ transportHintHttp: "连接远端服务,用 URL 与请求头配置",
644
+ transportHintSse: "旧式远端推送协议,用 URL 与请求头配置",
600
645
  detailCommand: "命令",
646
+ detailCommandPh: "npx -y @modelcontextprotocol/server-github",
601
647
  detailArgs: "参数",
602
648
  detailEnv: "环境变量",
603
649
  detailUrl: "URL",
650
+ detailUrlPh: "https://mcp.example.com/mcp",
604
651
  detailHeaders: "请求头",
652
+ detailHeaderKeyPh: "Authorization",
605
653
  detailCwd: "工作目录",
606
- detailScope: "OAuth scope",
654
+ detailRequired: "必填",
655
+ detailEmptyRowsMap: "没有内容:点这里添加一行,也可以直接粘贴多行 KEY=VALUE",
656
+ detailEmptyRowsList: "没有内容:点这里添加一行",
657
+ mcpOauthAuto: "服务返回 401 时自动协商 OAuth 授权,无需在此配置",
607
658
  detailExtensions: "语言扩展名映射",
608
659
  detailKey: "键",
609
660
  detailValue: "值",
@@ -687,7 +738,6 @@ const zh = {
687
738
  editorScopeUser: "用户目录",
688
739
  editorScopeLocal: "本地目录",
689
740
  sourceSuiteUnit: "个套件",
690
- oauthEnable: "启用 OAuth 流程",
691
741
  personaRouteCurrent: "当前路由:",
692
742
  idFixed: "id 不可修改(源标识全局唯一)",
693
743
  progressStarting: "正在提交…",
@@ -759,13 +809,31 @@ const zh = {
759
809
  mcpOrphaned: "来源缺失",
760
810
  mcpForeign: "外部挂载",
761
811
  mcpServerKeyLabel: "服务键",
812
+ mcpEnabledLabel: "启用此服务",
762
813
  mcpSearch: "搜索 MCP 名称、来源或地址…",
763
814
  mcpAll: "全部",
764
815
  mcpPlugin: "插件",
765
816
  mcpDirect: "用户",
766
817
  mcpTools: "工具",
818
+ mcpToolsMore: "还有 {count} 个工具",
819
+ mcpToolsSearch: "搜索工具",
820
+ mcpToolsNoMatch: "没有匹配的工具",
821
+ mcpToolParams: "参数",
822
+ mcpToolParamRequired: "必填",
823
+ mcpToolNoParameters: "这个工具不需要参数",
767
824
  mcpTool: "工具",
768
825
  mcpReasonLabel: "原因",
826
+ mcpGuideCredentials: "缺少凭据:在凭据区填入后再重试。",
827
+ mcpGuideAuth: "服务要求授权:确认 token 未过期,或重新授权。",
828
+ mcpGuideTransport: "当前后端不支持这种传输方式:切换到内置客户端。",
829
+ mcpGuideBackend: "当前后端无法执行这项配置:切换到内置客户端。",
830
+ mcpGuideDns: "域名解析失败:检查地址拼写、代理与网络。",
831
+ mcpGuideTls: "TLS 握手失败:确认证书有效,服务可能要求专线或来源 IP 白名单。",
832
+ mcpGuideRefused: "连接被拒绝:确认服务已启动、端口与路径正确。",
833
+ mcpGuideTimeout: "连接超时:确认服务可达;本地服务可以调高启动超时。",
834
+ mcpGuideCommandMissing: "找不到命令:确认它在 PATH 中,或改用绝对路径。",
835
+ mcpGuideProcessExit: "进程提前退出:检查命令、参数与运行环境。",
836
+ mcpGuideProtocol: "握手失败:确认地址指向 MCP 端点,而不是普通网页。",
769
837
  mcpRetrySuccess: "重连成功,服务已恢复",
770
838
  mcpReauthorize: "重新授权",
771
839
  mcpClose: "关闭",
@@ -800,6 +868,7 @@ const zh = {
800
868
  mcpBackendHostMissing: "宿主 dsh-mcp-client 在当前环境不可用,无法切换到兼容模式。",
801
869
  mcpZeroTools: "该服务已连接,但未声明任何工具。",
802
870
  mcpCredentialTitle: "凭据配置",
871
+ mcpCredentialConfigure: "配置",
803
872
  mcpCredentialConfigured: "已配置",
804
873
  mcpCredentialMissing: "未配置",
805
874
  mcpCredentialReadOnly: "由启动环境提供(只读;修改后需重启 DSH)",
@@ -813,8 +882,39 @@ const zh = {
813
882
  mcpNoTools: "当前没有已注册工具",
814
883
  mcpDirectBoundary: "用户 MCP 仅显示当前工具表中可观测的服务;宿主未提供配置与连接状态 API。",
815
884
  mcpAddTitle: "新建 MCP 服务",
885
+ mcpEditTitle: "编辑 MCP 服务",
886
+ mcpStarterTemplates: "从模板开始",
887
+ mcpStarterPaste: "粘贴 JSON",
888
+ mcpPasteApply: "填入表单",
889
+ mcpPastePlaceholder: "粘贴 mcpServers 条目或单个服务定义",
890
+ mcpPasteFound: "识别到 {count} 条服务",
891
+ mcpPasteImport: "导入这些服务",
892
+ mcpPasteOverwrite: "覆盖同名服务",
893
+ mcpPasteImported: "已导入:{names}",
894
+ mcpPasteSkipped: "跳过:{detail}",
895
+ mcpPasteUnnamed: "没有服务名,无法导入",
896
+ mcpTemplateFilesystem: "文件系统",
897
+ mcpTemplateMemory: "记忆",
898
+ mcpTemplateFetch: "网页抓取",
899
+ mcpTemplateContext7: "Context7 文档",
900
+ mcpTemplateGithub: "GitHub",
816
901
  mcpServerName: "服务名称",
817
902
  mcpRetry: "重试",
903
+ mcpAdvanced: "高级设置",
904
+ mcpAdvancedSummary: "连接选项与超时",
905
+ mcpToolCallTimeout: "工具调用超时",
906
+ mcpStartupTimeout: "启动超时",
907
+ mcpTimeoutInvalid: "请输入 1 到 2147483647 之间的整数毫秒",
908
+ mcpTimeoutInherit: "留空则继承",
909
+ mcpTimeoutFromSuite: "套件声明值",
910
+ mcpTimeoutFromDefault: "内置默认值",
911
+ mcpTimeoutUserSet: "已由你设置",
912
+ mcpTimeoutClear: "清除",
913
+ mcpTimeoutClearLabel: "清除「{name}」",
914
+ mcpHostStartupUnsupported: "宿主兼容后端不支持启动超时;切换到内置客户端后即可设置。",
915
+ mcpHostToolsUnsupported: "宿主兼容后端不支持工具勾选;切换到内置客户端后即可按工具启用或停用。",
916
+ mcpAllowTool: "允许工具 {name}",
917
+ mcpToolSuiteLimited: "由套件声明限定",
818
918
  mcpFilterAllHint: "全部:插件套件声明的 MCP 服务与用户自行添加的 MCP",
819
919
  mcpFilterPluginHint: "插件:来自插件市场套件的 mcp.json 声明",
820
920
  mcpFilterDirectHint: "用户:非套件来源的 MCP,来自本面板添加或宿主工具表观测",
@@ -881,6 +981,7 @@ const zh = {
881
981
  panelFilterAll: "全部",
882
982
  panelFilterDisabled: "已禁用",
883
983
  panelAdd: "新增",
984
+ panelEdit: "编辑",
884
985
  panelAddSkillTitle: "新建技能",
885
986
  panelAddCommandTitle: "新建命令",
886
987
  panelAddPersonaTitle: "新建代理角色",
@@ -922,6 +1023,7 @@ const en = {
922
1023
  serverConfigReadOnly: "This service is managed by the host. Edit its original configuration.",
923
1024
  lspServerName: "Server name",
924
1025
  lspAddTitle: "New LSP server",
1026
+ lspEditTitle: "Edit LSP server",
925
1027
  detailMarkdown: "Edit Markdown",
926
1028
  detailMetadata: "Metadata",
927
1029
  detailForm: "Form",
@@ -944,13 +1046,22 @@ const en = {
944
1046
  detailInvalidJson: "Invalid JSON",
945
1047
  detailUseJson: "These field types cannot be edited as a form. Correct them in JSON.",
946
1048
  detailTransport: "Transport",
1049
+ transportHintStdio: "Starts a local subprocess, configured by command and arguments",
1050
+ transportHintHttp: "Connects to a remote service, configured by URL and headers",
1051
+ transportHintSse: "Legacy remote push protocol, configured by URL and headers",
947
1052
  detailCommand: "Command",
1053
+ detailCommandPh: "npx -y @modelcontextprotocol/server-github",
948
1054
  detailArgs: "Arguments",
949
1055
  detailEnv: "Environment variables",
950
1056
  detailUrl: "URL",
1057
+ detailUrlPh: "https://mcp.example.com/mcp",
951
1058
  detailHeaders: "Headers",
1059
+ detailHeaderKeyPh: "Authorization",
952
1060
  detailCwd: "Working directory",
953
- detailScope: "OAuth scope",
1061
+ detailRequired: "Required",
1062
+ detailEmptyRowsMap: "Nothing yet: click to add a line, or paste several KEY=VALUE lines",
1063
+ detailEmptyRowsList: "Nothing yet: click to add a line",
1064
+ mcpOauthAuto: "OAuth is negotiated automatically when the server answers 401",
954
1065
  detailExtensions: "Extension mapping",
955
1066
  detailKey: "Key",
956
1067
  detailValue: "Value",
@@ -1034,7 +1145,6 @@ const en = {
1034
1145
  editorScopeUser: "User directory",
1035
1146
  editorScopeLocal: "Local directory",
1036
1147
  sourceSuiteUnit: "suites",
1037
- oauthEnable: "Enable the OAuth flow",
1038
1148
  personaRouteCurrent: "Current route: ",
1039
1149
  idFixed: "id is fixed (the source identifier is globally unique)",
1040
1150
  progressStarting: "Submitting…",
@@ -1106,13 +1216,31 @@ const en = {
1106
1216
  mcpOrphaned: "Source missing",
1107
1217
  mcpForeign: "Mounted elsewhere",
1108
1218
  mcpServerKeyLabel: "Server key",
1219
+ mcpEnabledLabel: "Enable this service",
1109
1220
  mcpSearch: "Search MCP names, sources, or endpoints…",
1110
1221
  mcpAll: "All",
1111
1222
  mcpPlugin: "Plugin",
1112
1223
  mcpDirect: "User",
1113
1224
  mcpTools: "tools",
1225
+ mcpToolsMore: "{count} more tools",
1226
+ mcpToolsSearch: "Search tools",
1227
+ mcpToolsNoMatch: "No matching tools",
1228
+ mcpToolParams: "Parameters",
1229
+ mcpToolParamRequired: "required",
1230
+ mcpToolNoParameters: "This tool takes no parameters",
1114
1231
  mcpTool: "tool",
1115
1232
  mcpReasonLabel: "Reason",
1233
+ mcpGuideCredentials: "Missing credential: fill it in the credentials area, then retry.",
1234
+ mcpGuideAuth: "The service asks for authorization: check that the token is current, or authorize again.",
1235
+ mcpGuideTransport: "This backend cannot speak that transport: switch to the built-in client.",
1236
+ mcpGuideBackend: "This backend cannot enforce that setting: switch to the built-in client.",
1237
+ mcpGuideDns: "Name resolution failed: check the address, the proxy and the network.",
1238
+ mcpGuideTls: "TLS handshake failed: check the certificate; the service may require a VPN or an IP allow-list.",
1239
+ mcpGuideRefused: "Connection refused: check that the service is running, and that the port and path are right.",
1240
+ mcpGuideTimeout: "Connection timed out: check that the service is reachable; a local server can raise its startup timeout.",
1241
+ mcpGuideCommandMissing: "Command not found: check that it is on PATH, or use an absolute path.",
1242
+ mcpGuideProcessExit: "The process exited early: check the command, its arguments and its environment.",
1243
+ mcpGuideProtocol: "Handshake failed: check that the address points at an MCP endpoint rather than a web page.",
1116
1244
  mcpRetrySuccess: "Reconnected — the service is live again",
1117
1245
  mcpReauthorize: "Re-authorize",
1118
1246
  mcpClose: "Close",
@@ -1147,6 +1275,7 @@ const en = {
1147
1275
  mcpBackendHostMissing: "The host dsh-mcp-client is not available here; compat mode cannot be enabled.",
1148
1276
  mcpZeroTools: "Connected, but this service advertises no tools.",
1149
1277
  mcpCredentialTitle: "Credential configuration",
1278
+ mcpCredentialConfigure: "Configure",
1150
1279
  mcpCredentialConfigured: "configured",
1151
1280
  mcpCredentialMissing: "not configured",
1152
1281
  mcpCredentialReadOnly: "provided by the launch environment (read-only; restart DSH after changes)",
@@ -1160,8 +1289,39 @@ const en = {
1160
1289
  mcpNoTools: "No registered tools",
1161
1290
  mcpDirectBoundary: "User MCP entries only show services observed in the current tool registry; the host exposes no config or connection-status API.",
1162
1291
  mcpAddTitle: "New MCP service",
1292
+ mcpEditTitle: "Edit MCP service",
1293
+ mcpStarterTemplates: "Start from a template",
1294
+ mcpStarterPaste: "Paste JSON",
1295
+ mcpPasteApply: "Fill the form",
1296
+ mcpPastePlaceholder: "Paste an mcpServers entry or a single server definition",
1297
+ mcpPasteFound: "Found {count} services",
1298
+ mcpPasteImport: "Import these services",
1299
+ mcpPasteOverwrite: "Overwrite existing names",
1300
+ mcpPasteImported: "Imported: {names}",
1301
+ mcpPasteSkipped: "Skipped: {detail}",
1302
+ mcpPasteUnnamed: "no service name, so it cannot be imported",
1303
+ mcpTemplateFilesystem: "Filesystem",
1304
+ mcpTemplateMemory: "Memory",
1305
+ mcpTemplateFetch: "Web fetch",
1306
+ mcpTemplateContext7: "Context7 docs",
1307
+ mcpTemplateGithub: "GitHub",
1163
1308
  mcpServerName: "Server name",
1164
1309
  mcpRetry: "Retry",
1310
+ mcpAdvanced: "Advanced settings",
1311
+ mcpAdvancedSummary: "Connection options and timeouts",
1312
+ mcpToolCallTimeout: "Tool call timeout",
1313
+ mcpStartupTimeout: "Startup timeout",
1314
+ mcpTimeoutInvalid: "Enter a whole number of milliseconds between 1 and 2147483647",
1315
+ mcpTimeoutInherit: "Empty inherits",
1316
+ mcpTimeoutFromSuite: "the suite declaration",
1317
+ mcpTimeoutFromDefault: "the built-in default",
1318
+ mcpTimeoutUserSet: "Set by you",
1319
+ mcpTimeoutClear: "Clear",
1320
+ mcpTimeoutClearLabel: "Clear {name}",
1321
+ mcpHostStartupUnsupported: "The host compatibility backend cannot enforce a startup timeout; switch to the built-in client to set one.",
1322
+ mcpHostToolsUnsupported: "The host compatibility backend cannot enforce tool filters; switch to the built-in client to choose tools.",
1323
+ mcpAllowTool: "Allow tool {name}",
1324
+ mcpToolSuiteLimited: "Limited by the suite declaration",
1165
1325
  mcpFilterAllHint: "All: MCP services declared by plugin suites plus MCP you added",
1166
1326
  mcpFilterPluginHint: "Plugin: mcp.json declarations from market suites",
1167
1327
  mcpFilterDirectHint: "User: MCP observed in the host tool registry outside any suite",
@@ -1228,6 +1388,7 @@ const en = {
1228
1388
  panelFilterAll: "All",
1229
1389
  panelFilterDisabled: "Disabled",
1230
1390
  panelAdd: "Add",
1391
+ panelEdit: "Edit",
1231
1392
  panelAddSkillTitle: "New skill",
1232
1393
  panelAddCommandTitle: "New command",
1233
1394
  panelAddPersonaTitle: "New agent role",
@@ -1578,7 +1739,10 @@ function SourceTabsRow(props) {
1578
1739
  //#region src/client/ui/form.module.css
1579
1740
  var form_module_default = {
1580
1741
  "addIcon": "_5JDFMW_addIcon",
1742
+ "editorBody": "_5JDFMW_editorBody",
1743
+ "emptyRows": "_5JDFMW_emptyRows",
1581
1744
  "field": "_5JDFMW_field",
1745
+ "fieldRow": "_5JDFMW_fieldRow",
1582
1746
  "fieldset": "_5JDFMW_fieldset",
1583
1747
  "footer": "_5JDFMW_footer",
1584
1748
  "footerError": "_5JDFMW_footerError",
@@ -1593,6 +1757,7 @@ var form_module_default = {
1593
1757
  "jsonArea": "_5JDFMW_jsonArea",
1594
1758
  "previewBox": "_5JDFMW_previewBox",
1595
1759
  "readonly": "_5JDFMW_readonly",
1760
+ "required": "_5JDFMW_required",
1596
1761
  "row": "_5JDFMW_row",
1597
1762
  "rowActions": "_5JDFMW_rowActions",
1598
1763
  "rowHead": "_5JDFMW_rowHead",
@@ -1818,7 +1983,7 @@ function SuiteCard(props) {
1818
1983
  "aria-label": t("refresh"),
1819
1984
  disabled: busy,
1820
1985
  onClick: stop(props.onRefresh)
1821
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16)),
1986
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutlineMedium)),
1822
1987
  (0, react.createElement)("button", {
1823
1988
  key: "uninstall",
1824
1989
  type: "button",
@@ -1827,7 +1992,7 @@ function SuiteCard(props) {
1827
1992
  "aria-label": t("uninstall"),
1828
1993
  disabled: busy,
1829
1994
  onClick: stop(props.onUninstall)
1830
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16)),
1995
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineMedium)),
1831
1996
  (0, react.createElement)("span", {
1832
1997
  key: "toggle",
1833
1998
  className: resource_card_module_default.switchWrap,
@@ -7833,7 +7998,7 @@ function DetailRow(props) {
7833
7998
  }, header[0], header[1], (0, react.createElement)("span", {
7834
7999
  className: detail_rows_module_default.chevron,
7835
8000
  "aria-hidden": true
7836
- }, open ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14) : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14))), open ? (0, react.createElement)("div", { className: detail_rows_module_default.body }, props.children) : null);
8001
+ }, open ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineMedium) : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineMedium))), open ? (0, react.createElement)("div", { className: detail_rows_module_default.body }, props.children) : null);
7837
8002
  }
7838
8003
  //#endregion
7839
8004
  //#region src/client/ui/last-change.ts
@@ -8192,7 +8357,7 @@ function SearchFilterToolbar(props) {
8192
8357
  "data-panel-toolbar": true
8193
8358
  }, (0, react.createElement)("label", { className: SearchFilterToolbar_module_default.search }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Input, {
8194
8359
  className: SearchFilterToolbar_module_default.searchInput,
8195
- icon: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutline16),
8360
+ icon: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutlineMedium),
8196
8361
  value: props.search,
8197
8362
  placeholder: props.searchPlaceholder,
8198
8363
  "aria-label": props.searchLabel,
@@ -8322,7 +8487,7 @@ function codePointSize$1(code) {
8322
8487
  return code < 65536 ? 1 : 2;
8323
8488
  }
8324
8489
  //#endregion
8325
- //#region node_modules/.pnpm/@codemirror+state@6.7.4/node_modules/@codemirror/state/dist/index.js
8490
+ //#region node_modules/.pnpm/@codemirror+state@6.7.5/node_modules/@codemirror/state/dist/index.js
8326
8491
  /**
8327
8492
  The data structure for documents. @nonabstract
8328
8493
  */
@@ -11660,7 +11825,10 @@ function compare(a, startA, b, startB, length, comparator) {
11660
11825
  if (!(a.point && b.point && cmpVal(a.point, b.point) && sameValues(a.activeForPoint(a.to), b.activeForPoint(b.to)))) comparator.comparePoint(pos, clipEnd, a.point, b.point);
11661
11826
  boundChange = false;
11662
11827
  } else {
11663
- if (boundChange) comparator.boundChange(pos);
11828
+ if (boundChange) {
11829
+ comparator.boundChange(pos);
11830
+ boundChange = false;
11831
+ }
11664
11832
  if (clipEnd > pos && !sameValues(a.active, b.active)) comparator.compareRange(pos, clipEnd, a.active, b.active);
11665
11833
  if (bounds && clipEnd < endB && (dEnd || a.openEnd(end) != b.openEnd(end))) boundChange = true;
11666
11834
  }
@@ -11916,7 +12084,7 @@ function keyName(event) {
11916
12084
  return name;
11917
12085
  }
11918
12086
  //#endregion
11919
- //#region node_modules/.pnpm/@codemirror+view@6.43.11/node_modules/@codemirror/view/dist/index.js
12087
+ //#region node_modules/.pnpm/@codemirror+view@6.43.12/node_modules/@codemirror/view/dist/index.js
11920
12088
  let nav = typeof navigator != "undefined" ? navigator : {
11921
12089
  userAgent: "",
11922
12090
  vendor: "",
@@ -13813,11 +13981,11 @@ var TileBuilder = class {
13813
13981
  if (last.dom != mark.dom) last.setDOM(freeNode(mark.dom));
13814
13982
  head = last;
13815
13983
  } else {
13984
+ let { dom } = mark;
13816
13985
  if (this.cache.reused.get(mark)) {
13817
- let tile = Tile.get(mark.dom);
13818
- if (tile) tile.setDOM(freeNode(mark.dom));
13986
+ if (Tile.get(mark.dom)) dom = freeNode(mark.dom);
13819
13987
  }
13820
- let nw = MarkTile.of(mark.mark, mark.dom);
13988
+ let nw = MarkTile.of(mark.mark, dom);
13821
13989
  head.append(nw);
13822
13990
  head = nw;
13823
13991
  }
@@ -14230,12 +14398,13 @@ var TileUpdate = class {
14230
14398
  if (tile instanceof MarkTile) marks.push(tile);
14231
14399
  else if (tile === null || tile === void 0 ? void 0 : tile.isLine()) line = tile;
14232
14400
  else if (tile instanceof BlockWrapperTile);
14233
- else if (parent.nodeName == "DIV" && !line && parent != this.view.contentDOM) line = new LineTile(parent, lineBaseAttrs);
14401
+ else if (parent.nodeName == "DIV" && !line) line = new LineTile(parent, lineBaseAttrs);
14234
14402
  else if (!line) marks.push(MarkTile.of(new MarkDecoration({
14235
14403
  tagName: parent.nodeName.toLowerCase(),
14236
14404
  attributes: getAttrs$1(parent)
14237
14405
  }), parent));
14238
14406
  }
14407
+ if (!line) return null;
14239
14408
  return {
14240
14409
  line,
14241
14410
  marks
@@ -14927,18 +15096,20 @@ function blockAt(view, pos, side) {
14927
15096
  return line;
14928
15097
  }
14929
15098
  function moveToLineBoundary(view, start, forward, includeWrap) {
14930
- let line = blockAt(view, start.head, start.assoc || -1);
14931
- let coords = !includeWrap || line.type != BlockType.Text || !(view.lineWrapping || line.widgetLineBreaks) ? null : view.coordsAtPos(start.assoc < 0 && start.head > line.from ? start.head - 1 : start.head);
15099
+ let block = blockAt(view, start.head, start.assoc || -1);
15100
+ let coords = !includeWrap || block.type != BlockType.Text || !(view.lineWrapping || block.widgetLineBreaks) ? null : view.coordsAtPos(start.assoc < 0 && start.head > block.from ? start.head - 1 : start.head);
14932
15101
  if (coords) {
14933
15102
  let editorRect = view.dom.getBoundingClientRect();
14934
- let direction = view.textDirectionAt(line.from);
15103
+ let direction = view.textDirectionAt(block.from);
14935
15104
  let pos = view.posAtCoords({
14936
15105
  x: forward == (direction == Direction.LTR) ? editorRect.right - 1 : editorRect.left + 1,
14937
15106
  y: (coords.top + coords.bottom) / 2
14938
15107
  });
14939
15108
  if (pos != null) return EditorSelection.cursor(pos, forward ? -1 : 1);
14940
15109
  }
14941
- return EditorSelection.cursor(forward ? line.to : line.from, forward ? -1 : 1);
15110
+ let line = view.state.doc.lineAt(start.head);
15111
+ if (forward ? line.to == block.to : line.from == block.from) return view.visualLineSide(line, forward);
15112
+ return EditorSelection.cursor(forward ? block.to : block.from, forward ? -1 : 1);
14942
15113
  }
14943
15114
  function moveByChar(view, start, forward, by) {
14944
15115
  let line = view.state.doc.lineAt(start.head), spans = view.bidiSpans(line);
@@ -16233,7 +16404,17 @@ observers.blur = (view) => {
16233
16404
  observers.compositionstart = observers.compositionupdate = (view) => {
16234
16405
  if (view.observer.editContext) return;
16235
16406
  if (view.inputState.compositionFirstChange == null) view.inputState.compositionFirstChange = true;
16236
- if (view.inputState.composing < 0) view.inputState.composing = 0;
16407
+ if (view.inputState.composing < 0) {
16408
+ let { main } = view.state.selection;
16409
+ if (!main.empty && view.lineBlockAt(main.from).from != view.lineBlockAt(main.to).from) view.dispatch({
16410
+ changes: view.state.selection.ranges.filter((r) => !r.empty).map((r) => ({
16411
+ from: r.from,
16412
+ to: r.to
16413
+ })),
16414
+ userEvent: "input"
16415
+ });
16416
+ view.inputState.composing = 0;
16417
+ }
16237
16418
  };
16238
16419
  observers.compositionend = (view) => {
16239
16420
  if (view.observer.editContext) return;
@@ -18403,6 +18584,7 @@ var EditorView = class EditorView {
18403
18584
  @internal
18404
18585
  */
18405
18586
  this.measureRequests = [];
18587
+ this.clearAnnouncement = -1;
18406
18588
  this.contentDOM = document.createElement("div");
18407
18589
  this.scrollDOM = document.createElement("div");
18408
18590
  this.scrollDOM.tabIndex = -1;
@@ -18711,8 +18893,14 @@ var EditorView = class EditorView {
18711
18893
  showAnnouncements(trs) {
18712
18894
  let first = true;
18713
18895
  for (let tr of trs) for (let effect of tr.effects) if (effect.is(EditorView.announce)) {
18714
- if (first) this.announceDOM.textContent = "";
18715
- first = false;
18896
+ if (first) {
18897
+ this.announceDOM.textContent = "";
18898
+ this.win.clearTimeout(this.clearAnnouncement);
18899
+ this.clearAnnouncement = this.win.setTimeout(() => {
18900
+ this.announceDOM.textContent = "\xA0";
18901
+ }, 200);
18902
+ first = false;
18903
+ }
18716
18904
  let div = this.announceDOM.appendChild(document.createElement("div"));
18717
18905
  div.textContent = effect.value;
18718
18906
  }
@@ -19056,6 +19244,7 @@ var EditorView = class EditorView {
19056
19244
  this.docView.destroy();
19057
19245
  this.dom.remove();
19058
19246
  this.observer.destroy();
19247
+ this.win.clearTimeout(this.clearAnnouncement);
19059
19248
  if (this.measureScheduled > -1) this.win.cancelAnimationFrame(this.measureScheduled);
19060
19249
  this.destroyed = true;
19061
19250
  }
@@ -24734,7 +24923,7 @@ function createTokenType(extra, tagStr) {
24734
24923
  }
24735
24924
  Direction.RTL, Direction.LTR;
24736
24925
  //#endregion
24737
- //#region node_modules/.pnpm/@codemirror+commands@6.11.0/node_modules/@codemirror/commands/dist/index.js
24926
+ //#region node_modules/.pnpm/@codemirror+commands@6.11.1/node_modules/@codemirror/commands/dist/index.js
24738
24927
  /**
24739
24928
  Comment or uncomment the current selection. Will use line comments
24740
24929
  if available, otherwise falling back to block comments.
@@ -25388,11 +25577,11 @@ const cursorLineBoundaryRight = (view) => moveSel(view, (range) => moveByLineBou
25388
25577
  /**
25389
25578
  Move the selection to the start of the line.
25390
25579
  */
25391
- const cursorLineStart = (view) => moveSel(view, (range) => EditorSelection.cursor(view.lineBlockAt(range.head).from, 1));
25580
+ const cursorLineStart = (view) => moveSel(view, (range) => view.moveToLineBoundary(range, false, false));
25392
25581
  /**
25393
25582
  Move the selection to the end of the line.
25394
25583
  */
25395
- const cursorLineEnd = (view) => moveSel(view, (range) => EditorSelection.cursor(view.lineBlockAt(range.head).to, -1));
25584
+ const cursorLineEnd = (view) => moveSel(view, (range) => view.moveToLineBoundary(range, true, false));
25396
25585
  function toMatchingBracket(state, dispatch, extend) {
25397
25586
  let found = false, selection = updateSel(state.selection, (range) => {
25398
25587
  let matching = matchBrackets(state, range.head, -1) || matchBrackets(state, range.head, 1) || range.head > 0 && matchBrackets(state, range.head - 1, 1) || range.head < state.doc.length && matchBrackets(state, range.head + 1, -1);
@@ -34571,14 +34760,14 @@ function PanelActions(props) {
34571
34760
  title: props.addLabel,
34572
34761
  "aria-label": props.addLabel,
34573
34762
  onClick: props.onAdd
34574
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16)), props.onRefresh === void 0 ? null : (0, react.createElement)("button", {
34763
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineMedium)), props.onRefresh === void 0 ? null : (0, react.createElement)("button", {
34575
34764
  type: "button",
34576
34765
  className: resource_card_module_default.iconBtn,
34577
34766
  disabled: props.busy,
34578
34767
  title: props.refreshLabel,
34579
34768
  "aria-label": props.refreshLabel,
34580
34769
  onClick: props.onRefresh
34581
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16)));
34770
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutlineMedium)));
34582
34771
  }
34583
34772
  /** Shared heading geometry for all resource tabs. */
34584
34773
  function PanelHeader(props) {
@@ -34599,7 +34788,7 @@ function BusyIndicator(props) {
34599
34788
  }, (0, react.createElement)("span", {
34600
34789
  className: `${panel_module_default.spinner} ${panel_module_default.spinning}`,
34601
34790
  "aria-hidden": true
34602
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconLoadingOutline16)), props.label === void 0 ? null : (0, react.createElement)("span", { className: panel_module_default.busyLabel }, props.label));
34791
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconLoadingOutlineMedium)), props.label === void 0 ? null : (0, react.createElement)("span", { className: panel_module_default.busyLabel }, props.label));
34603
34792
  }
34604
34793
  /** Hold the shared mask through local refresh/validation after the HTTP mutation finishes. */
34605
34794
  function BusyLease() {
@@ -35131,8 +35320,61 @@ function MarketSection({ t, mode = "settings" }) {
35131
35320
  }))
35132
35321
  });
35133
35322
  }
35134
- //#endregion
35135
- //#region src/client/ui/server-form.ts
35323
+ /**
35324
+ * Read one timeout field: empty inherits (`null`), a positive whole number of
35325
+ * milliseconds within the timer range is the value, and anything else is
35326
+ * `undefined`, which leaves the editor unsaveable.
35327
+ */
35328
+ function timeoutMsFromText(raw) {
35329
+ const text = raw.trim();
35330
+ if (text === "") return null;
35331
+ if (!/^\d+$/.test(text)) return void 0;
35332
+ const value = Number(text);
35333
+ return Number.isSafeInteger(value) && value > 0 && value <= 2147483647 ? value : void 0;
35334
+ }
35335
+ /** The same drafts, read off a document's policy half. */
35336
+ function policyDraftOfDocument(policy) {
35337
+ const text = (value) => typeof value === "number" || typeof value === "string" ? String(value) : "";
35338
+ return {
35339
+ toolCallTimeoutMs: text(policy["toolCallTimeoutMs"]),
35340
+ startupTimeoutMs: text(policy["startupTimeoutMs"])
35341
+ };
35342
+ }
35343
+ /**
35344
+ * Write the timeout drafts back into a document's policy half. An emptied field
35345
+ * asks for inheritance, which the document spells `null` — the value the save
35346
+ * route reads as "clear what was stored". An unparsable draft is left alone:
35347
+ * the editor's validity signal blocks that save instead of rewriting the value.
35348
+ */
35349
+ function policyDocumentOfDraft(policy, draft) {
35350
+ const next = { ...policy };
35351
+ for (const [field, raw] of [["toolCallTimeoutMs", draft.toolCallTimeoutMs], ["startupTimeoutMs", draft.startupTimeoutMs]]) {
35352
+ const value = timeoutMsFromText(raw);
35353
+ if (value === void 0) {
35354
+ next[field] = raw;
35355
+ continue;
35356
+ }
35357
+ if (value === null) {
35358
+ if (field in policy) next[field] = null;
35359
+ else delete next[field];
35360
+ continue;
35361
+ }
35362
+ next[field] = value;
35363
+ }
35364
+ return next;
35365
+ }
35366
+ /**
35367
+ * The policy half of one save: only the entries the user changed, because a
35368
+ * value edited on one backend must not ride along to another, where the same
35369
+ * value can be refused. A key dropped from the document asks for inheritance,
35370
+ * which the route reads as `null`.
35371
+ */
35372
+ function policyRequestOfDocuments(initial, current) {
35373
+ const request = {};
35374
+ for (const [field, value] of Object.entries(current)) if (JSON.stringify(value) !== JSON.stringify(initial[field])) request[field] = value;
35375
+ for (const field of Object.keys(initial)) if (!(field in current)) request[field] = null;
35376
+ return request;
35377
+ }
35136
35378
  function parseServerConfig(text) {
35137
35379
  const value = JSON.parse(text);
35138
35380
  if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("Configuration must be a JSON object");
@@ -35176,6 +35418,193 @@ function serverFormCompatible(config, kind) {
35176
35418
  if (auth?.scope !== void 0 && typeof auth.scope !== "string") return false;
35177
35419
  return true;
35178
35420
  }
35421
+ /**
35422
+ * Common MCP services, in the three shapes a new service takes: a local
35423
+ * process with no credential, a local process behind one, and a remote
35424
+ * endpoint behind one. The GitHub entry points at the vendor's remote server
35425
+ * because the old npm package is no longer maintained.
35426
+ */
35427
+ const MCP_TEMPLATES = [
35428
+ {
35429
+ id: "filesystem",
35430
+ labelKey: "mcpTemplateFilesystem",
35431
+ config: {
35432
+ type: "stdio",
35433
+ command: "npx",
35434
+ args: ["-y", "@modelcontextprotocol/server-filesystem"]
35435
+ }
35436
+ },
35437
+ {
35438
+ id: "memory",
35439
+ labelKey: "mcpTemplateMemory",
35440
+ config: {
35441
+ type: "stdio",
35442
+ command: "npx",
35443
+ args: ["-y", "@modelcontextprotocol/server-memory"]
35444
+ }
35445
+ },
35446
+ {
35447
+ id: "fetch",
35448
+ labelKey: "mcpTemplateFetch",
35449
+ config: {
35450
+ type: "stdio",
35451
+ command: "uvx",
35452
+ args: ["mcp-server-fetch"]
35453
+ }
35454
+ },
35455
+ {
35456
+ id: "context7",
35457
+ labelKey: "mcpTemplateContext7",
35458
+ config: {
35459
+ type: "streamable-http",
35460
+ url: "https://mcp.context7.com/mcp",
35461
+ headers: { Authorization: "Bearer ${CONTEXT7_API_KEY}" }
35462
+ }
35463
+ },
35464
+ {
35465
+ id: "github",
35466
+ labelKey: "mcpTemplateGithub",
35467
+ config: {
35468
+ type: "streamable-http",
35469
+ url: "https://api.githubcopilot.com/mcp/",
35470
+ headers: { Authorization: "Bearer ${GITHUB_PERSONAL_ACCESS_TOKEN}" }
35471
+ }
35472
+ }
35473
+ ];
35474
+ /**
35475
+ * Read one pasted configuration: a whole `mcpServers` map (its first entry
35476
+ * supplies the name), or a bare server definition. Claude-shaped files spell
35477
+ * the remote transport `http` and a stdio server `local`; a definition that
35478
+ * carries no transport is read from its command or url. The result is a form
35479
+ * document, not a validated server — the save path still validates it.
35480
+ */
35481
+ /** Normalize one pasted definition: Claude-shaped aliases and an inferred transport. */
35482
+ function normalizePastedServer(body) {
35483
+ if (body === null || typeof body !== "object" || Array.isArray(body)) throw new Error("Configuration must be a JSON object");
35484
+ const config = { ...body };
35485
+ if (config["type"] === "local") config["type"] = "stdio";
35486
+ if (config["type"] === "http") config["type"] = "streamable-http";
35487
+ if (config["type"] === void 0) {
35488
+ if (typeof config["command"] === "string") config["type"] = "stdio";
35489
+ else if (typeof config["url"] === "string" || typeof config["httpUrl"] === "string") config["type"] = "streamable-http";
35490
+ }
35491
+ if (config["type"] !== "stdio" && config["url"] === void 0 && typeof config["httpUrl"] === "string") {
35492
+ config["url"] = config["httpUrl"];
35493
+ delete config["httpUrl"];
35494
+ }
35495
+ return config;
35496
+ }
35497
+ /**
35498
+ * Read every server out of one pasted document: an `mcpServers` map (each key
35499
+ * becomes the service name) or a bare definition (which carries no name).
35500
+ */
35501
+ function parsePastedServers(text) {
35502
+ const parsed = JSON.parse(text);
35503
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("Configuration must be a JSON object");
35504
+ const record = parsed;
35505
+ const servers = record["mcpServers"];
35506
+ if (typeof servers === "object" && servers !== null && !Array.isArray(servers)) {
35507
+ const entries = Object.entries(servers);
35508
+ if (entries.length === 0) throw new Error("mcpServers is empty");
35509
+ return entries.map(([name, body]) => ({
35510
+ name,
35511
+ config: normalizePastedServer(body)
35512
+ }));
35513
+ }
35514
+ return [{ config: normalizePastedServer(record) }];
35515
+ }
35516
+ /** The first server of a pasted document, for filling the form rather than importing. */
35517
+ function parsePastedServer(text) {
35518
+ const [first] = parsePastedServers(text);
35519
+ if (first === void 0) throw new Error("mcpServers is empty");
35520
+ return first;
35521
+ }
35522
+ /**
35523
+ * Read one pasted block into rows.
35524
+ *
35525
+ * The two separators that appear in MCP documentation are `=` and `:`, taking
35526
+ * whichever comes first on a line, and values arrive quoted about as often as
35527
+ * not — so a pasted `"KEY": "value"` lands as a full row instead of one long
35528
+ * value. A list (arguments) keeps whole lines.
35529
+ */
35530
+ function rowsFromPastedText(text, map) {
35531
+ const lines = text.split(/\r?\n/).map((line) => line.trim()).filter((line) => line !== "");
35532
+ if (!map) return lines.map((line) => ["", line]);
35533
+ const rows = [];
35534
+ for (const line of lines) {
35535
+ const equals = line.indexOf("=");
35536
+ const colon = line.indexOf(":");
35537
+ const separator = equals === -1 ? colon : colon === -1 ? equals : Math.min(equals, colon);
35538
+ if (separator <= 0) continue;
35539
+ const key = stripQuotes(line.slice(0, separator).trim());
35540
+ if (key === "") continue;
35541
+ rows.push([key, stripQuotes(line.slice(separator + 1).trim())]);
35542
+ }
35543
+ return rows;
35544
+ }
35545
+ /** Drop one pair of matching quotes, the shape a value is copied in. */
35546
+ function stripQuotes(value) {
35547
+ if (value.length >= 2 && (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'"))) return value.slice(1, -1);
35548
+ return value;
35549
+ }
35550
+ /** The namespace seat this client's own per-server policy rides. */
35551
+ const HARNESS_NAMESPACE = "com.deepseek.harness";
35552
+ function asRecord(value) {
35553
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
35554
+ }
35555
+ /**
35556
+ * Read one service document: the definition under `mcpServers`, and this
35557
+ * client's policy under the `com.deepseek.harness` namespace — the two seats
35558
+ * the Agent Plugins specification gives a portable `mcp.json` and its client
35559
+ * extension. A document that omits either half reads as an empty one.
35560
+ */
35561
+ function parseServerDocument(text, key) {
35562
+ const parsed = JSON.parse(text);
35563
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("Configuration must be a JSON object");
35564
+ const record = parsed;
35565
+ return {
35566
+ config: asRecord(asRecord(record["mcpServers"])?.[key]) ?? {},
35567
+ policy: asRecord(asRecord(asRecord(record["com.deepseek.harness"])?.["mcpServers"])?.[key]) ?? {}
35568
+ };
35569
+ }
35570
+ /** Write the document back in the shape the specification seats it in. */
35571
+ function composeServerDocument(key, config, policy) {
35572
+ const document = { mcpServers: { [key]: config } };
35573
+ if (Object.keys(policy).length > 0) document[HARNESS_NAMESPACE] = { mcpServers: { [key]: policy } };
35574
+ return JSON.stringify(document, null, 2);
35575
+ }
35576
+ /**
35577
+ * The policy half of a document, built from what the user stored. Suite
35578
+ * declarations stay out: the editor shows them as the value in force, and a
35579
+ * document that repeated them would invite an edit the client cannot honour.
35580
+ */
35581
+ function serverPolicyDocument(policy) {
35582
+ if (policy === void 0) return {};
35583
+ const document = {};
35584
+ if (policy.toolCallTimeout.user !== null) document["toolCallTimeoutMs"] = policy.toolCallTimeout.user;
35585
+ if (policy.startupTimeout.user !== null) document["startupTimeoutMs"] = policy.startupTimeout.user;
35586
+ if (policy.deniedTools.user !== null) document["disabledTools"] = policy.deniedTools.user;
35587
+ if (policy.auth.user !== null) document["auth"] = { enabled: policy.auth.user };
35588
+ return document;
35589
+ }
35590
+ /**
35591
+ * Fold the API's field list into the map an editor renders. The first path
35592
+ * segment names the editor field; a nested key rides along with it, so a
35593
+ * rejected header lands on the headers field.
35594
+ */
35595
+ function fieldErrorsOf(reason) {
35596
+ const fields = reason.fields;
35597
+ if (!Array.isArray(fields)) return void 0;
35598
+ const map = {};
35599
+ for (const entry of fields) {
35600
+ if (typeof entry !== "object" || entry === null) continue;
35601
+ const { field, message } = entry;
35602
+ if (typeof field !== "string" || field === "" || typeof message !== "string") continue;
35603
+ const key = field.split(".")[0] ?? field;
35604
+ map[key] = map[key] === void 0 ? message : `${map[key]}; ${message}`;
35605
+ }
35606
+ return Object.keys(map).length === 0 ? void 0 : map;
35607
+ }
35179
35608
  //#endregion
35180
35609
  //#region src/client/ui/ServerConfigEditor.tsx
35181
35610
  /**
@@ -35189,11 +35618,17 @@ function serverFormCompatible(config, kind) {
35189
35618
  /** One JSON document backs both modes. Invalid JSON is retained, never silently converted or reset. */
35190
35619
  function ServerConfigEditor(props) {
35191
35620
  const [mode, setMode] = (0, react.useState)("form");
35621
+ const [advancedOpen, setAdvancedOpen] = (0, react.useState)(false);
35192
35622
  const [issues, setIssues] = (0, react.useState)({});
35193
35623
  let parsed;
35624
+ let policy = {};
35194
35625
  let parseError;
35195
35626
  try {
35196
- parsed = parseServerConfig(props.text);
35627
+ if (props.kind === "mcp") {
35628
+ const document = parseServerDocument(props.text, props.serverKey ?? "");
35629
+ parsed = document.config;
35630
+ policy = document.policy;
35631
+ } else parsed = parseServerConfig(props.text);
35197
35632
  } catch (error) {
35198
35633
  parseError = error instanceof Error ? error.message : String(error);
35199
35634
  }
@@ -35201,11 +35636,13 @@ function ServerConfigEditor(props) {
35201
35636
  const compatible = config !== void 0 && serverFormCompatible(config, props.kind);
35202
35637
  const hasIssue = Object.values(issues).some(Boolean);
35203
35638
  const requiredValid = config !== void 0 && (props.kind === "lsp" ? typeof config.command === "string" && config.command.trim() !== "" && config.extensionToLanguage !== null && typeof config.extensionToLanguage === "object" && Object.keys(config.extensionToLanguage).length > 0 : config.type === "stdio" ? typeof config.command === "string" && config.command.trim() !== "" : ["sse", "streamable-http"].includes(String(config.type)) && typeof config.url === "string" && config.url.trim() !== "");
35204
- const valid = compatible && !hasIssue && requiredValid;
35639
+ const timeouts = props.policy !== void 0 && props.policyDraft !== void 0 && props.onPolicyDraftChange !== void 0;
35640
+ const policyValid = !timeouts || timeoutMsFromText(props.policyDraft.toolCallTimeoutMs) !== void 0 && timeoutMsFromText(props.policyDraft.startupTimeoutMs) !== void 0;
35641
+ const valid = compatible && !hasIssue && requiredValid && policyValid;
35205
35642
  (0, react.useEffect)(() => {
35206
35643
  props.onValidityChange?.(valid);
35207
35644
  }, [valid, props.onValidityChange]);
35208
- const update = (next) => props.onChange(JSON.stringify(next, null, 2));
35645
+ const update = (next) => props.onChange(props.kind === "mcp" ? composeServerDocument(props.serverKey ?? "", next, policy) : JSON.stringify(next, null, 2));
35209
35646
  const field = (key, value) => {
35210
35647
  const next = { ...config };
35211
35648
  if (value === void 0) delete next[key];
@@ -35220,15 +35657,31 @@ function ServerConfigEditor(props) {
35220
35657
  };
35221
35658
  });
35222
35659
  };
35223
- const textField = (key, label, required = false, full = false) => (0, react.createElement)("label", {
35224
- className: full ? `${form_module_default.field} ${form_module_default.full}` : form_module_default.field,
35225
- key
35226
- }, (0, react.createElement)("span", null, label), (0, react.createElement)("input", {
35227
- value: typeof config?.[key] === "string" ? config[key] : "",
35228
- required,
35229
- "aria-label": label,
35230
- onChange: (event) => field(key, event.target.value === "" && !required ? void 0 : event.target.value)
35231
- }));
35660
+ /** The example a server's own documentation shows for this field. */
35661
+ const placeholderFor = (key) => {
35662
+ if (key === "command") return props.t("detailCommandPh");
35663
+ if (key === "url") return props.t("detailUrlPh");
35664
+ };
35665
+ /** The API's reason for one field, when it rejected a save. */
35666
+ const fieldError = (key) => props.fieldErrors?.[key] === void 0 ? null : (0, react.createElement)("span", { className: form_module_default.footerError }, props.fieldErrors[key]);
35667
+ const textField = (key, label, required = false, full = false) => {
35668
+ const placeholder = placeholderFor(key);
35669
+ return (0, react.createElement)("label", {
35670
+ className: full ? `${form_module_default.field} ${form_module_default.full}` : form_module_default.field,
35671
+ key
35672
+ }, (0, react.createElement)("span", null, label, required ? (0, react.createElement)("span", {
35673
+ key: "required",
35674
+ className: form_module_default.required,
35675
+ title: props.t("detailRequired"),
35676
+ "aria-hidden": true
35677
+ }, "*") : null), (0, react.createElement)("input", {
35678
+ value: typeof config?.[key] === "string" ? config[key] : "",
35679
+ required,
35680
+ ...placeholder === void 0 ? {} : { placeholder },
35681
+ "aria-label": label,
35682
+ onChange: (event) => field(key, event.target.value === "" && !required ? void 0 : event.target.value)
35683
+ }), fieldError(key));
35684
+ };
35232
35685
  const mapField = (key, label, addLabel, narrowKey = false) => (0, react.createElement)(StringRows, {
35233
35686
  key,
35234
35687
  label,
@@ -35238,34 +35691,96 @@ function ServerConfigEditor(props) {
35238
35691
  narrowKey,
35239
35692
  value: config?.[key],
35240
35693
  onChange: (value) => field(key, value),
35241
- onIssue: (bad) => issue(key, bad)
35694
+ onIssue: (bad) => issue(key, bad),
35695
+ ...props.fieldErrors?.[key] === void 0 ? {} : { error: props.fieldErrors[key] }
35242
35696
  });
35243
35697
  const type = typeof config?.type === "string" ? config.type : "stdio";
35244
- const auth = config?.auth ?? {};
35245
- const transportField = props.kind === "mcp" ? (0, react.createElement)("label", { className: form_module_default.field }, (0, react.createElement)("span", null, props.t("detailTransport")), (0, react.createElement)("select", {
35246
- value: type,
35247
- "aria-label": props.t("detailTransport"),
35248
- disabled: hasIssue,
35249
- onChange: (event) => {
35250
- if (config === void 0) return;
35251
- update(changeTransport(config, event.target.value));
35252
- }
35698
+ const transportField = props.kind === "mcp" ? (0, react.createElement)("div", { className: form_module_default.field }, (0, react.createElement)("span", null, props.t("detailTransport")), (0, react.createElement)("div", {
35699
+ className: form_module_default.seg,
35700
+ role: "group",
35701
+ "aria-label": props.t("detailTransport")
35253
35702
  }, [
35254
35703
  "stdio",
35255
35704
  "streamable-http",
35256
35705
  "sse"
35257
- ].map((value) => (0, react.createElement)("option", {
35706
+ ].map((value) => (0, react.createElement)("button", {
35707
+ type: "button",
35258
35708
  key: value,
35259
- value
35709
+ "aria-pressed": type === value,
35710
+ disabled: hasIssue,
35711
+ onClick: () => {
35712
+ if (config === void 0) return;
35713
+ update(changeTransport(config, value));
35714
+ }
35260
35715
  }, value)))) : null;
35261
35716
  const identityRow = props.nameField === void 0 ? null : props.kind === "mcp" ? (0, react.createElement)("div", { className: form_module_default.formGrid }, (0, react.createElement)("label", { className: form_module_default.field }, (0, react.createElement)("span", null, props.nameField.label), props.nameField.control), transportField) : (0, react.createElement)("label", { className: form_module_default.field }, (0, react.createElement)("span", null, props.nameField.label), props.nameField.control);
35262
- return (0, react.createElement)("div", { className: form_module_default.form }, (0, react.createElement)("div", { className: form_module_default.seg }, ["form", "json"].map((value) => (0, react.createElement)("button", {
35717
+ /**
35718
+ * The advanced disclosure: one seat for the optional inputs. A stdio server
35719
+ * offers its working directory there, a remote one its OAuth block, and both
35720
+ * offer the client timeouts when the calling dialog supplies the policy.
35721
+ */
35722
+ const advancedFields = [];
35723
+ if (props.createMode === true && config !== void 0) {
35724
+ if (props.kind === "lsp" || type === "stdio") advancedFields.push((0, react.createElement)(StringRows, {
35725
+ key: "args",
35726
+ label: props.t("detailArgs"),
35727
+ addLabel: props.t("detailAddArgs"),
35728
+ t: props.t,
35729
+ map: false,
35730
+ value: config.args,
35731
+ onChange: (value) => field("args", value),
35732
+ onIssue: (bad) => issue("args", bad)
35733
+ }), mapField("env", props.t("detailEnv"), props.t("detailAddEnv"), true));
35734
+ else advancedFields.push(mapField("headers", props.t("detailHeaders"), props.t("detailAddHeaders"), true));
35735
+ }
35736
+ if (config !== void 0) advancedFields.push(type === "stdio" ? textField("cwd", props.t("detailCwd"), false, true) : (0, react.createElement)("span", {
35737
+ key: "oauth",
35738
+ className: `${form_module_default.hint} ${form_module_default.full}`
35739
+ }, props.t("mcpOauthAuto")));
35740
+ if (timeouts) advancedFields.push((0, react.createElement)(TimeoutField, {
35741
+ key: "toolCallTimeout",
35742
+ label: props.t("mcpToolCallTimeout"),
35743
+ resolution: props.policy.toolCallTimeout,
35744
+ value: props.policyDraft.toolCallTimeoutMs,
35745
+ disabled: props.disabled === true,
35746
+ t: props.t,
35747
+ onChange: (value) => props.onPolicyDraftChange({
35748
+ ...props.policyDraft,
35749
+ toolCallTimeoutMs: value
35750
+ })
35751
+ }), (0, react.createElement)(TimeoutField, {
35752
+ key: "startupTimeout",
35753
+ label: props.t("mcpStartupTimeout"),
35754
+ resolution: props.policy.startupTimeout,
35755
+ value: props.policyDraft.startupTimeoutMs,
35756
+ disabled: props.disabled === true,
35757
+ ...props.backend === "host" ? { blocked: props.t("mcpHostStartupUnsupported") } : {},
35758
+ ...props.backend === "host" && props.policy.startupTimeout.user !== null ? {
35759
+ clearLabel: props.t("mcpTimeoutClearLabel", { name: props.t("mcpStartupTimeout") }),
35760
+ onClear: () => props.onPolicyDraftChange({
35761
+ ...props.policyDraft,
35762
+ startupTimeoutMs: ""
35763
+ })
35764
+ } : {},
35765
+ t: props.t,
35766
+ onChange: (value) => props.onPolicyDraftChange({
35767
+ ...props.policyDraft,
35768
+ startupTimeoutMs: value
35769
+ })
35770
+ }));
35771
+ const advancedSection = props.kind !== "mcp" || advancedFields.length === 0 ? null : (0, react.createElement)(DetailRows, null, (0, react.createElement)(DetailRow, {
35772
+ name: props.t("mcpAdvanced"),
35773
+ summary: props.t("mcpAdvancedSummary"),
35774
+ open: advancedOpen,
35775
+ onToggle: () => setAdvancedOpen((value) => !value)
35776
+ }, (0, react.createElement)("div", { className: form_module_default.form }, advancedFields)));
35777
+ return (0, react.createElement)("div", { className: `${form_module_default.form} ${form_module_default.editorBody}` }, (0, react.createElement)("div", { className: form_module_default.seg }, ["form", "json"].map((value) => (0, react.createElement)("button", {
35263
35778
  type: "button",
35264
35779
  key: value,
35265
35780
  "aria-pressed": mode === value,
35266
35781
  disabled: props.disabled || value === "json" && hasIssue,
35267
35782
  onClick: () => setMode(value)
35268
- }, props.t(value === "form" ? "detailForm" : "detailJson")))), identityRow, parseError ? (0, react.createElement)("div", {
35783
+ }, props.t(value === "form" ? "detailForm" : "detailJson")))), identityRow, mode === "form" && props.kind === "mcp" && config !== void 0 ? (0, react.createElement)("span", { className: `${form_module_default.hint} ${form_module_default.full}` }, props.t(type === "stdio" ? "transportHintStdio" : type === "sse" ? "transportHintSse" : "transportHintHttp")) : null, parseError ? (0, react.createElement)("div", {
35269
35784
  role: "alert",
35270
35785
  className: detail_module_default.error
35271
35786
  }, props.t("detailInvalidJson"), " ", parseError) : null, mode === "json" ? (0, react.createElement)("label", { className: form_module_default.field }, (0, react.createElement)("span", null, props.t("detailJsonConfig")), (0, react.createElement)("textarea", {
@@ -35286,43 +35801,47 @@ function ServerConfigEditor(props) {
35286
35801
  margin: 0,
35287
35802
  padding: 0
35288
35803
  }
35289
- }, props.nameField === void 0 ? transportField : null, props.kind === "lsp" || type === "stdio" ? [
35290
- textField("command", props.t("detailCommand"), true, true),
35291
- (0, react.createElement)(StringRows, {
35292
- key: "args",
35293
- label: props.t("detailArgs"),
35294
- addLabel: props.t("detailAddArgs"),
35295
- t: props.t,
35296
- map: false,
35297
- value: config.args,
35298
- onChange: (value) => field("args", value),
35299
- onIssue: (bad) => issue("args", bad)
35300
- }),
35301
- mapField("env", props.t("detailEnv"), props.t("detailAddEnv"), true)
35302
- ] : [textField("url", props.t("detailUrl"), true, true), mapField("headers", props.t("detailHeaders"), props.t("detailAddHeaders"), true)], props.kind === "mcp" && type === "stdio" ? textField("cwd", props.t("detailCwd"), false, true) : null, props.kind === "mcp" && type !== "stdio" ? (0, react.createElement)("fieldset", { className: `${form_module_default.fieldset} ${form_module_default.full}` }, (0, react.createElement)("legend", null, "OAuth"), (0, react.createElement)("label", { className: form_module_default.inlineCheck }, (0, react.createElement)("input", {
35303
- type: "checkbox",
35304
- checked: auth.enabled !== false,
35305
- onChange: (event) => field("auth", {
35306
- ...auth,
35307
- enabled: event.target.checked
35308
- })
35309
- }), " ", props.t("oauthEnable")), (0, react.createElement)("label", { className: `${form_module_default.field} ${form_module_default.full}` }, (0, react.createElement)("span", null, props.t("detailScope")), (0, react.createElement)("input", {
35310
- value: typeof auth.scope === "string" ? auth.scope : "",
35311
- "aria-label": props.t("detailScope"),
35312
- onChange: (event) => {
35313
- const next = {
35314
- ...auth,
35315
- scope: event.target.value
35316
- };
35317
- field("auth", next);
35318
- }
35319
- }))) : null, props.kind === "lsp" ? [mapField("extensionToLanguage", props.t("detailExtensions"), props.t("detailAddExtensions"), true), ...["initializationOptions", "configuration"].map((key) => (0, react.createElement)(JsonField, {
35804
+ }, props.nameField === void 0 ? transportField : null, props.kind === "lsp" || type === "stdio" ? [textField("command", props.t("detailCommand"), true, true), ...props.createMode === true ? [] : [(0, react.createElement)(StringRows, {
35805
+ key: "args",
35806
+ label: props.t("detailArgs"),
35807
+ addLabel: props.t("detailAddArgs"),
35808
+ t: props.t,
35809
+ map: false,
35810
+ value: config.args,
35811
+ onChange: (value) => field("args", value),
35812
+ onIssue: (bad) => issue("args", bad)
35813
+ }), mapField("env", props.t("detailEnv"), props.t("detailAddEnv"), true)]] : [textField("url", props.t("detailUrl"), true, true), ...props.createMode === true ? [] : [mapField("headers", props.t("detailHeaders"), props.t("detailAddHeaders"), true)]], props.kind === "lsp" ? [mapField("extensionToLanguage", props.t("detailExtensions"), props.t("detailAddExtensions"), true), ...["initializationOptions", "configuration"].map((key) => (0, react.createElement)(JsonField, {
35320
35814
  key,
35321
35815
  label: key,
35322
35816
  value: config[key],
35323
35817
  onChange: (value) => field(key, value),
35324
35818
  onIssue: (bad) => issue(key, bad)
35325
- }))] : null));
35819
+ }))] : null), advancedSection);
35820
+ }
35821
+ /**
35822
+ * One advanced timeout field: raw milliseconds text, with the effective value
35823
+ * as its placeholder, a line naming where an inherited value comes from, and an
35824
+ * optional control that empties the field back to inheritance.
35825
+ */
35826
+ function TimeoutField(props) {
35827
+ const invalid = timeoutMsFromText(props.value) === void 0;
35828
+ const hint = invalid ? props.t("mcpTimeoutInvalid") : props.value.trim() === "" ? `${props.t("mcpTimeoutInherit")} · ${props.resolution.suite === null ? props.t("mcpTimeoutFromDefault") : props.t("mcpTimeoutFromSuite")}` : props.t("mcpTimeoutUserSet");
35829
+ return (0, react.createElement)("div", { className: `${form_module_default.field} ${form_module_default.full}` }, (0, react.createElement)("span", null, props.label), (0, react.createElement)("div", { className: form_module_default.fieldRow }, (0, react.createElement)("input", {
35830
+ type: "text",
35831
+ inputMode: "numeric",
35832
+ value: props.value,
35833
+ placeholder: String(props.resolution.effective),
35834
+ "aria-label": props.label,
35835
+ disabled: props.disabled || props.blocked !== void 0,
35836
+ onChange: (event) => props.onChange(event.target.value)
35837
+ }), props.onClear === void 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
35838
+ variant: "ghost",
35839
+ size: "sm",
35840
+ type: "button",
35841
+ disabled: props.disabled,
35842
+ ...props.clearLabel === void 0 ? {} : { "aria-label": props.clearLabel },
35843
+ onClick: props.onClear
35844
+ }, props.t("mcpTimeoutClear"))), (0, react.createElement)("span", { className: invalid ? form_module_default.footerError : form_module_default.hint }, hint), props.blocked === void 0 ? null : (0, react.createElement)("span", { className: form_module_default.hint }, props.blocked));
35326
35845
  }
35327
35846
  /** The row editor behind a string list (arguments) and a string map (env, headers, extensions). */
35328
35847
  function StringRows(props) {
@@ -35342,7 +35861,11 @@ function StringRows(props) {
35342
35861
  title: props.addLabel,
35343
35862
  "aria-label": `${props.t("panelAdd")} ${props.label}`,
35344
35863
  onClick: () => change([...rows, ["", ""]])
35345
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16))), (0, react.createElement)("div", { className: form_module_default.rows }, rows.map(([key, value], index) => (0, react.createElement)("div", {
35864
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineMedium))), rows.length === 0 ? (0, react.createElement)("button", {
35865
+ type: "button",
35866
+ className: form_module_default.emptyRows,
35867
+ onClick: () => change([["", ""]])
35868
+ }, props.map ? props.t("detailEmptyRowsMap") : props.t("detailEmptyRowsList")) : null, (0, react.createElement)("div", { className: form_module_default.rows }, rows.map(([key, value], index) => (0, react.createElement)("div", {
35346
35869
  className: form_module_default.row,
35347
35870
  key: index
35348
35871
  }, props.map ? (0, react.createElement)("input", {
@@ -35353,17 +35876,28 @@ function StringRows(props) {
35353
35876
  }) : null, (0, react.createElement)("input", {
35354
35877
  value,
35355
35878
  "aria-label": `${props.label} ${props.t("detailValue")} ${index + 1}`,
35356
- onChange: (event) => change(rows.map((row, i) => i === index ? [row[0], event.target.value] : row))
35879
+ onChange: (event) => change(rows.map((row, i) => i === index ? [row[0], event.target.value] : row)),
35880
+ onPaste: (event) => {
35881
+ const pasted = event.clipboardData?.getData("text/plain") ?? "";
35882
+ if (!pasted.includes("\n")) return;
35883
+ const parsed = rowsFromPastedText(pasted, props.map);
35884
+ if (parsed.length === 0) return;
35885
+ event.preventDefault();
35886
+ change([...rows.filter(([key, value]) => key !== "" || value !== ""), ...parsed]);
35887
+ }
35357
35888
  }), (0, react.createElement)("button", {
35358
35889
  type: "button",
35359
35890
  className: form_module_default.iconBtn,
35360
35891
  title: props.t("panelDelete"),
35361
35892
  "aria-label": `${props.t("panelDelete")} ${props.label} ${index + 1}`,
35362
35893
  onClick: () => change(rows.filter((_, i) => i !== index))
35363
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16)))), invalid ? (0, react.createElement)("span", {
35894
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineMedium)))), invalid ? (0, react.createElement)("span", {
35364
35895
  role: "alert",
35365
35896
  className: form_module_default.footerError
35366
- }, props.t("detailUniqueKeys")) : null));
35897
+ }, props.t("detailUniqueKeys")) : null, props.error === void 0 ? null : (0, react.createElement)("span", {
35898
+ role: "alert",
35899
+ className: form_module_default.footerError
35900
+ }, props.error)));
35367
35901
  }
35368
35902
  /** One free-form JSON field (an LSP's initialization options or configuration). */
35369
35903
  function JsonField(props) {
@@ -35393,46 +35927,107 @@ function JsonField(props) {
35393
35927
  }
35394
35928
  //#endregion
35395
35929
  //#region src/client/ui/ServerConfigDetail.tsx
35396
- /** Loads complete configuration rather than editing the abbreviated status projection. */
35930
+ /**
35931
+ * One service's editor.
35932
+ *
35933
+ * The editor shows the document the specification seats a service in — the
35934
+ * portable definition under `mcpServers` plus this client's policy under the
35935
+ * `com.deepseek.harness` namespace — so every setting the client supports is
35936
+ * reachable as JSON. The form is a view over the same text and only writes the
35937
+ * half it owns, which is why a key the form has no control for survives an edit.
35938
+ */
35397
35939
  function ServerConfigDetail({ kind, id, t, onSaved, onDirtyChange }) {
35398
35940
  const [text, setText] = (0, react.useState)();
35941
+ const [initialText, setInitialText] = (0, react.useState)();
35942
+ const [serverKey, setServerKey] = (0, react.useState)("");
35399
35943
  const [editable, setEditable] = (0, react.useState)(false);
35400
35944
  const [valid, setValid] = (0, react.useState)(false);
35401
35945
  const [busy, setBusy] = (0, react.useState)(false);
35402
35946
  const [error, setError] = (0, react.useState)();
35403
35947
  const [loading, setLoading] = (0, react.useState)(true);
35404
- const [dirty, setDirty] = (0, react.useState)(false);
35948
+ const [policy, setPolicy] = (0, react.useState)();
35949
+ const [backend, setBackend] = (0, react.useState)();
35950
+ const [fieldErrors, setFieldErrors] = (0, react.useState)();
35951
+ const requestToken = (0, react.useRef)(0);
35952
+ const dirty = text !== void 0 && text !== initialText;
35405
35953
  (0, react.useEffect)(() => {
35406
35954
  onDirtyChange?.(dirty);
35407
35955
  }, [dirty, onDirtyChange]);
35408
- (0, react.useEffect)(() => {
35409
- let active = true;
35410
- setLoading(true);
35411
- setText(void 0);
35956
+ /** The document's policy half, as the string drafts the timeout fields edit. */
35957
+ const policyDraft = () => {
35958
+ if (kind !== "mcp" || text === void 0) return {
35959
+ toolCallTimeoutMs: "",
35960
+ startupTimeoutMs: ""
35961
+ };
35962
+ try {
35963
+ return policyDraftOfDocument(parseServerDocument(text, serverKey).policy);
35964
+ } catch {
35965
+ return {
35966
+ toolCallTimeoutMs: "",
35967
+ startupTimeoutMs: ""
35968
+ };
35969
+ }
35970
+ };
35971
+ /** Write the timeout drafts back into the document's policy half. */
35972
+ const updatePolicy = (draft) => {
35973
+ if (text === void 0) return;
35974
+ try {
35975
+ const document = parseServerDocument(text, serverKey);
35976
+ setText(composeServerDocument(serverKey, document.config, policyDocumentOfDraft(document.policy, draft)));
35977
+ } catch {}
35978
+ };
35979
+ /**
35980
+ * Read the service again and rebuild every derived value from the response.
35981
+ * `silent` keeps the editor mounted for the read-back that follows a save, so
35982
+ * the user stays in the section they were editing.
35983
+ */
35984
+ const load = async (silent = false) => {
35985
+ const token = ++requestToken.current;
35412
35986
  setError(void 0);
35413
- setDirty(false);
35414
- fetchServerConfig(kind, id).then((result) => {
35415
- if (!active) return;
35987
+ setFieldErrors(void 0);
35988
+ if (!silent) {
35989
+ setLoading(true);
35990
+ setText(void 0);
35991
+ setInitialText(void 0);
35992
+ setPolicy(void 0);
35993
+ }
35994
+ try {
35995
+ const result = await fetchServerConfig(kind, id);
35996
+ if (requestToken.current !== token) return;
35997
+ const next = kind === "mcp" ? composeServerDocument(result.key, result.config, serverPolicyDocument(result.policy)) : JSON.stringify(result.config, null, 2);
35416
35998
  setEditable(result.editable);
35417
- setText(result.config === void 0 ? void 0 : JSON.stringify(result.config, null, 2));
35418
- }).catch((reason) => {
35419
- if (active) setError(String(reason));
35420
- }).finally(() => {
35421
- if (active) setLoading(false);
35422
- });
35999
+ setServerKey(result.key);
36000
+ setText(next);
36001
+ setInitialText(next);
36002
+ setPolicy(result.policy);
36003
+ setBackend(result.backend);
36004
+ } catch (reason) {
36005
+ if (requestToken.current === token) setError(String(reason));
36006
+ } finally {
36007
+ if (!silent && requestToken.current === token) setLoading(false);
36008
+ }
36009
+ };
36010
+ (0, react.useEffect)(() => {
36011
+ load();
35423
36012
  return () => {
35424
- active = false;
36013
+ requestToken.current += 1;
35425
36014
  };
35426
36015
  }, [kind, id]);
35427
36016
  const save = async () => {
35428
36017
  setBusy(true);
35429
36018
  setError(void 0);
36019
+ setFieldErrors(void 0);
35430
36020
  try {
35431
- await saveServerConfig(kind, id, parseServerConfig(text ?? ""));
35432
- setDirty(false);
36021
+ if (kind === "mcp") {
36022
+ const document = parseServerDocument(text ?? "", serverKey);
36023
+ const initial = initialText === void 0 ? {} : parseServerDocument(initialText, serverKey).policy;
36024
+ await saveServerConfig(kind, id, document.config, policyRequestOfDocuments(initial, document.policy));
36025
+ } else await saveServerConfig(kind, id, parseServerConfig(text ?? ""));
36026
+ await load(true);
35433
36027
  onSaved?.();
35434
36028
  } catch (reason) {
35435
36029
  setError(clientErrorMessage(t, reason));
36030
+ setFieldErrors(fieldErrorsOf(reason));
35436
36031
  } finally {
35437
36032
  setBusy(false);
35438
36033
  }
@@ -35444,12 +36039,15 @@ function ServerConfigDetail({ kind, id, t, onSaved, onDirtyChange }) {
35444
36039
  kind,
35445
36040
  text,
35446
36041
  t,
36042
+ serverKey,
35447
36043
  disabled: busy || !editable,
35448
36044
  onValidityChange: setValid,
35449
- onChange: (value) => {
35450
- setText(value);
35451
- setDirty(true);
35452
- }
36045
+ ...policy === void 0 ? {} : { policy },
36046
+ policyDraft: policyDraft(),
36047
+ onPolicyDraftChange: updatePolicy,
36048
+ ...backend === void 0 ? {} : { backend },
36049
+ ...fieldErrors === void 0 ? {} : { fieldErrors },
36050
+ onChange: setText
35453
36051
  }), loading || error && text === void 0 ? null : editable ? (0, react.createElement)(DetailFooterAction, { children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
35454
36052
  variant: "primary",
35455
36053
  disabled: busy || !valid || !dirty,
@@ -35522,11 +36120,14 @@ var mcp_credential_module_default = {
35522
36120
  "factOk": "G2mDja_factOk",
35523
36121
  "facts": "G2mDja_facts",
35524
36122
  "form": "G2mDja_form",
36123
+ "grow": "G2mDja_grow",
35525
36124
  "head": "G2mDja_head",
35526
36125
  "input": "G2mDja_input",
35527
36126
  "note": "G2mDja_note",
35528
36127
  "ref": "G2mDja_ref",
35529
- "row": "G2mDja_row"
36128
+ "row": "G2mDja_row",
36129
+ "rowHead": "G2mDja_rowHead",
36130
+ "where": "G2mDja_where"
35530
36131
  };
35531
36132
  //#endregion
35532
36133
  //#region src/client/McpCredentialEditor.tsx
@@ -35538,11 +36139,15 @@ var mcp_credential_module_default = {
35538
36139
  * `credentials.set`, and never re-enters component state. Read-only
35539
36140
  * launch-environment credentials render guidance instead of a form that could
35540
36141
  * only fake success.
36142
+ *
36143
+ * One reference is one compact row: its name, its state, where the server uses
36144
+ * it, and a control that reveals the write field on demand.
35541
36145
  */
35542
36146
  function McpCredentialEditor(props) {
35543
- const { t, api, refs } = props;
36147
+ const { t, api, refs, usage } = props;
35544
36148
  const [views, setViews] = (0, react.useState)({});
35545
36149
  const [drafts, setDrafts] = (0, react.useState)({});
36150
+ const [open, setOpen] = (0, react.useState)({});
35546
36151
  const [busy, setBusy] = (0, react.useState)(void 0);
35547
36152
  const [error, setError] = (0, react.useState)(void 0);
35548
36153
  const refKey = refs.join("|");
@@ -35606,15 +36211,29 @@ function McpCredentialEditor(props) {
35606
36211
  return (0, react.createElement)("section", { className: mcp_credential_module_default.form }, busy === void 0 ? null : (0, react.createElement)(BusyIndicator, { overlay: true }), (0, react.createElement)("h4", { className: mcp_credential_module_default.head }, t("mcpCredentialTitle")), error === void 0 ? null : (0, react.createElement)("div", { className: mcp_credential_module_default.error }, error), refs.map((ref) => {
35607
36212
  const view = views[ref];
35608
36213
  const refBusy = busy === ref;
36214
+ const where = usage?.[ref] ?? [];
36215
+ const expanded = open[ref] === true;
36216
+ const configured = view?.configured === true;
35609
36217
  return (0, react.createElement)("div", {
35610
36218
  key: ref,
35611
36219
  className: mcp_credential_module_default.row
35612
- }, (0, react.createElement)("code", { className: mcp_credential_module_default.ref }, ref), view === void 0 ? (0, react.createElement)("div", { className: mcp_credential_module_default.note }, api === void 0 ? t("mcpCredentialUnavailable") : t("loading")) : (0, react.createElement)("div", { className: mcp_credential_module_default.controls }, (0, react.createElement)("div", { className: mcp_credential_module_default.facts }, (0, react.createElement)("span", { className: view.configured ? mcp_credential_module_default.factOk : mcp_credential_module_default.factMiss }, view.configured ? t("mcpCredentialConfigured") : t("mcpCredentialMissing")), view.source === void 0 ? null : (0, react.createElement)("span", { className: mcp_credential_module_default.note }, view.source)), view.writable ? (0, react.createElement)("div", { className: mcp_credential_module_default.editor }, (0, react.createElement)("input", {
36220
+ }, (0, react.createElement)("div", { className: mcp_credential_module_default.rowHead }, (0, react.createElement)("code", { className: mcp_credential_module_default.ref }, ref), view === void 0 ? (0, react.createElement)("span", { className: mcp_credential_module_default.note }, api === void 0 ? t("mcpCredentialUnavailable") : t("loading")) : (0, react.createElement)("span", { className: configured ? mcp_credential_module_default.factOk : mcp_credential_module_default.factMiss }, configured ? t("mcpCredentialConfigured") : t("mcpCredentialMissing")), view?.source === void 0 ? null : (0, react.createElement)("span", { className: mcp_credential_module_default.note }, view.source), (0, react.createElement)("span", { className: mcp_credential_module_default.grow }), view === void 0 ? null : view.writable ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36221
+ variant: "ghost",
36222
+ size: "sm",
36223
+ disabled: refBusy,
36224
+ "aria-expanded": expanded,
36225
+ "aria-label": `${t("mcpCredentialConfigure")} ${ref}`,
36226
+ onClick: () => setOpen((current) => ({
36227
+ ...current,
36228
+ [ref]: !expanded
36229
+ }))
36230
+ }, t("mcpCredentialConfigure")) : (0, react.createElement)("span", { className: mcp_credential_module_default.note }, t("mcpCredentialReadOnly"))), where.length === 0 ? null : (0, react.createElement)("span", { className: mcp_credential_module_default.where }, where.join(" · ")), expanded && view?.writable === true ? (0, react.createElement)("div", { className: mcp_credential_module_default.editor }, (0, react.createElement)("input", {
35613
36231
  className: mcp_credential_module_default.input,
35614
36232
  type: "password",
35615
36233
  autoComplete: "new-password",
35616
36234
  value: drafts[ref] ?? "",
35617
36235
  placeholder: t("mcpCredentialPlaceholder"),
36236
+ "aria-label": ref,
35618
36237
  disabled: refBusy,
35619
36238
  onChange: (event) => setDrafts((current) => ({
35620
36239
  ...current,
@@ -35625,12 +36244,12 @@ function McpCredentialEditor(props) {
35625
36244
  size: "sm",
35626
36245
  disabled: refBusy || (drafts[ref]?.trim() ?? "") === "",
35627
36246
  onClick: () => void save(ref)
35628
- }, t("mcpCredentialSave")), view.configured ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36247
+ }, t("mcpCredentialSave")), configured ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
35629
36248
  variant: "ghost",
35630
36249
  size: "sm",
35631
36250
  disabled: refBusy,
35632
36251
  onClick: () => void unset(ref)
35633
- }, t("mcpCredentialUnset")) : null)) : (0, react.createElement)("div", { className: mcp_credential_module_default.note }, t("mcpCredentialReadOnly"))));
36252
+ }, t("mcpCredentialUnset")) : null)) : null);
35634
36253
  }));
35635
36254
  }
35636
36255
  //#endregion
@@ -35694,9 +36313,75 @@ function searchableFor(payload) {
35694
36313
  searchableCache.set(payload, searchable);
35695
36314
  return searchable;
35696
36315
  }
36316
+ /**
36317
+ * Every tool worth listing: what the server registered, plus every name the
36318
+ * suite or the user mentions.
36319
+ *
36320
+ * A denied tool leaves the live registry, so the stored lists are the only
36321
+ * thing keeping it on screen and available to switch back on. The suite's
36322
+ * allow-list and deny list both read as suite-limited; the user's own denials
36323
+ * stay selectable.
36324
+ */
36325
+ function mcpToolRows(entry) {
36326
+ const allowedNames = entry.suiteEnabledTools;
36327
+ const suiteDenied = new Set(entry.suiteDisabledTools ?? []);
36328
+ const userDenied = new Set(entry.userDisabledTools ?? []);
36329
+ const names = /* @__PURE__ */ new Set([
36330
+ ...entry.tools.map((tool) => tool.name),
36331
+ ...allowedNames ?? [],
36332
+ ...suiteDenied,
36333
+ ...userDenied
36334
+ ]);
36335
+ const observed = new Map(entry.tools.map((tool) => [tool.name, tool]));
36336
+ return [...names].sort().map((name) => {
36337
+ const suiteLimited = allowedNames !== void 0 && !allowedNames.includes(name) || suiteDenied.has(name);
36338
+ const tool = observed.get(name);
36339
+ return {
36340
+ name,
36341
+ allowed: !suiteLimited && !userDenied.has(name),
36342
+ suiteLimited,
36343
+ ...tool?.description === void 0 ? {} : { description: tool.description },
36344
+ ...tool?.parameters === void 0 ? {} : { parameters: tool.parameters }
36345
+ };
36346
+ });
36347
+ }
36348
+ //#endregion
36349
+ //#region src/client/features/mcp-status/diagnostic-guidance.ts
36350
+ /** The locale key holding the advice for one classified failure. */
36351
+ const MCP_GUIDANCE_LABEL = {
36352
+ credentials: "mcpGuideCredentials",
36353
+ auth: "mcpGuideAuth",
36354
+ transport: "mcpGuideTransport",
36355
+ backend: "mcpGuideBackend",
36356
+ dns: "mcpGuideDns",
36357
+ tls: "mcpGuideTls",
36358
+ refused: "mcpGuideRefused",
36359
+ timeout: "mcpGuideTimeout",
36360
+ commandMissing: "mcpGuideCommandMissing",
36361
+ processExit: "mcpGuideProcessExit",
36362
+ protocol: "mcpGuideProtocol"
36363
+ };
36364
+ /** Classify one failure, or nothing when its wording matches no known shape. */
36365
+ function mcpGuidanceKey(code, reason) {
36366
+ const text = `${code ?? ""} ${reason ?? ""}`;
36367
+ if (code === "missing-credential") return "credentials";
36368
+ if (/credential|\$\{[A-Za-z_][A-Za-z0-9_]*\}/i.test(text)) return "credentials";
36369
+ if (code === "unsupported-transport") return "transport";
36370
+ if (/built-in backend|cannot enforce/i.test(text)) return "backend";
36371
+ if (/401|403|unauthor|oauth|forbidden|challenge/i.test(text)) return "auth";
36372
+ if (/ENOTFOUND|getaddrinfo|EAI_AGAIN|dns/i.test(text)) return "dns";
36373
+ if (/certificate|TLS|SSL|self.signed/i.test(text)) return "tls";
36374
+ if (/ECONNREFUSED|connection refused/i.test(text)) return "refused";
36375
+ if (/ETIMEDOUT|timed out|timeout/i.test(text)) return "timeout";
36376
+ if (/ENOENT|not found|no such file|spawn/i.test(text)) return "commandMissing";
36377
+ if (/exited|exit code|SIGTERM|SIGKILL|crash/i.test(text)) return "processExit";
36378
+ if (/jsonrpc|protocol|initialize|handshake/i.test(text)) return "protocol";
36379
+ }
35697
36380
  //#endregion
35698
36381
  //#region src/client/mcp-status.module.css
35699
36382
  var mcp_status_module_default = {
36383
+ "blockHeadRow": "AUWlZW_blockHeadRow",
36384
+ "blockSub": "AUWlZW_blockSub",
35700
36385
  "cardTop": "AUWlZW_cardTop",
35701
36386
  "detail": "AUWlZW_detail",
35702
36387
  "detailBody": "AUWlZW_detailBody",
@@ -35709,7 +36394,13 @@ var mcp_status_module_default = {
35709
36394
  "modalFooter": "AUWlZW_modalFooter",
35710
36395
  "modalFooterGrow": "AUWlZW_modalFooterGrow",
35711
36396
  "modalFooterHint": "AUWlZW_modalFooterHint",
36397
+ "pasteArea": "AUWlZW_pasteArea",
36398
+ "pasteCheck": "AUWlZW_pasteCheck",
36399
+ "pasteNote": "AUWlZW_pasteNote",
36400
+ "pasteOutcome": "AUWlZW_pasteOutcome",
36401
+ "reasonActions": "AUWlZW_reasonActions",
35712
36402
  "reasonBox": "AUWlZW_reasonBox",
36403
+ "reasonHint": "AUWlZW_reasonHint",
35713
36404
  "reasonLabel": "AUWlZW_reasonLabel",
35714
36405
  "reasonRaw": "AUWlZW_reasonRaw",
35715
36406
  "reasonText": "AUWlZW_reasonText",
@@ -35721,12 +36412,28 @@ var mcp_status_module_default = {
35721
36412
  "seamPath": "AUWlZW_seamPath",
35722
36413
  "seamPathLabel": "AUWlZW_seamPathLabel",
35723
36414
  "seamTitle": "AUWlZW_seamTitle",
36415
+ "starter": "AUWlZW_starter",
36416
+ "starterList": "AUWlZW_starterList",
36417
+ "starterPaste": "AUWlZW_starterPaste",
35724
36418
  "surface": "AUWlZW_surface HJ9x7a_shell",
35725
36419
  "tool": "AUWlZW_tool",
35726
36420
  "toolbar": "AUWlZW_toolbar",
35727
36421
  "toolDescription": "AUWlZW_toolDescription",
36422
+ "toolIdentity": "AUWlZW_toolIdentity",
35728
36423
  "toolList": "AUWlZW_toolList",
35729
- "toolName": "AUWlZW_toolName"
36424
+ "toolMore": "AUWlZW_toolMore",
36425
+ "toolName": "AUWlZW_toolName",
36426
+ "toolNameButton": "AUWlZW_toolNameButton",
36427
+ "toolNote": "AUWlZW_toolNote",
36428
+ "toolParam": "AUWlZW_toolParam",
36429
+ "toolParamDesc": "AUWlZW_toolParamDesc",
36430
+ "toolParamName": "AUWlZW_toolParamName",
36431
+ "toolParamRequired": "AUWlZW_toolParamRequired",
36432
+ "toolParams": "AUWlZW_toolParams",
36433
+ "toolParamsEmpty": "AUWlZW_toolParamsEmpty",
36434
+ "toolParamsGrid": "AUWlZW_toolParamsGrid",
36435
+ "toolParamType": "AUWlZW_toolParamType",
36436
+ "toolSearch": "AUWlZW_toolSearch"
35730
36437
  };
35731
36438
  //#endregion
35732
36439
  //#region src/client/McpStatusPanel.tsx
@@ -35745,6 +36452,8 @@ const EMPTY_STATUS$1 = {
35745
36452
  },
35746
36453
  directObservationOnly: true
35747
36454
  };
36455
+ /** How many tool rows a collapsed capability list shows before its expand row. */
36456
+ const TOOL_PAGE_SIZE = 8;
35748
36457
  /** DSH-native MCP inventory with a per-state overview and per-service detail. */
35749
36458
  function McpStatusPanel({ t, credentials }) {
35750
36459
  const [payload, setPayload] = (0, react.useState)(EMPTY_STATUS$1);
@@ -35754,6 +36463,7 @@ function McpStatusPanel({ t, credentials }) {
35754
36463
  const [search, setSearch] = (0, react.useState)("");
35755
36464
  const [view, setView] = useWorkspaceView();
35756
36465
  const [selected, setSelected] = (0, react.useState)(void 0);
36466
+ const [editing, setEditing] = (0, react.useState)();
35757
36467
  const [adding, setAdding] = (0, react.useState)(false);
35758
36468
  const observe = async (id) => {
35759
36469
  const refreshed = await fetchMcpStatus();
@@ -35828,10 +36538,12 @@ function McpStatusPanel({ t, credentials }) {
35828
36538
  entry,
35829
36539
  t,
35830
36540
  onClick: () => setSelected(entry),
35831
- onToggle: () => toggle(entry)
36541
+ onToggle: () => toggle(entry),
36542
+ onEdit: () => setEditing(entry)
35832
36543
  }))), adding ? (0, react.createElement)(McpAddModal, {
35833
36544
  t,
35834
36545
  onClose: () => setAdding(false),
36546
+ onChanged: refresh,
35835
36547
  onSaved: () => {
35836
36548
  setAdding(false);
35837
36549
  refresh();
@@ -35840,6 +36552,7 @@ function McpStatusPanel({ t, credentials }) {
35840
36552
  entry: selected,
35841
36553
  t,
35842
36554
  credentials,
36555
+ backend: payload.backend ?? "builtin",
35843
36556
  onClose: () => {
35844
36557
  setSelected(void 0);
35845
36558
  refresh();
@@ -35847,6 +36560,11 @@ function McpStatusPanel({ t, credentials }) {
35847
36560
  onRetry: retry,
35848
36561
  onReauthorize: reauthorize,
35849
36562
  onRefresh: observe
36563
+ }), editing === void 0 ? null : (0, react.createElement)(McpConfigModal, {
36564
+ entry: editing,
36565
+ t,
36566
+ onClose: () => setEditing(void 0),
36567
+ onSaved: refresh
35850
36568
  }));
35851
36569
  }
35852
36570
  /** The state tag's tone; a healthy server reads as success. */
@@ -35888,7 +36606,7 @@ function mcpDotState(state) {
35888
36606
  * configuration) live in the detail dialog, so a wall of failing cards stays
35889
36607
  * scannable.
35890
36608
  */
35891
- function McpCard({ entry, t, onClick, onToggle }) {
36609
+ function McpCard({ entry, t, onClick, onToggle, onEdit }) {
35892
36610
  const interactive = {
35893
36611
  role: "button",
35894
36612
  tabIndex: 0,
@@ -35906,7 +36624,16 @@ function McpCard({ entry, t, onClick, onToggle }) {
35906
36624
  state: entry.state === "connected" ? "active" : entry.state === "disabled" ? "disabled" : entry.state === "failed" || entry.state === "orphaned" ? "error" : "warning",
35907
36625
  surface: "mcp",
35908
36626
  ...interactive
35909
- }, (0, react.createElement)("div", { className: resource_card_module_default.rowId }, (0, react.createElement)("span", { className: `${resource_card_module_default.name} ${resource_card_module_default.nameMono}` }, entry.name), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: mcpTagTone(entry.state) }, mcpStateLabel(t, entry.state)), (0, react.createElement)("span", { className: resource_card_module_default.provenanceChip }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "neutral" }, entry.kind === "plugin" ? t("mcpPlugin") : t("mcpDirect")))), (0, react.createElement)("div", { className: resource_card_module_default.rowActions }, (0, react.createElement)("span", {
36627
+ }, (0, react.createElement)("div", { className: resource_card_module_default.rowId }, (0, react.createElement)("span", { className: `${resource_card_module_default.name} ${resource_card_module_default.nameMono}` }, entry.name), (0, react.createElement)("span", { className: resource_card_module_default.provenanceChip }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "neutral" }, entry.kind === "plugin" ? t("mcpPlugin") : t("mcpDirect")))), (0, react.createElement)("div", { className: resource_card_module_default.rowActions }, switchable ? (0, react.createElement)("button", {
36628
+ type: "button",
36629
+ className: resource_card_module_default.iconBtn,
36630
+ title: t("panelEdit"),
36631
+ "aria-label": `${t("panelEdit")} ${entry.name}`,
36632
+ onClick: (event) => {
36633
+ event.stopPropagation();
36634
+ onEdit();
36635
+ }
36636
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutlineMedium)) : null, (0, react.createElement)("span", {
35910
36637
  className: resource_card_module_default.switchWrap,
35911
36638
  onClick: (event) => event.stopPropagation()
35912
36639
  }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
@@ -35926,12 +36653,46 @@ function McpCard({ entry, t, onClick, onToggle }) {
35926
36653
  * echo. The state pill is dropped entirely — the dot and the reason box carry
35927
36654
  * that information without a second red stamp.
35928
36655
  */
35929
- function McpDetailModal({ entry, t, credentials, onClose, onRetry, onReauthorize, onRefresh }) {
36656
+ function McpDetailModal({ entry, t, credentials, backend, onClose, onRetry, onReauthorize, onRefresh }) {
35930
36657
  const [pending, setPending] = (0, react.useState)(false);
35931
- const [dirty, setDirty] = (0, react.useState)(false);
35932
36658
  const [confirmAuth, setConfirmAuth] = (0, react.useState)(false);
35933
36659
  const [feedback, setFeedback] = (0, react.useState)();
36660
+ const [toolBusy, setToolBusy] = (0, react.useState)(false);
36661
+ const [toolsExpanded, setToolsExpanded] = (0, react.useState)(false);
36662
+ const [toolSearch, setToolSearch] = (0, react.useState)("");
36663
+ const [expandedTools, setExpandedTools] = (0, react.useState)({});
36664
+ const [enabledBusy, setEnabledBusy] = (0, react.useState)(false);
35934
36665
  const actions = mcpDetailActions(entry);
36666
+ const guidance = mcpGuidanceKey(entry.code, entry.reason);
36667
+ const tools = mcpToolRows(entry);
36668
+ const needle = toolSearch.trim().toLowerCase();
36669
+ const matchingTools = needle === "" ? tools : tools.filter((tool) => tool.name.toLowerCase().includes(needle));
36670
+ const shownTools = toolsExpanded ? matchingTools : matchingTools.slice(0, TOOL_PAGE_SIZE);
36671
+ const hiddenToolCount = matchingTools.length - shownTools.length;
36672
+ const toolsEditable = entry.suiteId !== void 0 && entry.serverKey !== void 0 && entry.state !== "foreign";
36673
+ const toggleTool = (tool, enabled) => {
36674
+ const suiteId = entry.suiteId;
36675
+ const serverKey = entry.serverKey;
36676
+ if (suiteId === void 0 || serverKey === void 0) return;
36677
+ setToolBusy(true);
36678
+ setFeedback(void 0);
36679
+ setMcpServerTool(suiteId, serverKey, tool, enabled).then(() => onRefresh(entry.id)).catch((reason) => setFeedback({
36680
+ error: true,
36681
+ text: clientErrorMessage(t, reason)
36682
+ })).finally(() => setToolBusy(false));
36683
+ };
36684
+ /** Switch the whole server on or off through the same override the card's switch writes. */
36685
+ const toggleEnabled = () => {
36686
+ const suiteId = entry.suiteId;
36687
+ const serverKey = entry.serverKey;
36688
+ if (suiteId === void 0 || serverKey === void 0) return;
36689
+ setEnabledBusy(true);
36690
+ setFeedback(void 0);
36691
+ setMcpServerEnabled(suiteId, serverKey, entry.state === "disabled").then(() => onRefresh(entry.id)).catch((reason) => setFeedback({
36692
+ error: true,
36693
+ text: clientErrorMessage(t, reason)
36694
+ })).finally(() => setEnabledBusy(false));
36695
+ };
35935
36696
  const run = async (authorize) => {
35936
36697
  setConfirmAuth(false);
35937
36698
  setPending(true);
@@ -35961,19 +36722,11 @@ function McpDetailModal({ entry, t, credentials, onClose, onRetry, onReauthorize
35961
36722
  description: t("mcpServiceDetail"),
35962
36723
  closeLabel: t("mcpClose"),
35963
36724
  contentClassName: mcp_status_module_default.detailBody,
35964
- footer: (0, react.createElement)("div", { className: mcp_status_module_default.modalFooter }, actions.retry ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36725
+ footer: (0, react.createElement)("div", { className: mcp_status_module_default.modalFooter }, actions.reauthorize ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
35965
36726
  variant: "ghost",
35966
36727
  size: "sm",
35967
- disabled: pending || dirty,
35968
- title: dirty ? t("mcpSaveFirst") : t("mcpRetryPreservesCredentials"),
35969
- onClick: () => {
35970
- run(false);
35971
- }
35972
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16), t("mcpRetryConnection")) : null, actions.reauthorize ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
35973
- variant: "ghost",
35974
- size: "sm",
35975
- disabled: pending || dirty,
35976
- title: dirty ? t("mcpSaveFirst") : t("mcpReauthExplain"),
36728
+ disabled: pending,
36729
+ title: t("mcpReauthExplain"),
35977
36730
  onClick: () => {
35978
36731
  setConfirmAuth(true);
35979
36732
  setFeedback(void 0);
@@ -35982,7 +36735,13 @@ function McpDetailModal({ entry, t, credentials, onClose, onRetry, onReauthorize
35982
36735
  variant: "ghost",
35983
36736
  disabled: pending,
35984
36737
  onClick: onClose
35985
- }, t("mcpClose"))),
36738
+ }, t("mcpClose")), entry.suiteId === void 0 || entry.serverKey === void 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
36739
+ checked: entry.state !== "disabled",
36740
+ disabled: pending || enabledBusy,
36741
+ label: t("mcpEnabledLabel"),
36742
+ title: t("mcpEnabledLabel"),
36743
+ onChange: () => toggleEnabled()
36744
+ })),
35986
36745
  children: (0, react.createElement)("div", null, feedback ? (0, react.createElement)("p", {
35987
36746
  role: feedback.error ? "alert" : "status",
35988
36747
  className: feedback.error ? mcp_status_module_default.error : mcp_status_module_default.retryEchoSuccess
@@ -35994,45 +36753,154 @@ function McpDetailModal({ entry, t, credentials, onClose, onRetry, onReauthorize
35994
36753
  onClick: () => setConfirmAuth(false)
35995
36754
  }, t("cancel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
35996
36755
  variant: "primary",
35997
- disabled: dirty || pending,
36756
+ disabled: pending,
35998
36757
  onClick: () => {
35999
36758
  run(true);
36000
36759
  }
36001
- }, t("mcpConfirmReauth"))) : null, dirty && (actions.retry || actions.reauthorize) ? (0, react.createElement)("p", { className: mcp_status_module_default.reasonText }, t("mcpSaveFirst")) : null, entry.state === "needs-credentials" ? (0, react.createElement)("p", { className: mcp_status_module_default.reasonText }, t("mcpConfigureCredentialsFirst")) : null, (0, react.createElement)("div", { className: panel_module_default.hero }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: mcpDotState(entry.state) }), (0, react.createElement)("div", { className: panel_module_default.heroText }, (0, react.createElement)("div", { className: panel_module_default.heroLine }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: mcpTagTone(entry.state) }, mcpStateLabel(t, entry.state)), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, null, entry.kind === "plugin" ? t("mcpPlugin") : t("mcpDirect")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "quiet" }, entry.transport), entry.oauthDefault === true ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "quiet" }, t("mcpOauthDefault")) : null), (0, react.createElement)("p", { className: panel_module_default.heroMono }, entry.endpoint ?? t("mcpObservedEndpoint")))), (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("overviewSection")), (0, react.createElement)("dl", { className: panel_module_default.kvGrid }, kvCell(t("sourceLabel"), entry.kind === "plugin" ? entry.suiteId ?? entry.source ?? "—" : t("mcpDirect"), true), kvCell(t("detailTypeLabel"), entry.kind === "plugin" ? t("panelSourcePlugin") : t("panelSourceUser")), kvCell(t("detailTransport"), entry.transport, true), kvCell(t("mcpServerKeyLabel"), entry.serverKey ?? entry.name, true))), entry.state === "foreign" ? (0, react.createElement)("div", { className: mcp_status_module_default.reasonBox }, (0, react.createElement)("span", { className: mcp_status_module_default.reasonLabel }, t("mcpReasonLabel")), (0, react.createElement)("p", { className: mcp_status_module_default.reasonText }, entry.code === "duplicate-mount" ? t("mcpDuplicateHint") : t("mcpForeignHint")), entry.reason === void 0 ? null : (0, react.createElement)("p", { className: mcp_status_module_default.reasonRaw }, entry.reason)) : entry.reason === void 0 ? null : (0, react.createElement)("div", { className: mcp_status_module_default.reasonBox }, (0, react.createElement)("span", { className: mcp_status_module_default.reasonLabel }, t("mcpReasonLabel")), (0, react.createElement)("p", { className: mcp_status_module_default.reasonText }, entry.reason)), entry.kind === "direct" && !entry.managed ? (0, react.createElement)("div", { className: mcp_status_module_default.reasonBox }, (0, react.createElement)("p", { className: mcp_status_module_default.reasonText }, t("mcpDirectBoundary"))) : null, entry.credentialRefs?.length === 0 || entry.credentialRefs === void 0 ? null : (0, react.createElement)(McpCredentialEditor, {
36760
+ }, t("mcpConfirmReauth"))) : null, entry.state === "needs-credentials" ? (0, react.createElement)("p", { className: mcp_status_module_default.reasonText }, t("mcpConfigureCredentialsFirst")) : null, (0, react.createElement)("div", { className: panel_module_default.hero }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: mcpDotState(entry.state) }), (0, react.createElement)("div", { className: panel_module_default.heroText }, (0, react.createElement)("div", { className: panel_module_default.heroLine }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: mcpTagTone(entry.state) }, mcpStateLabel(t, entry.state)), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, null, entry.kind === "plugin" ? t("mcpPlugin") : t("mcpDirect")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "quiet" }, entry.transport), entry.oauthDefault === true ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "quiet" }, t("mcpOauthDefault")) : null), (0, react.createElement)("p", { className: panel_module_default.heroMono }, entry.endpoint ?? t("mcpObservedEndpoint")))), (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("overviewSection")), (0, react.createElement)("dl", { className: panel_module_default.kvGrid }, kvCell(t("sourceLabel"), entry.kind === "plugin" ? entry.suiteId ?? entry.source ?? "—" : t("mcpDirect"), true), kvCell(t("detailTypeLabel"), entry.kind === "plugin" ? t("panelSourcePlugin") : t("panelSourceUser")), kvCell(t("detailTransport"), entry.transport, true), kvCell(t("mcpServerKeyLabel"), entry.serverKey ?? entry.name, true))), entry.state === "foreign" ? (0, react.createElement)("div", { className: mcp_status_module_default.reasonBox }, (0, react.createElement)("span", { className: mcp_status_module_default.reasonLabel }, t("mcpReasonLabel")), (0, react.createElement)("p", { className: mcp_status_module_default.reasonText }, entry.code === "duplicate-mount" ? t("mcpDuplicateHint") : t("mcpForeignHint")), entry.reason === void 0 ? null : (0, react.createElement)("p", { className: mcp_status_module_default.reasonRaw }, entry.reason)) : entry.reason === void 0 && !actions.retry ? null : (0, react.createElement)("div", { className: mcp_status_module_default.reasonBox }, entry.reason === void 0 ? null : (0, react.createElement)("span", { className: mcp_status_module_default.reasonLabel }, t("mcpReasonLabel")), entry.reason === void 0 ? null : (0, react.createElement)("p", { className: mcp_status_module_default.reasonText }, entry.reason), guidance === void 0 ? null : (0, react.createElement)("p", { className: mcp_status_module_default.reasonHint }, t(MCP_GUIDANCE_LABEL[guidance])), actions.retry ? (0, react.createElement)("div", { className: mcp_status_module_default.reasonActions }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36761
+ variant: "outline",
36762
+ size: "sm",
36763
+ disabled: pending,
36764
+ title: t("mcpRetryPreservesCredentials"),
36765
+ onClick: () => {
36766
+ run(false);
36767
+ }
36768
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutlineMedium), t("mcpRetryConnection"))) : null), entry.kind === "direct" && !entry.managed ? (0, react.createElement)("div", { className: mcp_status_module_default.reasonBox }, (0, react.createElement)("p", { className: mcp_status_module_default.reasonText }, t("mcpDirectBoundary"))) : null, (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("div", { className: mcp_status_module_default.blockHeadRow }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, `${t("mcpTools")} (${tools.length})`), tools.length > TOOL_PAGE_SIZE ? (0, react.createElement)("label", { className: mcp_status_module_default.toolSearch }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Input, {
36769
+ icon: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutlineMedium),
36770
+ value: toolSearch,
36771
+ placeholder: t("mcpToolsSearch"),
36772
+ "aria-label": t("mcpToolsSearch"),
36773
+ onChange: (event) => setToolSearch(event.target.value)
36774
+ })) : null), toolsEditable && backend === "host" ? (0, react.createElement)("p", { className: mcp_status_module_default.blockSub }, t("mcpHostToolsUnsupported")) : null, tools.length === 0 ? (0, react.createElement)("p", { className: panel_module_default.detailProse }, entry.advertisedTools === false && entry.state === "degraded" ? t("mcpZeroTools") : t("mcpNoTools")) : matchingTools.length === 0 ? (0, react.createElement)("p", { className: panel_module_default.detailProse }, t("mcpToolsNoMatch")) : (0, react.createElement)("div", { className: mcp_status_module_default.toolList }, shownTools.map((tool) => (0, react.createElement)("div", {
36775
+ key: tool.name,
36776
+ className: mcp_status_module_default.tool
36777
+ }, (0, react.createElement)("span", { className: mcp_status_module_default.toolIdentity }, toolsEditable ? (0, react.createElement)("input", {
36778
+ type: "checkbox",
36779
+ checked: tool.allowed,
36780
+ disabled: toolBusy || tool.suiteLimited || backend === "host",
36781
+ "aria-label": `${t("mcpAllowTool")} ${tool.name}`,
36782
+ onChange: (event) => toggleTool(tool.name, event.target.checked)
36783
+ }) : null, tool.parameters === void 0 ? (0, react.createElement)("span", { className: mcp_status_module_default.toolName }, tool.name) : (0, react.createElement)("button", {
36784
+ type: "button",
36785
+ className: `${mcp_status_module_default.toolName} ${mcp_status_module_default.toolNameButton}`,
36786
+ "aria-expanded": expandedTools[tool.name] === true,
36787
+ onClick: () => setExpandedTools((current) => ({
36788
+ ...current,
36789
+ [tool.name]: current[tool.name] !== true
36790
+ }))
36791
+ }, tool.name)), (0, react.createElement)("span", { className: mcp_status_module_default.toolDescription }, tool.description ?? ""), (0, react.createElement)("span", { className: mcp_status_module_default.toolNote }, tool.suiteLimited ? t("mcpToolSuiteLimited") : ""), expandedTools[tool.name] === true ? (0, react.createElement)("div", { className: mcp_status_module_default.toolParams }, toolParameterRows(tool.parameters, t)) : null)), hiddenToolCount > 0 ? (0, react.createElement)("button", {
36792
+ type: "button",
36793
+ className: mcp_status_module_default.toolMore,
36794
+ onClick: () => setToolsExpanded(true)
36795
+ }, t("mcpToolsMore", { count: hiddenToolCount })) : null)), entry.credentialRefs?.length === 0 || entry.credentialRefs === void 0 ? null : (0, react.createElement)(McpCredentialEditor, {
36002
36796
  t,
36003
36797
  api: credentials,
36004
- refs: entry.credentialRefs
36005
- }), (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("serviceConfigLabel")), (0, react.createElement)(ServerConfigDetail, {
36798
+ refs: entry.credentialRefs,
36799
+ usage: credentialUsage(t, entry.config)
36800
+ }))
36801
+ });
36802
+ }
36803
+ /**
36804
+ * The editor dialog: one scroll column of form fields, opened from the detail
36805
+ * dialog's service-configuration block. Reporting and changing live in separate
36806
+ * dialogs, so neither has to share the other's layout.
36807
+ */
36808
+ function McpConfigModal({ entry, t, onClose, onSaved }) {
36809
+ return (0, react.createElement)(DetailModal, {
36810
+ open: true,
36811
+ title: t("mcpEditTitle"),
36812
+ description: entry.name,
36813
+ closeLabel: t("cancel"),
36814
+ onClose,
36815
+ size: "md",
36816
+ contentClassName: mcp_status_module_default.detailBody,
36817
+ footer: (0, react.createElement)("div", { className: mcp_status_module_default.modalFooter }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36818
+ variant: "ghost",
36819
+ onClick: onClose
36820
+ }, t("cancel"))),
36821
+ children: (0, react.createElement)(ServerConfigDetail, {
36006
36822
  kind: "mcp",
36007
36823
  id: entry.id,
36008
36824
  t,
36009
- onDirtyChange: setDirty,
36010
- onSaved: () => {
36011
- onRefresh(entry.id).catch((reason) => setFeedback({
36012
- error: true,
36013
- text: t("mcpSavedStatusUnknown") + ": " + String(reason)
36014
- }));
36015
- }
36016
- })), (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, `${t("mcpTools")} (${entry.tools.length})`), entry.tools.length === 0 ? (0, react.createElement)("p", { className: panel_module_default.detailProse }, entry.advertisedTools === false && entry.state === "degraded" ? t("mcpZeroTools") : t("mcpNoTools")) : (0, react.createElement)("div", { className: mcp_status_module_default.toolList }, entry.tools.map((tool) => (0, react.createElement)("div", {
36017
- key: tool.name,
36018
- className: mcp_status_module_default.tool
36019
- }, (0, react.createElement)("span", { className: mcp_status_module_default.toolName }, tool.name), tool.description === void 0 || tool.description === "" ? null : (0, react.createElement)("span", { className: mcp_status_module_default.toolDescription }, tool.description))))))
36825
+ onSaved
36826
+ })
36020
36827
  });
36021
36828
  }
36022
- function McpAddModal({ t, onClose, onSaved }) {
36829
+ function McpAddModal({ t, onClose, onSaved, onChanged }) {
36023
36830
  const [name, setName] = (0, react.useState)("");
36024
36831
  const [config, setConfig] = (0, react.useState)("{\"type\":\"stdio\",\"command\":\"\"}");
36025
36832
  const [valid, setValid] = (0, react.useState)(false);
36026
36833
  const [busy, setBusy] = (0, react.useState)(false);
36027
36834
  const [error, setError] = (0, react.useState)();
36835
+ const [fieldErrors, setFieldErrors] = (0, react.useState)();
36836
+ const [templatesOpen, setTemplatesOpen] = (0, react.useState)(false);
36837
+ const [pasteOpen, setPasteOpen] = (0, react.useState)(false);
36838
+ const [pasteText, setPasteText] = (0, react.useState)("");
36839
+ const [pasteError, setPasteError] = (0, react.useState)();
36840
+ const [overwrite, setOverwrite] = (0, react.useState)(false);
36841
+ const [pasteOutcome, setPasteOutcome] = (0, react.useState)();
36842
+ const pasted = pasteOpen && pasteText.trim() !== "" ? parsePastedServersOrUndefined(pasteText) : void 0;
36843
+ const applyTemplate = (template) => {
36844
+ setConfig(JSON.stringify(template.config, null, 2));
36845
+ setTemplatesOpen(false);
36846
+ setPasteError(void 0);
36847
+ };
36848
+ const applyPaste = () => {
36849
+ try {
36850
+ const pasted = parsePastedServer(pasteText);
36851
+ if (pasted.name !== void 0 && name.trim() === "") setName(pasted.name);
36852
+ setConfig(JSON.stringify(pasted.config, null, 2));
36853
+ setPasteOpen(false);
36854
+ setPasteError(void 0);
36855
+ } catch (reason) {
36856
+ setPasteError(reason instanceof Error ? reason.message : String(reason));
36857
+ }
36858
+ };
36859
+ const runImport = () => {
36860
+ if (pasted === void 0) return;
36861
+ const named = pasted.filter((entry) => entry.name !== void 0 && entry.name !== "");
36862
+ const unnamed = pasted.length - named.length;
36863
+ if (named.length === 0) {
36864
+ setPasteOutcome({
36865
+ imported: [],
36866
+ skipped: [{
36867
+ name: "—",
36868
+ reason: t("mcpPasteUnnamed")
36869
+ }]
36870
+ });
36871
+ return;
36872
+ }
36873
+ setBusy(true);
36874
+ setPasteError(void 0);
36875
+ setPasteOutcome(void 0);
36876
+ importMcpServers(named.map((entry) => ({
36877
+ name: entry.name,
36878
+ config: entry.config
36879
+ })), overwrite).then((result) => {
36880
+ const skipped = [...result.skipped, ...unnamed === 0 ? [] : [{
36881
+ name: "—",
36882
+ reason: t("mcpPasteUnnamed")
36883
+ }]];
36884
+ setPasteOutcome({
36885
+ imported: result.imported,
36886
+ skipped
36887
+ });
36888
+ if (result.imported.length > 0) onChanged?.();
36889
+ }).catch((reason) => setPasteError(clientErrorMessage(t, reason))).finally(() => setBusy(false));
36890
+ };
36028
36891
  const save = () => {
36029
36892
  setBusy(true);
36030
36893
  setError(void 0);
36031
- Promise.resolve().then(() => addMcpServer(name.trim(), parseServerConfig(config))).then(onSaved).catch((caught) => setError(clientErrorMessage(t, caught))).finally(() => setBusy(false));
36894
+ setFieldErrors(void 0);
36895
+ Promise.resolve().then(() => addMcpServer(name.trim(), parseServerConfig(config))).then(onSaved).catch((caught) => {
36896
+ setError(clientErrorMessage(t, caught));
36897
+ setFieldErrors(fieldErrorsOf(caught));
36898
+ }).finally(() => setBusy(false));
36032
36899
  };
36033
36900
  return (0, react.createElement)(DetailModal, {
36034
36901
  open: true,
36035
36902
  title: t("mcpAddTitle"),
36903
+ size: "md",
36036
36904
  onClose: busy ? () => {} : onClose,
36037
36905
  closeLabel: t("cancel"),
36038
36906
  contentClassName: mcp_status_module_default.detailBody,
@@ -36045,12 +36913,67 @@ function McpAddModal({ t, onClose, onSaved }) {
36045
36913
  disabled: busy || name.trim() === "" || !valid,
36046
36914
  onClick: save
36047
36915
  }, t("editorCreate"))),
36048
- children: (0, react.createElement)("div", { className: mcp_status_module_default.detail }, (0, react.createElement)(ServerConfigEditor, {
36916
+ children: (0, react.createElement)("div", { className: mcp_status_module_default.detail }, (0, react.createElement)("div", { className: mcp_status_module_default.starter }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36917
+ variant: "outline",
36918
+ size: "sm",
36919
+ type: "button",
36920
+ disabled: busy,
36921
+ "aria-expanded": templatesOpen,
36922
+ onClick: () => setTemplatesOpen((value) => !value)
36923
+ }, t("mcpStarterTemplates")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36924
+ variant: "outline",
36925
+ size: "sm",
36926
+ type: "button",
36927
+ disabled: busy,
36928
+ "aria-expanded": pasteOpen,
36929
+ onClick: () => setPasteOpen((value) => !value)
36930
+ }, t("mcpStarterPaste"))), templatesOpen ? (0, react.createElement)("div", { className: mcp_status_module_default.starterList }, ...MCP_TEMPLATES.map((template) => (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36931
+ key: template.id,
36932
+ variant: "ghost",
36933
+ size: "sm",
36934
+ type: "button",
36935
+ disabled: busy,
36936
+ onClick: () => applyTemplate(template)
36937
+ }, t(template.labelKey)))) : null, pasteOpen ? (0, react.createElement)("div", { className: mcp_status_module_default.starterPaste }, (0, react.createElement)("textarea", {
36938
+ className: mcp_status_module_default.pasteArea,
36939
+ value: pasteText,
36940
+ spellCheck: false,
36941
+ "aria-label": t("mcpStarterPaste"),
36942
+ placeholder: t("mcpPastePlaceholder"),
36943
+ disabled: busy,
36944
+ onChange: (event) => {
36945
+ setPasteText(event.target.value);
36946
+ setPasteOutcome(void 0);
36947
+ setPasteError(void 0);
36948
+ }
36949
+ }), pasted === void 0 ? null : (0, react.createElement)("p", { className: mcp_status_module_default.pasteNote }, t("mcpPasteFound", { count: pasted.length })), (0, react.createElement)("div", { className: mcp_status_module_default.starter }, pasted !== void 0 && pasted.length === 1 ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36950
+ variant: "outline",
36951
+ size: "sm",
36952
+ type: "button",
36953
+ disabled: busy,
36954
+ onClick: applyPaste
36955
+ }, t("mcpPasteApply")) : null, pasted === void 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36956
+ variant: "primary",
36957
+ size: "sm",
36958
+ type: "button",
36959
+ disabled: busy,
36960
+ onClick: runImport
36961
+ }, t("mcpPasteImport"))), pasted !== void 0 && pasted.length > 1 ? (0, react.createElement)("label", { className: mcp_status_module_default.pasteCheck }, (0, react.createElement)("input", {
36962
+ type: "checkbox",
36963
+ checked: overwrite,
36964
+ disabled: busy,
36965
+ onChange: (event) => setOverwrite(event.target.checked)
36966
+ }), " ", t("mcpPasteOverwrite")) : null, pasteOutcome === void 0 ? null : (0, react.createElement)("div", { className: mcp_status_module_default.pasteOutcome }, pasteOutcome.imported.length === 0 ? null : (0, react.createElement)("p", null, t("mcpPasteImported", { names: pasteOutcome.imported.join(", ") })), pasteOutcome.skipped.length === 0 ? null : (0, react.createElement)("p", null, t("mcpPasteSkipped", { detail: pasteOutcome.skipped.map((entry) => `${entry.name} (${entry.reason})`).join(", ") }))), pasteError === void 0 ? null : (0, react.createElement)("div", {
36967
+ role: "alert",
36968
+ className: mcp_status_module_default.error
36969
+ }, pasteError)) : null, (0, react.createElement)(ServerConfigEditor, {
36049
36970
  kind: "mcp",
36050
36971
  text: config,
36051
36972
  onChange: setConfig,
36052
36973
  t,
36053
36974
  disabled: busy,
36975
+ createMode: true,
36976
+ ...fieldErrors === void 0 ? {} : { fieldErrors },
36054
36977
  onValidityChange: setValid,
36055
36978
  nameField: {
36056
36979
  label: t("mcpServerName"),
@@ -36081,6 +37004,57 @@ function mcpFilterHint(t, kind) {
36081
37004
  if (kind === "disabled") return t("mcpFilterDisabledHint");
36082
37005
  return t("mcpFilterAllHint");
36083
37006
  }
37007
+ /**
37008
+ * Where each credential reference is used, as `<field label> <key>` entries read
37009
+ * from the server configuration: a token named in a request header and an
37010
+ * environment variable are the two seams the mount-time expander fills.
37011
+ */
37012
+ /**
37013
+ * The parameters one tool advertises: name, type, whether it is required, and
37014
+ * the server's own description. A nested schema keeps its type name; the full
37015
+ * definition stays with the tool list the model already receives.
37016
+ */
37017
+ function toolParameterRows(parameters, t) {
37018
+ const schema = parameters ?? {};
37019
+ const properties = schema.properties;
37020
+ if (properties === null || typeof properties !== "object" || Array.isArray(properties) || Object.keys(properties).length === 0) return (0, react.createElement)("p", { className: mcp_status_module_default.toolParamsEmpty }, t("mcpToolNoParameters"));
37021
+ const required = new Set(Array.isArray(schema.required) ? schema.required.filter((value) => typeof value === "string") : []);
37022
+ return (0, react.createElement)("div", { className: mcp_status_module_default.toolParamsGrid }, ...Object.entries(properties).map(([name, raw]) => {
37023
+ const node = raw ?? {};
37024
+ const type = typeof node.type === "string" ? node.type : Array.isArray(node.enum) ? "enum" : "any";
37025
+ return (0, react.createElement)("div", {
37026
+ key: name,
37027
+ className: mcp_status_module_default.toolParam
37028
+ }, (0, react.createElement)("span", { className: mcp_status_module_default.toolParamName }, name), (0, react.createElement)("span", { className: mcp_status_module_default.toolParamType }, type), (0, react.createElement)("span", { className: mcp_status_module_default.toolParamRequired }, required.has(name) ? t("mcpToolParamRequired") : ""), (0, react.createElement)("span", { className: mcp_status_module_default.toolParamDesc }, typeof node.description === "string" ? node.description : ""));
37029
+ }));
37030
+ }
37031
+ /** Parse a pasted document, or nothing while it is still half-typed. */
37032
+ function parsePastedServersOrUndefined(text) {
37033
+ try {
37034
+ return parsePastedServers(text);
37035
+ } catch {
37036
+ return;
37037
+ }
37038
+ }
37039
+ function credentialUsage(t, config) {
37040
+ const usage = {};
37041
+ if (config === void 0) return usage;
37042
+ for (const [field, label] of [["headers", t("detailHeaders")], ["env", t("detailEnv")]]) {
37043
+ const values = config[field];
37044
+ if (typeof values !== "object" || values === null) continue;
37045
+ for (const [key, value] of Object.entries(values)) {
37046
+ if (typeof value !== "string") continue;
37047
+ for (const match of value.matchAll(/\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g)) {
37048
+ const name = match[1];
37049
+ if (name === void 0) continue;
37050
+ const entries = usage[name] ?? [];
37051
+ entries.push(`${label} ${key}`);
37052
+ usage[name] = entries;
37053
+ }
37054
+ }
37055
+ }
37056
+ return usage;
37057
+ }
36084
37058
  //#endregion
36085
37059
  //#region src/client/features/lsp-status/lsp-status-view-model.ts
36086
37060
  /** Filter tabs in display order: scope first, the switched-off rows last. */
@@ -36189,6 +37163,7 @@ function LspStatusPanel({ t }) {
36189
37163
  const [search, setSearch] = (0, react.useState)("");
36190
37164
  const [view, setView] = useWorkspaceView();
36191
37165
  const [selected, setSelected] = (0, react.useState)(void 0);
37166
+ const [editing, setEditing] = (0, react.useState)();
36192
37167
  const [editorOpen, setEditorOpen] = (0, react.useState)(false);
36193
37168
  const [seamMigration, setSeamMigration] = (0, react.useState)(void 0);
36194
37169
  const refresh = () => {
@@ -36275,7 +37250,8 @@ function LspStatusPanel({ t }) {
36275
37250
  entry,
36276
37251
  t,
36277
37252
  onOpen: () => setSelected(entry),
36278
- onToggle: () => toggle(entry)
37253
+ onToggle: () => toggle(entry),
37254
+ onEdit: () => setEditing(entry)
36279
37255
  }))), selected === void 0 ? null : (0, react.createElement)(LspDetailModal, {
36280
37256
  entry: selected,
36281
37257
  t,
@@ -36283,6 +37259,11 @@ function LspStatusPanel({ t }) {
36283
37259
  setSelected(void 0);
36284
37260
  refresh();
36285
37261
  }
37262
+ }), editing === void 0 ? null : (0, react.createElement)(LspConfigModal, {
37263
+ entry: editing,
37264
+ t,
37265
+ onClose: () => setEditing(void 0),
37266
+ onSaved: refresh
36286
37267
  }), editorOpen ? (0, react.createElement)(LspConfigEditor, {
36287
37268
  t,
36288
37269
  onClose: () => setEditorOpen(false),
@@ -36361,6 +37342,7 @@ function LspConfigEditor({ t, onClose, onSaved }) {
36361
37342
  open: true,
36362
37343
  onClose: busy ? () => {} : onClose,
36363
37344
  title: t("lspAddTitle"),
37345
+ size: "md",
36364
37346
  closeLabel: t("cancel"),
36365
37347
  contentClassName: mcp_status_module_default.detailBody,
36366
37348
  footer: (0, react.createElement)("div", { className: mcp_status_module_default.modalFooter }, (0, react.createElement)("span", { className: mcp_status_module_default.modalFooterHint }, t("editorFooterCreate")), (0, react.createElement)("div", { className: mcp_status_module_default.modalFooterGrow }), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
@@ -36380,6 +37362,7 @@ function LspConfigEditor({ t, onClose, onSaved }) {
36380
37362
  onChange: setText,
36381
37363
  t,
36382
37364
  disabled: busy,
37365
+ createMode: true,
36383
37366
  onValidityChange: setValid,
36384
37367
  nameField: {
36385
37368
  label: t("lspServerName"),
@@ -36413,7 +37396,7 @@ function lspTagTone(state) {
36413
37396
  * row and the enable switch on its trailing edge; the command on the body row;
36414
37397
  * the declaring suite and the extension count on the source row.
36415
37398
  */
36416
- function LspRow({ entry, t, onOpen, onToggle }) {
37399
+ function LspRow({ entry, t, onOpen, onToggle, onEdit }) {
36417
37400
  const interactive = {
36418
37401
  role: "button",
36419
37402
  tabIndex: 0,
@@ -36430,7 +37413,16 @@ function LspRow({ entry, t, onOpen, onToggle }) {
36430
37413
  state: entry.state === "mounted" ? "active" : disabled ? "disabled" : entry.state === "failed" || entry.state === "conflict" ? "error" : "warning",
36431
37414
  surface: "lsp",
36432
37415
  ...interactive
36433
- }, (0, react.createElement)("div", { className: resource_card_module_default.rowId }, (0, react.createElement)("span", { className: `${resource_card_module_default.name} ${resource_card_module_default.nameMono}` }, entry.serverKey), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: lspTagTone(entry.state) }, stateLabel(t, entry.state)), (0, react.createElement)("span", { className: resource_card_module_default.provenanceChip }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "neutral" }, entry.kind === "plugin" ? t("lspPlugin") : t("lspDirect")))), (0, react.createElement)("div", { className: resource_card_module_default.rowActions }, (0, react.createElement)("span", {
37416
+ }, (0, react.createElement)("div", { className: resource_card_module_default.rowId }, (0, react.createElement)("span", { className: `${resource_card_module_default.name} ${resource_card_module_default.nameMono}` }, entry.serverKey), (0, react.createElement)("span", { className: resource_card_module_default.provenanceChip }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "neutral" }, entry.kind === "plugin" ? t("lspPlugin") : t("lspDirect")))), (0, react.createElement)("div", { className: resource_card_module_default.rowActions }, (0, react.createElement)("button", {
37417
+ type: "button",
37418
+ className: resource_card_module_default.iconBtn,
37419
+ title: t("panelEdit"),
37420
+ "aria-label": `${t("panelEdit")} ${entry.serverKey}`,
37421
+ onClick: (event) => {
37422
+ event.stopPropagation();
37423
+ onEdit();
37424
+ }
37425
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutlineMedium)), (0, react.createElement)("span", {
36434
37426
  className: resource_card_module_default.switchWrap,
36435
37427
  onClick: (event) => event.stopPropagation()
36436
37428
  }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
@@ -36455,16 +37447,37 @@ function LspDetailModal({ entry, t, onClose }) {
36455
37447
  variant: "ghost",
36456
37448
  onClick: onClose
36457
37449
  }, t("detailDone"))),
36458
- children: (0, react.createElement)("div", null, (0, react.createElement)("div", { className: panel_module_default.hero }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: lspDotState(entry.state) }), (0, react.createElement)("div", { className: panel_module_default.heroText }, (0, react.createElement)("div", { className: panel_module_default.heroLine }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: lspTagTone(entry.state) }, stateLabel(t, entry.state)), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, null, entry.kind === "plugin" ? t("lspPlugin") : t("lspDirect")), entry.kind === "plugin" ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "quiet" }, entry.suiteName) : null), (0, react.createElement)("p", { className: panel_module_default.heroMono }, [entry.command, ...entry.args].join(" ")))), (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("overviewSection")), (0, react.createElement)("dl", { className: panel_module_default.kvGrid }, kv$1(t("sourceLabel"), entry.kind === "plugin" ? entry.suiteName : t("lspDirect"), false), kv$1(t("detailTypeLabel"), entry.kind === "plugin" ? t("panelSourcePlugin") : t("panelSourceUser"), false), kv$1(t("lspDeclaredInLabel"), entry.kind === "plugin" ? `lsp.json · ${entry.suiteName}` : "lsp.json", true), kv$1(t("detailCommand"), entry.command, true))), entry.reason === void 0 ? null : (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("lspReasonLabel")), (0, react.createElement)("div", { className: mcp_status_module_default.reasonBox }, (0, react.createElement)("p", { className: mcp_status_module_default.reasonText }, entry.reason))), (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, `${t("detailExtensions")} (${Object.keys(entry.extensions).length})`), (0, react.createElement)(DetailRows, null, ...Object.entries(entry.extensions).map(([extension, language]) => (0, react.createElement)(DetailRow, {
37450
+ children: (0, react.createElement)("div", null, (0, react.createElement)("div", { className: panel_module_default.hero }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: lspDotState(entry.state) }), (0, react.createElement)("div", { className: panel_module_default.heroText }, (0, react.createElement)("div", { className: panel_module_default.heroLine }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: lspTagTone(entry.state) }, stateLabel(t, entry.state)), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, null, entry.kind === "plugin" ? t("lspPlugin") : t("lspDirect")), entry.kind === "plugin" ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "quiet" }, entry.suiteName) : null), (0, react.createElement)("p", { className: panel_module_default.heroMono }, [entry.command, ...entry.args].join(" ")))), (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("overviewSection")), (0, react.createElement)("dl", { className: panel_module_default.kvGrid }, kv$1(t("sourceLabel"), entry.kind === "plugin" ? entry.suiteName : t("lspDirect"), false), kv$1(t("detailTypeLabel"), entry.kind === "plugin" ? t("panelSourcePlugin") : t("panelSourceUser"), false), kv$1(t("lspDeclaredInLabel"), entry.kind === "plugin" ? `lsp.json · ${entry.suiteName}` : "lsp.json", true))), entry.reason === void 0 ? null : (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("lspReasonLabel")), (0, react.createElement)("div", { className: mcp_status_module_default.reasonBox }, (0, react.createElement)("p", { className: mcp_status_module_default.reasonText }, entry.reason))), (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, `${t("detailExtensions")} (${Object.keys(entry.extensions).length})`), (0, react.createElement)(DetailRows, null, ...Object.entries(entry.extensions).map(([extension, language]) => (0, react.createElement)(DetailRow, {
36459
37451
  key: extension,
36460
37452
  name: extension,
36461
37453
  summary: language,
36462
37454
  expandable: false
36463
- })))), (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("serviceConfigLabel")), (0, react.createElement)(ServerConfigDetail, {
37455
+ })))))
37456
+ });
37457
+ }
37458
+ /**
37459
+ * The editor dialog for one language server: a form of its own, opened from the
37460
+ * card's edit action and sharing the add flow's dialog.
37461
+ */
37462
+ function LspConfigModal({ entry, t, onClose, onSaved }) {
37463
+ return (0, react.createElement)(DetailModal, {
37464
+ open: true,
37465
+ title: t("lspEditTitle"),
37466
+ description: entry.serverKey,
37467
+ closeLabel: t("cancel"),
37468
+ onClose,
37469
+ size: "md",
37470
+ contentClassName: mcp_status_module_default.detailBody,
37471
+ footer: (0, react.createElement)("div", { className: mcp_status_module_default.modalFooter }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
37472
+ variant: "ghost",
37473
+ onClick: onClose
37474
+ }, t("cancel"))),
37475
+ children: (0, react.createElement)(ServerConfigDetail, {
36464
37476
  kind: "lsp",
36465
37477
  id: entry.id,
36466
- t
36467
- })))
37478
+ t,
37479
+ onSaved
37480
+ })
36468
37481
  });
36469
37482
  }
36470
37483
  /** One label/value pair in a detail dialog's overview grid. */
@@ -36483,6 +37496,22 @@ function stateLabel(t, state) {
36483
37496
  return t("lspDisabled");
36484
37497
  }
36485
37498
  //#endregion
37499
+ //#region src/model/command-names.ts
37500
+ /**
37501
+ * The call name a command resource registers under.
37502
+ *
37503
+ * A command resource may live at any depth under its `commands/` directory,
37504
+ * but the host's slash-command grammar accepts single-segment names only, so
37505
+ * registration flattens the path separators: `git/commit` registers as
37506
+ * `git-commit`. The user panel renders the same call name, so a card never
37507
+ * advertises a slash name the host cannot accept.
37508
+ * @module model/command-names
37509
+ */
37510
+ /** Flatten a resource path into the single-segment name a slash command registers under. */
37511
+ function commandCallName(name) {
37512
+ return name.replaceAll("/", "-").replaceAll("\\", "-").toLowerCase();
37513
+ }
37514
+ //#endregion
36486
37515
  //#region src/client/features/personas/RoleMetadataFields.tsx
36487
37516
  /** Structured controls edit the same frontmatter as the raw Markdown editor. */
36488
37517
  function RoleMetadataFields(props) {
@@ -36638,7 +37667,7 @@ function UserEntryDetailModal(props) {
36638
37667
  const [open, setOpen] = (0, react.useState)(false);
36639
37668
  const updated = entry.updatedAt === void 0 || entry.updatedAt === null ? null : lastChangeLabel(t, entry.updatedAt);
36640
37669
  const provenance = entry.origin === "user" ? t("panelSourceUser") : t("panelSourcePlugin");
36641
- const title = kind === "commands" ? `/${entry.name}` : entry.name;
37670
+ const title = kind === "commands" ? `/${commandCallName(entry.name)}` : entry.name;
36642
37671
  const docName = kind === "skills" ? "SKILL.md" : `${entry.name}.md`;
36643
37672
  const metaPairs = Object.entries(entry.metadata).filter(([key]) => !HIDDEN_META.has(key));
36644
37673
  return (0, react.createElement)(DetailModal, {
@@ -36942,7 +37971,7 @@ function UserPanelSurface(props) {
36942
37971
  */
36943
37972
  function UserEntryRow(props) {
36944
37973
  const { entry, t } = props;
36945
- const title = props.kind === "commands" ? `/${entry.name}` : entry.name;
37974
+ const title = props.kind === "commands" ? `/${commandCallName(entry.name)}` : entry.name;
36946
37975
  const mono = props.kind === "commands";
36947
37976
  const locked = props.busy || entry.metadata["validationError"] !== void 0;
36948
37977
  const stop = (callback) => (event) => {
@@ -36970,14 +37999,14 @@ function UserEntryRow(props) {
36970
37999
  disabled: props.busy,
36971
38000
  title: t("panelEditTitle"),
36972
38001
  onClick: stop(props.onEdit)
36973
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16)), (0, react.createElement)("button", {
38002
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutlineMedium)), (0, react.createElement)("button", {
36974
38003
  type: "button",
36975
38004
  className: `${resource_card_module_default.iconBtn} ${resource_card_module_default.iconBtnDanger} ${resource_card_module_default.revealOnHover}`,
36976
38005
  "aria-label": t("panelDelete"),
36977
38006
  disabled: props.busy,
36978
38007
  title: t("panelDelete"),
36979
38008
  onClick: stop(props.onDelete)
36980
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16)), (0, react.createElement)("span", {
38009
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineMedium)), (0, react.createElement)("span", {
36981
38010
  className: resource_card_module_default.switchWrap,
36982
38011
  onClick: (event) => event.stopPropagation()
36983
38012
  }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
@@ -37109,7 +38138,7 @@ function renderTab(tab, t, credentials, mode) {
37109
38138
  *
37110
38139
  * @module client/McpPluginCard
37111
38140
  */
37112
- /** Copy of the four boolean switches, in display order. */
38141
+ /** Copy of the boolean switches, in display order. */
37113
38142
  const SWITCH_FIELDS = [
37114
38143
  "mcpEnhanced",
37115
38144
  "scanProjectLayouts",
@@ -37181,7 +38210,7 @@ function McpPluginCard(props) {
37181
38210
  onClick: () => {
37182
38211
  setOpen((current) => !current);
37183
38212
  }
37184
- }, (0, react.createElement)("div", { className: market_module_default.pluginCardText }, (0, react.createElement)("div", { className: market_module_default.pluginCardTitle }, t("nav")), (0, react.createElement)("div", { className: market_module_default.pluginCardDesc }, t("marketCardDesc"))), state.dirty ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "neutral" }, t("settingUnsaved")) : null, (0, react.createElement)("span", { className: open ? `${market_module_default.pluginChevron} ${market_module_default.pluginChevronOpen}` : market_module_default.pluginChevron }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 }))), open ? (0, react.createElement)("div", { className: market_module_default.pluginCardBody }, state.writable ? null : (0, react.createElement)("p", {
38213
+ }, (0, react.createElement)("div", { className: market_module_default.pluginCardText }, (0, react.createElement)("div", { className: market_module_default.pluginCardTitle }, t("nav")), (0, react.createElement)("div", { className: market_module_default.pluginCardDesc }, t("marketCardDesc"))), state.dirty ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "neutral" }, t("settingUnsaved")) : null, (0, react.createElement)("span", { className: open ? `${market_module_default.pluginChevron} ${market_module_default.pluginChevronOpen}` : market_module_default.pluginChevron }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineMedium))), open ? (0, react.createElement)("div", { className: market_module_default.pluginCardBody }, state.writable ? null : (0, react.createElement)("p", {
37185
38214
  className: market_module_default.pluginCardReadonly,
37186
38215
  role: "status"
37187
38216
  }, t("mcpCardReadonly")), SWITCH_FIELDS.map((field) => (0, react.createElement)(SwitchRow, {
@@ -37274,7 +38303,7 @@ var MarketPluginCardController = class {
37274
38303
  failed = false;
37275
38304
  disposed = false;
37276
38305
  /**
37277
- * @param scope - the bound settings scope for the market namespace.
38306
+ * @param scope - the host configuration form for the market namespace.
37278
38307
  * @param probe - reads the live host-client and region state from the market API.
37279
38308
  */
37280
38309
  constructor(scope, probeSource) {
@@ -37778,20 +38807,24 @@ function apply(ctx) {
37778
38807
  isSettingsSurfaceAvailable: () => settingsSurfaceAvailable,
37779
38808
  subscribeLocale: ctx.locale.subscribe === void 0 ? void 0 : (listener) => ctx.locale.subscribe(listener)
37780
38809
  }), "dsh-agent-plugins-market: legacy page mode");
37781
- ctx.inject?.(["settingsScope"], (scoped) => {
37782
- const service = scoped.settingsScope;
38810
+ ctx.inject?.(["configForms"], (scoped) => {
38811
+ const service = scoped.configForms;
37783
38812
  const slots = scoped.slots;
37784
38813
  if (service === void 0 || slots === void 0) return;
37785
- slots.inject("settings.plugin.item", () => {
37786
- const card = new MarketPluginCardController(service.bind({ namespace: NS }), fetchMcpBackend);
38814
+ let card;
38815
+ service.whileServed([NS], () => {
38816
+ card = new MarketPluginCardController(service.get(NS), fetchMcpBackend);
37787
38817
  const dispose = slots.register({
37788
- name: "settings.plugin.item",
37789
- key: NS,
38818
+ name: "plugins.item",
38819
+ id: NS,
38820
+ order: 50,
38821
+ label: () => t("nav"),
37790
38822
  locale: NS,
37791
38823
  inject: () => card.inject()
37792
38824
  }, McpPluginCard);
37793
38825
  return () => {
37794
- card.dispose();
38826
+ card?.dispose();
38827
+ card = void 0;
37795
38828
  if (typeof dispose === "function") dispose();
37796
38829
  };
37797
38830
  });