dsh-agent-plugins-market 0.8.0 → 0.8.2

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 (158) hide show
  1. package/README.md +2 -2
  2. package/README.zh.md +2 -2
  3. package/client/client.js +1594 -1732
  4. package/client/client.js.map +1 -1
  5. package/lib/application/agent-roles.js +53 -0
  6. package/lib/application/catalog-context.js +2 -2
  7. package/lib/application/catalog.js +4 -8
  8. package/lib/{runtime → application}/deadline.js +1 -1
  9. package/lib/application/details.js +3 -3
  10. package/lib/application/json-file.js +43 -0
  11. package/lib/{runtime → application/lsp}/lsp-direct-config.js +9 -7
  12. package/lib/application/lsp/lsp-server-state.js +17 -0
  13. package/lib/{runtime → application/lsp}/lsp-status.js +22 -7
  14. package/lib/{runtime → application/lsp}/profile-seam.js +1 -1
  15. package/lib/application/lsp-service.js +5 -5
  16. package/lib/{runtime → application/mcp}/mcp-backend.js +6 -21
  17. package/lib/{runtime → application/mcp}/mcp-config.js +4 -4
  18. package/lib/{runtime → application/mcp}/mcp-direct-config.js +8 -49
  19. package/lib/{runtime → application/mcp}/mcp-overrides.js +3 -5
  20. package/lib/{runtime → application/mcp}/mcp-status.js +13 -7
  21. package/lib/application/mcp-service.js +11 -35
  22. package/lib/application/panel-resources.js +48 -11
  23. package/lib/{runtime → application/panels}/user-hooks.js +2 -2
  24. package/lib/{runtime → application/panels}/user-store.js +2 -2
  25. package/lib/application/ports.js +1 -0
  26. package/lib/application/project-agent-roles.js +1 -1
  27. package/lib/{runtime → application}/server-config.js +7 -17
  28. package/lib/application/snapshot-cache.js +1 -1
  29. package/lib/application/source-store.js +3 -4
  30. package/lib/{runtime → application/state}/state-store.js +5 -7
  31. package/lib/{runtime → application/state}/storage-migration.js +4 -4
  32. package/lib/catalog/source-catalog.js +0 -4
  33. package/lib/contracts/lsp.js +1 -0
  34. package/lib/contracts/market.js +0 -1
  35. package/lib/contracts/mcp.js +1 -0
  36. package/lib/index.js +64 -34
  37. package/lib/routes.js +2 -9
  38. package/lib/runtime/{agent-role-router.js → agents/agent-role-router.js} +7 -53
  39. package/lib/runtime/{subagent-catalog.js → agents/subagent-catalog.js} +24 -16
  40. package/lib/runtime/core/context.js +31 -0
  41. package/lib/runtime/{reconciler.js → core/reconciler.js} +5 -5
  42. package/lib/runtime/host/failure-detail.js +58 -0
  43. package/lib/runtime/{feedback-tool.js → host/feedback-tool.js} +1 -1
  44. package/lib/runtime/host/host-locale.js +83 -0
  45. package/lib/runtime/{settings-namespace.js → host/settings-namespace.js} +44 -66
  46. package/lib/runtime/host/shell-path.js +196 -0
  47. package/lib/runtime/{tool-registry-observer.js → host/tool-registry-observer.js} +2 -1
  48. package/lib/runtime/{lsp-mounts.js → lsp/lsp-mounts.js} +69 -20
  49. package/lib/runtime/{mcp-client → mcp/bridge}/bridge.js +52 -22
  50. package/lib/runtime/{mcp-client → mcp/bridge}/connection.js +2 -2
  51. package/lib/runtime/{mcp-client → mcp/bridge}/oauth.js +1 -1
  52. package/lib/runtime/{mcp-client → mcp/bridge}/tools.js +2 -2
  53. package/lib/runtime/{mcp-auth-record.js → mcp/mcp-auth-record.js} +1 -1
  54. package/lib/runtime/{mcp-mounts.js → mcp/mcp-mounts.js} +14 -7
  55. package/lib/runtime/{user-commands.js → panels/user-commands.js} +3 -3
  56. package/lib/runtime/{user-panels.js → panels/user-panels.js} +2 -2
  57. package/lib/runtime/{commands-mounts.js → surfaces/commands-mounts.js} +7 -7
  58. package/lib/runtime/{hooks-mounts.js → surfaces/hooks-mounts.js} +2 -2
  59. package/lib/runtime/{project-runtime.js → surfaces/project-runtime.js} +5 -5
  60. package/lib/runtime/{skills-provider.js → surfaces/skills-provider.js} +4 -4
  61. package/lib/types/application/agent-roles.d.ts +30 -0
  62. package/lib/types/application/catalog.d.ts +4 -7
  63. package/lib/types/application/details.d.ts +1 -1
  64. package/lib/types/application/json-file.d.ts +12 -0
  65. package/lib/types/{runtime → application/lsp}/lsp-direct-config.d.ts +1 -1
  66. package/lib/types/{runtime → application/lsp}/lsp-status.d.ts +3 -3
  67. package/lib/types/{runtime → application/mcp}/mcp-backend.d.ts +24 -22
  68. package/lib/types/{runtime/mcp-client/config.d.ts → application/mcp/mcp-bridge-config.d.ts} +11 -1
  69. package/lib/types/{runtime → application/mcp}/mcp-config.d.ts +6 -7
  70. package/lib/types/application/mcp/mcp-direct-config.d.ts +17 -0
  71. package/lib/types/{runtime → application/mcp}/mcp-overrides.d.ts +1 -1
  72. package/lib/types/{runtime → application/mcp}/mcp-status.d.ts +7 -7
  73. package/lib/types/application/mcp-service.d.ts +4 -11
  74. package/lib/types/application/panel-resources.d.ts +9 -2
  75. package/lib/types/{runtime → application/panels}/user-hooks.d.ts +1 -1
  76. package/lib/types/{runtime → application/panels}/user-store.d.ts +1 -1
  77. package/lib/types/application/ports.d.ts +17 -3
  78. package/lib/types/application/project-agent-roles.d.ts +1 -1
  79. package/lib/types/application/queries.d.ts +3 -6
  80. package/lib/types/{runtime → application}/regions.d.ts +1 -1
  81. package/lib/types/{runtime → application/state}/state-store.d.ts +2 -2
  82. package/lib/types/catalog/source-catalog.d.ts +0 -2
  83. package/lib/types/contracts/lsp-status.d.ts +6 -0
  84. package/lib/types/contracts/lsp.d.ts +16 -0
  85. package/lib/types/contracts/market.d.ts +1 -4
  86. package/lib/types/contracts/mcp-status.d.ts +21 -2
  87. package/lib/types/contracts/mcp.d.ts +20 -0
  88. package/lib/types/index.d.ts +87 -1
  89. package/lib/types/model/types.d.ts +0 -14
  90. package/lib/types/runtime/{agent-role-router.d.ts → agents/agent-role-router.d.ts} +3 -28
  91. package/lib/types/runtime/{subagent-catalog.d.ts → agents/subagent-catalog.d.ts} +6 -6
  92. package/lib/types/runtime/core/context.d.ts +14 -0
  93. package/lib/types/runtime/{reconcile-scheduler.d.ts → core/reconcile-scheduler.d.ts} +2 -2
  94. package/lib/types/runtime/{reconciler.d.ts → core/reconciler.d.ts} +8 -8
  95. package/lib/types/runtime/host/failure-detail.d.ts +6 -0
  96. package/lib/types/runtime/host/host-locale.d.ts +66 -0
  97. package/lib/types/runtime/{model-catalog.d.ts → host/model-catalog.d.ts} +1 -1
  98. package/lib/types/runtime/{settings-namespace.d.ts → host/settings-namespace.d.ts} +42 -32
  99. package/lib/types/runtime/host/shell-path.d.ts +70 -0
  100. package/lib/types/runtime/{lsp-mounts.d.ts → lsp/lsp-mounts.d.ts} +17 -11
  101. package/lib/types/runtime/{mcp-client → mcp/bridge}/bridge.d.ts +1 -1
  102. package/lib/types/runtime/{mcp-client → mcp/bridge}/connection.d.ts +3 -11
  103. package/lib/types/runtime/{mcp-client → mcp/bridge}/host-contract.d.ts +1 -1
  104. package/lib/types/runtime/{mcp-client → mcp/bridge}/oauth.d.ts +1 -1
  105. package/lib/types/runtime/{mcp-client → mcp/bridge}/transport.d.ts +1 -1
  106. package/lib/types/runtime/{mcp-auth-record.d.ts → mcp/mcp-auth-record.d.ts} +1 -1
  107. package/lib/types/runtime/{mcp-credentials.d.ts → mcp/mcp-credentials.d.ts} +1 -1
  108. package/lib/types/runtime/{mcp-mounts.d.ts → mcp/mcp-mounts.d.ts} +5 -11
  109. package/lib/types/runtime/{user-commands.d.ts → panels/user-commands.d.ts} +1 -1
  110. package/lib/types/runtime/{user-panels.d.ts → panels/user-panels.d.ts} +1 -1
  111. package/lib/types/runtime/{commands-mounts.d.ts → surfaces/commands-mounts.d.ts} +2 -2
  112. package/lib/types/runtime/{hooks-mounts.d.ts → surfaces/hooks-mounts.d.ts} +1 -1
  113. package/lib/types/runtime/{project-runtime.d.ts → surfaces/project-runtime.d.ts} +3 -3
  114. package/lib/types/runtime/{skills-provider.d.ts → surfaces/skills-provider.d.ts} +1 -1
  115. package/package.json +39 -33
  116. package/lib/runtime/host-locale.js +0 -89
  117. package/lib/runtime/legacy-root-migration.js +0 -12
  118. package/lib/runtime/lsp-server-state.js +0 -19
  119. package/lib/runtime/mcp-client/json-schema-subset.js +0 -181
  120. package/lib/types/runtime/host-locale.d.ts +0 -31
  121. package/lib/types/runtime/legacy-root-migration.d.ts +0 -2
  122. package/lib/types/runtime/mcp-client/json-schema-subset.d.ts +0 -58
  123. package/lib/types/runtime/mcp-direct-config.d.ts +0 -39
  124. /package/lib/{runtime/mcp-client/config.js → application/mcp/mcp-bridge-config.js} +0 -0
  125. /package/lib/{runtime → application/mcp}/mcp-redaction.js +0 -0
  126. /package/lib/{runtime → application}/regions.js +0 -0
  127. /package/lib/runtime/{agent-role-names.js → agents/agent-role-names.js} +0 -0
  128. /package/lib/runtime/{mount-lifecycle.js → core/mount-lifecycle.js} +0 -0
  129. /package/lib/runtime/{reconcile-scheduler.js → core/reconcile-scheduler.js} +0 -0
  130. /package/lib/runtime/{source-auto-update.js → core/source-auto-update.js} +0 -0
  131. /package/lib/runtime/{timer-seat.js → core/timer-seat.js} +0 -0
  132. /package/lib/runtime/{model-catalog.js → host/model-catalog.js} +0 -0
  133. /package/lib/runtime/{plugin-message-source.js → host/plugin-message-source.js} +0 -0
  134. /package/lib/runtime/{mcp-client → mcp/bridge}/host-contract.js +0 -0
  135. /package/lib/runtime/{mcp-client → mcp/bridge}/host-seams.js +0 -0
  136. /package/lib/runtime/{mcp-client → mcp/bridge}/plugin-identity.js +0 -0
  137. /package/lib/runtime/{mcp-client → mcp/bridge}/projection.js +0 -0
  138. /package/lib/runtime/{mcp-client → mcp/bridge}/transport.js +0 -0
  139. /package/lib/runtime/{mcp-credentials.js → mcp/mcp-credentials.js} +0 -0
  140. /package/lib/runtime/{dynamic-context.js → surfaces/dynamic-context.js} +0 -0
  141. /package/lib/types/{runtime → application}/deadline.d.ts +0 -0
  142. /package/lib/types/{runtime → application/lsp}/lsp-server-state.d.ts +0 -0
  143. /package/lib/types/{runtime → application/lsp}/profile-seam.d.ts +0 -0
  144. /package/lib/types/{runtime → application/mcp}/mcp-redaction.d.ts +0 -0
  145. /package/lib/types/{runtime → application}/server-config.d.ts +0 -0
  146. /package/lib/types/{runtime → application/state}/storage-migration.d.ts +0 -0
  147. /package/lib/types/runtime/{agent-role-names.d.ts → agents/agent-role-names.d.ts} +0 -0
  148. /package/lib/types/runtime/{mount-lifecycle.d.ts → core/mount-lifecycle.d.ts} +0 -0
  149. /package/lib/types/runtime/{source-auto-update.d.ts → core/source-auto-update.d.ts} +0 -0
  150. /package/lib/types/runtime/{timer-seat.d.ts → core/timer-seat.d.ts} +0 -0
  151. /package/lib/types/runtime/{feedback-tool.d.ts → host/feedback-tool.d.ts} +0 -0
  152. /package/lib/types/runtime/{plugin-message-source.d.ts → host/plugin-message-source.d.ts} +0 -0
  153. /package/lib/types/runtime/{tool-registry-observer.d.ts → host/tool-registry-observer.d.ts} +0 -0
  154. /package/lib/types/runtime/{mcp-client → mcp/bridge}/host-seams.d.ts +0 -0
  155. /package/lib/types/runtime/{mcp-client → mcp/bridge}/plugin-identity.d.ts +0 -0
  156. /package/lib/types/runtime/{mcp-client → mcp/bridge}/projection.d.ts +0 -0
  157. /package/lib/types/runtime/{mcp-client → mcp/bridge}/tools.d.ts +0 -0
  158. /package/lib/types/runtime/{dynamic-context.d.ts → surfaces/dynamic-context.d.ts} +0 -0
package/client/client.js CHANGED
@@ -2,7 +2,7 @@ window.__ModuleLoader__.load({ id: "dsh-agent-plugins-market", factory: (require
2
2
 
3
3
  var module = { exports: {} };
4
4
  var exports = module.exports;
5
- (function(){if(typeof document!=="undefined"){var s=document.createElement("style");s.setAttribute("data-dsh-client","dsh-agent-plugins-market");s.textContent=".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);}})();
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.U-hjqq_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.U-hjqq_pageMode {\n width: 100%;\n min-width: 0;\n height: 100%;\n min-height: 0;\n}\n\n.U-hjqq_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.U-hjqq_pageEntry:focus-visible, .U-hjqq_srcTabMain:focus-visible, .U-hjqq_srcTabEdit:focus-visible, .U-hjqq_srcTabDel:focus-visible, .U-hjqq_detailItemRow:focus-visible, .U-hjqq_detailItemOpen:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: 2px;\n}\n\n.U-hjqq_header {\n flex-direction: column;\n flex-shrink: 0;\n gap: 8px;\n display: flex;\n}\n\n.U-hjqq_sourceTabsBox {\n min-width: 0;\n position: relative;\n}\n\n.U-hjqq_sourceTabsRow {\n grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));\n gap: 4px;\n min-width: 0;\n display: grid;\n}\n\n.U-hjqq_sourceTabsBoxFold {\n clip-path: inset(-6px);\n height: 52px;\n}\n\n.U-hjqq_sourceTabsBoxFold:hover, .U-hjqq_sourceTabsBoxFold:has(:focus-visible) {\n clip-path: none;\n z-index: 20;\n}\n\n.U-hjqq_sourceTabsBoxFold .U-hjqq_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.U-hjqq_sourceTabsBoxFold:hover .U-hjqq_sourceTabsRow, .U-hjqq_sourceTabsBoxFold:has(:focus-visible) .U-hjqq_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.U-hjqq_sourceTabsBoxFold.U-hjqq_sourceTabsBoxPicked:hover, .U-hjqq_sourceTabsBoxFold.U-hjqq_sourceTabsBoxPicked:has(:focus-visible) {\n clip-path: inset(-6px);\n}\n\n.U-hjqq_sourceTabsBoxFold.U-hjqq_sourceTabsBoxPicked:hover .U-hjqq_sourceTabsRow, .U-hjqq_sourceTabsBoxFold.U-hjqq_sourceTabsBoxPicked:has(:focus-visible) .U-hjqq_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.U-hjqq_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.U-hjqq_unmanagedLabel {\n flex-shrink: 0;\n}\n\n.U-hjqq_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.U-hjqq_unmanagedChipName {\n white-space: nowrap;\n text-overflow: ellipsis;\n font-size: 12px;\n overflow: hidden;\n}\n\n.U-hjqq_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.U-hjqq_unmanagedAdopt:disabled {\n cursor: default;\n opacity: .5;\n}\n\n.U-hjqq_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.U-hjqq_srcTabEdit:hover {\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n.U-hjqq_srcTabOn .U-hjqq_srcTabEdit, .U-hjqq_srcTabOn .U-hjqq_srcTabEdit:hover {\n color: var(--dsw-alias-label-primary-foreground, #fff);\n}\n\n.U-hjqq_srcTab, .U-hjqq_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 position: relative;\n overflow: hidden;\n}\n\n.U-hjqq_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.U-hjqq_srcTabMain:hover {\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n.U-hjqq_srcTabOn {\n background: var(--dsw-alias-brand-primary, #0f1115);\n border-color: var(--dsw-alias-brand-primary, #0f1115);\n}\n\n.U-hjqq_srcTabOn .U-hjqq_srcTabMain {\n color: var(--dsw-alias-label-primary-foreground, #fff);\n font-weight: 600;\n}\n\n.U-hjqq_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.U-hjqq_srcTabDel:hover {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.U-hjqq_srcTabOn .U-hjqq_srcTabDel, .U-hjqq_srcTabOn .U-hjqq_srcTabDel:hover {\n color: var(--dsw-alias-label-primary-foreground, #fff);\n}\n\n.U-hjqq_srcTabControls {\n border-radius: inherit;\n background: inherit;\n height: 100%;\n box-shadow: 0 0 6px 6px var(--dsw-alias-bg-layer-1);\n opacity: 0;\n pointer-events: none;\n align-items: center;\n gap: 2px;\n padding: 0 6px 0 8px;\n transition: opacity .12s;\n display: inline-flex;\n position: absolute;\n top: 0;\n right: 0;\n}\n\n.U-hjqq_srcTabControls > button {\n pointer-events: auto;\n}\n\n.U-hjqq_srcTab:hover .U-hjqq_srcTabControls, .U-hjqq_srcTab:focus-within .U-hjqq_srcTabControls {\n opacity: 1;\n}\n\n.U-hjqq_srcTabOn .U-hjqq_srcTabControls {\n background: var(--dsw-alias-brand-primary, #0f1115);\n box-shadow: 0 0 6px 6px var(--dsw-alias-brand-primary, #0f1115);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .U-hjqq_srcTabControls {\n transition: none;\n }\n}\n\n.U-hjqq_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.U-hjqq_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.U-hjqq_list .U-hjqq_card {\n flex-flow: wrap;\n align-items: center;\n gap: 8px 14px;\n}\n\n.U-hjqq_list .U-hjqq_cardTop, .U-hjqq_list .U-hjqq_cardActions {\n flex: none;\n}\n\n.U-hjqq_list .U-hjqq_meta, .U-hjqq_list .U-hjqq_tagRow {\n flex-basis: 100%;\n}\n\n.U-hjqq_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.U-hjqq_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.U-hjqq_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.U-hjqq_modalFooter {\n justify-content: flex-end;\n gap: 8px;\n width: 100%;\n display: flex;\n}\n\n.U-hjqq_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.U-hjqq_modalFooterLeft {\n gap: 8px;\n margin-right: auto;\n display: flex;\n}\n\n.U-hjqq_editorDialog {\n width: min(640px, 92vw);\n}\n\n.U-hjqq_installConfirmBody {\n flex-direction: column;\n gap: 10px;\n min-width: 0;\n display: flex;\n}\n\n.U-hjqq_installConfirmSuite {\n color: var(--dsw-alias-label-primary, #111827);\n font-weight: 600;\n}\n\n.U-hjqq_installConfirmMeta {\n color: var(--dsw-alias-label-secondary, #4b5563);\n font-size: 12px;\n}\n\n.U-hjqq_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.U-hjqq_installConfirmTags {\n flex-wrap: wrap;\n gap: 6px;\n display: flex;\n}\n\n.U-hjqq_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.U-hjqq_progress, .U-hjqq_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.U-hjqq_progressError {\n border-color: var(--dsw-alias-state-error-primary, #ec1313);\n color: var(--dsw-alias-state-error-primary, #ec1313);\n}\n\n.U-hjqq_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 U-hjqq_dshApmSpin;\n}\n\n@keyframes U-hjqq_dshApmSpin {\n to {\n transform: rotate(360deg);\n }\n}\n\n.U-hjqq_progressFail {\n flex-shrink: 0;\n font-size: 13px;\n}\n\n.U-hjqq_progressText {\n overflow-wrap: anywhere;\n min-width: 0;\n}\n\n@media (width <= 720px) {\n .U-hjqq_pageView {\n padding: 14px;\n }\n\n .U-hjqq_sourceTabsRow {\n grid-template-columns: repeat(auto-fill, minmax(102px, 1fr));\n }\n\n .U-hjqq_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .U-hjqq_list .U-hjqq_cardTop, .U-hjqq_list .U-hjqq_cardActions {\n max-width: 100%;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .U-hjqq_progressSpin, .U-hjqq_switchOn, .U-hjqq_switchOff, .U-hjqq_switchThumb {\n transition: none;\n animation: none;\n }\n}\n\n.U-hjqq_surfaceToggles {\n flex-wrap: wrap;\n align-items: center;\n gap: 4px 14px;\n display: flex;\n}\n\n.U-hjqq_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.U-hjqq_surfaceToggle input[type=\"checkbox\"] {\n accent-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);\n margin: 0;\n}\n\n.U-hjqq_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: U-hjqq_market-config / inline-size;\n}\n\n.U-hjqq_pluginCard:hover {\n border-color: var(--dsw-alias-label-dimmed, #c8ccd4);\n}\n\n.U-hjqq_pluginCardOpen {\n background: var(--dsw-alias-bg-layer-2, #f7f8fa);\n border-color: var(--dsw-alias-label-dimmed, #c8ccd4);\n}\n\n.U-hjqq_pluginCard[data-busy=\"true\"] {\n opacity: .6;\n pointer-events: none;\n}\n\n.U-hjqq_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.U-hjqq_pluginCardHeader:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #4f6ef7);\n outline-offset: -2px;\n}\n\n.U-hjqq_pluginCardBody {\n flex-direction: column;\n gap: 8px;\n display: flex;\n}\n\n.U-hjqq_pluginCardRow {\n justify-content: space-between;\n align-items: center;\n gap: 16px;\n padding: 8px 0 4px;\n display: flex;\n}\n\n.U-hjqq_pluginCardText {\n flex-direction: column;\n flex: 1;\n gap: 4px;\n min-width: 0;\n display: flex;\n}\n\n.U-hjqq_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.U-hjqq_pluginCardDesc {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 13px;\n line-height: 1.5;\n}\n\n.U-hjqq_pluginCardRowLabel {\n font-size: 13px;\n font-weight: 500;\n line-height: 20px;\n}\n\n@container U-hjqq_market-config (width <= 320px) {\n .U-hjqq_pluginCardRow {\n flex-direction: column;\n align-items: flex-start;\n gap: 8px;\n }\n\n .U-hjqq_pluginCardText {\n overflow-wrap: anywhere;\n width: 100%;\n }\n}\n\n.U-hjqq_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.U-hjqq_pluginFieldHead {\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.U-hjqq_pluginFieldBadges {\n align-items: center;\n gap: 6px;\n display: inline-flex;\n}\n\n.U-hjqq_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.U-hjqq_pluginFieldReset:disabled {\n cursor: default;\n opacity: .5;\n}\n\n.U-hjqq_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.U-hjqq_pluginCardFooter {\n align-items: center;\n gap: 8px;\n padding-top: 16px;\n display: flex;\n}\n\n.U-hjqq_pluginCardFooter .U-hjqq_pluginCardError {\n flex: 1;\n}\n\n.U-hjqq_pluginCardDiscard {\n appearance: none;\n font: inherit;\n cursor: pointer;\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n color: var(--dsw-alias-label-primary, #1f2328);\n background: none;\n border-radius: 8px;\n padding: 4px 12px;\n font-size: 13px;\n line-height: 20px;\n}\n\n.U-hjqq_pluginCardDiscard:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, #0000000a);\n}\n\n.U-hjqq_pluginCardDiscard:disabled {\n cursor: default;\n opacity: .5;\n}\n\n.U-hjqq_pluginChevron {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n flex: none;\n transition: transform .16s;\n display: inline-flex;\n}\n\n.U-hjqq_pluginChevronOpen {\n transform: rotate(180deg);\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: minmax(0, 1fr);\n gap: 10px;\n min-width: 0;\n margin: 0;\n padding: 4px 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_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._4JL8qq_toolbar {\n flex: none;\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n._4JL8qq_search {\n flex: auto;\n align-items: center;\n min-width: 0;\n display: flex;\n}\n\n._4JL8qq_searchInput {\n flex: auto;\n min-width: 0;\n}\n\n._4JL8qq_searchInput input {\n font-size: 12px;\n line-height: 20px;\n}\n\n._4JL8qq_segment {\n flex: none;\n}\n\n@container (width <= 480px) {\n ._4JL8qq_toolbar {\n flex-wrap: wrap;\n justify-content: flex-end;\n }\n\n ._4JL8qq_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.AJn4ya_band {\n border-left: 3px solid var(--dsw-alias-label-tertiary);\n background: var(--dsw-alias-interactive-bg-hover);\n border-radius: 10px;\n flex-direction: column;\n gap: 6px;\n padding: 12px 14px;\n display: flex;\n}\n\n.AJn4ya_band[data-band-tone=\"success\"] {\n border-left-color: var(--dsw-alias-state-success-primary);\n}\n\n.AJn4ya_band[data-band-tone=\"warn\"] {\n border-left-color: var(--dsw-alias-state-warn-primary);\n}\n\n.AJn4ya_band[data-band-tone=\"error\"] {\n border-left-color: var(--dsw-alias-state-error-primary);\n}\n\n.AJn4ya_top {\n align-items: center;\n gap: 10px;\n display: flex;\n}\n\n.AJn4ya_labels {\n flex-wrap: wrap;\n align-items: center;\n gap: 7px;\n min-width: 0;\n display: flex;\n}\n\n.AJn4ya_actions {\n flex: none;\n align-items: center;\n gap: 8px;\n margin-left: auto;\n display: flex;\n}\n\n.AJn4ya_echo {\n color: var(--dsw-alias-label-primary);\n overflow-wrap: anywhere;\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n}\n\n.AJn4ya_echoSuccess {\n color: var(--dsw-alias-state-success-primary);\n}\n\n.AJn4ya_reason {\n color: var(--dsw-alias-label-primary);\n overflow-wrap: anywhere;\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n}\n\n.AJn4ya_diagnostic {\n flex-direction: column;\n gap: 2px;\n padding: 2px 0 2px 22px;\n display: flex;\n}\n\n.AJn4ya_diagnosticLine {\n color: var(--dsw-alias-label-tertiary);\n overflow-wrap: anywhere;\n margin: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n line-height: 16px;\n}\n\n.AJn4ya_mono {\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n margin: 0;\n font: 12px / 18px ui-monospace, Menlo, Consolas, monospace;\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._3f22mq_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._3f22mq_toolbar {\n flex: none;\n}\n\n@media (width <= 760px) {\n ._3f22mq_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n._3f22mq_empty, ._3f22mq_detailEmpty {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-align: center;\n padding: 24px;\n font-size: 12px;\n}\n\n._3f22mq_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._3f22mq_detailBody {\n max-height: 72vh;\n overflow-y: auto;\n}\n\n._3f22mq_modalFooter {\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n width: 100%;\n display: flex;\n}\n\n._3f22mq_modalFooterHint {\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n}\n\n._3f22mq_modalFooterGrow {\n flex: auto;\n}\n\n._3f22mq_detail {\n flex-direction: column;\n gap: 16px;\n display: flex;\n}\n\n._3f22mq_reauthConfirm {\n flex-direction: column;\n gap: 8px;\n margin-top: 10px;\n display: flex;\n}\n\n._3f22mq_reauthExplain {\n color: var(--dsw-alias-label-secondary, #4e5969);\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n}\n\n._3f22mq_reauthActions {\n justify-content: flex-end;\n gap: 8px;\n display: flex;\n}\n\n._3f22mq_blockHeadRow {\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n display: flex;\n}\n\n._3f22mq_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._3f22mq_toolSearch {\n flex: 0 220px;\n min-width: 0;\n display: block;\n}\n\n._3f22mq_toolList {\n flex-direction: column;\n display: flex;\n}\n\n._3f22mq_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._3f22mq_tool:last-child {\n border-bottom: none;\n}\n\n._3f22mq_toolIdentity {\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n._3f22mq_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._3f22mq_toolDescription, ._3f22mq_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._3f22mq_toolNameButton {\n cursor: pointer;\n text-align: left;\n background: none;\n border: none;\n padding: 0;\n}\n\n._3f22mq_toolNameButton:hover {\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n._3f22mq_toolParams {\n grid-column: 1 / -1;\n padding: 8px 0 2px 11px;\n}\n\n._3f22mq_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._3f22mq_toolParam {\n display: contents;\n}\n\n._3f22mq_toolParamName {\n color: var(--dsw-alias-label-primary, #1f2328);\n font: 11px / 16px ui-monospace, Menlo, Consolas, monospace;\n}\n\n._3f22mq_toolParamType {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font: 10px / 16px ui-monospace, Menlo, Consolas, monospace;\n}\n\n._3f22mq_toolParamRequired {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n font-size: 10px;\n line-height: 16px;\n}\n\n._3f22mq_toolParamDesc {\n overflow-wrap: anywhere;\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 10px;\n line-height: 16px;\n}\n\n._3f22mq_toolParamsEmpty {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n margin: 0;\n font-size: 10px;\n line-height: 16px;\n}\n\n._3f22mq_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._3f22mq_toolMore:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n@media (width <= 760px) {\n ._3f22mq_toolbar {\n padding-left: 0;\n padding-right: 0;\n }\n\n ._3f22mq_grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n ._3f22mq_list ._3f22mq_cardTop {\n max-width: 100%;\n }\n\n ._3f22mq_tool {\n grid-template-columns: minmax(0, 1fr);\n }\n\n ._3f22mq_toolDescription {\n display: none;\n }\n}\n\n@keyframes _3f22mq_lspStartingPulse {\n 50% {\n opacity: .35;\n }\n}\n\n._3f22mq_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._3f22mq_seamTitle {\n color: var(--dsw-alias-label-primary, #1f2329);\n font-size: 13px;\n font-weight: 600;\n}\n\n._3f22mq_seamBody {\n color: var(--dsw-alias-label-secondary, #4e5969);\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n}\n\n._3f22mq_seamPathLabel {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 11px;\n}\n\n._3f22mq_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._3f22mq_seamOther {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n margin: 0;\n font-size: 11px;\n line-height: 16px;\n}\n\n._3f22mq_seamDone {\n color: var(--dsw-alias-state-success-primary, #15803d);\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n}\n.r5yctG_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.r5yctG_pageMode {\n box-sizing: border-box;\n padding: 4px 0;\n}\n\n.r5yctG_tabRow {\n scrollbar-width: none;\n flex: none;\n min-width: 0;\n overflow-x: auto;\n}\n\n.r5yctG_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;
@@ -263,19 +263,6 @@ function ActiveOverlay$1({ target, t, visible, slow }) {
263
263
  */
264
264
  /** Settings namespace this plugin registers; the key the plugin-config tab pairs our card by. */
265
265
  const MARKET_SETTINGS_NAMESPACE = "dsh-agent-plugins-market";
266
- /**
267
- * The default of every market setting — the single place one is written.
268
- *
269
- * These are user-visible behavior: a flip here is a behavior change that ships
270
- * with its documentation, not a private implementation detail.
271
- */
272
- const MARKET_SETTINGS_DEFAULTS = {
273
- mcpEnhanced: true,
274
- scanProjectLayouts: false,
275
- downloadRegion: "auto",
276
- feedbackEnabled: true,
277
- autoUpdateSources: false
278
- };
279
266
  //#endregion
280
267
  //#region src/client/request-error.ts
281
268
  /**
@@ -303,7 +290,6 @@ const MARKET_ROUTES = {
303
290
  overview: `${MARKET_API_PREFIX}overview`,
304
291
  mcpStatus: `${MARKET_API_PREFIX}mcp-status`,
305
292
  addMcpServer: `${MARKET_API_PREFIX}mcp-servers/add`,
306
- importMcpServers: `${MARKET_API_PREFIX}mcp-servers/import`,
307
293
  lspStatus: `${MARKET_API_PREFIX}lsp-status`,
308
294
  lspServers: `${MARKET_API_PREFIX}lsp-servers`,
309
295
  addLspServer: `${MARKET_API_PREFIX}lsp-servers/add`,
@@ -497,26 +483,6 @@ async function addMcpServer(name, config) {
497
483
  });
498
484
  });
499
485
  }
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
- }
520
486
  /** Drop one server's OAuth grant so its next mount re-runs browser authorization. */
521
487
  async function reauthorizeMcpServer(serverName) {
522
488
  return withBusyOperation(async () => {
@@ -609,6 +575,7 @@ async function deleteUserPanelEntry(kind, name) {
609
575
  }
610
576
  //#endregion
611
577
  //#region src/client/locales.ts
578
+ /** zh/en dictionaries for the Agent Plugins Market section. */
612
579
  /** Chinese is the source-of-truth key set; English is checked against it below. */
613
580
  const zh = {
614
581
  nav: "Agent Plugins 市场",
@@ -619,6 +586,9 @@ const zh = {
619
586
  lspEditTitle: "编辑 LSP 服务",
620
587
  detailMarkdown: "编辑 Markdown",
621
588
  detailMetadata: "元数据",
589
+ detailModelLabel: "模型",
590
+ detailProviderLabel: "提供方",
591
+ detailReasoningLabel: "思考强度",
622
592
  detailForm: "表单",
623
593
  detailJson: "JSON",
624
594
  detailJsonConfig: "JSON 配置",
@@ -674,8 +644,6 @@ const zh = {
674
644
  sourceUrlEgArchive: "https://example.com/plugin.zip",
675
645
  branchPh: "分支(可选)",
676
646
  branchEg: "main",
677
- sourceLocal: "本地",
678
- sourceArchive: "压缩包",
679
647
  sha256Ph: "SHA-256(可选,64 位十六进制)",
680
648
  unmanagedTitle: "检测到未登记的本地仓库:",
681
649
  unmanagedAdopt: "收编为源(只登记,不克隆不删除)",
@@ -726,6 +694,7 @@ const zh = {
726
694
  editorCreate: "创建",
727
695
  editorFooterCreate: "创建后立即生效,可在列表里停用",
728
696
  editorFooterEdit: "未保存的改动会在关闭时丢失",
697
+ editorFooterRouting: "仅调整模型路由;角色内容由所属套件管理",
729
698
  panelSkillTextLabel: "文档",
730
699
  panelCommandTextLabel: "命令正文",
731
700
  panelPersonaTextLabel: "系统提示词",
@@ -809,7 +778,7 @@ const zh = {
809
778
  mcpOrphaned: "来源缺失",
810
779
  mcpForeign: "外部挂载",
811
780
  mcpServerKeyLabel: "服务键",
812
- mcpEnabledLabel: "启用此服务",
781
+ mcpMountNameLabel: "挂载名",
813
782
  mcpSearch: "搜索 MCP 名称、来源或地址…",
814
783
  mcpAll: "全部",
815
784
  mcpPlugin: "插件",
@@ -822,18 +791,6 @@ const zh = {
822
791
  mcpToolParamRequired: "必填",
823
792
  mcpToolNoParameters: "这个工具不需要参数",
824
793
  mcpTool: "工具",
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 端点,而不是普通网页。",
837
794
  mcpRetrySuccess: "重连成功,服务已恢复",
838
795
  mcpReauthorize: "重新授权",
839
796
  mcpClose: "关闭",
@@ -843,8 +800,7 @@ const zh = {
843
800
  mcpConfirmReauth: "清除授权并重新连接",
844
801
  mcpOauthDefault: "授权默认开启",
845
802
  mcpSaveFirst: "请先保存配置,再执行连接操作;连接操作只使用已保存的配置。",
846
- mcpStillUnavailable: "操作已执行,但当前尚未确认服务已连接,请检查连接状态和错误原因",
847
- mcpConfigureCredentialsFirst: "请先在凭据配置中填写缺失的凭据;重试连接不会自动补齐凭据。",
803
+ mcpStillUnavailable: "操作已执行,但服务仍未连接成功。",
848
804
  mcpSavedStatusUnknown: "配置已保存,但无法刷新连接状态",
849
805
  mcpEntryGone: "服务已不在当前列表中,请关闭详情并刷新",
850
806
  marketCardDesc: "管理套件来源、安装与运行时开关。",
@@ -856,15 +812,17 @@ const zh = {
856
812
  regionLabel: "下载线路",
857
813
  regionHint: "中国大陆走镜像线路,仅影响下载。",
858
814
  regionAuto: "跟随界面语言",
815
+ regionResolved: "→ {region}",
859
816
  regionGlobal: "全球",
860
817
  regionChina: "中国大陆",
861
818
  settingOverridden: "已自定义",
862
819
  settingReset: "恢复默认",
863
- settingUnsaved: "未保存",
864
820
  settingSave: "保存",
865
821
  settingSaving: "保存中…",
866
822
  settingDiscard: "放弃修改",
867
823
  settingSaveFailed: "保存未生效,请重试。",
824
+ settingUnavailable: "此插件设置在当前环境不可用。",
825
+ settingInvalid: "草稿中包含此字段不接受的内容,无法保存。",
868
826
  mcpBackendHostMissing: "宿主 dsh-mcp-client 在当前环境不可用,无法切换到兼容模式。",
869
827
  mcpZeroTools: "该服务已连接,但未声明任何工具。",
870
828
  mcpCredentialTitle: "凭据配置",
@@ -880,24 +838,10 @@ const zh = {
880
838
  mcpServiceDetail: "服务详情",
881
839
  mcpEmpty: "没有匹配的 MCP 服务",
882
840
  mcpNoTools: "当前没有已注册工具",
841
+ mcpToolsUnreachable: "服务未连接,暂时读不到工具清单",
883
842
  mcpDirectBoundary: "用户 MCP 仅显示当前工具表中可观测的服务;宿主未提供配置与连接状态 API。",
884
843
  mcpAddTitle: "新建 MCP 服务",
885
844
  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",
901
845
  mcpServerName: "服务名称",
902
846
  mcpRetry: "重试",
903
847
  mcpAdvanced: "高级设置",
@@ -929,7 +873,6 @@ const zh = {
929
873
  lspHostMissingShort: "LSP 组件缺失",
930
874
  lspConflict: "接缝冲突",
931
875
  lspEmpty: "没有已声明的 LSP 服务器",
932
- lspReasonLabel: "原因",
933
876
  lspDeclaredInLabel: "声明文件",
934
877
  serviceConfigLabel: "服务配置",
935
878
  lspFilterAllHint: "全部:套件声明与用户自配的全部语言服务器",
@@ -980,6 +923,27 @@ const zh = {
980
923
  panelSearchLabel: "搜索条目…",
981
924
  panelFilterAll: "全部",
982
925
  panelFilterDisabled: "已禁用",
926
+ failureDetailToggle: "诊断详情",
927
+ failureGuideCredentials: "缺少凭据:在凭据配置中填入后重试;重试连接不会自动补齐凭据。",
928
+ failureGuideAuth: "服务要求授权:确认 token 仍然有效,或重新授权。",
929
+ failureGuideTransport: "这种传输方式不受支持:改用 stdio 或 Streamable HTTP。",
930
+ failureGuideBackend: "当前后端无法执行这项配置:把 MCP 后端切回内置客户端。",
931
+ failureGuideBackendMissing: "宿主兼容模式需要的 dsh-mcp-client 没有安装:把 MCP 后端切回内置客户端。",
932
+ failureGuideMissingPackage: "当前 profile 缺少本插件需要的组件:重新安装本插件补齐依赖。",
933
+ failureGuideHostUnsupported: "当前宿主不支持动态挂载插件:确认宿主版本与启动方式后重试。",
934
+ failureGuideSeamConflict: "这条接缝已被其他层注册:移除手工添加的那一层,再重试。",
935
+ failureGuideDns: "域名解析失败:检查地址拼写、代理与网络。",
936
+ failureGuideTls: "TLS 握手失败:确认证书有效,服务可能要求专线或来源 IP 白名单。",
937
+ failureGuideRefused: "连接被拒绝:确认服务已启动,端口与路径正确。",
938
+ failureGuideTimeout: "连接超时:确认服务可达;本地服务可以调高启动超时。",
939
+ failureGuideCommandMissing: "找不到命令:确认它在 PATH 中,或改用绝对路径。",
940
+ failureGuideProcessExit: "进程提前退出:检查命令、参数与运行环境。",
941
+ failureGuideProtocol: "协议握手失败:确认远程地址指向正确的服务端点,本地命令能独立启动。",
942
+ failureGuideStartup: "服务没有完成初始化:先在终端手动运行启动命令,确认依赖齐全、参数正确,必要时调高启动超时。",
943
+ failureGuideUnmount: "卸载没有完成:宿主里可能还留着旧进程,重启宿主后再试。",
944
+ failureGuideOrphanedTools: "声明它的套件已停用或卸载,工具却仍在注册表中:重启宿主即可清除。",
945
+ failureGuideDisabledOverride: "已在配置覆写中停用这个服务。",
946
+ failureGuideModifiedOverride: "配置覆写改动了这个服务,实际运行的不是套件声明的原始配置。",
983
947
  panelAdd: "新增",
984
948
  panelEdit: "编辑",
985
949
  panelAddSkillTitle: "新建技能",
@@ -1026,6 +990,9 @@ const en = {
1026
990
  lspEditTitle: "Edit LSP server",
1027
991
  detailMarkdown: "Edit Markdown",
1028
992
  detailMetadata: "Metadata",
993
+ detailModelLabel: "Model",
994
+ detailProviderLabel: "Provider",
995
+ detailReasoningLabel: "Reasoning effort",
1029
996
  detailForm: "Form",
1030
997
  detailJson: "JSON",
1031
998
  detailJsonConfig: "JSON configuration",
@@ -1081,8 +1048,6 @@ const en = {
1081
1048
  sourceUrlEgArchive: "https://example.com/plugin.zip",
1082
1049
  branchPh: "branch (optional)",
1083
1050
  branchEg: "main",
1084
- sourceLocal: "local",
1085
- sourceArchive: "archive",
1086
1051
  sha256Ph: "SHA-256 (optional, 64 hex chars)",
1087
1052
  unmanagedTitle: "Unregistered local checkouts found:",
1088
1053
  unmanagedAdopt: "Adopt as a source (register only — no clone, no deletion)",
@@ -1133,6 +1098,7 @@ const en = {
1133
1098
  editorCreate: "Create",
1134
1099
  editorFooterCreate: "Takes effect as soon as it is created; switch it off from the list.",
1135
1100
  editorFooterEdit: "Unsaved changes are lost when this closes",
1101
+ editorFooterRouting: "Adjusts model routing only; the suite manages role content",
1136
1102
  panelSkillTextLabel: "Document",
1137
1103
  panelCommandTextLabel: "Command body",
1138
1104
  panelPersonaTextLabel: "System prompt",
@@ -1216,7 +1182,7 @@ const en = {
1216
1182
  mcpOrphaned: "Source missing",
1217
1183
  mcpForeign: "Mounted elsewhere",
1218
1184
  mcpServerKeyLabel: "Server key",
1219
- mcpEnabledLabel: "Enable this service",
1185
+ mcpMountNameLabel: "Mount name",
1220
1186
  mcpSearch: "Search MCP names, sources, or endpoints…",
1221
1187
  mcpAll: "All",
1222
1188
  mcpPlugin: "Plugin",
@@ -1229,18 +1195,6 @@ const en = {
1229
1195
  mcpToolParamRequired: "required",
1230
1196
  mcpToolNoParameters: "This tool takes no parameters",
1231
1197
  mcpTool: "tool",
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.",
1244
1198
  mcpRetrySuccess: "Reconnected — the service is live again",
1245
1199
  mcpReauthorize: "Re-authorize",
1246
1200
  mcpClose: "Close",
@@ -1250,8 +1204,7 @@ const en = {
1250
1204
  mcpConfirmReauth: "Clear authorization and reconnect",
1251
1205
  mcpOauthDefault: "OAuth on by default",
1252
1206
  mcpSaveFirst: "Save configuration before connection actions; they use saved configuration only.",
1253
- mcpStillUnavailable: "The operation finished, but the service is not confirmed connected. Check its status and error details",
1254
- mcpConfigureCredentialsFirst: "Configure the missing credentials first. Retrying cannot supply them automatically.",
1207
+ mcpStillUnavailable: "The operation finished, but the service is still not connected.",
1255
1208
  mcpSavedStatusUnknown: "Configuration saved, but connection status could not be refreshed",
1256
1209
  mcpEntryGone: "This service is no longer listed. Close the details and refresh.",
1257
1210
  marketCardDesc: "Manage suite sources, installs, and runtime switches.",
@@ -1263,15 +1216,17 @@ const en = {
1263
1216
  regionLabel: "Download route",
1264
1217
  regionHint: "China mainland uses a mirror. Affects downloads only.",
1265
1218
  regionAuto: "Follow interface language",
1219
+ regionResolved: "→ {region}",
1266
1220
  regionGlobal: "Global",
1267
1221
  regionChina: "China mainland",
1268
1222
  settingOverridden: "customized",
1269
1223
  settingReset: "Use default",
1270
- settingUnsaved: "Unsaved",
1271
1224
  settingSave: "Save",
1272
1225
  settingSaving: "Saving…",
1273
1226
  settingDiscard: "Discard",
1274
1227
  settingSaveFailed: "The save did not take effect. Try again.",
1228
+ settingUnavailable: "This plugin's settings are not available in this environment.",
1229
+ settingInvalid: "A draft holds something this field does not accept, so it cannot save.",
1275
1230
  mcpBackendHostMissing: "The host dsh-mcp-client is not available here; compat mode cannot be enabled.",
1276
1231
  mcpZeroTools: "Connected, but this service advertises no tools.",
1277
1232
  mcpCredentialTitle: "Credential configuration",
@@ -1287,24 +1242,10 @@ const en = {
1287
1242
  mcpServiceDetail: "Service detail",
1288
1243
  mcpEmpty: "No matching MCP services",
1289
1244
  mcpNoTools: "No registered tools",
1245
+ mcpToolsUnreachable: "The service is not connected, so its tool list cannot be read yet",
1290
1246
  mcpDirectBoundary: "User MCP entries only show services observed in the current tool registry; the host exposes no config or connection-status API.",
1291
1247
  mcpAddTitle: "New MCP service",
1292
1248
  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",
1308
1249
  mcpServerName: "Server name",
1309
1250
  mcpRetry: "Retry",
1310
1251
  mcpAdvanced: "Advanced settings",
@@ -1336,7 +1277,6 @@ const en = {
1336
1277
  lspHostMissingShort: "LSP components missing",
1337
1278
  lspConflict: "Seam conflict",
1338
1279
  lspEmpty: "No declared LSP servers",
1339
- lspReasonLabel: "Reason",
1340
1280
  lspDeclaredInLabel: "Declared in",
1341
1281
  serviceConfigLabel: "Service config",
1342
1282
  lspFilterAllHint: "All: suite-declared and user-configured language servers",
@@ -1387,6 +1327,27 @@ const en = {
1387
1327
  panelSearchLabel: "Search entries…",
1388
1328
  panelFilterAll: "All",
1389
1329
  panelFilterDisabled: "Disabled",
1330
+ failureDetailToggle: "Diagnostic details",
1331
+ failureGuideCredentials: "Missing credential: fill it in the credentials area, then retry; retrying cannot supply it.",
1332
+ failureGuideAuth: "The service asks for authorization: check that the token is still valid, or authorize again.",
1333
+ failureGuideTransport: "That transport is not supported: use stdio or Streamable HTTP.",
1334
+ failureGuideBackend: "This backend cannot enforce that setting: switch the MCP backend back to the built-in client.",
1335
+ failureGuideBackendMissing: "Host compatibility mode needs dsh-mcp-client, which is not installed: switch the MCP backend back to the built-in client.",
1336
+ failureGuideMissingPackage: "This profile is missing a component the plugin needs: reinstall the plugin to provision its dependencies.",
1337
+ failureGuideHostUnsupported: "This host does not support mounting plugins at runtime: check the host version and how it was started, then retry.",
1338
+ failureGuideSeamConflict: "Another layer already registers this seam: remove the hand-added layer, then retry.",
1339
+ failureGuideDns: "Name resolution failed: check the address, the proxy and the network.",
1340
+ failureGuideTls: "TLS handshake failed: check the certificate; the service may require a VPN or an IP allow-list.",
1341
+ failureGuideRefused: "Connection refused: check that the service is running, and that the port and path are right.",
1342
+ failureGuideTimeout: "Connection timed out: check that the service is reachable; a local server can raise its startup timeout.",
1343
+ failureGuideCommandMissing: "Command not found: check that it is on PATH, or use an absolute path.",
1344
+ failureGuideProcessExit: "The process exited early: check the command, its arguments and its environment.",
1345
+ failureGuideProtocol: "The protocol handshake failed: check that a remote address points at the right endpoint, and that a local command runs on its own.",
1346
+ failureGuideStartup: "The service did not finish starting: run its command by hand first to check that its dependencies are installed and its arguments are right, and raise the startup timeout if it needs longer.",
1347
+ failureGuideUnmount: "Unmounting did not finish: the host may still hold the old process; restart the host and try again.",
1348
+ failureGuideOrphanedTools: "The suite that declared it is off or uninstalled, but its tools are still registered: restart the host to clear them.",
1349
+ failureGuideDisabledOverride: "This service is switched off in the configuration override.",
1350
+ failureGuideModifiedOverride: "A configuration override changed this service; what runs is not the suite’s own declaration.",
1390
1351
  panelAdd: "Add",
1391
1352
  panelEdit: "Edit",
1392
1353
  panelAddSkillTitle: "New skill",
@@ -1532,85 +1493,81 @@ function searchableFor$1(overview) {
1532
1493
  return searchable;
1533
1494
  }
1534
1495
  //#endregion
1535
- //#region src/client/market.module.css
1496
+ //#region src/client/features/market/market.module.css
1536
1497
  var market_module_default = {
1537
- "card": "_72qoAq_card",
1538
- "cardActions": "_72qoAq_cardActions",
1539
- "cardTop": "_72qoAq_cardTop",
1540
- "confirmCheck": "_72qoAq_confirmCheck",
1541
- "detailItemOpen": "_72qoAq_detailItemOpen",
1542
- "detailItemRow": "_72qoAq_detailItemRow",
1543
- "dshApmSpin": "_72qoAq_dshApmSpin",
1544
- "editorDialog": "_72qoAq_editorDialog",
1545
- "empty": "_72qoAq_empty",
1546
- "grid": "_72qoAq_grid",
1547
- "header": "_72qoAq_header",
1548
- "installConfirmBody": "_72qoAq_installConfirmBody",
1549
- "installConfirmCommit": "_72qoAq_installConfirmCommit",
1550
- "installConfirmMeta": "_72qoAq_installConfirmMeta",
1551
- "installConfirmSuite": "_72qoAq_installConfirmSuite",
1552
- "installConfirmTags": "_72qoAq_installConfirmTags",
1553
- "installConfirmWarn": "_72qoAq_installConfirmWarn",
1554
- "list": "_72qoAq_list",
1555
- "market": "_72qoAq_market",
1556
- "market-config": "_72qoAq_market-config",
1557
- "marketControls": "_72qoAq_marketControls",
1558
- "meta": "_72qoAq_meta",
1559
- "modalFooter": "_72qoAq_modalFooter",
1560
- "modalFooterLeft": "_72qoAq_modalFooterLeft",
1561
- "pageEntry": "_72qoAq_pageEntry",
1562
- "pageMode": "_72qoAq_pageMode",
1563
- "pageView": "_72qoAq_pageView",
1564
- "pluginCard": "_72qoAq_pluginCard",
1565
- "pluginCardBody": "_72qoAq_pluginCardBody",
1566
- "pluginCardDesc": "_72qoAq_pluginCardDesc",
1567
- "pluginCardDiscard": "_72qoAq_pluginCardDiscard",
1568
- "pluginCardError": "_72qoAq_pluginCardError",
1569
- "pluginCardFooter": "_72qoAq_pluginCardFooter",
1570
- "pluginCardHeader": "_72qoAq_pluginCardHeader",
1571
- "pluginCardOpen": "_72qoAq_pluginCardOpen",
1572
- "pluginCardReadonly": "_72qoAq_pluginCardReadonly",
1573
- "pluginCardRow": "_72qoAq_pluginCardRow",
1574
- "pluginCardRowLabel": "_72qoAq_pluginCardRowLabel",
1575
- "pluginCardSave": "_72qoAq_pluginCardSave",
1576
- "pluginCardText": "_72qoAq_pluginCardText",
1577
- "pluginCardTitle": "_72qoAq_pluginCardTitle",
1578
- "pluginChevron": "_72qoAq_pluginChevron",
1579
- "pluginChevronOpen": "_72qoAq_pluginChevronOpen",
1580
- "pluginFieldBadges": "_72qoAq_pluginFieldBadges",
1581
- "pluginFieldHead": "_72qoAq_pluginFieldHead",
1582
- "pluginFieldReset": "_72qoAq_pluginFieldReset",
1583
- "progress": "_72qoAq_progress",
1584
- "progressError": "_72qoAq_progressError",
1585
- "progressFail": "_72qoAq_progressFail",
1586
- "progressSpin": "_72qoAq_progressSpin",
1587
- "progressText": "_72qoAq_progressText",
1588
- "regionSeg": "_72qoAq_regionSeg",
1589
- "regionSegBtn": "_72qoAq_regionSegBtn",
1590
- "regionSegEffective": "_72qoAq_regionSegEffective",
1591
- "regionSegOn": "_72qoAq_regionSegOn",
1592
- "sourceTabsBox": "_72qoAq_sourceTabsBox",
1593
- "sourceTabsBoxFold": "_72qoAq_sourceTabsBoxFold",
1594
- "sourceTabsBoxPicked": "_72qoAq_sourceTabsBoxPicked",
1595
- "sourceTabsRow": "_72qoAq_sourceTabsRow",
1596
- "srcTab": "_72qoAq_srcTab",
1597
- "srcTabDel": "_72qoAq_srcTabDel",
1598
- "srcTabEdit": "_72qoAq_srcTabEdit",
1599
- "srcTabMain": "_72qoAq_srcTabMain",
1600
- "srcTabOn": "_72qoAq_srcTabOn",
1601
- "surfaceToggle": "_72qoAq_surfaceToggle",
1602
- "surfaceToggles": "_72qoAq_surfaceToggles",
1603
- "switchOff": "_72qoAq_switchOff",
1604
- "switchOn": "_72qoAq_switchOn",
1605
- "switchThumb": "_72qoAq_switchThumb",
1606
- "tag": "_72qoAq_tag",
1607
- "tagRow": "_72qoAq_tagRow",
1608
- "unmanagedAdopt": "_72qoAq_unmanagedAdopt",
1609
- "unmanagedChip": "_72qoAq_unmanagedChip",
1610
- "unmanagedChipName": "_72qoAq_unmanagedChipName",
1611
- "unmanagedLabel": "_72qoAq_unmanagedLabel",
1612
- "unmanagedRow": "_72qoAq_unmanagedRow",
1613
- "warnLine": "_72qoAq_warnLine"
1498
+ "card": "U-hjqq_card",
1499
+ "cardActions": "U-hjqq_cardActions",
1500
+ "cardTop": "U-hjqq_cardTop",
1501
+ "confirmCheck": "U-hjqq_confirmCheck",
1502
+ "detailItemOpen": "U-hjqq_detailItemOpen",
1503
+ "detailItemRow": "U-hjqq_detailItemRow",
1504
+ "dshApmSpin": "U-hjqq_dshApmSpin",
1505
+ "editorDialog": "U-hjqq_editorDialog",
1506
+ "empty": "U-hjqq_empty",
1507
+ "grid": "U-hjqq_grid",
1508
+ "header": "U-hjqq_header",
1509
+ "installConfirmBody": "U-hjqq_installConfirmBody",
1510
+ "installConfirmCommit": "U-hjqq_installConfirmCommit",
1511
+ "installConfirmMeta": "U-hjqq_installConfirmMeta",
1512
+ "installConfirmSuite": "U-hjqq_installConfirmSuite",
1513
+ "installConfirmTags": "U-hjqq_installConfirmTags",
1514
+ "installConfirmWarn": "U-hjqq_installConfirmWarn",
1515
+ "list": "U-hjqq_list",
1516
+ "market": "U-hjqq_market",
1517
+ "market-config": "U-hjqq_market-config",
1518
+ "marketControls": "U-hjqq_marketControls",
1519
+ "meta": "U-hjqq_meta",
1520
+ "modalFooter": "U-hjqq_modalFooter",
1521
+ "modalFooterLeft": "U-hjqq_modalFooterLeft",
1522
+ "pageEntry": "U-hjqq_pageEntry",
1523
+ "pageMode": "U-hjqq_pageMode",
1524
+ "pageView": "U-hjqq_pageView",
1525
+ "pluginCard": "U-hjqq_pluginCard",
1526
+ "pluginCardBody": "U-hjqq_pluginCardBody",
1527
+ "pluginCardDesc": "U-hjqq_pluginCardDesc",
1528
+ "pluginCardDiscard": "U-hjqq_pluginCardDiscard",
1529
+ "pluginCardError": "U-hjqq_pluginCardError",
1530
+ "pluginCardFooter": "U-hjqq_pluginCardFooter",
1531
+ "pluginCardHeader": "U-hjqq_pluginCardHeader",
1532
+ "pluginCardOpen": "U-hjqq_pluginCardOpen",
1533
+ "pluginCardReadonly": "U-hjqq_pluginCardReadonly",
1534
+ "pluginCardRow": "U-hjqq_pluginCardRow",
1535
+ "pluginCardRowLabel": "U-hjqq_pluginCardRowLabel",
1536
+ "pluginCardText": "U-hjqq_pluginCardText",
1537
+ "pluginCardTitle": "U-hjqq_pluginCardTitle",
1538
+ "pluginChevron": "U-hjqq_pluginChevron",
1539
+ "pluginChevronOpen": "U-hjqq_pluginChevronOpen",
1540
+ "pluginFieldBadges": "U-hjqq_pluginFieldBadges",
1541
+ "pluginFieldHead": "U-hjqq_pluginFieldHead",
1542
+ "pluginFieldReset": "U-hjqq_pluginFieldReset",
1543
+ "progress": "U-hjqq_progress",
1544
+ "progressError": "U-hjqq_progressError",
1545
+ "progressFail": "U-hjqq_progressFail",
1546
+ "progressSpin": "U-hjqq_progressSpin",
1547
+ "progressText": "U-hjqq_progressText",
1548
+ "sourceTabsBox": "U-hjqq_sourceTabsBox",
1549
+ "sourceTabsBoxFold": "U-hjqq_sourceTabsBoxFold",
1550
+ "sourceTabsBoxPicked": "U-hjqq_sourceTabsBoxPicked",
1551
+ "sourceTabsRow": "U-hjqq_sourceTabsRow",
1552
+ "srcTab": "U-hjqq_srcTab",
1553
+ "srcTabControls": "U-hjqq_srcTabControls",
1554
+ "srcTabDel": "U-hjqq_srcTabDel",
1555
+ "srcTabEdit": "U-hjqq_srcTabEdit",
1556
+ "srcTabMain": "U-hjqq_srcTabMain",
1557
+ "srcTabOn": "U-hjqq_srcTabOn",
1558
+ "surfaceToggle": "U-hjqq_surfaceToggle",
1559
+ "surfaceToggles": "U-hjqq_surfaceToggles",
1560
+ "switchOff": "U-hjqq_switchOff",
1561
+ "switchOn": "U-hjqq_switchOn",
1562
+ "switchThumb": "U-hjqq_switchThumb",
1563
+ "tag": "U-hjqq_tag",
1564
+ "tagRow": "U-hjqq_tagRow",
1565
+ "unmanagedAdopt": "U-hjqq_unmanagedAdopt",
1566
+ "unmanagedChip": "U-hjqq_unmanagedChip",
1567
+ "unmanagedChipName": "U-hjqq_unmanagedChipName",
1568
+ "unmanagedLabel": "U-hjqq_unmanagedLabel",
1569
+ "unmanagedRow": "U-hjqq_unmanagedRow",
1570
+ "warnLine": "U-hjqq_warnLine"
1614
1571
  };
1615
1572
  //#endregion
1616
1573
  //#region src/client/features/market/SourceTab.tsx
@@ -1625,7 +1582,7 @@ function SourceTab(props) {
1625
1582
  type: "button",
1626
1583
  className: market_module_default.srcTabMain,
1627
1584
  onClick: onSelect
1628
- }, label), onEdit === void 0 ? null : (0, react.createElement)("button", {
1585
+ }, label), onEdit === void 0 && onDelete === void 0 ? null : (0, react.createElement)("span", { className: market_module_default.srcTabControls }, onEdit === void 0 ? null : (0, react.createElement)("button", {
1629
1586
  type: "button",
1630
1587
  className: market_module_default.srcTabEdit,
1631
1588
  title: t("editSource"),
@@ -1641,7 +1598,7 @@ function SourceTab(props) {
1641
1598
  event.stopPropagation();
1642
1599
  onDelete();
1643
1600
  }
1644
- }, "×"));
1601
+ }, "×")));
1645
1602
  }
1646
1603
  //#endregion
1647
1604
  //#region src/client/features/market/SourceTabsRow.tsx
@@ -1931,12 +1888,26 @@ function ResourceCard({ state, surface, className, children, ...props }) {
1931
1888
  }, children);
1932
1889
  }
1933
1890
  /** A shared, shrinkable scroll area: grid and list never stretch individual cards vertically. */
1934
- function ResourceCollection({ view, className, children }) {
1891
+ function ResourceCollection({ view, className, children, ...rest }) {
1935
1892
  return (0, react.createElement)("div", {
1936
1893
  className: `${className ?? ""} ${resource_card_module_default.collection}`,
1937
- "data-resource-view": view
1894
+ "data-resource-view": view,
1895
+ ...rest
1938
1896
  }, children);
1939
1897
  }
1898
+ /** Spread onto a card so it opens like a button: keyboard users included. */
1899
+ function interactiveCardProps(onClick) {
1900
+ return {
1901
+ role: "button",
1902
+ tabIndex: 0,
1903
+ onClick,
1904
+ onKeyDown: (event) => {
1905
+ if (event.key !== "Enter" && event.key !== " ") return;
1906
+ event.preventDefault();
1907
+ onClick();
1908
+ }
1909
+ };
1910
+ }
1940
1911
  //#endregion
1941
1912
  //#region src/client/features/market/SuiteCard.tsx
1942
1913
  /**
@@ -7836,7 +7807,7 @@ function parseDocument(source, options = {}) {
7836
7807
  return doc;
7837
7808
  }
7838
7809
  //#endregion
7839
- //#region src/client/features/personas/frontmatter.ts
7810
+ //#region src/client/ui/frontmatter.ts
7840
7811
  /** Parse an editable document without flattening nested YAML or discarding comments. */
7841
7812
  function frontmatter(text) {
7842
7813
  const match = /^(?:\uFEFF)?---\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n|$)/.exec(text);
@@ -7952,6 +7923,44 @@ var detail_rows_module_default = {
7952
7923
  "summary": "_9Lujra_summary"
7953
7924
  };
7954
7925
  //#endregion
7926
+ //#region src/client/ui/panel.module.css
7927
+ var panel_module_default = {
7928
+ "block": "HJ9x7a_block",
7929
+ "blockHead": "HJ9x7a_blockHead",
7930
+ "body": "HJ9x7a_body",
7931
+ "busyLabel": "HJ9x7a_busyLabel",
7932
+ "busyLine": "HJ9x7a_busyLine",
7933
+ "confirmCheck": "HJ9x7a_confirmCheck",
7934
+ "detailProse": "HJ9x7a_detailProse",
7935
+ "editorBody": "HJ9x7a_editorBody",
7936
+ "editorDialog": "HJ9x7a_editorDialog",
7937
+ "editorError": "HJ9x7a_editorError",
7938
+ "editorFooter": "HJ9x7a_editorFooter",
7939
+ "empty": "HJ9x7a_empty",
7940
+ "entryActions": "HJ9x7a_entryActions",
7941
+ "entryGrid": "HJ9x7a_entryGrid",
7942
+ "entryMain": "HJ9x7a_entryMain",
7943
+ "entryRow": "HJ9x7a_entryRow",
7944
+ "header": "HJ9x7a_header",
7945
+ "headerActions": "HJ9x7a_headerActions",
7946
+ "headerText": "HJ9x7a_headerText",
7947
+ "hero": "HJ9x7a_hero",
7948
+ "heroLine": "HJ9x7a_heroLine",
7949
+ "heroMono": "HJ9x7a_heroMono",
7950
+ "heroText": "HJ9x7a_heroText",
7951
+ "kvGrid": "HJ9x7a_kvGrid",
7952
+ "kvKey": "HJ9x7a_kvKey",
7953
+ "kvValue": "HJ9x7a_kvValue",
7954
+ "kvValueMono": "HJ9x7a_kvValueMono",
7955
+ "monoBlock": "HJ9x7a_monoBlock",
7956
+ "panel-spin": "HJ9x7a_panel-spin",
7957
+ "shell": "HJ9x7a_shell",
7958
+ "spinner": "HJ9x7a_spinner",
7959
+ "spinning": "HJ9x7a_spinning",
7960
+ "subtitle": "HJ9x7a_subtitle",
7961
+ "title": "HJ9x7a_title"
7962
+ };
7963
+ //#endregion
7955
7964
  //#region src/client/ui/DetailRows.tsx
7956
7965
  /**
7957
7966
  * The one disclosure row the detail dialogs share.
@@ -8000,6 +8009,13 @@ function DetailRow(props) {
8000
8009
  "aria-hidden": true
8001
8010
  }, 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);
8002
8011
  }
8012
+ /** One label/value pair in a detail dialog's overview grid; `key` props a row built in a loop. */
8013
+ function kvCell(label, value, mono = false, key) {
8014
+ return (0, react.createElement)("div", key === void 0 ? null : { key }, (0, react.createElement)("dt", { className: panel_module_default.kvKey }, label), (0, react.createElement)("dd", {
8015
+ className: mono ? `${panel_module_default.kvValue} ${panel_module_default.kvValueMono}` : panel_module_default.kvValue,
8016
+ title: value
8017
+ }, value));
8018
+ }
8003
8019
  //#endregion
8004
8020
  //#region src/client/ui/last-change.ts
8005
8021
  /**
@@ -8054,7 +8070,7 @@ function suiteLayoutLabel(layout, t) {
8054
8070
  return Object.hasOwn(KEYS, layout) ? t(KEYS[layout]) : layout;
8055
8071
  }
8056
8072
  //#endregion
8057
- //#region src/client/features/suite-detail/suite-detail-resource.ts
8073
+ //#region src/client/features/market/suite-detail-resource.ts
8058
8074
  /** Create a request guard for one detail modal instance. */
8059
8075
  function createLatestRequestGuard() {
8060
8076
  let revision = 0;
@@ -8067,44 +8083,6 @@ function createLatestRequestGuard() {
8067
8083
  };
8068
8084
  }
8069
8085
  //#endregion
8070
- //#region src/client/ui/panel.module.css
8071
- var panel_module_default = {
8072
- "block": "HJ9x7a_block",
8073
- "blockHead": "HJ9x7a_blockHead",
8074
- "body": "HJ9x7a_body",
8075
- "busyLabel": "HJ9x7a_busyLabel",
8076
- "busyLine": "HJ9x7a_busyLine",
8077
- "confirmCheck": "HJ9x7a_confirmCheck",
8078
- "detailProse": "HJ9x7a_detailProse",
8079
- "editorBody": "HJ9x7a_editorBody",
8080
- "editorDialog": "HJ9x7a_editorDialog",
8081
- "editorError": "HJ9x7a_editorError",
8082
- "editorFooter": "HJ9x7a_editorFooter",
8083
- "empty": "HJ9x7a_empty",
8084
- "entryActions": "HJ9x7a_entryActions",
8085
- "entryGrid": "HJ9x7a_entryGrid",
8086
- "entryMain": "HJ9x7a_entryMain",
8087
- "entryRow": "HJ9x7a_entryRow",
8088
- "header": "HJ9x7a_header",
8089
- "headerActions": "HJ9x7a_headerActions",
8090
- "headerText": "HJ9x7a_headerText",
8091
- "hero": "HJ9x7a_hero",
8092
- "heroLine": "HJ9x7a_heroLine",
8093
- "heroMono": "HJ9x7a_heroMono",
8094
- "heroText": "HJ9x7a_heroText",
8095
- "kvGrid": "HJ9x7a_kvGrid",
8096
- "kvKey": "HJ9x7a_kvKey",
8097
- "kvValue": "HJ9x7a_kvValue",
8098
- "kvValueMono": "HJ9x7a_kvValueMono",
8099
- "monoBlock": "HJ9x7a_monoBlock",
8100
- "panel-spin": "HJ9x7a_panel-spin",
8101
- "shell": "HJ9x7a_shell",
8102
- "spinner": "HJ9x7a_spinner",
8103
- "spinning": "HJ9x7a_spinning",
8104
- "subtitle": "HJ9x7a_subtitle",
8105
- "title": "HJ9x7a_title"
8106
- };
8107
- //#endregion
8108
8086
  //#region src/client/ui/error-message.ts
8109
8087
  /**
8110
8088
  * One user-facing failure line for every panel.
@@ -8120,7 +8098,7 @@ function clientErrorMessage(t, error) {
8120
8098
  return error instanceof Error ? error.message : String(error);
8121
8099
  }
8122
8100
  //#endregion
8123
- //#region src/client/SuiteDetail.tsx
8101
+ //#region src/client/features/market/SuiteDetail.tsx
8124
8102
  /**
8125
8103
  * Suite detail dialog: click one suite card to browse its internals.
8126
8104
  *
@@ -8220,7 +8198,7 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose, onInstall, onUninstal
8220
8198
  }),
8221
8199
  children: (0, react.createElement)(ErrorBoundary, {
8222
8200
  fallback: (boundaryError) => (0, react.createElement)("div", { className: market_module_default.warnLine }, `${t("actionFail")}: ${boundaryError.message}`),
8223
- children: error !== void 0 ? (0, react.createElement)("div", { className: market_module_default.warnLine }, error) : detail === void 0 ? (0, react.createElement)("div", { className: market_module_default.empty }, t("loading")) : (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: detail.installed ? detail.enabled ? "done" : "idle" : "idle" }), (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: detail.installed ? detail.enabled ? "success" : "neutral" : "neutral" }, statusLabel), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "neutral" }, detail.dimension === "user" ? t("panelSourceUser") : t("panelSourcePlugin")), detail.version === null ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "quiet" }, `v${detail.version}`)), (0, react.createElement)("p", { className: panel_module_default.heroMono }, detail.root))), (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$2(t("sourceLabel"), detail.sourceId, true), kv$2(t("layoutLabel"), layoutLabel), detail.author === null ? null : kv$2(t("authorLabel"), detail.author), updated === null ? null : kv$2(t("updatedLabel"), updated))), detail.description === null ? null : (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("detailDescriptionLabel")), (0, react.createElement)("p", { className: panel_module_default.detailProse }, detail.description)), (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("rootLabel")), (0, react.createElement)("pre", { className: panel_module_default.monoBlock }, detail.root)), detail.installed === false || detail.surfaceToggles === null ? null : (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("surfaceTogglesSection")), (0, react.createElement)("div", {
8201
+ children: error !== void 0 ? (0, react.createElement)("div", { className: market_module_default.warnLine }, error) : detail === void 0 ? (0, react.createElement)("div", { className: market_module_default.empty }, t("loading")) : (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: detail.installed ? detail.enabled ? "done" : "idle" : "idle" }), (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: detail.installed ? detail.enabled ? "success" : "neutral" : "neutral" }, statusLabel), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "neutral" }, detail.dimension === "user" ? t("panelSourceUser") : t("panelSourcePlugin")), detail.version === null ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "quiet" }, `v${detail.version}`)), (0, react.createElement)("p", { className: panel_module_default.heroMono }, detail.root))), (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"), detail.sourceId, true), kvCell(t("layoutLabel"), layoutLabel), detail.author === null ? null : kvCell(t("authorLabel"), detail.author), updated === null ? null : kvCell(t("updatedLabel"), updated))), detail.description === null ? null : (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("detailDescriptionLabel")), (0, react.createElement)("p", { className: panel_module_default.detailProse }, detail.description)), (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("rootLabel")), (0, react.createElement)("pre", { className: panel_module_default.monoBlock }, detail.root)), detail.installed === false || detail.surfaceToggles === null ? null : (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("surfaceTogglesSection")), (0, react.createElement)("div", {
8224
8202
  className: market_module_default.surfaceToggles,
8225
8203
  title: t("surfaceTogglesHint")
8226
8204
  }, ...SURFACE_TOGGLE_ROWS.map(([key, labelKey]) => (0, react.createElement)("label", {
@@ -8269,12 +8247,6 @@ function SuiteDetailModal({ t, sourceId, suiteId, onClose, onInstall, onUninstal
8269
8247
  })
8270
8248
  });
8271
8249
  }
8272
- function kv$2(label, value, mono = false) {
8273
- return (0, react.createElement)("div", null, (0, react.createElement)("dt", { className: panel_module_default.kvKey }, label), (0, react.createElement)("dd", {
8274
- className: mono ? `${panel_module_default.kvValue} ${panel_module_default.kvValueMono}` : panel_module_default.kvValue,
8275
- title: value
8276
- }, value));
8277
- }
8278
8250
  /** One surface group. A surface the suite does not carry is left out entirely. */
8279
8251
  function block(head, count, rows, note) {
8280
8252
  if (count === 0 && rows.length === 0) return null;
@@ -8293,28 +8265,17 @@ function row(current, id, name, description, onToggle, body) {
8293
8265
  });
8294
8266
  }
8295
8267
  function footer(t, detail, actions) {
8296
- if (detail !== void 0 && !detail.installed && actions.onInstall !== void 0) return [(0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8297
- key: "close",
8298
- variant: "ghost",
8299
- onClick: actions.onClose
8300
- }, t("mcpClose")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8268
+ if (detail !== void 0 && !detail.installed && actions.onInstall !== void 0) return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8301
8269
  key: "install",
8302
8270
  variant: "primary",
8303
8271
  onClick: actions.onInstall
8304
- }, t("install"))];
8305
- if (detail !== void 0 && detail.installed && actions.onUninstall !== void 0) return [(0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8272
+ }, t("install"));
8273
+ if (detail !== void 0 && detail.installed && actions.onUninstall !== void 0) return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8306
8274
  key: "uninstall",
8307
8275
  variant: "ghost",
8308
8276
  onClick: actions.onUninstall
8309
- }, t("uninstall")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8310
- key: "done",
8311
- variant: "primary",
8312
- onClick: actions.onClose
8313
- }, t("detailDone"))];
8314
- return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8315
- variant: "ghost",
8316
- onClick: actions.onClose
8317
- }, t("mcpClose"));
8277
+ }, t("uninstall"));
8278
+ return null;
8318
8279
  }
8319
8280
  function mcpSummary(server) {
8320
8281
  if (server.type === "stdio") return server.command ?? server.type;
@@ -8325,23 +8286,23 @@ function lspSummary(server) {
8325
8286
  return [server.command, Object.keys(server.extensions).join(" ")].join(" · ");
8326
8287
  }
8327
8288
  //#endregion
8328
- //#region src/client/SearchFilterToolbar.module.css
8289
+ //#region src/client/ui/SearchFilterToolbar.module.css
8329
8290
  var SearchFilterToolbar_module_default = {
8330
- "count": "vavGuW_count",
8331
- "search": "vavGuW_search",
8332
- "searchInput": "vavGuW_searchInput",
8333
- "segment": "vavGuW_segment",
8334
- "toolbar": "vavGuW_toolbar"
8291
+ "search": "_4JL8qq_search",
8292
+ "searchInput": "_4JL8qq_searchInput",
8293
+ "segment": "_4JL8qq_segment",
8294
+ "toolbar": "_4JL8qq_toolbar"
8335
8295
  };
8336
8296
  //#endregion
8337
- //#region src/client/SearchFilterToolbar.tsx
8297
+ //#region src/client/ui/SearchFilterToolbar.tsx
8338
8298
  /**
8339
8299
  * Shared search, filter, and view controls for catalog-style settings panels.
8340
8300
  *
8341
- * The filters are one segmented control and the view switch is a single icon
8342
- * button, so the current mode is always readable without hovering: the active
8343
- * filter carries the platform's pressed fill, and the view button shows the
8344
- * mode in force with that same fill.
8301
+ * The filters ride the host's SegmentedControl (one controlled tablist with
8302
+ * roving focus) and the view switch stays a single always-pressed Pill, so the
8303
+ * current mode is always readable without hovering: the selected filter
8304
+ * carries the host's raised indicator, and the view button shows the mode in
8305
+ * force with its pressed fill.
8345
8306
  */
8346
8307
  /**
8347
8308
  * Render a consistent control row for searchable grid and list content.
@@ -8362,17 +8323,18 @@ function SearchFilterToolbar(props) {
8362
8323
  placeholder: props.searchPlaceholder,
8363
8324
  "aria-label": props.searchLabel,
8364
8325
  onChange: (event) => props.onSearchChange(event.target.value)
8365
- })), (0, react.createElement)("div", {
8366
- className: SearchFilterToolbar_module_default.segment,
8367
- role: "group"
8368
- }, ...props.filters.map((filter) => (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
8369
- key: filter.id,
8370
- active: filter.active,
8371
- title: filter.hint ?? `${filter.label} ${filter.count}`,
8372
- "aria-label": filter.hint ?? `${filter.label} ${filter.count}`,
8373
- "aria-pressed": filter.active,
8374
- onClick: filter.onSelect
8375
- }, filter.label, (0, react.createElement)("span", { className: SearchFilterToolbar_module_default.count }, filter.count)))), (0, react.createElement)("div", { className: SearchFilterToolbar_module_default.segment }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
8326
+ })), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.SegmentedControl, {
8327
+ id: props.filterId,
8328
+ value: props.filters.find((filter) => filter.active)?.id ?? props.filters[0]?.id ?? "",
8329
+ options: props.filters.map((filter) => ({
8330
+ value: filter.id,
8331
+ label: `${filter.label} ${filter.count}`,
8332
+ ...filter.hint === void 0 ? {} : { title: filter.hint }
8333
+ })),
8334
+ onChange: (id) => props.filters.find((filter) => filter.id === id)?.onSelect(),
8335
+ label: props.filterLabel,
8336
+ className: SearchFilterToolbar_module_default.segment
8337
+ }), (0, react.createElement)("div", { className: SearchFilterToolbar_module_default.segment }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
8376
8338
  active: true,
8377
8339
  title: viewLabel,
8378
8340
  "aria-label": viewLabel,
@@ -8380,39 +8342,47 @@ function SearchFilterToolbar(props) {
8380
8342
  onClick: () => props.onViewChange(grid ? "list" : "grid")
8381
8343
  }, (0, react.createElement)(ViewIcon, { mode: props.view }))));
8382
8344
  }
8383
- /** The two view glyphs; the host icon set has no grid glyph, so both stay drawn here. */
8345
+ /**
8346
+ * The two view glyphs; the host icon set has no grid glyph, so both stay drawn
8347
+ * here in the platform's outline paint. An unfilled shape with no stroke of its
8348
+ * own renders nothing, so the shared stroke is what makes either glyph read —
8349
+ * at the pill's own colour, and at the host's medium outline weight.
8350
+ */
8384
8351
  function ViewIcon({ mode }) {
8385
8352
  const common = {
8386
8353
  width: 16,
8387
8354
  height: 16,
8388
8355
  viewBox: "0 0 16 16",
8389
8356
  fill: "none",
8357
+ stroke: "currentColor",
8358
+ strokeLinecap: "round",
8359
+ strokeWidth: 1.3,
8390
8360
  "aria-hidden": true
8391
8361
  };
8392
8362
  return mode === "list" ? (0, react.createElement)("svg", common, (0, react.createElement)("path", { d: "M3 4h10M3 8h10M3 12h10" })) : (0, react.createElement)("svg", common, (0, react.createElement)("rect", {
8393
- x: 2.5,
8394
- y: 2.5,
8363
+ x: 3,
8364
+ y: 3,
8395
8365
  width: 4,
8396
8366
  height: 4,
8397
- rx: .8
8367
+ rx: 1
8398
8368
  }), (0, react.createElement)("rect", {
8399
- x: 9.5,
8400
- y: 2.5,
8369
+ x: 9,
8370
+ y: 3,
8401
8371
  width: 4,
8402
8372
  height: 4,
8403
- rx: .8
8373
+ rx: 1
8404
8374
  }), (0, react.createElement)("rect", {
8405
- x: 2.5,
8406
- y: 9.5,
8375
+ x: 3,
8376
+ y: 9,
8407
8377
  width: 4,
8408
8378
  height: 4,
8409
- rx: .8
8379
+ rx: 1
8410
8380
  }), (0, react.createElement)("rect", {
8411
- x: 9.5,
8412
- y: 9.5,
8381
+ x: 9,
8382
+ y: 9,
8413
8383
  width: 4,
8414
8384
  height: 4,
8415
- rx: .8
8385
+ rx: 1
8416
8386
  }));
8417
8387
  }
8418
8388
  //#endregion
@@ -22667,7 +22637,7 @@ the language package and the highlighter), but such tags will not
22667
22637
  be picked up by regular highlighters (though you can derive them
22668
22638
  from standard tags to allow highlighters to fall back to those).
22669
22639
  */
22670
- var Tag$5 = class Tag$5 {
22640
+ var Tag$6 = class Tag$6 {
22671
22641
  /**
22672
22642
  @internal
22673
22643
  */
@@ -22688,9 +22658,9 @@ var Tag$5 = class Tag$5 {
22688
22658
  }
22689
22659
  static define(nameOrParent, parent) {
22690
22660
  let name = typeof nameOrParent == "string" ? nameOrParent : "?";
22691
- if (nameOrParent instanceof Tag$5) parent = nameOrParent;
22661
+ if (nameOrParent instanceof Tag$6) parent = nameOrParent;
22692
22662
  if (parent === null || parent === void 0 ? void 0 : parent.base) throw new Error("Can not derive from a modified tag");
22693
- let tag = new Tag$5(name, [], null, []);
22663
+ let tag = new Tag$6(name, [], null, []);
22694
22664
  tag.set.push(tag);
22695
22665
  if (parent) for (let t of parent.set) tag.set.push(t);
22696
22666
  return tag;
@@ -22726,7 +22696,7 @@ var Modifier = class Modifier {
22726
22696
  if (!mods.length) return base;
22727
22697
  let exists = mods[0].instances.find((t) => t.base == base && sameArray(mods, t.modified));
22728
22698
  if (exists) return exists;
22729
- let set = [], tag = new Tag$5(base.name, set, base, mods);
22699
+ let set = [], tag = new Tag$6(base.name, set, base, mods);
22730
22700
  for (let m of mods) m.instances.push(tag);
22731
22701
  let configs = powerSet(mods);
22732
22702
  for (let parent of base.set) if (!parent.modified.length) for (let config of configs) set.push(Modifier.get(parent, config));
@@ -22987,7 +22957,7 @@ function getStyleTags(node) {
22987
22957
  while (rule && rule.context && !node.matchContext(rule.context)) rule = rule.next;
22988
22958
  return rule || null;
22989
22959
  }
22990
- const t = Tag$5.define;
22960
+ const t = Tag$6.define;
22991
22961
  const comment = t();
22992
22962
  const name$1 = t();
22993
22963
  const typeName = t(name$1);
@@ -23353,31 +23323,31 @@ const tags$1 = {
23353
23323
  given element is being defined. Expected to be used with the
23354
23324
  various [name](#highlight.tags.name) tags.
23355
23325
  */
23356
- definition: Tag$5.defineModifier("definition"),
23326
+ definition: Tag$6.defineModifier("definition"),
23357
23327
  /**
23358
23328
  [Modifier](#highlight.Tag^defineModifier) that indicates that
23359
23329
  something is constant. Mostly expected to be used with
23360
23330
  [variable names](#highlight.tags.variableName).
23361
23331
  */
23362
- constant: Tag$5.defineModifier("constant"),
23332
+ constant: Tag$6.defineModifier("constant"),
23363
23333
  /**
23364
23334
  [Modifier](#highlight.Tag^defineModifier) used to indicate that
23365
23335
  a [variable](#highlight.tags.variableName) or [property
23366
23336
  name](#highlight.tags.propertyName) is being called or defined
23367
23337
  as a function.
23368
23338
  */
23369
- function: Tag$5.defineModifier("function"),
23339
+ function: Tag$6.defineModifier("function"),
23370
23340
  /**
23371
23341
  [Modifier](#highlight.Tag^defineModifier) that can be applied to
23372
23342
  [names](#highlight.tags.name) to indicate that they belong to
23373
23343
  the language's standard environment.
23374
23344
  */
23375
- standard: Tag$5.defineModifier("standard"),
23345
+ standard: Tag$6.defineModifier("standard"),
23376
23346
  /**
23377
23347
  [Modifier](#highlight.Tag^defineModifier) that indicates a given
23378
23348
  [names](#highlight.tags.name) is local to some scope.
23379
23349
  */
23380
- local: Tag$5.defineModifier("local"),
23350
+ local: Tag$6.defineModifier("local"),
23381
23351
  /**
23382
23352
  A generic variant [modifier](#highlight.Tag^defineModifier) that
23383
23353
  can be used to tag language-specific alternative variants of
@@ -23386,11 +23356,11 @@ const tags$1 = {
23386
23356
  [variable name](#highlight.tags.variableName) tags, since those
23387
23357
  come up a lot.
23388
23358
  */
23389
- special: Tag$5.defineModifier("special")
23359
+ special: Tag$6.defineModifier("special")
23390
23360
  };
23391
23361
  for (let name in tags$1) {
23392
23362
  let val = tags$1[name];
23393
- if (val instanceof Tag$5) val.name = name;
23363
+ if (val instanceof Tag$6) val.name = name;
23394
23364
  }
23395
23365
  tagHighlighter([
23396
23366
  {
@@ -29657,7 +29627,7 @@ var MarkdownParser = class MarkdownParser extends Parser {
29657
29627
  }));
29658
29628
  if (style) {
29659
29629
  if (!styles) styles = {};
29660
- if (Array.isArray(style) || style instanceof Tag$5) styles[name] = style;
29630
+ if (Array.isArray(style) || style instanceof Tag$6) styles[name] = style;
29661
29631
  else Object.assign(styles, style);
29662
29632
  }
29663
29633
  }
@@ -34855,7 +34825,7 @@ function EntryEditorModal(props) {
34855
34825
  }))), props.renderFields?.(current.text, (text) => setDraft({
34856
34826
  ...current,
34857
34827
  text
34858
- })), props.modeControl === void 0 && props.textLabel === void 0 ? null : (0, react.createElement)("div", { className: form_module_default.rowHead }, props.textLabel === void 0 ? null : (0, react.createElement)("span", null, props.textLabel), props.modeControl), props.showPreview === true ? (0, react.createElement)("div", { className: form_module_default.previewBox }, (0, react.createElement)(MarkdownDocument, {
34828
+ })), props.state.routingOnly === true ? null : (0, react.createElement)(react.Fragment, null, props.modeControl === void 0 && props.textLabel === void 0 ? null : (0, react.createElement)("div", { className: form_module_default.rowHead }, props.textLabel === void 0 ? null : (0, react.createElement)("span", null, props.textLabel), props.modeControl), props.showPreview === true ? (0, react.createElement)("div", { className: form_module_default.previewBox }, (0, react.createElement)(MarkdownDocument, {
34859
34829
  text: current.text,
34860
34830
  t: props.t
34861
34831
  })) : (0, react.createElement)(CodeEditor, {
@@ -34868,7 +34838,7 @@ function EntryEditorModal(props) {
34868
34838
  label: props.textLabel,
34869
34839
  disabled: props.busy,
34870
34840
  minHeight: 300
34871
- }));
34841
+ })));
34872
34842
  }
34873
34843
  /** The shared danger-confirm modal with an optional checkbox. */
34874
34844
  function ConfirmModal(props) {
@@ -34944,7 +34914,7 @@ function useWorkspaceView() {
34944
34914
  return [(0, react.useSyncExternalStore)((listener) => current.subscribe(listener), () => narrow(current.getSnapshot()), () => DEFAULT_VIEW), setView];
34945
34915
  }
34946
34916
  //#endregion
34947
- //#region src/client/MarketSection.tsx
34917
+ //#region src/client/features/market/MarketSection.tsx
34948
34918
  /**
34949
34919
  * The Agent Plugins Market settings section.
34950
34920
  *
@@ -34968,6 +34938,7 @@ function MarketSection({ t, mode = "settings" }) {
34968
34938
  const [loading, setLoading] = (0, react.useState)(() => loadOverview().revalidating);
34969
34939
  const [search, setSearch] = (0, react.useState)("");
34970
34940
  const [tab, setTab] = (0, react.useState)("all");
34941
+ const marketFilterId = "market-status-filter";
34971
34942
  const [category, setCategory] = (0, react.useState)("all");
34972
34943
  const [view, setView] = useWorkspaceView();
34973
34944
  const [busy, setBusy] = (0, react.useState)(void 0);
@@ -35059,12 +35030,11 @@ function MarketSection({ t, mode = "settings" }) {
35059
35030
  }, ...ordered.map((source) => {
35060
35031
  const notes = source.scanNotes ?? [];
35061
35032
  const noteHint = notes.length === 0 ? void 0 : `${t("scanNotes")}: ${notes.slice(0, 8).join(t("sourceErrorSeparator"))}`;
35062
- const kindBadge = source.local === true ? t("sourceLocal") : source.kind === "archive" ? t("sourceArchive") : void 0;
35063
35033
  return {
35064
35034
  id: source.id,
35065
- label: `${source.id}${kindBadge === void 0 ? "" : ` · ${kindBadge}`} ${source.suiteIds.length}${source.cloned === false || notes.length > 0 ? " ⚠" : ""}`,
35035
+ label: `${source.id} ${source.suiteIds.length}`,
35066
35036
  ...noteHint === void 0 ? {} : { title: noteHint },
35067
- editable: selectedSource?.id === source.id,
35037
+ editable: true,
35068
35038
  deletable: true
35069
35039
  };
35070
35040
  })];
@@ -35148,6 +35118,8 @@ function MarketSection({ t, mode = "settings" }) {
35148
35118
  onSelect: () => setTab("uninstalled")
35149
35119
  }
35150
35120
  ],
35121
+ filterId: marketFilterId,
35122
+ filterLabel: t("nav"),
35151
35123
  view,
35152
35124
  toListLabel: t("switchToList"),
35153
35125
  toGridLabel: t("switchToGrid"),
@@ -35155,7 +35127,12 @@ function MarketSection({ t, mode = "settings" }) {
35155
35127
  }))), busy !== void 0 ? (0, react.createElement)(BusyIndicator, {
35156
35128
  overlay: true,
35157
35129
  label: t("panelWorking")
35158
- }) : null, (0, react.createElement)(ResourceCollection, { view }, loading ? (0, react.createElement)("div", { className: market_module_default.empty }, t("loading")) : filtered.length === 0 ? (0, react.createElement)("div", { className: market_module_default.empty }, tab === "installed" ? t("installedEmpty") : t("empty")) : filtered.map((suite) => (0, react.createElement)(SuiteCard, {
35130
+ }) : null, (0, react.createElement)(ResourceCollection, {
35131
+ view,
35132
+ role: "tabpanel",
35133
+ id: `${marketFilterId}-${tab}-panel`,
35134
+ "aria-labelledby": `${marketFilterId}-${tab}`
35135
+ }, loading ? (0, react.createElement)("div", { className: market_module_default.empty }, t("loading")) : filtered.length === 0 ? (0, react.createElement)("div", { className: market_module_default.empty }, tab === "installed" ? t("installedEmpty") : t("empty")) : filtered.map((suite) => (0, react.createElement)(SuiteCard, {
35159
35136
  key: `${suite.sourceId}/${suite.suiteId}`,
35160
35137
  t,
35161
35138
  suite,
@@ -35320,6 +35297,682 @@ function MarketSection({ t, mode = "settings" }) {
35320
35297
  }))
35321
35298
  });
35322
35299
  }
35300
+ //#endregion
35301
+ //#region src/client/features/mcp/mcp-status-view-model.ts
35302
+ /** Filter tabs in display order: scope first, the switched-off rows last. */
35303
+ const MCP_FILTERS = [
35304
+ "all",
35305
+ "direct",
35306
+ "plugin",
35307
+ "disabled"
35308
+ ];
35309
+ const searchableCache = /* @__PURE__ */ new WeakMap();
35310
+ /**
35311
+ * Derive the rows, the per-filter counts, and the visible rows in one pass.
35312
+ *
35313
+ * One predicate decides both the counts and the visible rows, so a tab's number
35314
+ * is always the number of rows clicking it shows.
35315
+ */
35316
+ function deriveMcpStatusViewModel(payload, filter, search) {
35317
+ const searchable = searchableFor(payload);
35318
+ const activeEntries = searchable.map((item) => item.entry);
35319
+ const filterCounts = {
35320
+ all: 0,
35321
+ plugin: 0,
35322
+ direct: 0,
35323
+ disabled: 0
35324
+ };
35325
+ const filtered = [];
35326
+ const needle = search.trim().toLowerCase();
35327
+ for (const item of searchable) {
35328
+ const entry = item.entry;
35329
+ for (const key of MCP_FILTERS) if (matchesMcpFilter(entry, key)) filterCounts[key]++;
35330
+ if (!matchesMcpFilter(entry, filter)) continue;
35331
+ if (needle !== "" && !item.haystack.includes(needle)) continue;
35332
+ filtered.push(entry);
35333
+ }
35334
+ return {
35335
+ activeEntries,
35336
+ filtered,
35337
+ filterCounts
35338
+ };
35339
+ }
35340
+ /**
35341
+ * Whether one row belongs to a filter.
35342
+ *
35343
+ * A switched-off row keeps its own scope, so it is reachable both through
35344
+ * `plugin`/`direct` and through `disabled`.
35345
+ */
35346
+ function matchesMcpFilter(entry, filter) {
35347
+ if (filter === "all") return true;
35348
+ if (filter === "disabled") return entry.state === "disabled";
35349
+ return entry.kind === filter;
35350
+ }
35351
+ function searchableFor(payload) {
35352
+ const cached = searchableCache.get(payload);
35353
+ if (cached !== void 0) return cached;
35354
+ const searchable = payload.entries.map((entry) => ({
35355
+ entry,
35356
+ haystack: `${entry.name} ${entry.source ?? ""} ${entry.endpoint ?? ""} ${entry.transport} ${entry.reason ?? ""} ${(entry.credentialRefs ?? []).join(" ")}`.toLowerCase()
35357
+ }));
35358
+ searchableCache.set(payload, searchable);
35359
+ return searchable;
35360
+ }
35361
+ /**
35362
+ * Every tool worth listing: what the server registered, plus every name the
35363
+ * suite or the user mentions.
35364
+ *
35365
+ * A denied tool leaves the live registry, so the stored lists are the only
35366
+ * thing keeping it on screen and available to switch back on. The suite's
35367
+ * allow-list and deny list both read as suite-limited; the user's own denials
35368
+ * stay selectable.
35369
+ */
35370
+ function mcpToolRows(entry) {
35371
+ const allowedNames = entry.suiteEnabledTools;
35372
+ const suiteDenied = new Set(entry.suiteDisabledTools ?? []);
35373
+ const userDenied = new Set(entry.userDisabledTools ?? []);
35374
+ const names = /* @__PURE__ */ new Set([
35375
+ ...entry.tools.map((tool) => tool.name),
35376
+ ...allowedNames ?? [],
35377
+ ...suiteDenied,
35378
+ ...userDenied
35379
+ ]);
35380
+ const observed = new Map(entry.tools.map((tool) => [tool.name, tool]));
35381
+ return [...names].sort().map((name) => {
35382
+ const suiteLimited = allowedNames !== void 0 && !allowedNames.includes(name) || suiteDenied.has(name);
35383
+ const tool = observed.get(name);
35384
+ return {
35385
+ name,
35386
+ allowed: !suiteLimited && !userDenied.has(name),
35387
+ suiteLimited,
35388
+ ...tool?.description === void 0 ? {} : { description: tool.description },
35389
+ ...tool?.parameters === void 0 ? {} : { parameters: tool.parameters }
35390
+ };
35391
+ });
35392
+ }
35393
+ //#endregion
35394
+ //#region src/client/features/mcp/state-helpers.ts
35395
+ /**
35396
+ * The inventory card's state for one row. The detail band derives its edge and
35397
+ * dot from this same value, so a service cannot read one colour on its card and
35398
+ * another in its detail dialog.
35399
+ */
35400
+ function mcpCardState(state) {
35401
+ if (state === "connected") return "active";
35402
+ if (state === "disabled") return "disabled";
35403
+ if (state === "failed" || state === "orphaned") return "error";
35404
+ return "warning";
35405
+ }
35406
+ function mcpTagTone(state) {
35407
+ if (state === "connected") return "success";
35408
+ if (state === "failed" || state === "orphaned") return "danger";
35409
+ if (state === "disabled" || state === "foreign") return "neutral";
35410
+ return "warning";
35411
+ }
35412
+ /** The identity a reader recognizes: the declaration key, or the row's own name. */
35413
+ function mcpDisplayName(entry) {
35414
+ return entry.kind === "plugin" ? entry.serverKey ?? entry.name : entry.name;
35415
+ }
35416
+ /** The one-line verdict the detail's status band shows. */
35417
+ function mcpStateLabel(t, state) {
35418
+ if (state === "connected") return t("mcpConnected");
35419
+ if (state === "degraded") return t("mcpDegraded");
35420
+ if (state === "failed") return t("mcpFailed");
35421
+ if (state === "needs-credentials") return t("mcpNeedsCredentials");
35422
+ if (state === "orphaned") return t("mcpOrphaned");
35423
+ if (state === "foreign") return t("mcpForeign");
35424
+ return t("panelFilterDisabled");
35425
+ }
35426
+ /** The card dot colour: the states the detail dialog also reports. */
35427
+ function mcpDotState(state) {
35428
+ if (state === "connected") return "done";
35429
+ if (state === "failed" || state === "orphaned") return "error";
35430
+ if (state === "disabled" || state === "foreign") return "idle";
35431
+ return "warning";
35432
+ }
35433
+ //#endregion
35434
+ //#region src/client/ui/failure-guidance.ts
35435
+ /** The locale key holding the sentence one classified failure reports. */
35436
+ const FAILURE_GUIDANCE_LABEL = {
35437
+ credentials: "failureGuideCredentials",
35438
+ auth: "failureGuideAuth",
35439
+ transport: "failureGuideTransport",
35440
+ backend: "failureGuideBackend",
35441
+ backendMissing: "failureGuideBackendMissing",
35442
+ missingPackage: "failureGuideMissingPackage",
35443
+ hostUnsupported: "failureGuideHostUnsupported",
35444
+ seamConflict: "failureGuideSeamConflict",
35445
+ dns: "failureGuideDns",
35446
+ tls: "failureGuideTls",
35447
+ refused: "failureGuideRefused",
35448
+ timeout: "failureGuideTimeout",
35449
+ commandMissing: "failureGuideCommandMissing",
35450
+ processExit: "failureGuideProcessExit",
35451
+ protocol: "failureGuideProtocol",
35452
+ startup: "failureGuideStartup",
35453
+ unmount: "failureGuideUnmount",
35454
+ orphanedTools: "failureGuideOrphanedTools",
35455
+ disabledOverride: "failureGuideDisabledOverride",
35456
+ modifiedOverride: "failureGuideModifiedOverride",
35457
+ foreignMount: "mcpForeignHint",
35458
+ duplicateMount: "mcpDuplicateHint"
35459
+ };
35460
+ /** Classify one failure, or nothing when it carries no recognizable shape. */
35461
+ function failureGuidanceKey(diagnostic) {
35462
+ const code = diagnostic.code;
35463
+ if (code === "missing-credential" || code === "credential-error") return "credentials";
35464
+ if (code === "unsupported-transport") return "transport";
35465
+ if (code === "host-missing") return "missingPackage";
35466
+ if (code === "seam-conflict") return "seamConflict";
35467
+ if (code === "unmount-failed") return "unmount";
35468
+ if (code === "foreign-mount") return "foreignMount";
35469
+ if (code === "duplicate-mount") return "duplicateMount";
35470
+ if (code === "orphaned-tools") return "orphanedTools";
35471
+ if (code === "disabled-override") return "disabledOverride";
35472
+ if (code === "modified-override") return "modifiedOverride";
35473
+ const text = [diagnostic.reason, ...diagnostic.causes ?? []].filter((line) => line !== void 0).join("\n");
35474
+ if (/does not support dynamic plugin mounting/i.test(text)) return "hostUnsupported";
35475
+ if (/dsh-mcp-client package is not installed/i.test(text)) return "backendMissing";
35476
+ if (/built-in backend|cannot enforce|does not support the legacy SSE transport/i.test(text)) return "backend";
35477
+ if (/\$\{[A-Za-z_][A-Za-z0-9_]*\}|credential/i.test(text)) return "credentials";
35478
+ if (/401|403|unauthor|oauth|forbidden|challenge/i.test(text)) return "auth";
35479
+ if (/ENOTFOUND|getaddrinfo|EAI_AGAIN|dns/i.test(text)) return "dns";
35480
+ if (/certificate|TLS|SSL|self.signed/i.test(text)) return "tls";
35481
+ if (/ECONNREFUSED|connection refused/i.test(text)) return "refused";
35482
+ if (/ETIMEDOUT|timed out|timeout/i.test(text)) return "timeout";
35483
+ if (/ENOENT|not found|no such file|spawn/i.test(text)) return "commandMissing";
35484
+ if (/exited|exit code|SIGTERM|SIGKILL|crash/i.test(text)) return "processExit";
35485
+ if (/jsonrpc|protocol|initialize|handshake/i.test(text)) return "protocol";
35486
+ if (code === "mount-failed") return "startup";
35487
+ }
35488
+ //#endregion
35489
+ //#region src/client/ui/status-band.module.css
35490
+ var status_band_module_default = {
35491
+ "actions": "AJn4ya_actions",
35492
+ "band": "AJn4ya_band",
35493
+ "diagnostic": "AJn4ya_diagnostic",
35494
+ "diagnosticLine": "AJn4ya_diagnosticLine",
35495
+ "echo": "AJn4ya_echo",
35496
+ "echoSuccess": "AJn4ya_echoSuccess",
35497
+ "labels": "AJn4ya_labels",
35498
+ "mono": "AJn4ya_mono",
35499
+ "reason": "AJn4ya_reason",
35500
+ "top": "AJn4ya_top"
35501
+ };
35502
+ //#endregion
35503
+ //#region src/client/ui/StatusBand.tsx
35504
+ /**
35505
+ * The one status band the MCP and LSP service details open with.
35506
+ *
35507
+ * The band is the dialog's only state container. Its first line holds the state
35508
+ * dot, the state tags, and the one recovery action the state offers on the
35509
+ * trailing edge; under it come what the last operation did, the sentence the
35510
+ * failure classifier picked, the recorded diagnostic behind a disclosure, and
35511
+ * the endpoint or command the service runs.
35512
+ *
35513
+ * The 3px leading edge carries the state with the same mapping the inventory
35514
+ * card uses, while the fill stays the platform's soft neutral one: a healthy
35515
+ * service reads calm, and a failure is marked by its edge, never by making the
35516
+ * prose or the whole block take the error colour.
35517
+ *
35518
+ * @module client/ui/StatusBand
35519
+ */
35520
+ /**
35521
+ * The band edge for a card state, so a service's card and its detail band can
35522
+ * never disagree about what colour the state is.
35523
+ */
35524
+ function bandTone(state) {
35525
+ if (state === "active") return "success";
35526
+ if (state === "error") return "error";
35527
+ if (state === "warning") return "warn";
35528
+ return "neutral";
35529
+ }
35530
+ function StatusBand({ t, dot, tone, labels, action, echo, guidance, reason, causes, mono }) {
35531
+ const [open, setOpen] = (0, react.useState)(false);
35532
+ const lead = guidance === void 0 ? reason : t(FAILURE_GUIDANCE_LABEL[guidance]);
35533
+ const diagnostic = guidance === void 0 ? [] : [reason, ...causes ?? []].filter((line) => line !== void 0 && line !== "");
35534
+ return (0, react.createElement)("section", {
35535
+ className: status_band_module_default.band,
35536
+ "data-band-tone": tone,
35537
+ "data-status-band": true
35538
+ }, (0, react.createElement)("div", { className: status_band_module_default.top }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: dot }), (0, react.createElement)("div", { className: status_band_module_default.labels }, labels), action === void 0 ? null : (0, react.createElement)("div", { className: status_band_module_default.actions }, action)), echo === void 0 ? null : (0, react.createElement)("p", {
35539
+ className: echo.error ? status_band_module_default.echo : `${status_band_module_default.echo} ${status_band_module_default.echoSuccess}`,
35540
+ role: echo.error ? "alert" : "status"
35541
+ }, echo.text), lead === void 0 ? null : (0, react.createElement)("p", { className: status_band_module_default.reason }, lead), diagnostic.length === 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.DisclosureRow, {
35542
+ icon: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineMedium),
35543
+ title: t("failureDetailToggle"),
35544
+ open,
35545
+ expandable: true,
35546
+ onToggle: () => setOpen((value) => !value),
35547
+ expandOnRowClick: true,
35548
+ previewChevron: false
35549
+ }, (0, react.createElement)("div", { className: status_band_module_default.diagnostic }, ...diagnostic.map((line, index) => (0, react.createElement)("p", {
35550
+ key: index,
35551
+ className: status_band_module_default.diagnosticLine
35552
+ }, line)))), mono === void 0 ? null : (0, react.createElement)("p", { className: status_band_module_default.mono }, mono));
35553
+ }
35554
+ //#endregion
35555
+ //#region src/client/credentials.ts
35556
+ /** Read one value-free credential view; secret values never enter the browser state. */
35557
+ async function describeCredential(api, ref) {
35558
+ if (api === void 0) return void 0;
35559
+ const response = await api.describe({ refs: [ref] });
35560
+ if (response.result?.ok !== true) throw new Error(response.result?.error?.message ?? "credential lookup failed");
35561
+ return response.result.value?.credentials?.[ref];
35562
+ }
35563
+ async function setCredential(api, ref, value) {
35564
+ return withBusyOperation(async () => {
35565
+ const response = await api.set({
35566
+ ref,
35567
+ value
35568
+ });
35569
+ if (response.result?.ok !== true) throw new Error(response.result?.error?.message ?? "credential save failed");
35570
+ });
35571
+ }
35572
+ async function unsetCredential(api, ref) {
35573
+ return withBusyOperation(async () => {
35574
+ const response = await api.unset({ ref });
35575
+ if (response.result?.ok !== true) throw new Error(response.result?.error?.message ?? "credential removal failed");
35576
+ });
35577
+ }
35578
+ /** Adapt the current Host service to the credential editor's wire contract. */
35579
+ function credentialApi(remote) {
35580
+ return {
35581
+ describe: async ({ refs }) => {
35582
+ const result = await remote.describe(refs);
35583
+ return { result: result.ok ? {
35584
+ ok: true,
35585
+ value: { credentials: result.value }
35586
+ } : result };
35587
+ },
35588
+ set: async ({ ref, value }) => ({ result: await remote.set(ref, value) }),
35589
+ unset: async ({ ref }) => ({ result: await remote.unset(ref) })
35590
+ };
35591
+ }
35592
+ //#endregion
35593
+ //#region src/client/features/mcp/McpCredentialFields.tsx
35594
+ /**
35595
+ * One MCP server's credential references as write-only `SettingsSecretField`
35596
+ * controls.
35597
+ *
35598
+ * Read facts (configured / source / writable) come from the value-free
35599
+ * credentials wire; a typed value crosses the wire exactly once, on the save
35600
+ * gesture, and never re-enters component state — the host control keeps no
35601
+ * value to render back. A blank draft writes nothing, which is what keeps the
35602
+ * stored key instead of clearing it. A reference the launch environment
35603
+ * supplies is read-only: it renders guidance instead of a control that could
35604
+ * only fake success. The modal hosting these fields stands outside any
35605
+ * settings form, so the commit gesture is the field's own save control rather
35606
+ * than the form-model's save — the one deliberate local piece.
35607
+ *
35608
+ * @module client/McpCredentialFields
35609
+ */
35610
+ /** The empty facts a fresh mount starts from: nothing known, service presumed. */
35611
+ const UNKNOWN_FACTS = {
35612
+ configured: {},
35613
+ writable: {},
35614
+ available: true
35615
+ };
35616
+ /** One reference's write-only control bound to the credentials wire. */
35617
+ function CredentialField(props) {
35618
+ const { t, api, credentialRef, usage, facts } = props;
35619
+ const [draft, setDraft] = (0, react.useState)("");
35620
+ const [busy, setBusy] = (0, react.useState)(false);
35621
+ const configured = facts.configured[credentialRef];
35622
+ const writable = facts.writable[credentialRef] ?? true;
35623
+ if (configured !== void 0 && !writable) return (0, react.createElement)("p", { role: "note" }, `${credentialRef} — ${t("mcpCredentialReadOnly")}`);
35624
+ /** Push the staged literal across the wire once, then re-read the truth. */
35625
+ const save = async () => {
35626
+ const value = draft.trim();
35627
+ if (value === "" || busy) return;
35628
+ setBusy(true);
35629
+ try {
35630
+ await setCredential(api, credentialRef, value);
35631
+ setDraft("");
35632
+ const view = await describeCredential(api, credentialRef).catch(() => void 0);
35633
+ props.onFact(credentialRef, { configured: view?.configured === true });
35634
+ } catch {} finally {
35635
+ setBusy(false);
35636
+ }
35637
+ };
35638
+ /** Drop the stored credential so the server mounts without it. */
35639
+ const unset = async () => {
35640
+ if (busy) return;
35641
+ setBusy(true);
35642
+ try {
35643
+ await unsetCredential(api, credentialRef);
35644
+ const view = await describeCredential(api, credentialRef).catch(() => void 0);
35645
+ props.onFact(credentialRef, { configured: view?.configured === true });
35646
+ } catch {} finally {
35647
+ setBusy(false);
35648
+ }
35649
+ };
35650
+ return (0, react.createElement)("div", null, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.SettingsSecretField, {
35651
+ id: `mcp-credential-${credentialRef}`,
35652
+ label: credentialRef,
35653
+ hint: usage,
35654
+ text: draft,
35655
+ disabled: busy,
35656
+ configured: configured === true,
35657
+ stateLabel: configured === void 0 ? t("loading") : configured ? t("mcpCredentialConfigured") : t("mcpCredentialMissing"),
35658
+ onEdit: setDraft
35659
+ }), (0, react.createElement)("div", { style: {
35660
+ display: "flex",
35661
+ gap: "8px"
35662
+ } }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
35663
+ variant: "primary",
35664
+ size: "sm",
35665
+ disabled: busy || draft.trim() === "",
35666
+ onClick: () => {
35667
+ save();
35668
+ }
35669
+ }, t("mcpCredentialSave")), configured === true ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
35670
+ variant: "ghost",
35671
+ size: "sm",
35672
+ disabled: busy,
35673
+ onClick: () => {
35674
+ unset();
35675
+ }
35676
+ }, t("mcpCredentialUnset")) : null));
35677
+ }
35678
+ /**
35679
+ * The write-only credential controls of one MCP server.
35680
+ * @param props - the translate, the credentials API, the server's references,
35681
+ * and where each reference is used, shown as the field's hint.
35682
+ * @returns the fields, or nothing when the server declares no references.
35683
+ */
35684
+ function McpCredentialFields(props) {
35685
+ const { t, api, refs, usage } = props;
35686
+ const [facts, setFacts] = (0, react.useState)(UNKNOWN_FACTS);
35687
+ const refKey = refs.join("|");
35688
+ (0, react.useEffect)(() => {
35689
+ let cancelled = false;
35690
+ setFacts(UNKNOWN_FACTS);
35691
+ if (api === void 0 || refs.length === 0) return () => {
35692
+ cancelled = true;
35693
+ };
35694
+ Promise.all(refs.map(async (ref) => [ref, await describeCredential(api, ref).catch(() => void 0)])).then((entries) => {
35695
+ if (cancelled) return;
35696
+ setFacts({
35697
+ configured: Object.fromEntries(entries.flatMap(([ref, view]) => view === void 0 ? [] : [[ref, view.configured === true]])),
35698
+ writable: Object.fromEntries(entries.flatMap(([ref, view]) => view === void 0 ? [] : [[ref, view.writable === true]])),
35699
+ available: true
35700
+ });
35701
+ }).catch(() => {
35702
+ if (!cancelled) setFacts({
35703
+ ...UNKNOWN_FACTS,
35704
+ available: false
35705
+ });
35706
+ });
35707
+ return () => {
35708
+ cancelled = true;
35709
+ };
35710
+ }, [api, refKey]);
35711
+ if (refs.length === 0) return null;
35712
+ if (api === void 0 || !facts.available) return (0, react.createElement)("p", { role: "status" }, t("mcpCredentialUnavailable"));
35713
+ const onFact = (ref, fact) => {
35714
+ setFacts((current) => ({
35715
+ ...current,
35716
+ configured: fact.configured === void 0 ? current.configured : {
35717
+ ...current.configured,
35718
+ [ref]: fact.configured
35719
+ },
35720
+ writable: fact.writable === void 0 ? current.writable : {
35721
+ ...current.writable,
35722
+ [ref]: fact.writable
35723
+ }
35724
+ }));
35725
+ };
35726
+ return (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("mcpCredentialTitle")), refs.map((ref) => (0, react.createElement)(CredentialField, {
35727
+ key: ref,
35728
+ t,
35729
+ api,
35730
+ credentialRef: ref,
35731
+ usage: (usage?.[ref] ?? []).join(" · "),
35732
+ facts,
35733
+ onFact
35734
+ })));
35735
+ }
35736
+ //#endregion
35737
+ //#region src/client/features/mcp/detail-actions.ts
35738
+ /** Actions describe different effects: retry preserves credentials; OAuth reset is explicit. */
35739
+ function mcpDetailActions(entry) {
35740
+ const owned = entry.kind === "plugin" || entry.managed === true;
35741
+ return {
35742
+ retry: owned && (entry.state === "failed" || entry.state === "orphaned") && entry.code !== "unsupported-transport",
35743
+ reauthorize: owned && entry.canReauthorize === true && ![
35744
+ "disabled",
35745
+ "foreign",
35746
+ "orphaned",
35747
+ "needs-credentials"
35748
+ ].includes(entry.state)
35749
+ };
35750
+ }
35751
+ //#endregion
35752
+ //#region src/client/features/mcp/mcp-status.module.css
35753
+ var mcp_status_module_default = {
35754
+ "blockHeadRow": "_3f22mq_blockHeadRow",
35755
+ "blockSub": "_3f22mq_blockSub",
35756
+ "cardTop": "_3f22mq_cardTop",
35757
+ "detail": "_3f22mq_detail",
35758
+ "detailBody": "_3f22mq_detailBody",
35759
+ "detailEmpty": "_3f22mq_detailEmpty",
35760
+ "empty": "_3f22mq_empty",
35761
+ "error": "_3f22mq_error",
35762
+ "grid": "_3f22mq_grid",
35763
+ "list": "_3f22mq_list",
35764
+ "lspStartingPulse": "_3f22mq_lspStartingPulse",
35765
+ "modalFooter": "_3f22mq_modalFooter",
35766
+ "modalFooterGrow": "_3f22mq_modalFooterGrow",
35767
+ "modalFooterHint": "_3f22mq_modalFooterHint",
35768
+ "reauthActions": "_3f22mq_reauthActions",
35769
+ "reauthConfirm": "_3f22mq_reauthConfirm",
35770
+ "reauthExplain": "_3f22mq_reauthExplain",
35771
+ "seamBanner": "_3f22mq_seamBanner",
35772
+ "seamBody": "_3f22mq_seamBody",
35773
+ "seamDone": "_3f22mq_seamDone",
35774
+ "seamOther": "_3f22mq_seamOther",
35775
+ "seamPath": "_3f22mq_seamPath",
35776
+ "seamPathLabel": "_3f22mq_seamPathLabel",
35777
+ "seamTitle": "_3f22mq_seamTitle",
35778
+ "surface": "_3f22mq_surface HJ9x7a_shell",
35779
+ "tool": "_3f22mq_tool",
35780
+ "toolbar": "_3f22mq_toolbar",
35781
+ "toolDescription": "_3f22mq_toolDescription",
35782
+ "toolIdentity": "_3f22mq_toolIdentity",
35783
+ "toolList": "_3f22mq_toolList",
35784
+ "toolMore": "_3f22mq_toolMore",
35785
+ "toolName": "_3f22mq_toolName",
35786
+ "toolNameButton": "_3f22mq_toolNameButton",
35787
+ "toolNote": "_3f22mq_toolNote",
35788
+ "toolParam": "_3f22mq_toolParam",
35789
+ "toolParamDesc": "_3f22mq_toolParamDesc",
35790
+ "toolParamName": "_3f22mq_toolParamName",
35791
+ "toolParamRequired": "_3f22mq_toolParamRequired",
35792
+ "toolParams": "_3f22mq_toolParams",
35793
+ "toolParamsEmpty": "_3f22mq_toolParamsEmpty",
35794
+ "toolParamsGrid": "_3f22mq_toolParamsGrid",
35795
+ "toolParamType": "_3f22mq_toolParamType",
35796
+ "toolSearch": "_3f22mq_toolSearch"
35797
+ };
35798
+ //#endregion
35799
+ //#region src/client/features/mcp/detail-helpers.ts
35800
+ /** Shared builders for the MCP detail dialogs: tool parameter rows and credential usage. */
35801
+ function toolParameterRows(parameters, t) {
35802
+ const schema = parameters ?? {};
35803
+ const properties = schema.properties;
35804
+ 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"));
35805
+ const required = new Set(Array.isArray(schema.required) ? schema.required.filter((value) => typeof value === "string") : []);
35806
+ return (0, react.createElement)("div", { className: mcp_status_module_default.toolParamsGrid }, ...Object.entries(properties).map(([name, raw]) => {
35807
+ const node = raw ?? {};
35808
+ const type = typeof node.type === "string" ? node.type : Array.isArray(node.enum) ? "enum" : "any";
35809
+ return (0, react.createElement)("div", {
35810
+ key: name,
35811
+ className: mcp_status_module_default.toolParam
35812
+ }, (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 : ""));
35813
+ }));
35814
+ }
35815
+ function credentialUsage(t, config) {
35816
+ const usage = {};
35817
+ if (config === void 0) return usage;
35818
+ for (const [field, label] of [["headers", t("detailHeaders")], ["env", t("detailEnv")]]) {
35819
+ const values = config[field];
35820
+ if (typeof values !== "object" || values === null) continue;
35821
+ for (const [key, value] of Object.entries(values)) {
35822
+ if (typeof value !== "string") continue;
35823
+ for (const match of value.matchAll(/\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g)) {
35824
+ const name = match[1];
35825
+ if (name === void 0) continue;
35826
+ const entries = usage[name] ?? [];
35827
+ entries.push(`${label} ${key}`);
35828
+ usage[name] = entries;
35829
+ }
35830
+ }
35831
+ }
35832
+ return usage;
35833
+ }
35834
+ //#endregion
35835
+ //#region src/client/features/mcp/McpDetailModal.tsx
35836
+ function McpDetailModal({ entry, t, credentials, backend, onClose, onRetry, onReauthorize, onRefresh }) {
35837
+ const [pending, setPending] = (0, react.useState)(false);
35838
+ const [confirmAuth, setConfirmAuth] = (0, react.useState)(false);
35839
+ const [feedback, setFeedback] = (0, react.useState)();
35840
+ const [toolBusy, setToolBusy] = (0, react.useState)(false);
35841
+ const [toolsExpanded, setToolsExpanded] = (0, react.useState)(false);
35842
+ const [toolSearch, setToolSearch] = (0, react.useState)("");
35843
+ const [expandedTools, setExpandedTools] = (0, react.useState)({});
35844
+ const actions = mcpDetailActions(entry);
35845
+ const guidance = failureGuidanceKey({
35846
+ code: entry.code,
35847
+ reason: entry.reason,
35848
+ causes: entry.causes
35849
+ });
35850
+ const tools = mcpToolRows(entry);
35851
+ const needle = toolSearch.trim().toLowerCase();
35852
+ const matchingTools = needle === "" ? tools : tools.filter((tool) => tool.name.toLowerCase().includes(needle));
35853
+ const shownTools = toolsExpanded ? matchingTools : matchingTools.slice(0, 8);
35854
+ const hiddenToolCount = matchingTools.length - shownTools.length;
35855
+ const toolsEditable = entry.suiteId !== void 0 && entry.serverKey !== void 0 && entry.state !== "foreign";
35856
+ const toggleTool = (tool, enabled) => {
35857
+ const suiteId = entry.suiteId;
35858
+ const serverKey = entry.serverKey;
35859
+ if (suiteId === void 0 || serverKey === void 0) return;
35860
+ setToolBusy(true);
35861
+ setFeedback(void 0);
35862
+ setMcpServerTool(suiteId, serverKey, tool, enabled).then(() => onRefresh(entry.id)).catch((reason) => setFeedback({
35863
+ error: true,
35864
+ text: clientErrorMessage(t, reason)
35865
+ })).finally(() => setToolBusy(false));
35866
+ };
35867
+ const run = async (authorize) => {
35868
+ setConfirmAuth(false);
35869
+ setPending(true);
35870
+ setFeedback(void 0);
35871
+ try {
35872
+ const connected = (authorize ? await onReauthorize(entry.id, entry.name) : await onRetry(entry.id)).state === "connected";
35873
+ setFeedback({
35874
+ error: !connected,
35875
+ text: connected ? t("mcpRetrySuccess") : t("mcpStillUnavailable")
35876
+ });
35877
+ } catch (reason) {
35878
+ setFeedback({
35879
+ error: true,
35880
+ text: t("actionFail") + ": " + clientErrorMessage(t, reason)
35881
+ });
35882
+ } finally {
35883
+ setPending(false);
35884
+ }
35885
+ };
35886
+ const recovery = [];
35887
+ if (actions.retry) recovery.push((0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
35888
+ key: "retry",
35889
+ variant: "outline",
35890
+ size: "sm",
35891
+ disabled: pending,
35892
+ title: t("mcpRetryPreservesCredentials"),
35893
+ "aria-label": t("mcpRetryConnection"),
35894
+ onClick: () => {
35895
+ run(false);
35896
+ }
35897
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutlineMedium), t("mcpRetryConnection")));
35898
+ if (actions.reauthorize) recovery.push((0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
35899
+ key: "reauthorize",
35900
+ variant: "ghost",
35901
+ size: "sm",
35902
+ disabled: pending,
35903
+ title: t("mcpReauthExplain"),
35904
+ onClick: () => {
35905
+ setConfirmAuth(true);
35906
+ setFeedback(void 0);
35907
+ }
35908
+ }, t("mcpReauthorize")));
35909
+ return (0, react.createElement)(DetailModal, {
35910
+ open: true,
35911
+ onClose: () => {
35912
+ if (!pending) onClose();
35913
+ },
35914
+ title: mcpDisplayName(entry),
35915
+ description: t("mcpServiceDetail"),
35916
+ closeLabel: t("mcpClose"),
35917
+ contentClassName: mcp_status_module_default.detailBody,
35918
+ children: (0, react.createElement)("div", null, (0, react.createElement)(StatusBand, {
35919
+ t,
35920
+ dot: mcpDotState(entry.state),
35921
+ tone: bandTone(mcpCardState(entry.state)),
35922
+ labels: (0, react.createElement)(react.Fragment, null, (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),
35923
+ ...recovery.length === 0 ? {} : { action: recovery },
35924
+ ...feedback === void 0 ? {} : { echo: feedback },
35925
+ ...guidance === void 0 ? {} : { guidance },
35926
+ ...entry.reason === void 0 ? {} : { reason: entry.reason },
35927
+ ...entry.causes === void 0 ? {} : { causes: entry.causes },
35928
+ mono: entry.endpoint ?? t("mcpObservedEndpoint")
35929
+ }), confirmAuth ? (0, react.createElement)("div", {
35930
+ className: mcp_status_module_default.reauthConfirm,
35931
+ role: "alert"
35932
+ }, (0, react.createElement)("p", { className: mcp_status_module_default.reauthExplain }, t("mcpReauthExplain")), (0, react.createElement)("div", { className: mcp_status_module_default.reauthActions }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
35933
+ variant: "ghost",
35934
+ onClick: () => setConfirmAuth(false)
35935
+ }, t("cancel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
35936
+ variant: "primary",
35937
+ disabled: pending,
35938
+ onClick: () => {
35939
+ run(true);
35940
+ }
35941
+ }, t("mcpConfirmReauth")))) : null, (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), kvCell(t("mcpMountNameLabel"), entry.name, true))), entry.kind === "direct" && !entry.managed ? (0, react.createElement)("p", { className: panel_module_default.detailProse }, 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 > 8 ? (0, react.createElement)("label", { className: mcp_status_module_default.toolSearch }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Input, {
35942
+ icon: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutlineMedium),
35943
+ value: toolSearch,
35944
+ placeholder: t("mcpToolsSearch"),
35945
+ "aria-label": t("mcpToolsSearch"),
35946
+ onChange: (event) => setToolSearch(event.target.value)
35947
+ })) : 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.state === "failed" || entry.state === "orphaned" ? t("mcpToolsUnreachable") : 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", {
35948
+ key: tool.name,
35949
+ className: mcp_status_module_default.tool
35950
+ }, (0, react.createElement)("span", { className: mcp_status_module_default.toolIdentity }, toolsEditable ? (0, react.createElement)("input", {
35951
+ type: "checkbox",
35952
+ checked: tool.allowed,
35953
+ disabled: toolBusy || tool.suiteLimited || backend === "host",
35954
+ "aria-label": `${t("mcpAllowTool")} ${tool.name}`,
35955
+ onChange: (event) => toggleTool(tool.name, event.target.checked)
35956
+ }) : null, tool.parameters === void 0 ? (0, react.createElement)("span", { className: mcp_status_module_default.toolName }, tool.name) : (0, react.createElement)("button", {
35957
+ type: "button",
35958
+ className: `${mcp_status_module_default.toolName} ${mcp_status_module_default.toolNameButton}`,
35959
+ "aria-expanded": expandedTools[tool.name] === true,
35960
+ onClick: () => setExpandedTools((current) => ({
35961
+ ...current,
35962
+ [tool.name]: current[tool.name] !== true
35963
+ }))
35964
+ }, 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", {
35965
+ type: "button",
35966
+ className: mcp_status_module_default.toolMore,
35967
+ onClick: () => setToolsExpanded(true)
35968
+ }, t("mcpToolsMore", { count: hiddenToolCount })) : null)), entry.credentialRefs?.length === 0 || entry.credentialRefs === void 0 ? null : (0, react.createElement)(McpCredentialFields, {
35969
+ t,
35970
+ api: credentials,
35971
+ refs: entry.credentialRefs,
35972
+ usage: credentialUsage(t, entry.config)
35973
+ }))
35974
+ });
35975
+ }
35323
35976
  /**
35324
35977
  * Read one timeout field: empty inherits (`null`), a positive whole number of
35325
35978
  * milliseconds within the timer range is the value, and anything else is
@@ -35419,107 +36072,6 @@ function serverFormCompatible(config, kind) {
35419
36072
  return true;
35420
36073
  }
35421
36074
  /**
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
36075
  * Read one pasted block into rows.
35524
36076
  *
35525
36077
  * The two separators that appear in MCP documentation are `=` and `:`, taking
@@ -35774,13 +36326,21 @@ function ServerConfigEditor(props) {
35774
36326
  open: advancedOpen,
35775
36327
  onToggle: () => setAdvancedOpen((value) => !value)
35776
36328
  }, (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", {
35778
- type: "button",
35779
- key: value,
35780
- "aria-pressed": mode === value,
35781
- disabled: props.disabled || value === "json" && hasIssue,
35782
- onClick: () => setMode(value)
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", {
36329
+ return (0, react.createElement)("div", { className: `${form_module_default.form} ${form_module_default.editorBody}` }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.SegmentedControl, {
36330
+ id: "server-config-mode",
36331
+ value: mode,
36332
+ options: [{
36333
+ value: "form",
36334
+ label: props.t("detailForm")
36335
+ }, {
36336
+ value: "json",
36337
+ label: props.t("detailJson")
36338
+ }],
36339
+ disabled: props.disabled || hasIssue,
36340
+ label: props.t("detailJsonConfig"),
36341
+ onChange: setMode,
36342
+ className: form_module_default.seg
36343
+ }), 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", {
35784
36344
  role: "alert",
35785
36345
  className: detail_module_default.error
35786
36346
  }, 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", {
@@ -36057,754 +36617,7 @@ function ServerConfigDetail({ kind, id, t, onSaved, onDirtyChange }) {
36057
36617
  }, busy ? t("loading") : t("save")) }) : (0, react.createElement)("p", null, t("serverConfigReadOnly")));
36058
36618
  }
36059
36619
  //#endregion
36060
- //#region src/client/features/mcp-status/detail-actions.ts
36061
- /** Actions describe different effects: retry preserves credentials; OAuth reset is explicit. */
36062
- function mcpDetailActions(entry) {
36063
- const owned = entry.kind === "plugin" || entry.managed === true;
36064
- return {
36065
- retry: owned && (entry.state === "failed" || entry.state === "orphaned") && entry.code !== "unsupported-transport",
36066
- reauthorize: owned && entry.canReauthorize === true && ![
36067
- "disabled",
36068
- "foreign",
36069
- "orphaned",
36070
- "needs-credentials"
36071
- ].includes(entry.state)
36072
- };
36073
- }
36074
- //#endregion
36075
- //#region src/client/credentials.ts
36076
- /** Read one value-free credential view; secret values never enter the browser state. */
36077
- async function describeCredential(api, ref) {
36078
- if (api === void 0) return void 0;
36079
- const response = await api.describe({ refs: [ref] });
36080
- if (response.result?.ok !== true) throw new Error(response.result?.error?.message ?? "credential lookup failed");
36081
- return response.result.value?.credentials?.[ref];
36082
- }
36083
- async function setCredential(api, ref, value) {
36084
- return withBusyOperation(async () => {
36085
- const response = await api.set({
36086
- ref,
36087
- value
36088
- });
36089
- if (response.result?.ok !== true) throw new Error(response.result?.error?.message ?? "credential save failed");
36090
- });
36091
- }
36092
- async function unsetCredential(api, ref) {
36093
- return withBusyOperation(async () => {
36094
- const response = await api.unset({ ref });
36095
- if (response.result?.ok !== true) throw new Error(response.result?.error?.message ?? "credential removal failed");
36096
- });
36097
- }
36098
- /** Adapt the current Host service to the credential editor's wire contract. */
36099
- function credentialApi(remote) {
36100
- return {
36101
- describe: async ({ refs }) => {
36102
- const result = await remote.describe(refs);
36103
- return { result: result.ok ? {
36104
- ok: true,
36105
- value: { credentials: result.value }
36106
- } : result };
36107
- },
36108
- set: async ({ ref, value }) => ({ result: await remote.set(ref, value) }),
36109
- unset: async ({ ref }) => ({ result: await remote.unset(ref) })
36110
- };
36111
- }
36112
- //#endregion
36113
- //#region src/client/mcp-credential.module.css
36114
- var mcp_credential_module_default = {
36115
- "actions": "G2mDja_actions",
36116
- "controls": "G2mDja_controls",
36117
- "editor": "G2mDja_editor",
36118
- "error": "G2mDja_error",
36119
- "factMiss": "G2mDja_factMiss",
36120
- "factOk": "G2mDja_factOk",
36121
- "facts": "G2mDja_facts",
36122
- "form": "G2mDja_form",
36123
- "grow": "G2mDja_grow",
36124
- "head": "G2mDja_head",
36125
- "input": "G2mDja_input",
36126
- "note": "G2mDja_note",
36127
- "ref": "G2mDja_ref",
36128
- "row": "G2mDja_row",
36129
- "rowHead": "G2mDja_rowHead",
36130
- "where": "G2mDja_where"
36131
- };
36132
- //#endregion
36133
- //#region src/client/McpCredentialEditor.tsx
36134
- /**
36135
- * Write-only credential editor for MCP `${ENV_NAME}` references.
36136
- *
36137
- * Read facts (configured / source / writable) come from the value-free
36138
- * credentials wire; a typed value crosses the wire exactly once, inside
36139
- * `credentials.set`, and never re-enters component state. Read-only
36140
- * launch-environment credentials render guidance instead of a form that could
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.
36145
- */
36146
- function McpCredentialEditor(props) {
36147
- const { t, api, refs, usage } = props;
36148
- const [views, setViews] = (0, react.useState)({});
36149
- const [drafts, setDrafts] = (0, react.useState)({});
36150
- const [open, setOpen] = (0, react.useState)({});
36151
- const [busy, setBusy] = (0, react.useState)(void 0);
36152
- const [error, setError] = (0, react.useState)(void 0);
36153
- const refKey = refs.join("|");
36154
- (0, react.useEffect)(() => {
36155
- let cancelled = false;
36156
- setViews({});
36157
- setError(void 0);
36158
- if (api === void 0 || refs.length === 0) return () => {
36159
- cancelled = true;
36160
- };
36161
- Promise.all(refs.map(async (ref) => [ref, await describeCredential(api, ref)])).then((entries) => {
36162
- if (cancelled) return;
36163
- setViews(Object.fromEntries(entries.flatMap(([ref, view]) => view === void 0 ? [] : [[ref, view]])));
36164
- }).catch((reason) => {
36165
- if (!cancelled) setError(clientErrorMessage(t, reason));
36166
- });
36167
- return () => {
36168
- cancelled = true;
36169
- };
36170
- }, [api, refKey]);
36171
- if (refs.length === 0) return null;
36172
- const refresh = async (ref) => {
36173
- if (api === void 0) return;
36174
- const view = await describeCredential(api, ref);
36175
- if (view !== void 0) setViews((current) => ({
36176
- ...current,
36177
- [ref]: view
36178
- }));
36179
- };
36180
- const save = async (ref) => {
36181
- const value = drafts[ref]?.trim();
36182
- if (api === void 0 || value === void 0 || value === "") return;
36183
- setBusy(ref);
36184
- setError(void 0);
36185
- try {
36186
- await setCredential(api, ref, value);
36187
- setDrafts((current) => ({
36188
- ...current,
36189
- [ref]: ""
36190
- }));
36191
- await refresh(ref);
36192
- } catch (reason) {
36193
- setError(clientErrorMessage(t, reason));
36194
- } finally {
36195
- setBusy(void 0);
36196
- }
36197
- };
36198
- const unset = async (ref) => {
36199
- if (api === void 0) return;
36200
- setBusy(ref);
36201
- setError(void 0);
36202
- try {
36203
- await unsetCredential(api, ref);
36204
- await refresh(ref);
36205
- } catch (reason) {
36206
- setError(clientErrorMessage(t, reason));
36207
- } finally {
36208
- setBusy(void 0);
36209
- }
36210
- };
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) => {
36212
- const view = views[ref];
36213
- const refBusy = busy === ref;
36214
- const where = usage?.[ref] ?? [];
36215
- const expanded = open[ref] === true;
36216
- const configured = view?.configured === true;
36217
- return (0, react.createElement)("div", {
36218
- key: ref,
36219
- className: mcp_credential_module_default.row
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", {
36231
- className: mcp_credential_module_default.input,
36232
- type: "password",
36233
- autoComplete: "new-password",
36234
- value: drafts[ref] ?? "",
36235
- placeholder: t("mcpCredentialPlaceholder"),
36236
- "aria-label": ref,
36237
- disabled: refBusy,
36238
- onChange: (event) => setDrafts((current) => ({
36239
- ...current,
36240
- [ref]: event.target.value
36241
- }))
36242
- }), (0, react.createElement)("div", { className: mcp_credential_module_default.actions }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36243
- variant: "primary",
36244
- size: "sm",
36245
- disabled: refBusy || (drafts[ref]?.trim() ?? "") === "",
36246
- onClick: () => void save(ref)
36247
- }, t("mcpCredentialSave")), configured ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36248
- variant: "ghost",
36249
- size: "sm",
36250
- disabled: refBusy,
36251
- onClick: () => void unset(ref)
36252
- }, t("mcpCredentialUnset")) : null)) : null);
36253
- }));
36254
- }
36255
- //#endregion
36256
- //#region src/client/features/mcp-status/mcp-status-view-model.ts
36257
- /** Filter tabs in display order: scope first, the switched-off rows last. */
36258
- const MCP_FILTERS = [
36259
- "all",
36260
- "direct",
36261
- "plugin",
36262
- "disabled"
36263
- ];
36264
- const searchableCache = /* @__PURE__ */ new WeakMap();
36265
- /**
36266
- * Derive the rows, the per-filter counts, and the visible rows in one pass.
36267
- *
36268
- * One predicate decides both the counts and the visible rows, so a tab's number
36269
- * is always the number of rows clicking it shows.
36270
- */
36271
- function deriveMcpStatusViewModel(payload, filter, search) {
36272
- const searchable = searchableFor(payload);
36273
- const activeEntries = searchable.map((item) => item.entry);
36274
- const filterCounts = {
36275
- all: 0,
36276
- plugin: 0,
36277
- direct: 0,
36278
- disabled: 0
36279
- };
36280
- const filtered = [];
36281
- const needle = search.trim().toLowerCase();
36282
- for (const item of searchable) {
36283
- const entry = item.entry;
36284
- for (const key of MCP_FILTERS) if (matchesMcpFilter(entry, key)) filterCounts[key]++;
36285
- if (!matchesMcpFilter(entry, filter)) continue;
36286
- if (needle !== "" && !item.haystack.includes(needle)) continue;
36287
- filtered.push(entry);
36288
- }
36289
- return {
36290
- activeEntries,
36291
- filtered,
36292
- filterCounts
36293
- };
36294
- }
36295
- /**
36296
- * Whether one row belongs to a filter.
36297
- *
36298
- * A switched-off row keeps its own scope, so it is reachable both through
36299
- * `plugin`/`direct` and through `disabled`.
36300
- */
36301
- function matchesMcpFilter(entry, filter) {
36302
- if (filter === "all") return true;
36303
- if (filter === "disabled") return entry.state === "disabled";
36304
- return entry.kind === filter;
36305
- }
36306
- function searchableFor(payload) {
36307
- const cached = searchableCache.get(payload);
36308
- if (cached !== void 0) return cached;
36309
- const searchable = payload.entries.map((entry) => ({
36310
- entry,
36311
- haystack: `${entry.name} ${entry.source ?? ""} ${entry.endpoint ?? ""} ${entry.transport} ${entry.reason ?? ""} ${(entry.credentialRefs ?? []).join(" ")}`.toLowerCase()
36312
- }));
36313
- searchableCache.set(payload, searchable);
36314
- return searchable;
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
- }
36380
- //#endregion
36381
- //#region src/client/mcp-status.module.css
36382
- var mcp_status_module_default = {
36383
- "blockHeadRow": "AUWlZW_blockHeadRow",
36384
- "blockSub": "AUWlZW_blockSub",
36385
- "cardTop": "AUWlZW_cardTop",
36386
- "detail": "AUWlZW_detail",
36387
- "detailBody": "AUWlZW_detailBody",
36388
- "detailEmpty": "AUWlZW_detailEmpty",
36389
- "empty": "AUWlZW_empty",
36390
- "error": "AUWlZW_error",
36391
- "grid": "AUWlZW_grid",
36392
- "list": "AUWlZW_list",
36393
- "lspStartingPulse": "AUWlZW_lspStartingPulse",
36394
- "modalFooter": "AUWlZW_modalFooter",
36395
- "modalFooterGrow": "AUWlZW_modalFooterGrow",
36396
- "modalFooterHint": "AUWlZW_modalFooterHint",
36397
- "pasteArea": "AUWlZW_pasteArea",
36398
- "pasteCheck": "AUWlZW_pasteCheck",
36399
- "pasteNote": "AUWlZW_pasteNote",
36400
- "pasteOutcome": "AUWlZW_pasteOutcome",
36401
- "reasonActions": "AUWlZW_reasonActions",
36402
- "reasonBox": "AUWlZW_reasonBox",
36403
- "reasonHint": "AUWlZW_reasonHint",
36404
- "reasonLabel": "AUWlZW_reasonLabel",
36405
- "reasonRaw": "AUWlZW_reasonRaw",
36406
- "reasonText": "AUWlZW_reasonText",
36407
- "retryEchoSuccess": "AUWlZW_retryEchoSuccess",
36408
- "seamBanner": "AUWlZW_seamBanner",
36409
- "seamBody": "AUWlZW_seamBody",
36410
- "seamDone": "AUWlZW_seamDone",
36411
- "seamOther": "AUWlZW_seamOther",
36412
- "seamPath": "AUWlZW_seamPath",
36413
- "seamPathLabel": "AUWlZW_seamPathLabel",
36414
- "seamTitle": "AUWlZW_seamTitle",
36415
- "starter": "AUWlZW_starter",
36416
- "starterList": "AUWlZW_starterList",
36417
- "starterPaste": "AUWlZW_starterPaste",
36418
- "surface": "AUWlZW_surface HJ9x7a_shell",
36419
- "tool": "AUWlZW_tool",
36420
- "toolbar": "AUWlZW_toolbar",
36421
- "toolDescription": "AUWlZW_toolDescription",
36422
- "toolIdentity": "AUWlZW_toolIdentity",
36423
- "toolList": "AUWlZW_toolList",
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"
36437
- };
36438
- //#endregion
36439
- //#region src/client/McpStatusPanel.tsx
36440
- const EMPTY_STATUS$1 = {
36441
- entries: [],
36442
- observedAt: "",
36443
- totals: {
36444
- all: 0,
36445
- connected: 0,
36446
- degraded: 0,
36447
- failed: 0,
36448
- needsCredentials: 0,
36449
- orphaned: 0,
36450
- disabled: 0,
36451
- foreign: 0
36452
- },
36453
- directObservationOnly: true
36454
- };
36455
- /** How many tool rows a collapsed capability list shows before its expand row. */
36456
- const TOOL_PAGE_SIZE = 8;
36457
- /** DSH-native MCP inventory with a per-state overview and per-service detail. */
36458
- function McpStatusPanel({ t, credentials }) {
36459
- const [payload, setPayload] = (0, react.useState)(EMPTY_STATUS$1);
36460
- const [loading, setLoading] = (0, react.useState)(true);
36461
- const [error, setError] = (0, react.useState)(void 0);
36462
- const [filter, setFilter] = (0, react.useState)("all");
36463
- const [search, setSearch] = (0, react.useState)("");
36464
- const [view, setView] = useWorkspaceView();
36465
- const [selected, setSelected] = (0, react.useState)(void 0);
36466
- const [editing, setEditing] = (0, react.useState)();
36467
- const [adding, setAdding] = (0, react.useState)(false);
36468
- const observe = async (id) => {
36469
- const refreshed = await fetchMcpStatus();
36470
- setPayload(refreshed);
36471
- const current = refreshed.entries.find((item) => item.id === id);
36472
- if (!current) throw new Error(t("mcpEntryGone"));
36473
- setSelected(current);
36474
- return current;
36475
- };
36476
- const retry = (id) => withBusyOperation(async () => {
36477
- await retryMcpMounts();
36478
- return observe(id);
36479
- });
36480
- const reauthorize = (id, serverName) => withBusyOperation(async () => {
36481
- await reauthorizeMcpServer(serverName);
36482
- return observe(id);
36483
- });
36484
- const refresh = () => {
36485
- setLoading(true);
36486
- setError(void 0);
36487
- fetchMcpStatus().then(setPayload).catch((caught) => {
36488
- setError(clientErrorMessage(t, caught));
36489
- }).finally(() => setLoading(false));
36490
- };
36491
- const toggle = (entry) => {
36492
- const suiteId = entry.suiteId;
36493
- const serverKey = entry.serverKey;
36494
- if (suiteId === void 0 || serverKey === void 0) return;
36495
- setError(void 0);
36496
- withBusyOperation(() => setMcpServerEnabled(suiteId, serverKey, entry.state === "disabled")).then(() => fetchMcpStatus()).then(setPayload).catch((caught) => {
36497
- setError(clientErrorMessage(t, caught));
36498
- });
36499
- };
36500
- (0, react.useEffect)(() => {
36501
- refresh();
36502
- }, []);
36503
- const { activeEntries, filtered, filterCounts } = deriveMcpStatusViewModel(payload, filter, search);
36504
- return (0, react.createElement)("div", { className: mcp_status_module_default.surface }, (0, react.createElement)(PanelHeader, {
36505
- title: t("mcpStatusTitle"),
36506
- subtitle: t("mcpStatusSubtitle"),
36507
- actions: (0, react.createElement)(PanelActions, {
36508
- addLabel: t("panelAdd"),
36509
- onAdd: () => setAdding(true),
36510
- refreshLabel: t("refresh"),
36511
- onRefresh: refresh,
36512
- busy: loading
36513
- })
36514
- }), (0, react.createElement)(SearchFilterToolbar, {
36515
- className: mcp_status_module_default.toolbar,
36516
- search,
36517
- searchLabel: t("mcpSearch"),
36518
- searchPlaceholder: t("mcpSearch"),
36519
- onSearchChange: setSearch,
36520
- filters: MCP_FILTERS.map((kind) => ({
36521
- id: kind,
36522
- label: filterLabel(t, kind),
36523
- count: filterCounts[kind],
36524
- active: filter === kind,
36525
- onSelect: () => setFilter(kind),
36526
- hint: mcpFilterHint(t, kind)
36527
- })),
36528
- view,
36529
- toListLabel: t("switchToList"),
36530
- toGridLabel: t("switchToGrid"),
36531
- onViewChange: (nextView) => setView(nextView)
36532
- }), error !== void 0 ? (0, react.createElement)("div", { className: mcp_status_module_default.error }, error, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36533
- variant: "ghost",
36534
- size: "sm",
36535
- onClick: refresh
36536
- }, t("mcpRetry"))) : loading && activeEntries.length === 0 ? (0, react.createElement)("div", { className: mcp_status_module_default.empty }, t("loading")) : filtered.length === 0 ? (0, react.createElement)("div", { className: mcp_status_module_default.empty }, t("mcpEmpty")) : (0, react.createElement)(ResourceCollection, { view }, filtered.map((entry) => (0, react.createElement)(McpCard, {
36537
- key: entry.id,
36538
- entry,
36539
- t,
36540
- onClick: () => setSelected(entry),
36541
- onToggle: () => toggle(entry),
36542
- onEdit: () => setEditing(entry)
36543
- }))), adding ? (0, react.createElement)(McpAddModal, {
36544
- t,
36545
- onClose: () => setAdding(false),
36546
- onChanged: refresh,
36547
- onSaved: () => {
36548
- setAdding(false);
36549
- refresh();
36550
- }
36551
- }) : null, selected === void 0 ? null : (0, react.createElement)(McpDetailModal, {
36552
- entry: selected,
36553
- t,
36554
- credentials,
36555
- backend: payload.backend ?? "builtin",
36556
- onClose: () => {
36557
- setSelected(void 0);
36558
- refresh();
36559
- },
36560
- onRetry: retry,
36561
- onReauthorize: reauthorize,
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
36568
- }));
36569
- }
36570
- /** The state tag's tone; a healthy server reads as success. */
36571
- function mcpTagTone(state) {
36572
- if (state === "connected") return "success";
36573
- if (state === "failed" || state === "orphaned") return "danger";
36574
- if (state === "disabled" || state === "foreign") return "neutral";
36575
- return "warning";
36576
- }
36577
- /** The one-line verdict the detail's status band shows. */
36578
- function mcpStateLabel(t, state) {
36579
- if (state === "connected") return t("mcpConnected");
36580
- if (state === "degraded") return t("mcpDegraded");
36581
- if (state === "failed") return t("mcpFailed");
36582
- if (state === "needs-credentials") return t("mcpNeedsCredentials");
36583
- if (state === "orphaned") return t("mcpOrphaned");
36584
- if (state === "foreign") return t("mcpForeign");
36585
- return t("panelFilterDisabled");
36586
- }
36587
- /** One label/value pair in a detail dialog's overview grid. */
36588
- function kvCell(label, value, mono = false) {
36589
- return (0, react.createElement)("div", null, (0, react.createElement)("dt", { className: panel_module_default.kvKey }, label), (0, react.createElement)("dd", {
36590
- className: mono ? `${panel_module_default.kvValue} ${panel_module_default.kvValueMono}` : panel_module_default.kvValue,
36591
- title: value
36592
- }, value));
36593
- }
36594
- /** The card dot colour: the states the detail dialog also reports. */
36595
- function mcpDotState(state) {
36596
- if (state === "connected") return "done";
36597
- if (state === "failed" || state === "orphaned") return "error";
36598
- if (state === "disabled" || state === "foreign") return "idle";
36599
- return "warning";
36600
- }
36601
- /**
36602
- * One inventory card: the server name with its state tag on the identity row
36603
- * and the enable switch on its trailing edge; the endpoint on the body row;
36604
- * tool count and transport on the source row. The reason text, the state
36605
- * label's long form, and the remaining actions (retry, reauthorize,
36606
- * configuration) live in the detail dialog, so a wall of failing cards stays
36607
- * scannable.
36608
- */
36609
- function McpCard({ entry, t, onClick, onToggle, onEdit }) {
36610
- const interactive = {
36611
- role: "button",
36612
- tabIndex: 0,
36613
- onClick,
36614
- onKeyDown: (event) => {
36615
- if (event.key !== "Enter" && event.key !== " ") return;
36616
- event.preventDefault();
36617
- onClick();
36618
- }
36619
- };
36620
- const toolCount = entry.tools.length === 1 ? t("mcpTool") : t("mcpTools");
36621
- const switchable = entry.suiteId !== void 0 && entry.serverKey !== void 0 && entry.state !== "foreign";
36622
- const disabled = entry.state === "disabled";
36623
- return (0, react.createElement)(ResourceCard, {
36624
- state: entry.state === "connected" ? "active" : entry.state === "disabled" ? "disabled" : entry.state === "failed" || entry.state === "orphaned" ? "error" : "warning",
36625
- surface: "mcp",
36626
- ...interactive
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", {
36637
- className: resource_card_module_default.switchWrap,
36638
- onClick: (event) => event.stopPropagation()
36639
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
36640
- checked: !disabled,
36641
- disabled: !switchable,
36642
- label: disabled ? t("enable") : t("disable"),
36643
- title: disabled ? t("enable") : t("disable"),
36644
- onChange: onToggle
36645
- }))), (0, react.createElement)("p", { className: `${resource_card_module_default.rowBody} ${resource_card_module_default.monoLine}` }, entry.endpoint ?? t("mcpObservedEndpoint")), (0, react.createElement)("div", { className: resource_card_module_default.rowFoot }, (0, react.createElement)("span", {
36646
- className: resource_card_module_default.provenance,
36647
- title: entry.suiteId ?? entry.source
36648
- }, entry.kind === "plugin" ? entry.suiteId ?? entry.source ?? "—" : t("mcpDirect")), (0, react.createElement)("span", { className: resource_card_module_default.separator }, "·"), (0, react.createElement)("span", { className: resource_card_module_default.count }, (0, react.createElement)("span", { className: resource_card_module_default.countValue }, String(entry.tools.length)), " ", toolCount), (0, react.createElement)("span", { className: resource_card_module_default.separator }, "·"), (0, react.createElement)("span", { className: resource_card_module_default.count }, entry.transport)));
36649
- }
36650
- /**
36651
- * The detail dialog owns every action and every long text: state, reason,
36652
- * credentials, config, tools, and the retry control with its in-place result
36653
- * echo. The state pill is dropped entirely — the dot and the reason box carry
36654
- * that information without a second red stamp.
36655
- */
36656
- function McpDetailModal({ entry, t, credentials, backend, onClose, onRetry, onReauthorize, onRefresh }) {
36657
- const [pending, setPending] = (0, react.useState)(false);
36658
- const [confirmAuth, setConfirmAuth] = (0, react.useState)(false);
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);
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
- };
36696
- const run = async (authorize) => {
36697
- setConfirmAuth(false);
36698
- setPending(true);
36699
- setFeedback(void 0);
36700
- try {
36701
- const current = authorize ? await onReauthorize(entry.id, entry.name) : await onRetry(entry.id);
36702
- const connected = current.state === "connected";
36703
- setFeedback({
36704
- error: !connected,
36705
- text: connected ? t("mcpRetrySuccess") : t("mcpStillUnavailable") + (current.reason ? ": " + current.reason : "")
36706
- });
36707
- } catch (reason) {
36708
- setFeedback({
36709
- error: true,
36710
- text: t("actionFail") + ": " + clientErrorMessage(t, reason)
36711
- });
36712
- } finally {
36713
- setPending(false);
36714
- }
36715
- };
36716
- return (0, react.createElement)(DetailModal, {
36717
- open: true,
36718
- onClose: () => {
36719
- if (!pending) onClose();
36720
- },
36721
- title: entry.name,
36722
- description: t("mcpServiceDetail"),
36723
- closeLabel: t("mcpClose"),
36724
- contentClassName: mcp_status_module_default.detailBody,
36725
- footer: (0, react.createElement)("div", { className: mcp_status_module_default.modalFooter }, actions.reauthorize ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36726
- variant: "ghost",
36727
- size: "sm",
36728
- disabled: pending,
36729
- title: t("mcpReauthExplain"),
36730
- onClick: () => {
36731
- setConfirmAuth(true);
36732
- setFeedback(void 0);
36733
- }
36734
- }, t("mcpReauthorize")) : null, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36735
- variant: "ghost",
36736
- disabled: pending,
36737
- onClick: onClose
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
- })),
36745
- children: (0, react.createElement)("div", null, feedback ? (0, react.createElement)("p", {
36746
- role: feedback.error ? "alert" : "status",
36747
- className: feedback.error ? mcp_status_module_default.error : mcp_status_module_default.retryEchoSuccess
36748
- }, feedback.text) : null, confirmAuth ? (0, react.createElement)("section", {
36749
- className: mcp_status_module_default.reasonBox,
36750
- role: "alert"
36751
- }, (0, react.createElement)("p", null, t("mcpReauthExplain")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36752
- variant: "ghost",
36753
- onClick: () => setConfirmAuth(false)
36754
- }, t("cancel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36755
- variant: "primary",
36756
- disabled: pending,
36757
- onClick: () => {
36758
- run(true);
36759
- }
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, {
36796
- t,
36797
- api: credentials,
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
- */
36620
+ //#region src/client/features/mcp/McpConfigModal.tsx
36808
36621
  function McpConfigModal({ entry, t, onClose, onSaved }) {
36809
36622
  return (0, react.createElement)(DetailModal, {
36810
36623
  open: true,
@@ -36814,10 +36627,6 @@ function McpConfigModal({ entry, t, onClose, onSaved }) {
36814
36627
  onClose,
36815
36628
  size: "md",
36816
36629
  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
36630
  children: (0, react.createElement)(ServerConfigDetail, {
36822
36631
  kind: "mcp",
36823
36632
  id: entry.id,
@@ -36826,68 +36635,20 @@ function McpConfigModal({ entry, t, onClose, onSaved }) {
36826
36635
  })
36827
36636
  });
36828
36637
  }
36829
- function McpAddModal({ t, onClose, onSaved, onChanged }) {
36638
+ //#endregion
36639
+ //#region src/client/features/mcp/McpAddModal.tsx
36640
+ /**
36641
+ * The new-service dialog is one short form: name, transport, and the field
36642
+ * that transport requires. A definition too complex for the form is entered in
36643
+ * the editor's JSON view instead — the same document, written by hand.
36644
+ */
36645
+ function McpAddModal({ t, onClose, onSaved }) {
36830
36646
  const [name, setName] = (0, react.useState)("");
36831
36647
  const [config, setConfig] = (0, react.useState)("{\"type\":\"stdio\",\"command\":\"\"}");
36832
36648
  const [valid, setValid] = (0, react.useState)(false);
36833
36649
  const [busy, setBusy] = (0, react.useState)(false);
36834
36650
  const [error, setError] = (0, react.useState)();
36835
36651
  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
- };
36891
36652
  const save = () => {
36892
36653
  setBusy(true);
36893
36654
  setError(void 0);
@@ -36905,68 +36666,11 @@ function McpAddModal({ t, onClose, onSaved, onChanged }) {
36905
36666
  closeLabel: t("cancel"),
36906
36667
  contentClassName: mcp_status_module_default.detailBody,
36907
36668
  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, {
36908
- variant: "outline",
36909
- disabled: busy,
36910
- onClick: onClose
36911
- }, t("cancel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36912
36669
  variant: "primary",
36913
36670
  disabled: busy || name.trim() === "" || !valid,
36914
36671
  onClick: save
36915
36672
  }, t("editorCreate"))),
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, {
36673
+ children: (0, react.createElement)("div", { className: mcp_status_module_default.detail }, (0, react.createElement)(ServerConfigEditor, {
36970
36674
  kind: "mcp",
36971
36675
  text: config,
36972
36676
  onChange: setConfig,
@@ -36991,6 +36695,205 @@ function McpAddModal({ t, onClose, onSaved, onChanged }) {
36991
36695
  }, error))
36992
36696
  });
36993
36697
  }
36698
+ //#endregion
36699
+ //#region src/client/features/mcp/StatusPanel.tsx
36700
+ const EMPTY_STATUS$1 = {
36701
+ entries: [],
36702
+ observedAt: "",
36703
+ totals: {
36704
+ all: 0,
36705
+ connected: 0,
36706
+ degraded: 0,
36707
+ failed: 0,
36708
+ needsCredentials: 0,
36709
+ orphaned: 0,
36710
+ disabled: 0,
36711
+ foreign: 0
36712
+ },
36713
+ directObservationOnly: true
36714
+ };
36715
+ /** DSH-native MCP inventory with a per-state overview and per-service detail. */
36716
+ function McpStatusPanel({ t, credentials }) {
36717
+ const [payload, setPayload] = (0, react.useState)(EMPTY_STATUS$1);
36718
+ const [loading, setLoading] = (0, react.useState)(true);
36719
+ const [error, setError] = (0, react.useState)(void 0);
36720
+ const [filter, setFilter] = (0, react.useState)("all");
36721
+ const [search, setSearch] = (0, react.useState)("");
36722
+ const [view, setView] = useWorkspaceView();
36723
+ const [selected, setSelected] = (0, react.useState)(void 0);
36724
+ const [editing, setEditing] = (0, react.useState)();
36725
+ const [adding, setAdding] = (0, react.useState)(false);
36726
+ const observe = async (id) => {
36727
+ const refreshed = await fetchMcpStatus();
36728
+ setPayload(refreshed);
36729
+ const current = refreshed.entries.find((item) => item.id === id);
36730
+ if (!current) throw new Error(t("mcpEntryGone"));
36731
+ setSelected(current);
36732
+ return current;
36733
+ };
36734
+ const retry = (id) => withBusyOperation(async () => {
36735
+ await retryMcpMounts();
36736
+ return observe(id);
36737
+ });
36738
+ const reauthorize = (id, serverName) => withBusyOperation(async () => {
36739
+ await reauthorizeMcpServer(serverName);
36740
+ return observe(id);
36741
+ });
36742
+ const refresh = () => {
36743
+ setLoading(true);
36744
+ setError(void 0);
36745
+ fetchMcpStatus().then(setPayload).catch((caught) => {
36746
+ setError(clientErrorMessage(t, caught));
36747
+ }).finally(() => setLoading(false));
36748
+ };
36749
+ const toggle = (entry) => {
36750
+ const suiteId = entry.suiteId;
36751
+ const serverKey = entry.serverKey;
36752
+ if (suiteId === void 0 || serverKey === void 0) return;
36753
+ setError(void 0);
36754
+ withBusyOperation(() => setMcpServerEnabled(suiteId, serverKey, entry.state === "disabled")).then(() => fetchMcpStatus()).then(setPayload).catch((caught) => {
36755
+ setError(clientErrorMessage(t, caught));
36756
+ });
36757
+ };
36758
+ (0, react.useEffect)(() => {
36759
+ refresh();
36760
+ }, []);
36761
+ const { activeEntries, filtered, filterCounts } = deriveMcpStatusViewModel(payload, filter, search);
36762
+ const filterId = "mcp-status-filter";
36763
+ const panelProps = {
36764
+ role: "tabpanel",
36765
+ id: `${filterId}-${filter}-panel`,
36766
+ "aria-labelledby": `${filterId}-${filter}`
36767
+ };
36768
+ return (0, react.createElement)("div", { className: mcp_status_module_default.surface }, (0, react.createElement)(PanelHeader, {
36769
+ title: t("mcpStatusTitle"),
36770
+ subtitle: t("mcpStatusSubtitle"),
36771
+ actions: (0, react.createElement)(PanelActions, {
36772
+ addLabel: t("panelAdd"),
36773
+ onAdd: () => setAdding(true),
36774
+ refreshLabel: t("refresh"),
36775
+ onRefresh: refresh,
36776
+ busy: loading
36777
+ })
36778
+ }), (0, react.createElement)(SearchFilterToolbar, {
36779
+ className: mcp_status_module_default.toolbar,
36780
+ search,
36781
+ searchLabel: t("mcpSearch"),
36782
+ searchPlaceholder: t("mcpSearch"),
36783
+ onSearchChange: setSearch,
36784
+ filters: MCP_FILTERS.map((kind) => ({
36785
+ id: kind,
36786
+ label: filterLabel(t, kind),
36787
+ count: filterCounts[kind],
36788
+ active: filter === kind,
36789
+ onSelect: () => setFilter(kind),
36790
+ hint: mcpFilterHint(t, kind)
36791
+ })),
36792
+ filterId,
36793
+ filterLabel: t("mcpStatusTitle"),
36794
+ view,
36795
+ toListLabel: t("switchToList"),
36796
+ toGridLabel: t("switchToGrid"),
36797
+ onViewChange: (nextView) => setView(nextView)
36798
+ }), error !== void 0 ? (0, react.createElement)("div", {
36799
+ className: mcp_status_module_default.error,
36800
+ ...panelProps
36801
+ }, error, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
36802
+ variant: "ghost",
36803
+ size: "sm",
36804
+ onClick: refresh
36805
+ }, t("mcpRetry"))) : loading && activeEntries.length === 0 ? (0, react.createElement)("div", {
36806
+ className: mcp_status_module_default.empty,
36807
+ ...panelProps
36808
+ }, t("loading")) : filtered.length === 0 ? (0, react.createElement)("div", {
36809
+ className: mcp_status_module_default.empty,
36810
+ ...panelProps
36811
+ }, t("mcpEmpty")) : (0, react.createElement)(ResourceCollection, {
36812
+ view,
36813
+ ...panelProps
36814
+ }, filtered.map((entry) => (0, react.createElement)(McpCard, {
36815
+ key: entry.id,
36816
+ entry,
36817
+ t,
36818
+ onClick: () => setSelected(entry),
36819
+ onToggle: () => toggle(entry),
36820
+ onEdit: () => setEditing(entry)
36821
+ }))), adding ? (0, react.createElement)(McpAddModal, {
36822
+ t,
36823
+ onClose: () => setAdding(false),
36824
+ onSaved: () => {
36825
+ setAdding(false);
36826
+ refresh();
36827
+ }
36828
+ }) : null, selected === void 0 ? null : (0, react.createElement)(McpDetailModal, {
36829
+ entry: selected,
36830
+ t,
36831
+ credentials,
36832
+ backend: payload.backend ?? "builtin",
36833
+ onClose: () => {
36834
+ setSelected(void 0);
36835
+ refresh();
36836
+ },
36837
+ onRetry: retry,
36838
+ onReauthorize: reauthorize,
36839
+ onRefresh: observe
36840
+ }), editing === void 0 ? null : (0, react.createElement)(McpConfigModal, {
36841
+ entry: editing,
36842
+ t,
36843
+ onClose: () => setEditing(void 0),
36844
+ onSaved: refresh
36845
+ }));
36846
+ }
36847
+ /**
36848
+ * One inventory card: the server name with its state tag on the identity row
36849
+ * and the enable switch on its trailing edge; the endpoint on the body row;
36850
+ * tool count and transport on the source row. The reason text, the state
36851
+ * label's long form, and the remaining actions (retry, reauthorize,
36852
+ * configuration) live in the detail dialog, so a wall of failing cards stays
36853
+ * scannable.
36854
+ */
36855
+ function McpCard({ entry, t, onClick, onToggle, onEdit }) {
36856
+ const interactive = interactiveCardProps(onClick);
36857
+ const toolCount = entry.tools.length === 1 ? t("mcpTool") : t("mcpTools");
36858
+ const switchable = entry.suiteId !== void 0 && entry.serverKey !== void 0 && entry.state !== "foreign";
36859
+ const disabled = entry.state === "disabled";
36860
+ const displayName = mcpDisplayName(entry);
36861
+ return (0, react.createElement)(ResourceCard, {
36862
+ state: mcpCardState(entry.state),
36863
+ surface: "mcp",
36864
+ ...interactive
36865
+ }, (0, react.createElement)("div", { className: resource_card_module_default.rowId }, (0, react.createElement)("span", {
36866
+ className: `${resource_card_module_default.name} ${resource_card_module_default.nameMono}`,
36867
+ title: entry.name
36868
+ }, displayName), (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", {
36869
+ type: "button",
36870
+ className: resource_card_module_default.iconBtn,
36871
+ title: t("panelEdit"),
36872
+ "aria-label": `${t("panelEdit")} ${displayName}`,
36873
+ onClick: (event) => {
36874
+ event.stopPropagation();
36875
+ onEdit();
36876
+ }
36877
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutlineMedium)) : null, (0, react.createElement)("span", {
36878
+ className: resource_card_module_default.switchWrap,
36879
+ onClick: (event) => event.stopPropagation()
36880
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
36881
+ checked: !disabled,
36882
+ disabled: !switchable,
36883
+ label: disabled ? t("enable") : t("disable"),
36884
+ title: disabled ? t("enable") : t("disable"),
36885
+ onChange: onToggle
36886
+ }))), (0, react.createElement)("p", { className: `${resource_card_module_default.rowBody} ${resource_card_module_default.monoLine}` }, entry.endpoint ?? t("mcpObservedEndpoint")), (0, react.createElement)("div", { className: resource_card_module_default.rowFoot }, (0, react.createElement)("span", {
36887
+ className: resource_card_module_default.provenance,
36888
+ title: entry.suiteId ?? entry.source
36889
+ }, entry.kind === "plugin" ? entry.suiteId ?? entry.source ?? "—" : t("mcpDirect")), (0, react.createElement)("span", { className: resource_card_module_default.separator }, "·"), (0, react.createElement)("span", { className: resource_card_module_default.count }, (0, react.createElement)("span", { className: resource_card_module_default.countValue }, String(entry.tools.length)), " ", toolCount), (0, react.createElement)("span", { className: resource_card_module_default.separator }, "·"), (0, react.createElement)("span", { className: resource_card_module_default.count }, entry.transport)));
36890
+ }
36891
+ /**
36892
+ * The detail dialog owns every action and every long text: state, reason,
36893
+ * credentials, config, tools, and the retry control with its in-place result
36894
+ * echo. The state pill is dropped entirely — the dot and the reason box carry
36895
+ * that information without a second red stamp.
36896
+ */
36994
36897
  function filterLabel(t, kind) {
36995
36898
  if (kind === "plugin") return t("mcpPlugin");
36996
36899
  if (kind === "direct") return t("mcpDirect");
@@ -37004,59 +36907,8 @@ function mcpFilterHint(t, kind) {
37004
36907
  if (kind === "disabled") return t("mcpFilterDisabledHint");
37005
36908
  return t("mcpFilterAllHint");
37006
36909
  }
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
- }
37058
36910
  //#endregion
37059
- //#region src/client/features/lsp-status/lsp-status-view-model.ts
36911
+ //#region src/client/features/lsp/lsp-status-view-model.ts
37060
36912
  /** Filter tabs in display order: scope first, the switched-off rows last. */
37061
36913
  const LSP_FILTERS = [
37062
36914
  "all",
@@ -37116,7 +36968,7 @@ function severity(state) {
37116
36968
  return 5;
37117
36969
  }
37118
36970
  //#endregion
37119
- //#region src/client/LspStatusPanel.tsx
36971
+ //#region src/client/features/lsp/LspStatusPanel.tsx
37120
36972
  /**
37121
36973
  * LSP status panel: declared language servers of enabled suites with their
37122
36974
  * mount state. Rows come from the declaration-and-diagnostic model — the DSH
@@ -37203,6 +37055,12 @@ function LspStatusPanel({ t }) {
37203
37055
  };
37204
37056
  }, [anyStarting]);
37205
37057
  const { filtered, filterCounts } = deriveLspStatusViewModel(payload, filter, search);
37058
+ const filterId = "lsp-status-filter";
37059
+ const panelProps = {
37060
+ role: "tabpanel",
37061
+ id: `${filterId}-${filter}-panel`,
37062
+ "aria-labelledby": `${filterId}-${filter}`
37063
+ };
37206
37064
  return (0, react.createElement)("div", { className: mcp_status_module_default.surface }, (0, react.createElement)(PanelHeader, {
37207
37065
  title: t("lspStatusTitle"),
37208
37066
  subtitle: t("lspStatusSubtitle"),
@@ -37237,15 +37095,29 @@ function LspStatusPanel({ t }) {
37237
37095
  onSelect: () => setFilter(key),
37238
37096
  hint: lspFilterHint(t, key)
37239
37097
  })),
37098
+ filterId,
37099
+ filterLabel: t("lspStatusTitle"),
37240
37100
  view,
37241
37101
  toListLabel: t("switchToList"),
37242
37102
  toGridLabel: t("switchToGrid"),
37243
37103
  onViewChange: (nextView) => setView(nextView)
37244
- }), error !== void 0 ? (0, react.createElement)("div", { className: mcp_status_module_default.error }, error, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
37104
+ }), error !== void 0 ? (0, react.createElement)("div", {
37105
+ className: mcp_status_module_default.error,
37106
+ ...panelProps
37107
+ }, error, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
37245
37108
  variant: "ghost",
37246
37109
  size: "sm",
37247
37110
  onClick: refresh
37248
- }, t("mcpRetry"))) : loading && payload.entries.length === 0 ? (0, react.createElement)("div", { className: mcp_status_module_default.empty }, t("loading")) : filtered.length === 0 ? (0, react.createElement)("div", { className: mcp_status_module_default.empty }, t("lspEmpty")) : (0, react.createElement)(ResourceCollection, { view }, filtered.map((entry) => (0, react.createElement)(LspRow, {
37111
+ }, t("mcpRetry"))) : loading && payload.entries.length === 0 ? (0, react.createElement)("div", {
37112
+ className: mcp_status_module_default.empty,
37113
+ ...panelProps
37114
+ }, t("loading")) : filtered.length === 0 ? (0, react.createElement)("div", {
37115
+ className: mcp_status_module_default.empty,
37116
+ ...panelProps
37117
+ }, t("lspEmpty")) : (0, react.createElement)(ResourceCollection, {
37118
+ view,
37119
+ ...panelProps
37120
+ }, filtered.map((entry) => (0, react.createElement)(LspRow, {
37249
37121
  key: entry.id,
37250
37122
  entry,
37251
37123
  t,
@@ -37385,6 +37257,17 @@ function lspDotState(state) {
37385
37257
  if (state === "disabled") return "idle";
37386
37258
  return "warning";
37387
37259
  }
37260
+ /**
37261
+ * The inventory card's state for one row. The detail band derives its edge from
37262
+ * this same value, so a server cannot read one colour on its card and another
37263
+ * in its detail dialog.
37264
+ */
37265
+ function lspCardState(state) {
37266
+ if (state === "mounted") return "active";
37267
+ if (state === "disabled") return "disabled";
37268
+ if (state === "failed" || state === "conflict") return "error";
37269
+ return "warning";
37270
+ }
37388
37271
  function lspTagTone(state) {
37389
37272
  if (state === "mounted") return "success";
37390
37273
  if (state === "failed" || state === "conflict") return "danger";
@@ -37397,20 +37280,11 @@ function lspTagTone(state) {
37397
37280
  * the declaring suite and the extension count on the source row.
37398
37281
  */
37399
37282
  function LspRow({ entry, t, onOpen, onToggle, onEdit }) {
37400
- const interactive = {
37401
- role: "button",
37402
- tabIndex: 0,
37403
- onClick: onOpen,
37404
- onKeyDown: (event) => {
37405
- if (event.key !== "Enter" && event.key !== " ") return;
37406
- event.preventDefault();
37407
- onOpen();
37408
- }
37409
- };
37283
+ const interactive = interactiveCardProps(onOpen);
37410
37284
  const extensions = Object.keys(entry.extensions).length;
37411
37285
  const disabled = entry.state === "disabled";
37412
37286
  return (0, react.createElement)(ResourceCard, {
37413
- state: entry.state === "mounted" ? "active" : disabled ? "disabled" : entry.state === "failed" || entry.state === "conflict" ? "error" : "warning",
37287
+ state: lspCardState(entry.state),
37414
37288
  surface: "lsp",
37415
37289
  ...interactive
37416
37290
  }, (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", {
@@ -37436,6 +37310,11 @@ function LspRow({ entry, t, onOpen, onToggle, onEdit }) {
37436
37310
  }, entry.kind === "plugin" ? entry.suiteName : t("lspDirect")), (0, react.createElement)("span", { className: resource_card_module_default.separator }, "·"), (0, react.createElement)("span", { className: resource_card_module_default.count }, (0, react.createElement)("span", { className: resource_card_module_default.countValue }, String(extensions)), " ", t("lspExtensionCount"))));
37437
37311
  }
37438
37312
  function LspDetailModal({ entry, t, onClose }) {
37313
+ const guidance = failureGuidanceKey({
37314
+ code: entry.code,
37315
+ reason: entry.reason,
37316
+ causes: entry.causes
37317
+ });
37439
37318
  return (0, react.createElement)(DetailModal, {
37440
37319
  open: true,
37441
37320
  onClose,
@@ -37447,7 +37326,16 @@ function LspDetailModal({ entry, t, onClose }) {
37447
37326
  variant: "ghost",
37448
37327
  onClick: onClose
37449
37328
  }, t("detailDone"))),
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, {
37329
+ children: (0, react.createElement)("div", null, (0, react.createElement)(StatusBand, {
37330
+ t,
37331
+ dot: lspDotState(entry.state),
37332
+ tone: bandTone(lspCardState(entry.state)),
37333
+ labels: (0, react.createElement)(react.Fragment, null, (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),
37334
+ ...guidance === void 0 ? {} : { guidance },
37335
+ ...entry.reason === void 0 ? {} : { reason: entry.reason },
37336
+ ...entry.causes === void 0 ? {} : { causes: entry.causes },
37337
+ mono: [entry.command, ...entry.args].join(" ")
37338
+ }), (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.suiteName : t("lspDirect"), false), kvCell(t("detailTypeLabel"), entry.kind === "plugin" ? t("panelSourcePlugin") : t("panelSourceUser"), false), kvCell(t("lspDeclaredInLabel"), entry.kind === "plugin" ? `lsp.json · ${entry.suiteName}` : "lsp.json", true))), (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, {
37451
37339
  key: extension,
37452
37340
  name: extension,
37453
37341
  summary: language,
@@ -37480,13 +37368,6 @@ function LspConfigModal({ entry, t, onClose, onSaved }) {
37480
37368
  })
37481
37369
  });
37482
37370
  }
37483
- /** One label/value pair in a detail dialog's overview grid. */
37484
- function kv$1(label, value, mono = false) {
37485
- return (0, react.createElement)("div", null, (0, react.createElement)("dt", { className: panel_module_default.kvKey }, label), (0, react.createElement)("dd", {
37486
- className: mono ? `${panel_module_default.kvValue} ${panel_module_default.kvValueMono}` : panel_module_default.kvValue,
37487
- title: value
37488
- }, value));
37489
- }
37490
37371
  function stateLabel(t, state) {
37491
37372
  if (state === "mounted") return t("lspMounted");
37492
37373
  if (state === "starting") return t("lspStarting");
@@ -37512,7 +37393,7 @@ function commandCallName(name) {
37512
37393
  return name.replaceAll("/", "-").replaceAll("\\", "-").toLowerCase();
37513
37394
  }
37514
37395
  //#endregion
37515
- //#region src/client/features/personas/RoleMetadataFields.tsx
37396
+ //#region src/client/ui/RoleMetadataFields.tsx
37516
37397
  /** Structured controls edit the same frontmatter as the raw Markdown editor. */
37517
37398
  function RoleMetadataFields(props) {
37518
37399
  let fields;
@@ -37661,6 +37542,13 @@ const HIDDEN_META = /* @__PURE__ */ new Set([
37661
37542
  "disabled",
37662
37543
  "name"
37663
37544
  ]);
37545
+ /** Routing keys an agent persona renders as its own rows, not in the catch-all. */
37546
+ const ROUTING_META = /* @__PURE__ */ new Set([
37547
+ "model",
37548
+ "provider",
37549
+ "reasoning_effort",
37550
+ "reasoningEffort"
37551
+ ]);
37664
37552
  /** The entry's document, its overview, and its metadata. */
37665
37553
  function UserEntryDetailModal(props) {
37666
37554
  const { t, kind, entry } = props;
@@ -37669,18 +37557,14 @@ function UserEntryDetailModal(props) {
37669
37557
  const provenance = entry.origin === "user" ? t("panelSourceUser") : t("panelSourcePlugin");
37670
37558
  const title = kind === "commands" ? `/${commandCallName(entry.name)}` : entry.name;
37671
37559
  const docName = kind === "skills" ? "SKILL.md" : `${entry.name}.md`;
37672
- const metaPairs = Object.entries(entry.metadata).filter(([key]) => !HIDDEN_META.has(key));
37560
+ const metaPairs = Object.entries(entry.metadata).filter(([key]) => !HIDDEN_META.has(key) && !(kind === "agents" && ROUTING_META.has(key)));
37673
37561
  return (0, react.createElement)(DetailModal, {
37674
37562
  open: true,
37675
37563
  onClose: props.onClose,
37676
37564
  title,
37677
37565
  description: `${t(NOUN_KEY[kind])} · ${provenance}`,
37678
- closeLabel: t("cancel"),
37679
- footer: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
37680
- variant: "ghost",
37681
- onClick: props.onClose
37682
- }, t("detailDone"))
37683
- }, (0, react.createElement)("div", { className: panel_module_default.hero }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: entry.disabled ? "idle" : "done" }), (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: entry.disabled ? "quiet" : "success" }, entry.disabled ? t("disabledLabel") : t("enabledLabel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, null, provenance), entry.suiteName === void 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "quiet" }, entry.suiteName)), (0, react.createElement)("p", { className: panel_module_default.heroMono }, entry.path))), (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(t("sourceLabel"), entry.suiteName ?? t("panelSourceUser")), kv(t("detailTypeLabel"), entry.origin === "user" ? t("panelSourceUser") : t("panelSourcePlugin")), kv(t("diskPathLabel"), entry.path, true), updated === null ? null : kv(t("updatedLabel"), updated), metaPairs.length === 0 ? null : kv(metaPairs.map(([key, value]) => `${key}: ${typeof value === "string" ? value : JSON.stringify(value)}`).join(" · "), t("detailMetadata")))), entry.description === "" ? null : (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("detailDescriptionLabel")), (0, react.createElement)("p", { className: panel_module_default.detailProse }, entry.description)), (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t(kind === "skills" ? "docSectionSkill" : kind === "commands" ? "docSectionCommand" : "docSectionPersona")), (0, react.createElement)(DetailRows, null, (0, react.createElement)(DetailRow, {
37566
+ closeLabel: t("cancel")
37567
+ }, (0, react.createElement)("div", { className: panel_module_default.hero }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: entry.disabled ? "idle" : "done" }), (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: entry.disabled ? "quiet" : "success" }, entry.disabled ? t("disabledLabel") : t("enabledLabel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, null, provenance), entry.suiteName === void 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "quiet" }, entry.suiteName)), (0, react.createElement)("p", { className: panel_module_default.heroMono }, entry.path))), (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.suiteName ?? t("panelSourceUser")), kvCell(t("detailTypeLabel"), entry.origin === "user" ? t("panelSourceUser") : t("panelSourcePlugin")), kvCell(t("diskPathLabel"), entry.path, true), updated === null ? null : kvCell(t("updatedLabel"), updated), kind === "agents" ? routingRows(t, entry.metadata) : null, metaPairs.length === 0 ? null : kvCell(t("detailMetadata"), metaPairs.map(([key, value]) => `${key}: ${typeof value === "string" ? value : JSON.stringify(value)}`).join(" · ")))), entry.description === "" ? null : (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t("detailDescriptionLabel")), (0, react.createElement)("p", { className: panel_module_default.detailProse }, entry.description)), (0, react.createElement)("div", { className: panel_module_default.block }, (0, react.createElement)("h4", { className: panel_module_default.blockHead }, t(kind === "skills" ? "docSectionSkill" : kind === "commands" ? "docSectionCommand" : "docSectionPersona")), (0, react.createElement)(DetailRows, null, (0, react.createElement)(DetailRow, {
37684
37568
  name: docName,
37685
37569
  summary: t("detailDocHint"),
37686
37570
  open,
@@ -37691,11 +37575,18 @@ function UserEntryDetailModal(props) {
37691
37575
  })
37692
37576
  }))));
37693
37577
  }
37694
- function kv(label, value, mono = false) {
37695
- return (0, react.createElement)("div", null, (0, react.createElement)("dt", { className: panel_module_default.kvKey }, label), (0, react.createElement)("dd", {
37696
- className: mono ? `${panel_module_default.kvValue} ${panel_module_default.kvValueMono}` : panel_module_default.kvValue,
37697
- title: value
37698
- }, value));
37578
+ /** Routing frontmatter rows for agent personas: model, provider, reasoning effort. */
37579
+ function routingRows(t, metadata) {
37580
+ const model = typeof metadata["model"] === "string" ? metadata["model"] : void 0;
37581
+ const provider = typeof metadata["provider"] === "string" ? metadata["provider"] : void 0;
37582
+ const snake = typeof metadata["reasoning_effort"] === "string" ? metadata["reasoning_effort"] : void 0;
37583
+ const camel = typeof metadata["reasoningEffort"] === "string" ? metadata["reasoningEffort"] : void 0;
37584
+ const reasoning = snake ?? camel;
37585
+ return [
37586
+ model === void 0 ? null : kvCell(t("detailModelLabel"), model, true, "model"),
37587
+ provider === void 0 ? null : kvCell(t("detailProviderLabel"), provider, true, "provider"),
37588
+ reasoning === void 0 ? null : kvCell(t("detailReasoningLabel"), reasoning, true, "reasoning")
37589
+ ];
37699
37590
  }
37700
37591
  //#endregion
37701
37592
  //#region src/client/ui/UserPanelSurface.tsx
@@ -37743,6 +37634,7 @@ function UserPanelSurface(props) {
37743
37634
  const [busy, setBusy] = (0, react.useState)(false);
37744
37635
  const [search, setSearch] = (0, react.useState)("");
37745
37636
  const [filter, setFilter] = (0, react.useState)("all");
37637
+ const filterId = `${kind}-panel-filter`;
37746
37638
  const [view, setView] = useWorkspaceView();
37747
37639
  const [editor, setEditor] = (0, react.useState)(void 0);
37748
37640
  const [showPreview, setShowPreview] = (0, react.useState)(false);
@@ -37814,6 +37706,8 @@ function UserPanelSurface(props) {
37814
37706
  setDetail(entry);
37815
37707
  };
37816
37708
  const openEdit = (entry) => {
37709
+ const routingEditable = entry.origin === "plugin" && kind === "agents";
37710
+ if (entry.origin !== "user" && !routingEditable) return;
37817
37711
  setError(void 0);
37818
37712
  setShowPreview(false);
37819
37713
  setEditor({
@@ -37821,7 +37715,8 @@ function UserPanelSurface(props) {
37821
37715
  id: entry.id ?? entry.name,
37822
37716
  name: entry.name,
37823
37717
  path: entry.path,
37824
- text: entry.rawText
37718
+ text: entry.rawText,
37719
+ ...routingEditable ? { routingOnly: true } : {}
37825
37720
  });
37826
37721
  };
37827
37722
  const toggleDisabled = (entry) => {
@@ -37899,20 +37794,27 @@ function UserPanelSurface(props) {
37899
37794
  onSelect: () => setFilter("disabled")
37900
37795
  }
37901
37796
  ],
37797
+ filterId,
37798
+ filterLabel: panelTitle,
37902
37799
  view,
37903
37800
  toListLabel: t("switchToList"),
37904
37801
  toGridLabel: t("switchToGrid"),
37905
37802
  onViewChange: (nextView) => setView(nextView)
37906
- }), (0, react.createElement)("div", { className: panel_module_default.body }, loading && entries.length === 0 ? (0, react.createElement)("div", { className: panel_module_default.empty }, t("loading")) : visible.length === 0 ? (0, react.createElement)("div", { className: panel_module_default.empty }, t("panelEmpty")) : (0, react.createElement)(ResourceCollection, { view }, visible.map((entry) => (0, react.createElement)(UserEntryRow, {
37803
+ }), (0, react.createElement)("div", {
37804
+ className: panel_module_default.body,
37805
+ role: "tabpanel",
37806
+ id: `${filterId}-${filter}-panel`,
37807
+ "aria-labelledby": `${filterId}-${filter}`
37808
+ }, loading && entries.length === 0 ? (0, react.createElement)("div", { className: panel_module_default.empty }, t("loading")) : visible.length === 0 ? (0, react.createElement)("div", { className: panel_module_default.empty }, t("panelEmpty")) : (0, react.createElement)(ResourceCollection, { view }, visible.map((entry) => (0, react.createElement)(UserEntryRow, {
37907
37809
  key: entry.id ?? entry.name,
37908
37810
  entry,
37909
37811
  t,
37910
37812
  kind,
37911
37813
  busy,
37912
37814
  onOpen: () => openDetail(entry),
37913
- onEdit: () => openEdit(entry),
37815
+ onEdit: entry.origin === "user" || entry.origin === "plugin" && kind === "agents" ? () => openEdit(entry) : void 0,
37914
37816
  onToggle: () => toggleDisabled(entry),
37915
- onDelete: () => openDelete(entry)
37817
+ onDelete: entry.origin === "user" ? () => openDelete(entry) : void 0
37916
37818
  })))), (0, react.createElement)(EntryEditorModal, {
37917
37819
  t,
37918
37820
  open: editor !== void 0,
@@ -37931,7 +37833,7 @@ function UserPanelSurface(props) {
37931
37833
  nameLabel: t("panelNamePh"),
37932
37834
  namePlaceholder: t(kind === "skills" ? "editorNamePhSkill" : kind === "commands" ? "editorNamePhCommand" : "editorNamePhPersona"),
37933
37835
  textLabel: t(kind === "skills" ? "panelSkillTextLabel" : kind === "commands" ? "panelCommandTextLabel" : "panelPersonaTextLabel"),
37934
- footerHint: t(editor?.mode === "create" ? "editorFooterCreate" : "editorFooterEdit"),
37836
+ footerHint: t(editor?.mode === "create" ? "editorFooterCreate" : editor?.routingOnly === true ? "editorFooterRouting" : "editorFooterEdit"),
37935
37837
  busy,
37936
37838
  saveError: error,
37937
37839
  saveLabel: editor?.mode === "create" ? t("editorCreate") : t("panelSave"),
@@ -37992,14 +37894,14 @@ function UserEntryRow(props) {
37992
37894
  state: entry.disabled ? "disabled" : "active",
37993
37895
  surface: props.kind === "agents" ? "personas" : props.kind,
37994
37896
  ...interactive
37995
- }, (0, react.createElement)("div", { className: resource_card_module_default.rowId }, (0, react.createElement)("span", { className: mono ? `${resource_card_module_default.name} ${resource_card_module_default.nameMono}` : resource_card_module_default.name }, title), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "neutral" }, entry.origin === "user" ? t("panelSourceUser") : t("panelSourcePlugin"))), (0, react.createElement)("div", { className: resource_card_module_default.rowActions }, (0, react.createElement)("button", {
37897
+ }, (0, react.createElement)("div", { className: resource_card_module_default.rowId }, (0, react.createElement)("span", { className: mono ? `${resource_card_module_default.name} ${resource_card_module_default.nameMono}` : resource_card_module_default.name }, title), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "neutral" }, entry.origin === "user" ? t("panelSourceUser") : t("panelSourcePlugin"))), (0, react.createElement)("div", { className: resource_card_module_default.rowActions }, props.onEdit === void 0 ? null : (0, react.createElement)("button", {
37996
37898
  type: "button",
37997
37899
  className: `${resource_card_module_default.iconBtn} ${resource_card_module_default.revealOnHover}`,
37998
37900
  "aria-label": t("panelEditTitle"),
37999
37901
  disabled: props.busy,
38000
37902
  title: t("panelEditTitle"),
38001
37903
  onClick: stop(props.onEdit)
38002
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutlineMedium)), (0, react.createElement)("button", {
37904
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutlineMedium)), props.onDelete === void 0 ? null : (0, react.createElement)("button", {
38003
37905
  type: "button",
38004
37906
  className: `${resource_card_module_default.iconBtn} ${resource_card_module_default.iconBtnDanger} ${resource_card_module_default.revealOnHover}`,
38005
37907
  "aria-label": t("panelDelete"),
@@ -38021,17 +37923,15 @@ function UserEntryRow(props) {
38021
37923
  }, entry.origin === "plugin" && entry.suiteName !== void 0 ? entry.suiteName : entry.path)));
38022
37924
  }
38023
37925
  //#endregion
38024
- //#region src/client/workspace.module.css
37926
+ //#region src/client/workspace/workspace.module.css
38025
37927
  var workspace_module_default = {
38026
- "pageMode": "l0H8fW_pageMode",
38027
- "tab": "l0H8fW_tab",
38028
- "tabOn": "l0H8fW_tabOn",
38029
- "tabPanel": "l0H8fW_tabPanel",
38030
- "tabRow": "l0H8fW_tabRow",
38031
- "workspace": "l0H8fW_workspace"
37928
+ "pageMode": "r5yctG_pageMode",
37929
+ "tabPanel": "r5yctG_tabPanel",
37930
+ "tabRow": "r5yctG_tabRow",
37931
+ "workspace": "r5yctG_workspace"
38032
37932
  };
38033
37933
  //#endregion
38034
- //#region src/client/PluginWorkspace.tsx
37934
+ //#region src/client/workspace/PluginWorkspace.tsx
38035
37935
  /**
38036
37936
  * The plugin workspace: one page, six top tabs.
38037
37937
  *
@@ -38084,19 +37984,54 @@ function PluginWorkspace({ t, credentials, mode = "settings" }) {
38084
37984
  return (0, react.createElement)("div", {
38085
37985
  className: mode === "page" ? `${workspace_module_default.workspace} ${workspace_module_default.pageMode}` : workspace_module_default.workspace,
38086
37986
  "data-agent-plugins-workspace": true
38087
- }, (0, react.createElement)("nav", {
37987
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.SegmentedTabs, {
38088
37988
  className: workspace_module_default.tabRow,
38089
- role: "tablist"
38090
- }, TAB_ORDER.map((tab) => (0, react.createElement)("button", {
38091
- key: tab,
38092
- type: "button",
38093
- role: "tab",
38094
- "aria-selected": active === tab,
38095
- className: active === tab ? workspace_module_default.tabOn : workspace_module_default.tab,
38096
- onClick: () => select(tab)
38097
- }, labelKeys[tab]))), (0, react.createElement)("div", {
37989
+ label: labelKeys.market,
37990
+ value: active,
37991
+ onChange: select,
37992
+ items: [
37993
+ {
37994
+ value: "market",
37995
+ label: labelKeys.market,
37996
+ id: "agent-plugins-tab-market",
37997
+ panelId: "agent-plugins-panel"
37998
+ },
37999
+ {
38000
+ value: "skills",
38001
+ label: labelKeys.skills,
38002
+ id: "agent-plugins-tab-skills",
38003
+ panelId: "agent-plugins-panel"
38004
+ },
38005
+ {
38006
+ value: "commands",
38007
+ label: labelKeys.commands,
38008
+ id: "agent-plugins-tab-commands",
38009
+ panelId: "agent-plugins-panel"
38010
+ },
38011
+ {
38012
+ value: "personas",
38013
+ label: labelKeys.personas,
38014
+ id: "agent-plugins-tab-personas",
38015
+ panelId: "agent-plugins-panel"
38016
+ },
38017
+ {
38018
+ value: "mcp",
38019
+ label: labelKeys.mcp,
38020
+ id: "agent-plugins-tab-mcp",
38021
+ panelId: "agent-plugins-panel"
38022
+ },
38023
+ {
38024
+ value: "lsp",
38025
+ label: labelKeys.lsp,
38026
+ id: "agent-plugins-tab-lsp",
38027
+ panelId: "agent-plugins-panel"
38028
+ }
38029
+ ]
38030
+ }), (0, react.createElement)("div", {
38098
38031
  className: workspace_module_default.tabPanel,
38099
- role: "tabpanel"
38032
+ role: "tabpanel",
38033
+ id: "agent-plugins-panel",
38034
+ "aria-labelledby": `agent-plugins-tab-${active}`
38100
38035
  }, renderTab(active, t, credentials, mode)));
38101
38036
  }
38102
38037
  function renderTab(tab, t, credentials, mode) {
@@ -38125,26 +38060,190 @@ function renderTab(tab, t, credentials, mode) {
38125
38060
  }
38126
38061
  }
38127
38062
  //#endregion
38128
- //#region src/client/McpPluginCard.tsx
38063
+ //#region src/client/features/settings-card/market-card-form.ts
38129
38064
  /**
38130
- * The Agent Plugins Market card on the host's 插件配置 (plugin configuration)
38131
- * tab: the market feature's configuration entry, named after the market itself.
38065
+ * The market settings card's binding onto the host's published settings-form
38066
+ * model (`@deepseek-ai/dsh-client-ui-primitives.SettingsFormModel`).
38132
38067
  *
38133
- * The card is a renderer. It draws what the bound form projects and reports what
38134
- * the user picks through the injected actions, following the contract every card
38135
- * in this slot uses: controls stage edits, one save commits them, an untouched
38136
- * field keeps following the plugin, and a card whose namespace is not served
38137
- * leaves no trace.
38068
+ * The card's fields are four booleans and one enum — none of them text — so
38069
+ * they bind through custom `SettingsFieldSpec` values whose draft text is the
38070
+ * value's wire spelling (`true`/`false`, the region word) instead of the
38071
+ * published text and number factories. A draft that is not a value the field
38072
+ * accepts blocks the save; an empty draft stages the clear that hands the
38073
+ * field back to the composition layer, which is how "follow the interface
38074
+ * language" and the plugin defaults are expressed. The live host-client probe
38075
+ * is browser-local knowledge, so it rides the projection rather than the
38076
+ * settings document, and a late probe answer cannot overwrite a newer one.
38138
38077
  *
38139
- * @module client/McpPluginCard
38078
+ * @module client/market-card-form
38140
38079
  */
38141
- /** Copy of the boolean switches, in display order. */
38142
- const SWITCH_FIELDS = [
38080
+ /** The boolean switches this card renders, in display order. */
38081
+ const MARKET_SWITCH_FIELDS = [
38143
38082
  "mcpEnhanced",
38144
38083
  "scanProjectLayouts",
38145
38084
  "autoUpdateSources",
38146
38085
  "feedbackEnabled"
38147
38086
  ];
38087
+ /** The region words a stored `downloadRegion` may carry. */
38088
+ const REGION_WORDS = [
38089
+ "auto",
38090
+ "global",
38091
+ "china"
38092
+ ];
38093
+ /**
38094
+ * The segment a region draft answers. An empty draft is the staged clear that
38095
+ * hands the field back to the interface language, which is the `auto` choice;
38096
+ * a draft the field does not accept also reads as `auto` on screen, while
38097
+ * `invalid` reports it and blocks the save.
38098
+ * @param draft - the field's staged text.
38099
+ * @returns the segment value the control highlights.
38100
+ */
38101
+ function regionChoice(draft) {
38102
+ return REGION_WORDS.includes(draft) ? draft : "auto";
38103
+ }
38104
+ /**
38105
+ * A boolean field: the draft text is the value's wire spelling.
38106
+ * @param field - field name inside the namespace section.
38107
+ * @returns the field's conversion spec.
38108
+ */
38109
+ function settingsBooleanField(field) {
38110
+ return {
38111
+ field,
38112
+ format: (value) => typeof value === "boolean" ? String(value) : "",
38113
+ parse: (text) => {
38114
+ const trimmed = text.trim();
38115
+ if (trimmed === "true") return {
38116
+ kind: "set",
38117
+ value: true
38118
+ };
38119
+ if (trimmed === "false") return {
38120
+ kind: "set",
38121
+ value: false
38122
+ };
38123
+ }
38124
+ };
38125
+ }
38126
+ /**
38127
+ * The download-region enum field: the draft text is the stored word.
38128
+ * @param field - field name inside the namespace section.
38129
+ * @returns the field's conversion spec.
38130
+ */
38131
+ function settingsRegionField(field) {
38132
+ return {
38133
+ field,
38134
+ format: (value) => REGION_WORDS.includes(value) ? value : "",
38135
+ parse: (text) => {
38136
+ const trimmed = text.trim();
38137
+ return REGION_WORDS.includes(trimmed) ? {
38138
+ kind: "set",
38139
+ value: trimmed
38140
+ } : void 0;
38141
+ }
38142
+ };
38143
+ }
38144
+ /**
38145
+ * Bind the market settings scope onto the published form model and build the
38146
+ * renderer face for the card.
38147
+ * @param scope - the host configuration form for the market namespace.
38148
+ * @param probeSource - reads the live host-client and region state from the market API.
38149
+ * @returns the model, the injected face, and the disposer releasing the form.
38150
+ */
38151
+ function bindMarketCardForm(scope, probeSource) {
38152
+ const model = new _deepseek_ai_dsh_client_ui_primitives.SettingsFormModel(scope, [
38153
+ settingsBooleanField("mcpEnhanced"),
38154
+ settingsBooleanField("scanProjectLayouts"),
38155
+ settingsBooleanField("autoUpdateSources"),
38156
+ settingsBooleanField("feedbackEnabled"),
38157
+ settingsRegionField("downloadRegion")
38158
+ ]);
38159
+ const actions = model.actions();
38160
+ const stagedActions = {
38161
+ edit: (field, text) => {
38162
+ if (model.shell().saving) return;
38163
+ actions.edit(field, text);
38164
+ },
38165
+ resetField: (field) => {
38166
+ if (model.shell().saving) return;
38167
+ actions.resetField(field);
38168
+ },
38169
+ save: actions.save,
38170
+ discard: () => {
38171
+ if (model.shell().saving) return;
38172
+ actions.discard();
38173
+ }
38174
+ };
38175
+ let probe;
38176
+ let probeStatus = "idle";
38177
+ /** Bumped by every probe read and by dispose so a late answer cannot win. */
38178
+ let probeGeneration = 0;
38179
+ const hostClientMissing = () => probe !== void 0 && !probe.hostClient.available;
38180
+ const compatBlocked = () => model.field("mcpEnhanced").text !== "true" && (probeStatus === "loading" || hostClientMissing());
38181
+ const project = () => {
38182
+ const shell = model.shell();
38183
+ return {
38184
+ ...shell,
38185
+ invalid: shell.invalid || compatBlocked(),
38186
+ mcpEnhanced: model.field("mcpEnhanced"),
38187
+ scanProjectLayouts: model.field("scanProjectLayouts"),
38188
+ autoUpdateSources: model.field("autoUpdateSources"),
38189
+ feedbackEnabled: model.field("feedbackEnabled"),
38190
+ downloadRegion: model.field("downloadRegion"),
38191
+ probe,
38192
+ hostClientMissing: hostClientMissing()
38193
+ };
38194
+ };
38195
+ const store = model.bind(project);
38196
+ /** Read the host-client probe once; a second call while one is in flight is a no-op. */
38197
+ const loadProbe = async () => {
38198
+ if (probeStatus === "loading") return;
38199
+ probeStatus = "loading";
38200
+ const generation = probeGeneration;
38201
+ try {
38202
+ const info = await probeSource();
38203
+ if (generation !== probeGeneration) return;
38204
+ probe = info;
38205
+ } catch {} finally {
38206
+ if (generation === probeGeneration) {
38207
+ probeStatus = "idle";
38208
+ store.set(project());
38209
+ }
38210
+ }
38211
+ };
38212
+ return {
38213
+ model,
38214
+ face: {
38215
+ hooks: { marketCard: store },
38216
+ ...stagedActions,
38217
+ refreshProbe: () => {
38218
+ loadProbe();
38219
+ }
38220
+ },
38221
+ dispose: () => {
38222
+ probeGeneration += 1;
38223
+ model.dispose();
38224
+ }
38225
+ };
38226
+ }
38227
+ //#endregion
38228
+ //#region src/client/features/settings-card/McpPluginCard.tsx
38229
+ /**
38230
+ * The Agent Plugins Market page on the host's Plugins panel: the market
38231
+ * feature's configuration entry, named after the market itself.
38232
+ *
38233
+ * The page's Plugins panel renders every `plugins.item` entry twice: a
38234
+ * `summary` one-liner on the official card, and the `page` form on the
38235
+ * entry's detail page. This component answers both views. The page view is
38236
+ * the host's `SettingsForm` frame around controls bound to the published
38237
+ * `SettingsFormModel` through the market's binding (`market-card-form.ts`):
38238
+ * booleans ride the host Switch atom, the download region rides the host
38239
+ * SegmentedControl atom, and every control stages through the form's actions
38240
+ * so one save commits all of them. Leaving the page discards the staged
38241
+ * edits — the host form's own contract, which this entry adopts.
38242
+ *
38243
+ * @module client/McpPluginCard
38244
+ */
38245
+ /** Copy of the boolean switches, in display order. */
38246
+ const SWITCH_FIELDS = MARKET_SWITCH_FIELDS;
38148
38247
  /** Copy keys of each switch. */
38149
38248
  const SWITCH_COPY = {
38150
38249
  mcpEnhanced: {
@@ -38164,6 +38263,8 @@ const SWITCH_COPY = {
38164
38263
  description: "feedbackToggleDesc"
38165
38264
  }
38166
38265
  };
38266
+ /** Copy key of the summary one-liner the official card renders. */
38267
+ const SUMMARY_KEY = "marketCardDesc";
38167
38268
  /** The overridden badge and the reset that hands the field back to the plugin. */
38168
38269
  function OverrideBadge(props) {
38169
38270
  return (0, react.createElement)("span", { className: market_module_default.pluginFieldBadges }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tag, { tone: "neutral" }, props.t("settingOverridden")), (0, react.createElement)("button", {
@@ -38173,350 +38274,110 @@ function OverrideBadge(props) {
38173
38274
  onClick: props.onReset
38174
38275
  }, props.t("settingReset")));
38175
38276
  }
38277
+ /** The head of one field row: its label and the override state above the control. */
38278
+ function FieldHead(props) {
38279
+ return (0, react.createElement)("div", { className: market_module_default.pluginFieldHead }, (0, react.createElement)("div", { className: market_module_default.pluginCardRowLabel }, props.label), props.overridden ? props.badge : null);
38280
+ }
38176
38281
  /** One boolean switch row: its copy, the control, and the reset when it is overridden. */
38177
38282
  function SwitchRow(props) {
38178
38283
  const copy = SWITCH_COPY[props.field];
38179
38284
  const label = props.t(copy.label);
38180
- return (0, react.createElement)("div", { className: market_module_default.pluginCardRow }, (0, react.createElement)("div", { className: market_module_default.pluginCardText }, (0, react.createElement)("div", { className: market_module_default.pluginFieldHead }, (0, react.createElement)("div", { className: market_module_default.pluginCardRowLabel }, label), props.state.overridden ? (0, react.createElement)(OverrideBadge, {
38181
- t: props.t,
38182
- disabled: props.disabled,
38183
- onReset: () => {
38184
- props.onReset(props.field);
38185
- }
38186
- }) : null), (0, react.createElement)("div", { className: market_module_default.pluginCardDesc }, props.t(copy.description))), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
38187
- checked: props.state.value,
38285
+ return (0, react.createElement)("div", { className: market_module_default.pluginCardRow }, (0, react.createElement)("div", { className: market_module_default.pluginCardText }, (0, react.createElement)(FieldHead, {
38286
+ label,
38287
+ overridden: props.state.overridden,
38288
+ badge: (0, react.createElement)(OverrideBadge, {
38289
+ t: props.t,
38290
+ disabled: props.disabled,
38291
+ onReset: () => {
38292
+ props.onReset(props.field);
38293
+ }
38294
+ })
38295
+ }), (0, react.createElement)("div", { className: market_module_default.pluginCardDesc }, props.t(copy.description))), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
38296
+ checked: props.state.text === "true",
38188
38297
  label,
38189
38298
  disabled: props.disabled,
38190
38299
  onChange: () => {
38191
- props.onToggle(props.field);
38300
+ props.onEdit(props.field, props.state.text === "true" ? "false" : "true");
38192
38301
  }
38193
38302
  }));
38194
38303
  }
38304
+ /** The download-region segment options, with the label of each. */
38305
+ const REGION_OPTIONS = [
38306
+ {
38307
+ value: "auto",
38308
+ label: "regionAuto"
38309
+ },
38310
+ {
38311
+ value: "global",
38312
+ label: "regionGlobal"
38313
+ },
38314
+ {
38315
+ value: "china",
38316
+ label: "regionChina"
38317
+ }
38318
+ ];
38195
38319
  function McpPluginCard(props) {
38196
- const { t, useMarketCard, toggle, setRegion, resetField, save, discard, refreshProbe } = props;
38197
- const [open, setOpen] = (0, react.useState)(false);
38320
+ const { t, useMarketCard, edit, resetField, save, discard, refreshProbe } = props;
38198
38321
  const state = useMarketCard((current) => current);
38199
38322
  (0, react.useEffect)(() => {
38200
- refreshProbe();
38201
- }, [refreshProbe]);
38202
- if (!state.available) return null;
38203
- const blocked = !state.writable || state.saving;
38323
+ if (props.view === "page") refreshProbe();
38324
+ }, [refreshProbe, props.view]);
38325
+ if (props.view === "summary") return state.available ? t(SUMMARY_KEY) : null;
38326
+ const disabled = !state.writable || state.saving;
38204
38327
  const region = state.downloadRegion;
38205
- const effectiveRegion = state.probe?.downloadRegion.effective ?? (region.value === "china" ? "china" : "global");
38206
- return (0, react.createElement)("li", { className: open ? `${market_module_default.pluginCard} ${market_module_default.pluginCardOpen}` : market_module_default.pluginCard }, (0, react.createElement)("button", {
38207
- type: "button",
38208
- className: market_module_default.pluginCardHeader,
38209
- "aria-expanded": open,
38210
- onClick: () => {
38211
- setOpen((current) => !current);
38212
- }
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", {
38214
- className: market_module_default.pluginCardReadonly,
38215
- role: "status"
38216
- }, t("mcpCardReadonly")), SWITCH_FIELDS.map((field) => (0, react.createElement)(SwitchRow, {
38217
- key: field,
38218
- t,
38219
- field,
38220
- state: state[field],
38221
- disabled: blocked,
38222
- onToggle: toggle,
38223
- onReset: resetField
38224
- })), state.hostClientMissing && !state.mcpEnhanced.value ? (0, react.createElement)("p", { className: market_module_default.pluginCardError }, t("mcpBackendHostMissing")) : null, (0, react.createElement)("div", { className: market_module_default.pluginCardRow }, (0, react.createElement)("div", { className: market_module_default.pluginCardText }, (0, react.createElement)("div", { className: market_module_default.pluginFieldHead }, (0, react.createElement)("div", { className: market_module_default.pluginCardRowLabel }, t("regionLabel")), region.overridden ? (0, react.createElement)(OverrideBadge, {
38225
- t,
38226
- disabled: blocked,
38227
- onReset: () => {
38228
- resetField("downloadRegion");
38229
- }
38230
- }) : null), (0, react.createElement)("div", { className: market_module_default.pluginCardDesc }, t("regionHint"))), (0, react.createElement)("div", { className: market_module_default.regionSeg }, [
38231
- "auto",
38232
- "global",
38233
- "china"
38234
- ].map((option) => {
38235
- const selected = option === "auto" ? !region.overridden : region.overridden && region.value === option;
38236
- const resolved = !region.overridden && option === effectiveRegion;
38237
- return (0, react.createElement)("button", {
38238
- key: option,
38239
- type: "button",
38240
- disabled: blocked,
38241
- className: selected ? market_module_default.regionSegOn : resolved ? market_module_default.regionSegEffective : market_module_default.regionSegBtn,
38242
- onClick: () => {
38243
- if (option === "auto") {
38244
- if (region.overridden) resetField("downloadRegion");
38245
- return;
38328
+ const effectiveRegion = state.probe?.downloadRegion.effective ?? (region.text === "china" ? "china" : "global");
38329
+ return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.SettingsForm, {
38330
+ labels: {
38331
+ unavailable: t("settingUnavailable"),
38332
+ readOnly: t("mcpCardReadonly"),
38333
+ saveFailed: t("settingSaveFailed"),
38334
+ save: t("settingSave"),
38335
+ saving: t("settingSaving")
38336
+ },
38337
+ state,
38338
+ onSave: save,
38339
+ onDiscard: discard,
38340
+ children: (0, react.createElement)("div", { className: market_module_default.pluginCardBody }, SWITCH_FIELDS.map((field) => (0, react.createElement)(SwitchRow, {
38341
+ key: field,
38342
+ t,
38343
+ field,
38344
+ state: state[field],
38345
+ disabled,
38346
+ onEdit: edit,
38347
+ onReset: resetField
38348
+ })), state.hostClientMissing && state.mcpEnhanced.text !== "true" ? (0, react.createElement)("p", { className: market_module_default.pluginCardError }, t("mcpBackendHostMissing")) : null, (0, react.createElement)("div", { className: market_module_default.pluginCardRow }, (0, react.createElement)("div", { className: market_module_default.pluginCardText }, (0, react.createElement)(FieldHead, {
38349
+ label: t("regionLabel"),
38350
+ overridden: region.overridden,
38351
+ badge: (0, react.createElement)(OverrideBadge, {
38352
+ t,
38353
+ disabled,
38354
+ onReset: () => {
38355
+ resetField("downloadRegion");
38246
38356
  }
38247
- if (region.value === option && region.overridden) return;
38248
- setRegion(option);
38357
+ })
38358
+ }), (0, react.createElement)("div", { className: market_module_default.pluginCardDesc }, t("regionHint"))), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.SegmentedControl, {
38359
+ id: "plugin-config-market-region",
38360
+ label: t("regionLabel"),
38361
+ disabled,
38362
+ value: regionChoice(region.text),
38363
+ options: REGION_OPTIONS.map((option) => ({
38364
+ value: option.value,
38365
+ label: t(option.label)
38366
+ })),
38367
+ onChange: (value) => {
38368
+ if (value === "auto") resetField("downloadRegion");
38369
+ else edit("downloadRegion", value);
38249
38370
  }
38250
- }, option === "auto" ? t("regionAuto") : option === "global" ? t("regionGlobal") : t("regionChina"));
38251
- }))), (0, react.createElement)("div", { className: market_module_default.pluginCardFooter }, state.failed ? (0, react.createElement)("p", {
38252
- className: market_module_default.pluginCardError,
38253
- role: "status"
38254
- }, t("settingSaveFailed")) : null, (0, react.createElement)("button", {
38255
- type: "button",
38256
- className: market_module_default.pluginCardDiscard,
38257
- disabled: !state.dirty || state.saving,
38258
- onClick: discard
38259
- }, t("settingDiscard")), (0, react.createElement)("button", {
38260
- type: "button",
38261
- className: market_module_default.pluginCardSave,
38262
- disabled: !state.dirty || state.invalid || state.saving,
38263
- onClick: save
38264
- }, t(state.saving ? "settingSaving" : "settingSave")))) : null);
38371
+ })), region.overridden ? null : (0, react.createElement)("p", { className: market_module_default.pluginCardDesc }, t("regionResolved", { region: t(effectiveRegion === "china" ? "regionChina" : "regionGlobal") })), state.dirty ? (0, react.createElement)("div", { className: market_module_default.pluginCardFooter }, (0, react.createElement)("button", {
38372
+ type: "button",
38373
+ className: market_module_default.pluginCardDiscard,
38374
+ disabled: state.saving,
38375
+ onClick: discard
38376
+ }, t("settingDiscard"))) : null)
38377
+ });
38265
38378
  }
38266
38379
  //#endregion
38267
- //#region src/client/plugin-card-controller.ts
38268
- /**
38269
- * Staged form behind the Agent Plugins Market card on the host's plugin
38270
- * configuration tab.
38271
- *
38272
- * The card's controls edit the market's host settings namespace, so every write
38273
- * is a durable, revision-fenced document mutation the node half reacts to —
38274
- * flipping the MCP switch tears down and remounts suite servers. The form
38275
- * therefore stages what the user picks and writes it on save, which is the
38276
- * contract every card in this slot follows: what is on screen is exactly what a
38277
- * save would store, one save is one committed change, and a field the user
38278
- * never touched stays untouched.
38279
- *
38280
- * Every default the card renders comes from the contract module, which is the
38281
- * single place a default is written; the card never restates one. A field still
38282
- * carrying no user-layer entry is marked overridable rather than overridden, and
38283
- * resetting it clears the entry instead of writing today's default in, so the
38284
- * field goes back to following the plugin rather than pinning the value it
38285
- * happened to have.
38286
- *
38287
- * @module client/plugin-card-controller
38288
- */
38289
- /** Bridges the market settings scope onto the card's staged form. */
38290
- var MarketPluginCardController = class {
38291
- scope;
38292
- probeSource;
38293
- store;
38294
- unsubscribe;
38295
- staged = /* @__PURE__ */ new Map();
38296
- probe;
38297
- probeStatus = "idle";
38298
- /** Bumped by every probe read so a late answer cannot overwrite a newer one. */
38299
- probeGeneration = 0;
38300
- /** Bumped by every save and every dispose so a late write cannot publish over a newer state. */
38301
- saveGeneration = 0;
38302
- saving = false;
38303
- failed = false;
38304
- disposed = false;
38305
- /**
38306
- * @param scope - the host configuration form for the market namespace.
38307
- * @param probe - reads the live host-client and region state from the market API.
38308
- */
38309
- constructor(scope, probeSource) {
38310
- this.scope = scope;
38311
- this.probeSource = probeSource;
38312
- this.store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(this.projection());
38313
- this.unsubscribe = scope.subscribe(() => {
38314
- this.publish();
38315
- });
38316
- }
38317
- /** Stop observing settings and suppress late probe/write settlements. */
38318
- dispose() {
38319
- this.disposed = true;
38320
- this.saveGeneration += 1;
38321
- this.probeGeneration += 1;
38322
- this.unsubscribe();
38323
- }
38324
- /**
38325
- * Build the renderer face for this card.
38326
- * @returns the card snapshot and its staged form actions.
38327
- */
38328
- inject() {
38329
- return {
38330
- hooks: { marketCard: this.store },
38331
- toggle: (field) => {
38332
- this.toggle(field);
38333
- },
38334
- setRegion: (next) => {
38335
- this.stageSet("downloadRegion", next);
38336
- },
38337
- resetField: (field) => {
38338
- this.stageClear(field);
38339
- },
38340
- save: () => {
38341
- this.save();
38342
- },
38343
- discard: () => {
38344
- this.discard();
38345
- },
38346
- refreshProbe: () => {
38347
- this.loadProbe();
38348
- }
38349
- };
38350
- }
38351
- /** Read the host-client probe once; a second call while one is in flight is a no-op. */
38352
- async loadProbe() {
38353
- if (this.disposed || this.probeStatus === "loading") return;
38354
- this.probeStatus = "loading";
38355
- const generation = this.probeGeneration;
38356
- try {
38357
- const info = await this.probeSource();
38358
- if (generation !== this.probeGeneration || this.disposed) return;
38359
- this.probe = info;
38360
- } catch {} finally {
38361
- if (generation === this.probeGeneration) this.probeStatus = "idle";
38362
- this.publish();
38363
- }
38364
- }
38365
- /** Stage the opposite of one switch's shown value. */
38366
- toggle(field) {
38367
- if (!this.editable()) return;
38368
- this.stageSet(field, !this.fieldValue(field));
38369
- }
38370
- stageSet(field, value) {
38371
- if (!this.editable()) return;
38372
- this.staged.set(field, {
38373
- kind: "set",
38374
- value
38375
- });
38376
- this.failed = false;
38377
- this.publish();
38378
- }
38379
- stageClear(field) {
38380
- if (!this.editable()) return;
38381
- this.staged.set(field, { kind: "clear" });
38382
- this.failed = false;
38383
- this.publish();
38384
- }
38385
- discard() {
38386
- if (this.saving || this.staged.size === 0 && !this.failed) return;
38387
- this.staged.clear();
38388
- this.failed = false;
38389
- this.publish();
38390
- }
38391
- /**
38392
- * Write every staged edit, then re-read what the host accepted.
38393
- *
38394
- * The host is the only authority on whether a write landed — it owns the
38395
- * document, its validation, and any concurrent writer — so the outcome is read
38396
- * back rather than predicted. A save that did not land keeps its edits so the
38397
- * user can correct them instead of retyping.
38398
- */
38399
- async save() {
38400
- const plan = this.plan();
38401
- if (plan.length === 0 || this.saving || this.invalid()) return;
38402
- const generation = this.saveGeneration;
38403
- this.saving = true;
38404
- this.failed = false;
38405
- this.publish();
38406
- let landed = true;
38407
- for (const write of plan) try {
38408
- landed = await write.run() && landed;
38409
- } catch {
38410
- landed = false;
38411
- }
38412
- if (generation !== this.saveGeneration) return;
38413
- if (landed) this.staged.clear();
38414
- this.saving = false;
38415
- this.failed = !landed;
38416
- this.publish();
38417
- }
38418
- /**
38419
- * Every staged edit a save would write. An edit that would leave the document
38420
- * exactly as it already is carries no write, which is what keeps `dirty` from
38421
- * reporting a save that would do nothing.
38422
- */
38423
- plan() {
38424
- const plan = [];
38425
- for (const [field, edit] of this.staged) {
38426
- if (edit.kind === "clear") {
38427
- if (this.overridden(field)) plan.push({
38428
- field,
38429
- run: () => this.clear(field)
38430
- });
38431
- continue;
38432
- }
38433
- if (edit.value === this.storedValue(field)) continue;
38434
- plan.push({
38435
- field,
38436
- run: () => this.storeValue(field, edit.value)
38437
- });
38438
- }
38439
- return plan;
38440
- }
38441
- async clear(field) {
38442
- await this.scope.unset(field);
38443
- return !this.overridden(field);
38444
- }
38445
- async storeValue(field, value) {
38446
- await this.scope.set(field, value);
38447
- return this.overridden(field) && this.fieldValue(field) === value;
38448
- }
38449
- /** Whether the form accepts edits at all: served, writable, and not mid-save. */
38450
- editable() {
38451
- const snapshot = this.scope.getSnapshot();
38452
- return !this.disposed && snapshot.status === "ready" && snapshot.writable && !this.saving;
38453
- }
38454
- /** The document's resolved value for one field. */
38455
- storedValue(field) {
38456
- return this.scope.getSnapshot().value?.[field] ?? MARKET_SETTINGS_DEFAULTS[field];
38457
- }
38458
- /** The value the card shows: the staged edit when one stands, else the document's. */
38459
- fieldValue(field) {
38460
- const edit = this.staged.get(field);
38461
- if (edit !== void 0 && edit.kind === "set") return edit.value;
38462
- return this.storedValue(field);
38463
- }
38464
- /** Whether a user-layer entry stands for this field, which is what marks it overridden. */
38465
- overridden(field) {
38466
- const user = this.scope.getSnapshot().user;
38467
- return typeof user === "object" && user !== null && Object.hasOwn(user, field);
38468
- }
38469
- switchState(field) {
38470
- const edit = this.staged.get(field);
38471
- return {
38472
- value: this.fieldValue(field),
38473
- overridden: edit === void 0 ? this.overridden(field) : edit.kind === "set",
38474
- staged: edit !== void 0
38475
- };
38476
- }
38477
- /** Whether the host client is known to be missing, which blocks compat mode. */
38478
- hostClientMissing() {
38479
- return this.probe !== void 0 && !this.probe.hostClient.available;
38480
- }
38481
- /**
38482
- * Whether the form is in a state a save must refuse: compat mode asks for the
38483
- * host's MCP client, and a deployment that does not resolve it would leave MCP
38484
- * servers with no mount path at all.
38485
- */
38486
- invalid() {
38487
- return !this.fieldValue("mcpEnhanced") && this.hostClientMissing();
38488
- }
38489
- projection() {
38490
- const snapshot = this.scope.getSnapshot();
38491
- const plan = this.plan();
38492
- const regionEdit = this.staged.get("downloadRegion");
38493
- return {
38494
- available: snapshot.status === "ready",
38495
- writable: snapshot.writable,
38496
- dirty: plan.length > 0,
38497
- invalid: this.invalid(),
38498
- saving: this.saving,
38499
- failed: this.failed,
38500
- mcpEnhanced: this.switchState("mcpEnhanced"),
38501
- scanProjectLayouts: this.switchState("scanProjectLayouts"),
38502
- autoUpdateSources: this.switchState("autoUpdateSources"),
38503
- feedbackEnabled: this.switchState("feedbackEnabled"),
38504
- downloadRegion: {
38505
- value: this.fieldValue("downloadRegion"),
38506
- overridden: regionEdit === void 0 ? this.overridden("downloadRegion") : regionEdit.kind === "set",
38507
- staged: regionEdit !== void 0
38508
- },
38509
- probe: this.probe,
38510
- hostClientMissing: this.hostClientMissing()
38511
- };
38512
- }
38513
- publish() {
38514
- if (this.disposed) return;
38515
- this.store.set(this.projection());
38516
- }
38517
- };
38518
- //#endregion
38519
- //#region src/client/page-mode-selection.ts
38380
+ //#region src/client/workspace/page-mode-selection.ts
38520
38381
  /** Pure capability decision for the legacy page-mode fallback. */
38521
38382
  /**
38522
38383
  * Use the DOM page fallback only when the host has no settings page and does
@@ -38530,7 +38391,7 @@ function shouldUseLegacyPageMode(settingsSurfaceAvailable, pageShellAvailable) {
38530
38391
  return !settingsSurfaceAvailable && pageShellAvailable;
38531
38392
  }
38532
38393
  //#endregion
38533
- //#region src/client/page-mode.tsx
38394
+ //#region src/client/workspace/page-mode.tsx
38534
38395
  /**
38535
38396
  * Legacy Web page-mode adapter.
38536
38397
  *
@@ -38813,17 +38674,18 @@ function apply(ctx) {
38813
38674
  if (service === void 0 || slots === void 0) return;
38814
38675
  let card;
38815
38676
  service.whileServed([NS], () => {
38816
- card = new MarketPluginCardController(service.get(NS), fetchMcpBackend);
38677
+ const bound = bindMarketCardForm(service.get(NS), fetchMcpBackend);
38678
+ card = bound.face;
38817
38679
  const dispose = slots.register({
38818
38680
  name: "plugins.item",
38819
38681
  id: NS,
38820
38682
  order: 50,
38821
38683
  label: () => t("nav"),
38822
38684
  locale: NS,
38823
- inject: () => card.inject()
38685
+ inject: () => card
38824
38686
  }, McpPluginCard);
38825
38687
  return () => {
38826
- card?.dispose();
38688
+ bound.dispose();
38827
38689
  card = void 0;
38828
38690
  if (typeof dispose === "function") dispose();
38829
38691
  };