dsh-agent-plugins-market 0.8.1 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/README.zh.md +2 -2
- package/client/client.js +1593 -1728
- package/client/client.js.map +1 -1
- package/lib/application/agent-roles.js +53 -0
- package/lib/application/catalog-context.js +2 -2
- package/lib/application/catalog.js +4 -8
- package/lib/{runtime → application}/deadline.js +1 -1
- package/lib/application/details.js +3 -3
- package/lib/application/json-file.js +43 -0
- package/lib/{runtime → application/lsp}/lsp-direct-config.js +9 -7
- package/lib/application/lsp/lsp-server-state.js +17 -0
- package/lib/{runtime → application/lsp}/lsp-status.js +22 -7
- package/lib/{runtime → application/lsp}/profile-seam.js +1 -1
- package/lib/application/lsp-service.js +5 -5
- package/lib/{runtime → application/mcp}/mcp-backend.js +3 -19
- package/lib/{runtime → application/mcp}/mcp-config.js +4 -4
- package/lib/{runtime → application/mcp}/mcp-direct-config.js +8 -49
- package/lib/{runtime → application/mcp}/mcp-overrides.js +3 -5
- package/lib/{runtime → application/mcp}/mcp-redaction.js +27 -4
- package/lib/{runtime → application/mcp}/mcp-status.js +13 -7
- package/lib/application/mcp-service.js +11 -35
- package/lib/application/panel-resources.js +48 -11
- package/lib/{runtime → application/panels}/user-hooks.js +2 -2
- package/lib/{runtime → application/panels}/user-store.js +2 -2
- package/lib/application/ports.js +1 -0
- package/lib/application/project-agent-roles.js +1 -1
- package/lib/{runtime → application}/server-config.js +7 -17
- package/lib/application/snapshot-cache.js +1 -1
- package/lib/application/source-store.js +3 -4
- package/lib/{runtime → application/state}/state-store.js +5 -7
- package/lib/{runtime → application/state}/storage-migration.js +4 -4
- package/lib/catalog/source-catalog.js +0 -4
- package/lib/contracts/lsp.js +1 -0
- package/lib/contracts/market.js +0 -1
- package/lib/contracts/mcp.js +1 -0
- package/lib/index.js +42 -33
- package/lib/routes.js +2 -9
- package/lib/runtime/{agent-role-router.js → agents/agent-role-router.js} +7 -53
- package/lib/runtime/{subagent-catalog.js → agents/subagent-catalog.js} +24 -16
- package/lib/runtime/core/context.js +31 -0
- package/lib/runtime/{reconciler.js → core/reconciler.js} +5 -5
- package/lib/runtime/host/failure-detail.js +58 -0
- package/lib/runtime/{feedback-tool.js → host/feedback-tool.js} +1 -1
- package/lib/runtime/host/host-locale.js +83 -0
- package/lib/runtime/{settings-namespace.js → host/settings-namespace.js} +1 -1
- package/lib/runtime/host/shell-path.js +196 -0
- package/lib/runtime/{tool-registry-observer.js → host/tool-registry-observer.js} +2 -1
- package/lib/runtime/{lsp-mounts.js → lsp/lsp-mounts.js} +69 -20
- package/lib/runtime/{mcp-client → mcp/bridge}/bridge.js +52 -22
- package/lib/runtime/{mcp-client → mcp/bridge}/connection.js +2 -2
- package/lib/runtime/{mcp-client → mcp/bridge}/oauth.js +1 -1
- package/lib/runtime/{mcp-client → mcp/bridge}/tools.js +2 -2
- package/lib/runtime/{mcp-auth-record.js → mcp/mcp-auth-record.js} +1 -1
- package/lib/runtime/{mcp-mounts.js → mcp/mcp-mounts.js} +14 -7
- package/lib/runtime/{user-commands.js → panels/user-commands.js} +3 -3
- package/lib/runtime/{user-panels.js → panels/user-panels.js} +2 -2
- package/lib/runtime/{commands-mounts.js → surfaces/commands-mounts.js} +7 -7
- package/lib/runtime/{hooks-mounts.js → surfaces/hooks-mounts.js} +2 -2
- package/lib/runtime/{project-runtime.js → surfaces/project-runtime.js} +5 -5
- package/lib/runtime/{skills-provider.js → surfaces/skills-provider.js} +4 -4
- package/lib/types/application/agent-roles.d.ts +30 -0
- package/lib/types/application/catalog.d.ts +4 -7
- package/lib/types/application/details.d.ts +1 -1
- package/lib/types/application/json-file.d.ts +12 -0
- package/lib/types/{runtime → application/lsp}/lsp-direct-config.d.ts +1 -1
- package/lib/types/{runtime → application/lsp}/lsp-status.d.ts +3 -3
- package/lib/types/{runtime → application/mcp}/mcp-backend.d.ts +4 -9
- package/lib/types/{runtime/mcp-client/config.d.ts → application/mcp/mcp-bridge-config.d.ts} +11 -1
- package/lib/types/{runtime → application/mcp}/mcp-config.d.ts +6 -7
- package/lib/types/application/mcp/mcp-direct-config.d.ts +17 -0
- package/lib/types/{runtime → application/mcp}/mcp-overrides.d.ts +1 -1
- package/lib/types/{runtime → application/mcp}/mcp-status.d.ts +7 -7
- package/lib/types/application/mcp-service.d.ts +4 -11
- package/lib/types/application/panel-resources.d.ts +9 -2
- package/lib/types/{runtime → application/panels}/user-hooks.d.ts +1 -1
- package/lib/types/{runtime → application/panels}/user-store.d.ts +1 -1
- package/lib/types/application/ports.d.ts +17 -3
- package/lib/types/application/project-agent-roles.d.ts +1 -1
- package/lib/types/application/queries.d.ts +3 -6
- package/lib/types/{runtime → application}/regions.d.ts +1 -1
- package/lib/types/{runtime → application/state}/state-store.d.ts +2 -2
- package/lib/types/catalog/source-catalog.d.ts +0 -2
- package/lib/types/contracts/lsp-status.d.ts +6 -0
- package/lib/types/contracts/lsp.d.ts +16 -0
- package/lib/types/contracts/market.d.ts +1 -4
- package/lib/types/contracts/mcp-status.d.ts +21 -2
- package/lib/types/contracts/mcp.d.ts +20 -0
- package/lib/types/model/types.d.ts +0 -14
- package/lib/types/runtime/{agent-role-router.d.ts → agents/agent-role-router.d.ts} +3 -28
- package/lib/types/runtime/{subagent-catalog.d.ts → agents/subagent-catalog.d.ts} +6 -6
- package/lib/types/runtime/core/context.d.ts +14 -0
- package/lib/types/runtime/{reconcile-scheduler.d.ts → core/reconcile-scheduler.d.ts} +2 -2
- package/lib/types/runtime/{reconciler.d.ts → core/reconciler.d.ts} +8 -8
- package/lib/types/runtime/host/failure-detail.d.ts +6 -0
- package/lib/types/runtime/host/host-locale.d.ts +66 -0
- package/lib/types/runtime/{model-catalog.d.ts → host/model-catalog.d.ts} +1 -1
- package/lib/types/runtime/{settings-namespace.d.ts → host/settings-namespace.d.ts} +2 -2
- package/lib/types/runtime/host/shell-path.d.ts +70 -0
- package/lib/types/runtime/{lsp-mounts.d.ts → lsp/lsp-mounts.d.ts} +17 -11
- package/lib/types/runtime/{mcp-client → mcp/bridge}/bridge.d.ts +1 -1
- package/lib/types/runtime/{mcp-client → mcp/bridge}/connection.d.ts +3 -11
- package/lib/types/runtime/{mcp-client → mcp/bridge}/host-contract.d.ts +1 -1
- package/lib/types/runtime/{mcp-client → mcp/bridge}/oauth.d.ts +1 -1
- package/lib/types/runtime/{mcp-client → mcp/bridge}/transport.d.ts +1 -1
- package/lib/types/runtime/{mcp-auth-record.d.ts → mcp/mcp-auth-record.d.ts} +1 -1
- package/lib/types/runtime/{mcp-credentials.d.ts → mcp/mcp-credentials.d.ts} +1 -1
- package/lib/types/runtime/{mcp-mounts.d.ts → mcp/mcp-mounts.d.ts} +5 -11
- package/lib/types/runtime/{user-commands.d.ts → panels/user-commands.d.ts} +1 -1
- package/lib/types/runtime/{user-panels.d.ts → panels/user-panels.d.ts} +1 -1
- package/lib/types/runtime/{commands-mounts.d.ts → surfaces/commands-mounts.d.ts} +2 -2
- package/lib/types/runtime/{hooks-mounts.d.ts → surfaces/hooks-mounts.d.ts} +1 -1
- package/lib/types/runtime/{project-runtime.d.ts → surfaces/project-runtime.d.ts} +3 -3
- package/lib/types/runtime/{skills-provider.d.ts → surfaces/skills-provider.d.ts} +1 -1
- package/package.json +38 -35
- package/lib/runtime/host-locale.js +0 -89
- package/lib/runtime/legacy-root-migration.js +0 -12
- package/lib/runtime/lsp-server-state.js +0 -19
- package/lib/runtime/mcp-client/json-schema-subset.js +0 -181
- package/lib/types/runtime/host-locale.d.ts +0 -31
- package/lib/types/runtime/legacy-root-migration.d.ts +0 -2
- package/lib/types/runtime/mcp-client/json-schema-subset.d.ts +0 -58
- package/lib/types/runtime/mcp-direct-config.d.ts +0 -39
- /package/lib/{runtime/mcp-client/config.js → application/mcp/mcp-bridge-config.js} +0 -0
- /package/lib/{runtime → application}/regions.js +0 -0
- /package/lib/runtime/{agent-role-names.js → agents/agent-role-names.js} +0 -0
- /package/lib/runtime/{mount-lifecycle.js → core/mount-lifecycle.js} +0 -0
- /package/lib/runtime/{reconcile-scheduler.js → core/reconcile-scheduler.js} +0 -0
- /package/lib/runtime/{source-auto-update.js → core/source-auto-update.js} +0 -0
- /package/lib/runtime/{timer-seat.js → core/timer-seat.js} +0 -0
- /package/lib/runtime/{model-catalog.js → host/model-catalog.js} +0 -0
- /package/lib/runtime/{plugin-message-source.js → host/plugin-message-source.js} +0 -0
- /package/lib/runtime/{mcp-client → mcp/bridge}/host-contract.js +0 -0
- /package/lib/runtime/{mcp-client → mcp/bridge}/host-seams.js +0 -0
- /package/lib/runtime/{mcp-client → mcp/bridge}/plugin-identity.js +0 -0
- /package/lib/runtime/{mcp-client → mcp/bridge}/projection.js +0 -0
- /package/lib/runtime/{mcp-client → mcp/bridge}/transport.js +0 -0
- /package/lib/runtime/{mcp-credentials.js → mcp/mcp-credentials.js} +0 -0
- /package/lib/runtime/{dynamic-context.js → surfaces/dynamic-context.js} +0 -0
- /package/lib/types/{runtime → application}/deadline.d.ts +0 -0
- /package/lib/types/{runtime → application/lsp}/lsp-server-state.d.ts +0 -0
- /package/lib/types/{runtime → application/lsp}/profile-seam.d.ts +0 -0
- /package/lib/types/{runtime → application/mcp}/mcp-redaction.d.ts +0 -0
- /package/lib/types/{runtime → application}/server-config.d.ts +0 -0
- /package/lib/types/{runtime → application/state}/storage-migration.d.ts +0 -0
- /package/lib/types/runtime/{agent-role-names.d.ts → agents/agent-role-names.d.ts} +0 -0
- /package/lib/types/runtime/{mount-lifecycle.d.ts → core/mount-lifecycle.d.ts} +0 -0
- /package/lib/types/runtime/{source-auto-update.d.ts → core/source-auto-update.d.ts} +0 -0
- /package/lib/types/runtime/{timer-seat.d.ts → core/timer-seat.d.ts} +0 -0
- /package/lib/types/runtime/{feedback-tool.d.ts → host/feedback-tool.d.ts} +0 -0
- /package/lib/types/runtime/{plugin-message-source.d.ts → host/plugin-message-source.d.ts} +0 -0
- /package/lib/types/runtime/{tool-registry-observer.d.ts → host/tool-registry-observer.d.ts} +0 -0
- /package/lib/types/runtime/{mcp-client → mcp/bridge}/host-seams.d.ts +0 -0
- /package/lib/types/runtime/{mcp-client → mcp/bridge}/plugin-identity.d.ts +0 -0
- /package/lib/types/runtime/{mcp-client → mcp/bridge}/projection.d.ts +0 -0
- /package/lib/types/runtime/{mcp-client → mcp/bridge}/tools.d.ts +0 -0
- /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 flex-direction: column;\n gap: 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 align-items: center;\n gap: 8px;\n padding-top: 16px;\n display: flex;\n}\n\n._72qoAq_pluginCardFooter ._72qoAq_pluginCardError {\n flex: 1;\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=new TextDecoder().decode(Uint8Array.from(atob("LnFVbGs2YV9vdmVybGF5IHsKICB6LWluZGV4OiAyMTQ3NDgzNjQ3OwogIGJveC1zaXppbmc6IGJvcmRlci1ib3g7CiAgYmFja2dyb3VuZDogdmFyKC0tZHN3LWFsaWFzLWJnLW1hc2stMyk7CiAgYmFja2Ryb3AtZmlsdGVyOiBibHVyKDNweCk7CiAgY3Vyc29yOiBwcm9ncmVzczsKICBvdXRsaW5lOiBub25lOwogIHBsYWNlLWl0ZW1zOiBjZW50ZXI7CiAgZGlzcGxheTogZ3JpZDsKICBwb3NpdGlvbjogZml4ZWQ7CiAgb3ZlcmZsb3c6IGhpZGRlbjsKfQoKLnFVbGs2YV9vdmVybGF5W2RhdGEtdmlzaWJsZT0iZmFsc2UiXSB7CiAgYmFja2Ryb3AtZmlsdGVyOiBub25lOwogIGJhY2tncm91bmQ6IG5vbmU7Cn0KCi5xVWxrNmFfb3ZlcmxheVtkYXRhLXZpc2libGU9InRydWUiXSB7CiAgYW5pbWF0aW9uOiAuMTRzIGVhc2Utb3V0IHFVbGs2YV9idXN5LWVudGVyOwp9CgoucVVsazZhX2NvbnRlbnQgewogIGJveC1zaXppbmc6IGJvcmRlci1ib3g7CiAgYm9yZGVyOiAxcHggc29saWQgdmFyKC0tZHN3LWFsaWFzLWJvcmRlci1sMik7CiAgYmFja2dyb3VuZDogdmFyKC0tZHN3LWFsaWFzLWJnLWxheWVyLTIpOwogIHdpZHRoOiBtaW4oMzYwcHgsIDEwMCUgLSAzMnB4KTsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnkpOwogIHRleHQtYWxpZ246IGNlbnRlcjsKICBib3JkZXItcmFkaXVzOiA4cHg7CiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGdhcDogMTJweDsKICBwYWRkaW5nOiAyNHB4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5xVWxrNmFfc3Bpbm5lciB7CiAgd2lkdGg6IDI4cHg7CiAgaGVpZ2h0OiAyOHB4OwogIGFuaW1hdGlvbjogLjlzIGxpbmVhciBpbmZpbml0ZSBxVWxrNmFfYnVzeS1zcGluOwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5xVWxrNmFfbGFiZWwgewogIGZvbnQtc2l6ZTogMTRweDsKICBmb250LXdlaWdodDogNjAwOwogIGxpbmUtaGVpZ2h0OiAyMHB4Owp9CgoucVVsazZhX2hpbnRWaWV3cG9ydCB7CiAgd2lkdGg6IDEwMCU7CiAgbWluLWhlaWdodDogNTRweDsKICBvdmVyZmxvdzogaGlkZGVuOwp9CgoucVVsazZhX2hpbnQgewogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtc2Vjb25kYXJ5KTsKICBvdmVyZmxvdy13cmFwOiBhbnl3aGVyZTsKICBtYXJnaW46IDA7CiAgZm9udC1zaXplOiAxM3B4OwogIGxpbmUtaGVpZ2h0OiAxOHB4OwogIGFuaW1hdGlvbjogLjNzIGVhc2Utb3V0IHFVbGs2YV9idXN5LWhpbnQ7Cn0KCi5xVWxrNmFfd2FybmluZyB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1zdGF0ZS13YXJuLXByaW1hcnksICNiNDUzMDkpOwogIGJhY2tncm91bmQ6IHZhcigtLWRzdy1hbGlhcy1zdGF0ZS13YXJuLXRlcnRpYXJ5LCAjZmVmNWU3KTsKICBvdmVyZmxvdy13cmFwOiBhbnl3aGVyZTsKICBib3JkZXItcmFkaXVzOiA2cHg7CiAgbWFyZ2luOiAwOwogIHBhZGRpbmc6IDZweCA4cHg7CiAgZm9udC1zaXplOiAxMnB4OwogIGxpbmUtaGVpZ2h0OiAxN3B4Owp9CgpAa2V5ZnJhbWVzIHFVbGs2YV9idXN5LXNwaW4gewogIHRvIHsKICAgIHRyYW5zZm9ybTogcm90YXRlKDM2MGRlZyk7CiAgfQp9CgpAa2V5ZnJhbWVzIHFVbGs2YV9idXN5LWVudGVyIHsKICBmcm9tIHsKICAgIG9wYWNpdHk6IDA7CiAgfQoKICB0byB7CiAgICBvcGFjaXR5OiAxOwogIH0KfQoKQGtleWZyYW1lcyBxVWxrNmFfYnVzeS1oaW50IHsKICBmcm9tIHsKICAgIG9wYWNpdHk6IDA7CiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVkoMTRweCk7CiAgfQoKICB0byB7CiAgICBvcGFjaXR5OiAxOwogICAgdHJhbnNmb3JtOiB0cmFuc2xhdGVZKDApOwogIH0KfQoKQG1lZGlhIChwcmVmZXJzLXJlZHVjZWQtbW90aW9uOiByZWR1Y2UpIHsKICAucVVsazZhX292ZXJsYXksIC5xVWxrNmFfaGludCB7CiAgICBhbmltYXRpb246IG5vbmU7CiAgfQoKICAucVVsazZhX3NwaW5uZXIgewogICAgYW5pbWF0aW9uLWR1cmF0aW9uOiAyLjRzOwogIH0KfQouVS1oanFxX21hcmtldCB7CiAgbWluLXdpZHRoOiAwOwogIG1pbi1oZWlnaHQ6IDA7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1wcmltYXJ5LCAjMWYyMzI4KTsKICBmbGV4LWRpcmVjdGlvbjogY29sdW1uOwogIGZsZXg6IDE7CiAgZ2FwOiAyNHB4OwogIGRpc3BsYXk6IGZsZXg7CiAgY29udGFpbmVyLXR5cGU6IGlubGluZS1zaXplOwp9CgouVS1oanFxX3BhZ2VNb2RlIHsKICB3aWR0aDogMTAwJTsKICBtaW4td2lkdGg6IDA7CiAgaGVpZ2h0OiAxMDAlOwogIG1pbi1oZWlnaHQ6IDA7Cn0KCi5VLWhqcXFfbWFya2V0Q29udHJvbHMgewogIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47CiAgZ2FwOiA4cHg7CiAgbWluLWhlaWdodDogMDsKICBkaXNwbGF5OiBmbGV4Owp9CgpodG1sW2RhdGEtZHNoLWFnZW50LXBsdWdpbnMtbWFya2V0LXBhZ2VdIFtkYXRhLXBhbmU9ImNvbnZlcnNhdGlvbiJdLCBodG1sW2RhdGEtZHNoLWFnZW50LXBsdWdpbnMtbWFya2V0LXBhZ2VdIFtjbGFzcyo9ImNlbnRlckNvbCJdIHsKICBwb3NpdGlvbjogcmVsYXRpdmU7Cn0KCmh0bWxbZGF0YS1kc2gtYWdlbnQtcGx1Z2lucy1tYXJrZXQtcGFnZV0gW2RhdGEtcGFuZT0iY29udmVyc2F0aW9uIl0gPiA6bm90KFtkYXRhLWRzaC1hZ2VudC1wbHVnaW5zLW1hcmtldC1wYWdlLXZpZXddKSwgaHRtbFtkYXRhLWRzaC1hZ2VudC1wbHVnaW5zLW1hcmtldC1wYWdlXSBbY2xhc3MqPSJjZW50ZXJDb2wiXSA+IDpub3QoW2RhdGEtZHNoLWFnZW50LXBsdWdpbnMtbWFya2V0LXBhZ2Utdmlld10pIHsKICBkaXNwbGF5OiBub25lICFpbXBvcnRhbnQ7Cn0KCi5VLWhqcXFfcGFnZUVudHJ5OmZvY3VzLXZpc2libGUsIC5VLWhqcXFfc3JjVGFiTWFpbjpmb2N1cy12aXNpYmxlLCAuVS1oanFxX3NyY1RhYkVkaXQ6Zm9jdXMtdmlzaWJsZSwgLlUtaGpxcV9zcmNUYWJEZWw6Zm9jdXMtdmlzaWJsZSwgLlUtaGpxcV9kZXRhaWxJdGVtUm93OmZvY3VzLXZpc2libGUsIC5VLWhqcXFfZGV0YWlsSXRlbU9wZW46Zm9jdXMtdmlzaWJsZSB7CiAgb3V0bGluZTogMnB4IHNvbGlkIHZhcigtLWRzdy1hbGlhcy1icmFuZC1wcmltYXJ5LCAjNGY2ZWY3KTsKICBvdXRsaW5lLW9mZnNldDogMnB4Owp9CgouVS1oanFxX2hlYWRlciB7CiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjsKICBmbGV4LXNocmluazogMDsKICBnYXA6IDhweDsKICBkaXNwbGF5OiBmbGV4Owp9CgouVS1oanFxX3NvdXJjZVRhYnNCb3ggewogIG1pbi13aWR0aDogMDsKICBwb3NpdGlvbjogcmVsYXRpdmU7Cn0KCi5VLWhqcXFfc291cmNlVGFic1JvdyB7CiAgZ3JpZC10ZW1wbGF0ZS1jb2x1bW5zOiByZXBlYXQoYXV0by1maWxsLCBtaW5tYXgoMTE4cHgsIDFmcikpOwogIGdhcDogNHB4OwogIG1pbi13aWR0aDogMDsKICBkaXNwbGF5OiBncmlkOwp9CgouVS1oanFxX3NvdXJjZVRhYnNCb3hGb2xkIHsKICBjbGlwLXBhdGg6IGluc2V0KC02cHgpOwogIGhlaWdodDogNTJweDsKfQoKLlUtaGpxcV9zb3VyY2VUYWJzQm94Rm9sZDpob3ZlciwgLlUtaGpxcV9zb3VyY2VUYWJzQm94Rm9sZDpoYXMoOmZvY3VzLXZpc2libGUpIHsKICBjbGlwLXBhdGg6IG5vbmU7CiAgei1pbmRleDogMjA7Cn0KCi5VLWhqcXFfc291cmNlVGFic0JveEZvbGQgLlUtaGpxcV9zb3VyY2VUYWJzUm93IHsKICBib3gtc2l6aW5nOiBib3JkZXItYm94OwogIGJhY2tncm91bmQ6IHZhcigtLWRzdy1hbGlhcy1iZy1sYXllci0xLCAjZmZmKTsKICBib3JkZXItcmFkaXVzOiAxMHB4OwogIG1heC1oZWlnaHQ6IDU4cHg7CiAgcGFkZGluZzogNnB4IDZweCAwOwogIHRyYW5zaXRpb246IG1heC1oZWlnaHQgLjE2cywgYm94LXNoYWRvdyAuMTZzLCBwYWRkaW5nLWJvdHRvbSAuMTZzOwogIHBvc2l0aW9uOiBhYnNvbHV0ZTsKICBpbnNldDogLTZweCAtNnB4IGF1dG87CiAgb3ZlcmZsb3c6IGhpZGRlbjsKICAtd2Via2l0LW1hc2staW1hZ2U6IGxpbmVhci1ncmFkaWVudCgjMDAwIDc4JSwgIzAwMDAgMTAwJSk7CiAgbWFzay1pbWFnZTogbGluZWFyLWdyYWRpZW50KCMwMDAgNzglLCAjMDAwMCAxMDAlKTsKfQoKLlUtaGpxcV9zb3VyY2VUYWJzQm94Rm9sZDpob3ZlciAuVS1oanFxX3NvdXJjZVRhYnNSb3csIC5VLWhqcXFfc291cmNlVGFic0JveEZvbGQ6aGFzKDpmb2N1cy12aXNpYmxlKSAuVS1oanFxX3NvdXJjZVRhYnNSb3cgewogIHotaW5kZXg6IDMwOwogIG1heC1oZWlnaHQ6IDQyMHB4OwogIGJveC1zaGFkb3c6IDAgMCAwIDFweCB2YXIoLS1kc3ctYWxpYXMtYm9yZGVyLWwzLCAjZDlkZGUzKSwKICAgIDAgMTJweCAyOHB4ICMxMDE4MjgyOTsKICBwYWRkaW5nLWJvdHRvbTogNnB4OwogIC13ZWJraXQtbWFzay1pbWFnZTogbm9uZTsKICBtYXNrLWltYWdlOiBub25lOwp9CgouVS1oanFxX3NvdXJjZVRhYnNCb3hGb2xkLlUtaGpxcV9zb3VyY2VUYWJzQm94UGlja2VkOmhvdmVyLCAuVS1oanFxX3NvdXJjZVRhYnNCb3hGb2xkLlUtaGpxcV9zb3VyY2VUYWJzQm94UGlja2VkOmhhcyg6Zm9jdXMtdmlzaWJsZSkgewogIGNsaXAtcGF0aDogaW5zZXQoLTZweCk7Cn0KCi5VLWhqcXFfc291cmNlVGFic0JveEZvbGQuVS1oanFxX3NvdXJjZVRhYnNCb3hQaWNrZWQ6aG92ZXIgLlUtaGpxcV9zb3VyY2VUYWJzUm93LCAuVS1oanFxX3NvdXJjZVRhYnNCb3hGb2xkLlUtaGpxcV9zb3VyY2VUYWJzQm94UGlja2VkOmhhcyg6Zm9jdXMtdmlzaWJsZSkgLlUtaGpxcV9zb3VyY2VUYWJzUm93IHsKICBtYXgtaGVpZ2h0OiA1OHB4OwogIGJveC1zaGFkb3c6IG5vbmU7CiAgcGFkZGluZy1ib3R0b206IDA7CiAgLXdlYmtpdC1tYXNrLWltYWdlOiBsaW5lYXItZ3JhZGllbnQoIzAwMCA3OCUsICMwMDAwIDEwMCUpOwogIG1hc2staW1hZ2U6IGxpbmVhci1ncmFkaWVudCgjMDAwIDc4JSwgIzAwMDAgMTAwJSk7Cn0KCi5VLWhqcXFfdW5tYW5hZ2VkUm93IHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXNlY29uZGFyeSwgIzU3NjA2YSk7CiAgZmxleC13cmFwOiB3cmFwOwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiA2cHg7CiAgbWFyZ2luLXRvcDogNnB4OwogIGZvbnQtc2l6ZTogMTJweDsKICBkaXNwbGF5OiBmbGV4Owp9CgouVS1oanFxX3VubWFuYWdlZExhYmVsIHsKICBmbGV4LXNocmluazogMDsKfQoKLlUtaGpxcV91bm1hbmFnZWRDaGlwIHsKICBib3JkZXI6IDFweCBkYXNoZWQgdmFyKC0tZHN3LWFsaWFzLWJvcmRlci1sMywgI2Q5ZGRlMyk7CiAgYmFja2dyb3VuZDogdmFyKC0tZHN3LWFsaWFzLWJnLWxheWVyLTEsICNmZmYpOwogIGJvcmRlci1yYWRpdXM6IDk5OXB4OwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiAycHg7CiAgbWF4LXdpZHRoOiAyMjBweDsKICBoZWlnaHQ6IDIycHg7CiAgcGFkZGluZzogMCA0cHggMCA4cHg7CiAgZGlzcGxheTogaW5saW5lLWZsZXg7Cn0KCi5VLWhqcXFfdW5tYW5hZ2VkQ2hpcE5hbWUgewogIHdoaXRlLXNwYWNlOiBub3dyYXA7CiAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7CiAgZm9udC1zaXplOiAxMnB4OwogIG92ZXJmbG93OiBoaWRkZW47Cn0KCi5VLWhqcXFfdW5tYW5hZ2VkQWRvcHQgewogIGZvbnQ6IGluaGVyaXQ7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1icmFuZC1wcmltYXJ5LCAjNGY2ZWY3KTsKICBjdXJzb3I6IHBvaW50ZXI7CiAgYmFja2dyb3VuZDogbm9uZTsKICBib3JkZXI6IG5vbmU7CiAgZmxleC1zaHJpbms6IDA7CiAgcGFkZGluZzogMCA0cHg7CiAgZm9udC1zaXplOiAxMnB4OwogIGxpbmUtaGVpZ2h0OiAxOHB4Owp9CgouVS1oanFxX3VubWFuYWdlZEFkb3B0OmRpc2FibGVkIHsKICBjdXJzb3I6IGRlZmF1bHQ7CiAgb3BhY2l0eTogLjU7Cn0KCi5VLWhqcXFfc3JjVGFiRWRpdCB7CiAgZm9udDogaW5oZXJpdDsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXRlcnRpYXJ5LCAjOWNhM2FmKTsKICBjdXJzb3I6IHBvaW50ZXI7CiAgYmFja2dyb3VuZDogbm9uZTsKICBib3JkZXI6IG5vbmU7CiAgZmxleC1zaHJpbms6IDA7CiAgbWFyZ2luLWxlZnQ6IDRweDsKICBwYWRkaW5nOiAwIDJweDsKICBmb250LXNpemU6IDEycHg7CiAgbGluZS1oZWlnaHQ6IDE4cHg7Cn0KCi5VLWhqcXFfc3JjVGFiRWRpdDpob3ZlciB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1wcmltYXJ5LCAjMWYyMzI4KTsKfQoKLlUtaGpxcV9zcmNUYWJPbiAuVS1oanFxX3NyY1RhYkVkaXQsIC5VLWhqcXFfc3JjVGFiT24gLlUtaGpxcV9zcmNUYWJFZGl0OmhvdmVyIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnktZm9yZWdyb3VuZCwgI2ZmZik7Cn0KCi5VLWhqcXFfc3JjVGFiLCAuVS1oanFxX3NyY1RhYk9uIHsKICBib3JkZXI6IDFweCBzb2xpZCB2YXIoLS1kc3ctYWxpYXMtYm9yZGVyLWwzLCAjZDlkZGUzKTsKICBiYWNrZ3JvdW5kOiB2YXIoLS1kc3ctYWxpYXMtYmctbGF5ZXItMSwgI2ZmZik7CiAgYm9yZGVyLXJhZGl1czogOTk5cHg7CiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICB3aWR0aDogYXV0bzsKICBtYXgtd2lkdGg6IDEwMCU7CiAgaGVpZ2h0OiAyNHB4OwogIHBhZGRpbmc6IDAgMTBweDsKICBkaXNwbGF5OiBpbmxpbmUtZmxleDsKICBwb3NpdGlvbjogcmVsYXRpdmU7CiAgb3ZlcmZsb3c6IGhpZGRlbjsKfQoKLlUtaGpxcV9zcmNUYWJNYWluIHsKICBmb250OiBpbmhlcml0OwogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtcHJpbWFyeSwgIzFmMjMyOCk7CiAgY3Vyc29yOiBwb2ludGVyOwogIHdoaXRlLXNwYWNlOiBub3dyYXA7CiAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7CiAgYmFja2dyb3VuZDogbm9uZTsKICBib3JkZXI6IG5vbmU7CiAgZmxleDogMTsKICBtaW4td2lkdGg6IDA7CiAgcGFkZGluZzogMDsKICBmb250LXNpemU6IDEycHg7CiAgbGluZS1oZWlnaHQ6IDE4cHg7CiAgb3ZlcmZsb3c6IGhpZGRlbjsKfQoKLlUtaGpxcV9zcmNUYWJNYWluOmhvdmVyIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWJyYW5kLXByaW1hcnksICM0ZjZlZjcpOwp9CgouVS1oanFxX3NyY1RhYk9uIHsKICBiYWNrZ3JvdW5kOiB2YXIoLS1kc3ctYWxpYXMtYnJhbmQtcHJpbWFyeSwgIzBmMTExNSk7CiAgYm9yZGVyLWNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtYnJhbmQtcHJpbWFyeSwgIzBmMTExNSk7Cn0KCi5VLWhqcXFfc3JjVGFiT24gLlUtaGpxcV9zcmNUYWJNYWluIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnktZm9yZWdyb3VuZCwgI2ZmZik7CiAgZm9udC13ZWlnaHQ6IDYwMDsKfQoKLlUtaGpxcV9zcmNUYWJEZWwgewogIGZvbnQ6IGluaGVyaXQ7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC10ZXJ0aWFyeSwgIzljYTNhZik7CiAgY3Vyc29yOiBwb2ludGVyOwogIGJhY2tncm91bmQ6IG5vbmU7CiAgYm9yZGVyOiBub25lOwogIGZsZXgtc2hyaW5rOiAwOwogIG1hcmdpbi1sZWZ0OiA0cHg7CiAgcGFkZGluZzogMCAycHg7CiAgZm9udC1zaXplOiAxMnB4OwogIGxpbmUtaGVpZ2h0OiAxOHB4Owp9CgouVS1oanFxX3NyY1RhYkRlbDpob3ZlciB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1zdGF0ZS1lcnJvci1wcmltYXJ5LCAjZGMyNjI2KTsKfQoKLlUtaGpxcV9zcmNUYWJPbiAuVS1oanFxX3NyY1RhYkRlbCwgLlUtaGpxcV9zcmNUYWJPbiAuVS1oanFxX3NyY1RhYkRlbDpob3ZlciB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1wcmltYXJ5LWZvcmVncm91bmQsICNmZmYpOwp9CgouVS1oanFxX3NyY1RhYkNvbnRyb2xzIHsKICBib3JkZXItcmFkaXVzOiBpbmhlcml0OwogIGJhY2tncm91bmQ6IGluaGVyaXQ7CiAgaGVpZ2h0OiAxMDAlOwogIGJveC1zaGFkb3c6IDAgMCA2cHggNnB4IHZhcigtLWRzdy1hbGlhcy1iZy1sYXllci0xKTsKICBvcGFjaXR5OiAwOwogIHBvaW50ZXItZXZlbnRzOiBub25lOwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiAycHg7CiAgcGFkZGluZzogMCA2cHggMCA4cHg7CiAgdHJhbnNpdGlvbjogb3BhY2l0eSAuMTJzOwogIGRpc3BsYXk6IGlubGluZS1mbGV4OwogIHBvc2l0aW9uOiBhYnNvbHV0ZTsKICB0b3A6IDA7CiAgcmlnaHQ6IDA7Cn0KCi5VLWhqcXFfc3JjVGFiQ29udHJvbHMgPiBidXR0b24gewogIHBvaW50ZXItZXZlbnRzOiBhdXRvOwp9CgouVS1oanFxX3NyY1RhYjpob3ZlciAuVS1oanFxX3NyY1RhYkNvbnRyb2xzLCAuVS1oanFxX3NyY1RhYjpmb2N1cy13aXRoaW4gLlUtaGpxcV9zcmNUYWJDb250cm9scyB7CiAgb3BhY2l0eTogMTsKfQoKLlUtaGpxcV9zcmNUYWJPbiAuVS1oanFxX3NyY1RhYkNvbnRyb2xzIHsKICBiYWNrZ3JvdW5kOiB2YXIoLS1kc3ctYWxpYXMtYnJhbmQtcHJpbWFyeSwgIzBmMTExNSk7CiAgYm94LXNoYWRvdzogMCAwIDZweCA2cHggdmFyKC0tZHN3LWFsaWFzLWJyYW5kLXByaW1hcnksICMwZjExMTUpOwp9CgpAbWVkaWEgKHByZWZlcnMtcmVkdWNlZC1tb3Rpb246IHJlZHVjZSkgewogIC5VLWhqcXFfc3JjVGFiQ29udHJvbHMgewogICAgdHJhbnNpdGlvbjogbm9uZTsKICB9Cn0KCi5VLWhqcXFfZ3JpZCB7CiAgc2Nyb2xsYmFyLWd1dHRlcjogc3RhYmxlOwogIGZsZXg6IDE7CiAgZ3JpZC10ZW1wbGF0ZS1jb2x1bW5zOiByZXBlYXQoMiwgbWlubWF4KDAsIDFmcikpOwogIGFsaWduLWNvbnRlbnQ6IHN0YXJ0OwogIGdhcDogMTJweDsKICBtaW4td2lkdGg6IDA7CiAgbWluLWhlaWdodDogMDsKICBwYWRkaW5nLXJpZ2h0OiA0cHg7CiAgZGlzcGxheTogZ3JpZDsKICBvdmVyZmxvdy15OiBhdXRvOwp9CgouVS1oanFxX2xpc3QgewogIHNjcm9sbGJhci1ndXR0ZXI6IHN0YWJsZTsKICBmbGV4LWRpcmVjdGlvbjogY29sdW1uOwogIGZsZXg6IDE7CiAgZ2FwOiA4cHg7CiAgbWluLXdpZHRoOiAwOwogIG1pbi1oZWlnaHQ6IDA7CiAgcGFkZGluZy1yaWdodDogNHB4OwogIGRpc3BsYXk6IGZsZXg7CiAgb3ZlcmZsb3cteTogYXV0bzsKfQoKLlUtaGpxcV9saXN0IC5VLWhqcXFfY2FyZCB7CiAgZmxleC1mbG93OiB3cmFwOwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiA4cHggMTRweDsKfQoKLlUtaGpxcV9saXN0IC5VLWhqcXFfY2FyZFRvcCwgLlUtaGpxcV9saXN0IC5VLWhqcXFfY2FyZEFjdGlvbnMgewogIGZsZXg6IG5vbmU7Cn0KCi5VLWhqcXFfbGlzdCAuVS1oanFxX21ldGEsIC5VLWhqcXFfbGlzdCAuVS1oanFxX3RhZ1JvdyB7CiAgZmxleC1iYXNpczogMTAwJTsKfQoKLlUtaGpxcV9lbXB0eSB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC10ZXJ0aWFyeSwgIzhiOTNhMSk7CiAgdGV4dC1hbGlnbjogY2VudGVyOwogIGdyaWQtY29sdW1uOiAxIC8gLTE7CiAgcGFkZGluZzogNDhweCAwOwogIGZvbnQtc2l6ZTogMTNweDsKfQoKLlUtaGpxcV90YWcgewogIGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWRzdy1hbGlhcy1ib3JkZXItbDMsICNkOWRkZTMpOwogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtc2Vjb25kYXJ5LCAjNmI3MjgwKTsKICBib3JkZXItcmFkaXVzOiA0cHg7CiAgZmxleC1zaHJpbms6IDA7CiAgcGFkZGluZzogMXB4IDZweDsKICBmb250LXNpemU6IDEycHg7CiAgbGluZS1oZWlnaHQ6IDE4cHg7Cn0KCi5VLWhqcXFfd2FybkxpbmUgewogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtc3RhdGUtd2Fybi1wcmltYXJ5LCAjYjQ1MzA5KTsKICBjdXJzb3I6IGhlbHA7CiAgbWFyZ2luOiAwOwogIGZvbnQtc2l6ZTogMTJweDsKICBmb250LXdlaWdodDogNjAwOwogIGxpbmUtaGVpZ2h0OiAxOHB4Owp9CgouVS1oanFxX21vZGFsRm9vdGVyIHsKICBqdXN0aWZ5LWNvbnRlbnQ6IGZsZXgtZW5kOwogIGdhcDogOHB4OwogIHdpZHRoOiAxMDAlOwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5VLWhqcXFfY29uZmlybUNoZWNrIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnksICMxZjIzMjgpOwogIGZsZXgtZGlyZWN0aW9uOiByb3c7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBnYXA6IDhweDsKICBmb250LXNpemU6IDEycHg7CiAgZGlzcGxheTogZmxleDsKfQoKLlUtaGpxcV9tb2RhbEZvb3RlckxlZnQgewogIGdhcDogOHB4OwogIG1hcmdpbi1yaWdodDogYXV0bzsKICBkaXNwbGF5OiBmbGV4Owp9CgouVS1oanFxX2VkaXRvckRpYWxvZyB7CiAgd2lkdGg6IG1pbig2NDBweCwgOTJ2dyk7Cn0KCi5VLWhqcXFfaW5zdGFsbENvbmZpcm1Cb2R5IHsKICBmbGV4LWRpcmVjdGlvbjogY29sdW1uOwogIGdhcDogMTBweDsKICBtaW4td2lkdGg6IDA7CiAgZGlzcGxheTogZmxleDsKfQoKLlUtaGpxcV9pbnN0YWxsQ29uZmlybVN1aXRlIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnksICMxMTE4MjcpOwogIGZvbnQtd2VpZ2h0OiA2MDA7Cn0KCi5VLWhqcXFfaW5zdGFsbENvbmZpcm1NZXRhIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXNlY29uZGFyeSwgIzRiNTU2Myk7CiAgZm9udC1zaXplOiAxMnB4Owp9CgouVS1oanFxX2luc3RhbGxDb25maXJtQ29tbWl0IHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXNlY29uZGFyeSwgIzRiNTU2Myk7CiAgZm9udC1mYW1pbHk6IHVpLW1vbm9zcGFjZSwgU0ZNb25vLVJlZ3VsYXIsIE1lbmxvLCBtb25vc3BhY2U7CiAgZm9udC1zaXplOiAxMnB4Owp9CgouVS1oanFxX2luc3RhbGxDb25maXJtVGFncyB7CiAgZmxleC13cmFwOiB3cmFwOwogIGdhcDogNnB4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5VLWhqcXFfaW5zdGFsbENvbmZpcm1XYXJuIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLXN0YXRlLXdhcm4tbGFiZWwsICNkZDg2MjkpOwogIGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWRzdy1hbGlhcy1zdGF0ZS13YXJuLWxhYmVsLCAjZGQ4NjI5KTsKICBib3JkZXItcmFkaXVzOiA4cHg7CiAgcGFkZGluZzogOHB4IDEwcHg7CiAgZm9udC1zaXplOiAxMnB4Owp9CgouVS1oanFxX3Byb2dyZXNzLCAuVS1oanFxX3Byb2dyZXNzRXJyb3IgewogIGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWRzdy1hbGlhcy1ib3JkZXItbDIsICNlNWU3ZWIpOwogIGJhY2tncm91bmQ6IHZhcigtLWRzdy1hbGlhcy1iZy1sYXllci0yLCAjN2Y3ZjdmMGYpOwogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtcHJpbWFyeSwgIzFmMjMyOCk7CiAgYm9yZGVyLXJhZGl1czogOHB4OwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiAxMHB4OwogIHBhZGRpbmc6IDEwcHggMTJweDsKICBmb250LXNpemU6IDEzcHg7CiAgbGluZS1oZWlnaHQ6IDIwcHg7CiAgZGlzcGxheTogZmxleDsKfQoKLlUtaGpxcV9wcm9ncmVzc0Vycm9yIHsKICBib3JkZXItY29sb3I6IHZhcigtLWRzdy1hbGlhcy1zdGF0ZS1lcnJvci1wcmltYXJ5LCAjZWMxMzEzKTsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLXN0YXRlLWVycm9yLXByaW1hcnksICNlYzEzMTMpOwp9CgouVS1oanFxX3Byb2dyZXNzU3BpbiB7CiAgYm9yZGVyOiAycHggc29saWQgdmFyKC0tZHN3LWFsaWFzLWJvcmRlci1sMiwgI2U1ZTdlYik7CiAgYm9yZGVyLXRvcC1jb2xvcjogdmFyKC0tZHN3LWFsaWFzLWJyYW5kLXByaW1hcnksICM0ZjZlZjcpOwogIGJvcmRlci1yYWRpdXM6IDUwJTsKICBmbGV4LXNocmluazogMDsKICB3aWR0aDogMTRweDsKICBoZWlnaHQ6IDE0cHg7CiAgYW5pbWF0aW9uOiAuOHMgbGluZWFyIGluZmluaXRlIFUtaGpxcV9kc2hBcG1TcGluOwp9CgpAa2V5ZnJhbWVzIFUtaGpxcV9kc2hBcG1TcGluIHsKICB0byB7CiAgICB0cmFuc2Zvcm06IHJvdGF0ZSgzNjBkZWcpOwogIH0KfQoKLlUtaGpxcV9wcm9ncmVzc0ZhaWwgewogIGZsZXgtc2hyaW5rOiAwOwogIGZvbnQtc2l6ZTogMTNweDsKfQoKLlUtaGpxcV9wcm9ncmVzc1RleHQgewogIG92ZXJmbG93LXdyYXA6IGFueXdoZXJlOwogIG1pbi13aWR0aDogMDsKfQoKQG1lZGlhICh3aWR0aCA8PSA3MjBweCkgewogIC5VLWhqcXFfcGFnZVZpZXcgewogICAgcGFkZGluZzogMTRweDsKICB9CgogIC5VLWhqcXFfc291cmNlVGFic1JvdyB7CiAgICBncmlkLXRlbXBsYXRlLWNvbHVtbnM6IHJlcGVhdChhdXRvLWZpbGwsIG1pbm1heCgxMDJweCwgMWZyKSk7CiAgfQoKICAuVS1oanFxX2dyaWQgewogICAgZ3JpZC10ZW1wbGF0ZS1jb2x1bW5zOiBtaW5tYXgoMCwgMWZyKTsKICB9CgogIC5VLWhqcXFfbGlzdCAuVS1oanFxX2NhcmRUb3AsIC5VLWhqcXFfbGlzdCAuVS1oanFxX2NhcmRBY3Rpb25zIHsKICAgIG1heC13aWR0aDogMTAwJTsKICB9Cn0KCkBtZWRpYSAocHJlZmVycy1yZWR1Y2VkLW1vdGlvbjogcmVkdWNlKSB7CiAgLlUtaGpxcV9wcm9ncmVzc1NwaW4sIC5VLWhqcXFfc3dpdGNoT24sIC5VLWhqcXFfc3dpdGNoT2ZmLCAuVS1oanFxX3N3aXRjaFRodW1iIHsKICAgIHRyYW5zaXRpb246IG5vbmU7CiAgICBhbmltYXRpb246IG5vbmU7CiAgfQp9CgouVS1oanFxX3N1cmZhY2VUb2dnbGVzIHsKICBmbGV4LXdyYXA6IHdyYXA7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBnYXA6IDRweCAxNHB4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5VLWhqcXFfc3VyZmFjZVRvZ2dsZSB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1zZWNvbmRhcnksICM2MTY2NmIpOwogIGN1cnNvcjogcG9pbnRlcjsKICB1c2VyLXNlbGVjdDogbm9uZTsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGdhcDogNXB4OwogIGZvbnQtc2l6ZTogMTJweDsKICBkaXNwbGF5OiBpbmxpbmUtZmxleDsKfQoKLlUtaGpxcV9zdXJmYWNlVG9nZ2xlIGlucHV0W3R5cGU9ImNoZWNrYm94Il0gewogIGFjY2VudC1jb2xvcjogdmFyKC0tZHN3LWFsaWFzLWJyYW5kLXByaW1hcnktbmV3LWNvbG9ycHJpbWFyeS1uZXctY29sb3IsICM0MTc2ZTYpOwogIG1hcmdpbjogMDsKfQoKLlUtaGpxcV9wbHVnaW5DYXJkIHsKICBib3JkZXI6IDFweCBzb2xpZCB2YXIoLS1kc3ctYWxpYXMtYm9yZGVyLWwyLCAjZTVlN2ViKTsKICBiYWNrZ3JvdW5kOiB2YXIoLS1kc3ctYWxpYXMtYmctbGF5ZXItMywgI2ZmZik7CiAgYm9yZGVyLXJhZGl1czogMTJweDsKICBsaXN0LXN0eWxlOiBub25lOwogIHRyYW5zaXRpb246IGJvcmRlci1jb2xvciAuMTZzLCBiYWNrZ3JvdW5kIC4xNnM7CiAgY29udGFpbmVyOiBVLWhqcXFfbWFya2V0LWNvbmZpZyAvIGlubGluZS1zaXplOwp9CgouVS1oanFxX3BsdWdpbkNhcmQ6aG92ZXIgewogIGJvcmRlci1jb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLWRpbW1lZCwgI2M4Y2NkNCk7Cn0KCi5VLWhqcXFfcGx1Z2luQ2FyZE9wZW4gewogIGJhY2tncm91bmQ6IHZhcigtLWRzdy1hbGlhcy1iZy1sYXllci0yLCAjZjdmOGZhKTsKICBib3JkZXItY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1kaW1tZWQsICNjOGNjZDQpOwp9CgouVS1oanFxX3BsdWdpbkNhcmRbZGF0YS1idXN5PSJ0cnVlIl0gewogIG9wYWNpdHk6IC42OwogIHBvaW50ZXItZXZlbnRzOiBub25lOwp9CgouVS1oanFxX3BsdWdpbkNhcmRIZWFkZXIgewogIGFwcGVhcmFuY2U6IG5vbmU7CiAgd2lkdGg6IDEwMCU7CiAgZm9udDogaW5oZXJpdDsKICBjb2xvcjogaW5oZXJpdDsKICB0ZXh0LWFsaWduOiBsZWZ0OwogIGN1cnNvcjogcG9pbnRlcjsKICBiYWNrZ3JvdW5kOiBub25lOwogIGJvcmRlcjogMDsKICBib3JkZXItcmFkaXVzOiAxMnB4OwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiAxMnB4OwogIHBhZGRpbmc6IDE0cHggMTZweDsKICBkaXNwbGF5OiBmbGV4Owp9CgouVS1oanFxX3BsdWdpbkNhcmRIZWFkZXI6Zm9jdXMtdmlzaWJsZSB7CiAgb3V0bGluZTogMnB4IHNvbGlkIHZhcigtLWRzdy1hbGlhcy1icmFuZC1wcmltYXJ5LCAjNGY2ZWY3KTsKICBvdXRsaW5lLW9mZnNldDogLTJweDsKfQoKLlUtaGpxcV9wbHVnaW5DYXJkQm9keSB7CiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjsKICBnYXA6IDhweDsKICBkaXNwbGF5OiBmbGV4Owp9CgouVS1oanFxX3BsdWdpbkNhcmRSb3cgewogIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGdhcDogMTZweDsKICBwYWRkaW5nOiA4cHggMCA0cHg7CiAgZGlzcGxheTogZmxleDsKfQoKLlUtaGpxcV9wbHVnaW5DYXJkVGV4dCB7CiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjsKICBmbGV4OiAxOwogIGdhcDogNHB4OwogIG1pbi13aWR0aDogMDsKICBkaXNwbGF5OiBmbGV4Owp9CgouVS1oanFxX3BsdWdpbkNhcmRUaXRsZSB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1wcmltYXJ5LCAjMWYyMzI4KTsKICBmb250LXNpemU6IDE1cHg7CiAgZm9udC13ZWlnaHQ6IDYwMDsKICBsaW5lLWhlaWdodDogMS40Owp9CgouVS1oanFxX3BsdWdpbkNhcmREZXNjIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXRlcnRpYXJ5LCAjOGI5M2ExKTsKICBmb250LXNpemU6IDEzcHg7CiAgbGluZS1oZWlnaHQ6IDEuNTsKfQoKLlUtaGpxcV9wbHVnaW5DYXJkUm93TGFiZWwgewogIGZvbnQtc2l6ZTogMTNweDsKICBmb250LXdlaWdodDogNTAwOwogIGxpbmUtaGVpZ2h0OiAyMHB4Owp9CgpAY29udGFpbmVyIFUtaGpxcV9tYXJrZXQtY29uZmlnICh3aWR0aCA8PSAzMjBweCkgewogIC5VLWhqcXFfcGx1Z2luQ2FyZFJvdyB7CiAgICBmbGV4LWRpcmVjdGlvbjogY29sdW1uOwogICAgYWxpZ24taXRlbXM6IGZsZXgtc3RhcnQ7CiAgICBnYXA6IDhweDsKICB9CgogIC5VLWhqcXFfcGx1Z2luQ2FyZFRleHQgewogICAgb3ZlcmZsb3ctd3JhcDogYW55d2hlcmU7CiAgICB3aWR0aDogMTAwJTsKICB9Cn0KCi5VLWhqcXFfcGx1Z2luQ2FyZEVycm9yIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLXN0YXRlLWVycm9yLXByaW1hcnksICNkYzI2MjYpOwogIG1hcmdpbjogMDsKICBmb250LXNpemU6IDEycHg7CiAgbGluZS1oZWlnaHQ6IDEuNTsKfQoKLlUtaGpxcV9wbHVnaW5GaWVsZEhlYWQgewogIGZsZXgtd3JhcDogd3JhcDsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGdhcDogOHB4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5VLWhqcXFfcGx1Z2luRmllbGRCYWRnZXMgewogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiA2cHg7CiAgZGlzcGxheTogaW5saW5lLWZsZXg7Cn0KCi5VLWhqcXFfcGx1Z2luRmllbGRSZXNldCB7CiAgYXBwZWFyYW5jZTogbm9uZTsKICBmb250OiBpbmhlcml0OwogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtc2Vjb25kYXJ5LCAjNmI3MjgwKTsKICBjdXJzb3I6IHBvaW50ZXI7CiAgdGV4dC11bmRlcmxpbmUtb2Zmc2V0OiAycHg7CiAgYmFja2dyb3VuZDogbm9uZTsKICBib3JkZXI6IDA7CiAgcGFkZGluZzogMDsKICBmb250LXNpemU6IDEycHg7CiAgbGluZS1oZWlnaHQ6IDE4cHg7CiAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7Cn0KCi5VLWhqcXFfcGx1Z2luRmllbGRSZXNldDpkaXNhYmxlZCB7CiAgY3Vyc29yOiBkZWZhdWx0OwogIG9wYWNpdHk6IC41Owp9CgouVS1oanFxX3BsdWdpbkNhcmRSZWFkb25seSB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC10ZXJ0aWFyeSwgIzhiOTNhMSk7CiAgbWFyZ2luOiA0cHggMCAwOwogIGZvbnQtc2l6ZTogMTJweDsKICBsaW5lLWhlaWdodDogMS41Owp9CgouVS1oanFxX3BsdWdpbkNhcmRGb290ZXIgewogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiA4cHg7CiAgcGFkZGluZy10b3A6IDE2cHg7CiAgZGlzcGxheTogZmxleDsKfQoKLlUtaGpxcV9wbHVnaW5DYXJkRm9vdGVyIC5VLWhqcXFfcGx1Z2luQ2FyZEVycm9yIHsKICBmbGV4OiAxOwp9CgouVS1oanFxX3BsdWdpbkNhcmREaXNjYXJkIHsKICBhcHBlYXJhbmNlOiBub25lOwogIGZvbnQ6IGluaGVyaXQ7CiAgY3Vyc29yOiBwb2ludGVyOwogIGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWRzdy1hbGlhcy1ib3JkZXItbDIsICNlNWU3ZWIpOwogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtcHJpbWFyeSwgIzFmMjMyOCk7CiAgYmFja2dyb3VuZDogbm9uZTsKICBib3JkZXItcmFkaXVzOiA4cHg7CiAgcGFkZGluZzogNHB4IDEycHg7CiAgZm9udC1zaXplOiAxM3B4OwogIGxpbmUtaGVpZ2h0OiAyMHB4Owp9CgouVS1oanFxX3BsdWdpbkNhcmREaXNjYXJkOmhvdmVyOm5vdCg6ZGlzYWJsZWQpIHsKICBiYWNrZ3JvdW5kOiB2YXIoLS1kc3ctYWxpYXMtaW50ZXJhY3RpdmUtYmctaG92ZXIsICMwMDAwMDAwYSk7Cn0KCi5VLWhqcXFfcGx1Z2luQ2FyZERpc2NhcmQ6ZGlzYWJsZWQgewogIGN1cnNvcjogZGVmYXVsdDsKICBvcGFjaXR5OiAuNTsKfQoKLlUtaGpxcV9wbHVnaW5DaGV2cm9uIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXRlcnRpYXJ5LCAjOGI5M2ExKTsKICBmbGV4OiBub25lOwogIHRyYW5zaXRpb246IHRyYW5zZm9ybSAuMTZzOwogIGRpc3BsYXk6IGlubGluZS1mbGV4Owp9CgouVS1oanFxX3BsdWdpbkNoZXZyb25PcGVuIHsKICB0cmFuc2Zvcm06IHJvdGF0ZSgxODBkZWcpOwp9Ci5fNUpERk1XX2ZpZWxkIHsKICBmbGV4LWRpcmVjdGlvbjogY29sdW1uOwogIGdhcDogNXB4OwogIG1pbi13aWR0aDogMDsKICBkaXNwbGF5OiBmbGV4Owp9CgouXzVKREZNV19maWVsZCA+IGxhYmVsLCAuXzVKREZNV19maWVsZCA+IHNwYW4sIC5fNUpERk1XX2ZpZWxkID4gLl81SkRGTVdfcm93SGVhZCA+IHNwYW4gewogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtc2Vjb25kYXJ5KTsKICBmb250LXNpemU6IDEycHg7CiAgZm9udC13ZWlnaHQ6IDYwMDsKfQoKLl81SkRGTVdfZmllbGQgaW5wdXQsIC5fNUpERk1XX2ZpZWxkIHNlbGVjdCwgLl81SkRGTVdfZmllbGQgdGV4dGFyZWEgewogIGJveC1zaXppbmc6IGJvcmRlci1ib3g7CiAgYm9yZGVyOiAxcHggc29saWQgdmFyKC0tZHN3LWFsaWFzLWJvcmRlci1sMik7CiAgYmFja2dyb3VuZDogdmFyKC0tZHN3LWFsaWFzLWJnLWxheWVyLTEpOwogIHdpZHRoOiAxMDAlOwogIG1pbi13aWR0aDogMDsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnkpOwogIGZvbnQ6IGluaGVyaXQ7CiAgYm9yZGVyLXJhZGl1czogOHB4OwogIHBhZGRpbmc6IDdweCA5cHg7CiAgZm9udC1zaXplOiAxMnB4Owp9CgouXzVKREZNV19maWVsZCB0ZXh0YXJlYSB7CiAgcmVzaXplOiB2ZXJ0aWNhbDsKICBtaW4taGVpZ2h0OiAyNDBweDsKICBmb250LWZhbWlseTogdWktbW9ub3NwYWNlLCBTRk1vbm8tUmVndWxhciwgTWVubG8sIENvbnNvbGFzLCBtb25vc3BhY2U7CiAgZm9udC1zaXplOiAxMnB4OwogIGxpbmUtaGVpZ2h0OiAxOXB4Owp9CgouXzVKREZNV19qc29uQXJlYSB7CiAgbWluLWhlaWdodDogMjIwcHg7Cn0KCi5fNUpERk1XX2ZpZWxkUm93IHsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGdhcDogOHB4OwogIG1pbi13aWR0aDogMDsKICBkaXNwbGF5OiBmbGV4Owp9CgouXzVKREZNV19maWVsZFJvdyA+IGlucHV0IHsKICBmbGV4OiBhdXRvOwp9CgouXzVKREZNV19maWVsZCBpbnB1dDpmb2N1cy12aXNpYmxlLCAuXzVKREZNV19maWVsZCBzZWxlY3Q6Zm9jdXMtdmlzaWJsZSwgLl81SkRGTVdfZmllbGQgdGV4dGFyZWE6Zm9jdXMtdmlzaWJsZSB7CiAgb3V0bGluZTogMnB4IHNvbGlkIHZhcigtLWRzdy1hbGlhcy1icmFuZC1wcmltYXJ5KTsKICBvdXRsaW5lLW9mZnNldDogMXB4Owp9CgouXzVKREZNV19oaW50IHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXRlcnRpYXJ5KTsKICBmb250LXNpemU6IDExcHg7CiAgZm9udC13ZWlnaHQ6IDQwMDsKICBsaW5lLWhlaWdodDogMTZweDsKfQoKLl81SkRGTVdfcmVxdWlyZWQgewogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtc3RhdGUtZXJyb3ItcHJpbWFyeSk7CiAgbWFyZ2luLWxlZnQ6IDRweDsKICBmb250LXdlaWdodDogNDAwOwp9CgouXzVKREZNV19lbXB0eVJvd3MgewogIGJvcmRlcjogMXB4IGRhc2hlZCB2YXIoLS1kc3ctYWxpYXMtYm9yZGVyLWwzKTsKICB3aWR0aDogMTAwJTsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXRlcnRpYXJ5KTsKICBmb250OiBpbmhlcml0OwogIHRleHQtYWxpZ246IGxlZnQ7CiAgY3Vyc29yOiBwb2ludGVyOwogIGJhY2tncm91bmQ6IG5vbmU7CiAgYm9yZGVyLXJhZGl1czogOHB4OwogIHBhZGRpbmc6IDhweCAxMHB4OwogIGZvbnQtc2l6ZTogMTFweDsKICBsaW5lLWhlaWdodDogMTZweDsKfQoKLl81SkRGTVdfZW1wdHlSb3dzOmhvdmVyIHsKICBiYWNrZ3JvdW5kOiB2YXIoLS1kc3ctYWxpYXMtaW50ZXJhY3RpdmUtYmctaG92ZXIpOwogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtc2Vjb25kYXJ5KTsKfQoKLl81SkRGTVdfZm9ybSB7CiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjsKICBnYXA6IDEwcHg7CiAgbWluLXdpZHRoOiAwOwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5fNUpERk1XX2VkaXRvckJvZHkgewogIG1heC13aWR0aDogNjIwcHg7Cn0KCi5fNUpERk1XX2Zvcm1HcmlkIHsKICBncmlkLXRlbXBsYXRlLWNvbHVtbnM6IHJlcGVhdCgyLCBtaW5tYXgoMCwgMWZyKSk7CiAgYWxpZ24taXRlbXM6IHN0YXJ0OwogIGdhcDogMTBweDsKICBkaXNwbGF5OiBncmlkOwp9CgouXzVKREZNV19mdWxsIHsKICBncmlkLWNvbHVtbjogMSAvIC0xOwp9CgouXzVKREZNV19zZWcgewogIGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWRzdy1hbGlhcy1ib3JkZXItbDIpOwogIGJvcmRlci1yYWRpdXM6IDhweDsKICBmbGV4OiBub25lOwogIGdhcDogMnB4OwogIHBhZGRpbmc6IDJweDsKICBkaXNwbGF5OiBpbmxpbmUtZmxleDsKfQoKLl81SkRGTVdfc2VnIGJ1dHRvbiB7CiAgaGVpZ2h0OiAyNHB4OwogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtc2Vjb25kYXJ5KTsKICBjdXJzb3I6IHBvaW50ZXI7CiAgZm9udDogaW5oZXJpdDsKICBiYWNrZ3JvdW5kOiBub25lOwogIGJvcmRlcjogbm9uZTsKICBib3JkZXItcmFkaXVzOiA2cHg7CiAgcGFkZGluZzogMCAxMHB4OwogIGZvbnQtc2l6ZTogMTJweDsKfQoKLl81SkRGTVdfc2VnIGJ1dHRvbjpob3ZlciB7CiAgYmFja2dyb3VuZDogdmFyKC0tZHN3LWFsaWFzLWludGVyYWN0aXZlLWJnLWhvdmVyKTsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnkpOwp9CgouXzVKREZNV19zZWcgYnV0dG9uW2FyaWEtcHJlc3NlZD0idHJ1ZSJdIHsKICBiYWNrZ3JvdW5kOiB2YXIoLS1kc3ctYWxpYXMtaW50ZXJhY3RpdmUtYmctYWN0aXZlKTsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnkpOwogIGZvbnQtd2VpZ2h0OiA2MDA7Cn0KCi5fNUpERk1XX3NlZyBidXR0b246Zm9jdXMtdmlzaWJsZSB7CiAgb3V0bGluZTogMnB4IHNvbGlkIHZhcigtLWRzdy1hbGlhcy1icmFuZC1wcmltYXJ5KTsKICBvdXRsaW5lLW9mZnNldDogMnB4Owp9CgouXzVKREZNV19yZWFkb25seSB7CiAgYm9yZGVyOiAxcHggZGFzaGVkIHZhcigtLWRzdy1hbGlhcy1ib3JkZXItbDMpOwogIGJhY2tncm91bmQ6IHZhcigtLWRzdy1hbGlhcy1pbnRlcmFjdGl2ZS1iZy1ob3Zlcik7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1wcmltYXJ5KTsKICBib3JkZXItcmFkaXVzOiA4cHg7CiAgcGFkZGluZzogN3B4IDlweDsKICBmb250LWZhbWlseTogdWktbW9ub3NwYWNlLCBTRk1vbm8tUmVndWxhciwgTWVubG8sIENvbnNvbGFzLCBtb25vc3BhY2U7CiAgZm9udC1zaXplOiAxMnB4Owp9CgouXzVKREZNV19yb3dzIHsKICBmbGV4LWRpcmVjdGlvbjogY29sdW1uOwogIGdhcDogNHB4OwogIG1pbi13aWR0aDogMDsKICBkaXNwbGF5OiBmbGV4Owp9CgouXzVKREZNV19yb3cgewogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiA2cHg7CiAgbWluLXdpZHRoOiAwOwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5fNUpERk1XX3JvdyBpbnB1dCB7CiAgZmxleDogYXV0bzsKICB3aWR0aDogMDsKICBtaW4td2lkdGg6IDA7Cn0KCi5fNUpERk1XX3Jvd0tleSB7CiAgZmxleDogMCAwIDM0JTsKfQoKLl81SkRGTVdfcm93S2V5TmFycm93IHsKICBmbGV4OiAwIDAgMjYlOwp9CgouXzVKREZNV19yb3dBY3Rpb25zIHsKICBmbGV4OiBub25lOwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiAycHg7CiAgZGlzcGxheTogZmxleDsKfQoKLl81SkRGTVdfaWNvbkJ0biB7CiAgd2lkdGg6IDI0cHg7CiAgaGVpZ2h0OiAyNHB4OwogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtdGVydGlhcnkpOwogIGN1cnNvcjogcG9pbnRlcjsKICBiYWNrZ3JvdW5kOiBub25lOwogIGJvcmRlcjogbm9uZTsKICBib3JkZXItcmFkaXVzOiA2cHg7CiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBwYWRkaW5nOiAwOwogIGRpc3BsYXk6IGlubGluZS1mbGV4Owp9CgouXzVKREZNV19pY29uQnRuOmhvdmVyIHsKICBiYWNrZ3JvdW5kOiB2YXIoLS1kc3ctYWxpYXMtaW50ZXJhY3RpdmUtYmctaG92ZXItZGFuZ2VyKTsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLXN0YXRlLWVycm9yLXByaW1hcnkpOwp9CgouXzVKREZNV19yb3dIZWFkIHsKICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBnYXA6IDhweDsKICBtaW4taGVpZ2h0OiAyNHB4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5fNUpERk1XX2FkZEljb24gewogIHdpZHRoOiAyNHB4OwogIGhlaWdodDogMjRweDsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWJyYW5kLXByaW1hcnkpOwogIGN1cnNvcjogcG9pbnRlcjsKICBiYWNrZ3JvdW5kOiBub25lOwogIGJvcmRlcjogbm9uZTsKICBib3JkZXItcmFkaXVzOiA2cHg7CiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBwYWRkaW5nOiAwOwogIGRpc3BsYXk6IGlubGluZS1mbGV4Owp9CgouXzVKREZNV19hZGRJY29uOmhvdmVyOm5vdCg6ZGlzYWJsZWQpIHsKICBiYWNrZ3JvdW5kOiB2YXIoLS1kc3ctYWxpYXMtaW50ZXJhY3RpdmUtYmctaG92ZXIpOwogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtcHJpbWFyeSk7Cn0KCi5fNUpERk1XX2FkZEljb246ZGlzYWJsZWQgewogIGN1cnNvcjogZGVmYXVsdDsKICBvcGFjaXR5OiAuNDsKfQoKLl81SkRGTVdfYWRkSWNvbiBzdmcgewogIGRpc3BsYXk6IGJsb2NrOwp9CgouXzVKREZNV19pbmxpbmVDaGVjayB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1wcmltYXJ5KTsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGdhcDogOHB4OwogIGZvbnQtc2l6ZTogMTJweDsKICBkaXNwbGF5OiBpbmxpbmUtZmxleDsKfQoKLl81SkRGTVdfZmllbGRzZXQgewogIGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWRzdy1hbGlhcy1ib3JkZXItbDIpOwogIGJvcmRlci1yYWRpdXM6IDhweDsKICBncmlkLXRlbXBsYXRlLWNvbHVtbnM6IG1pbm1heCgwLCAxZnIpOwogIGdhcDogMTBweDsKICBtaW4td2lkdGg6IDA7CiAgbWFyZ2luOiAwOwogIHBhZGRpbmc6IDRweCAxMnB4IDEycHg7CiAgZGlzcGxheTogZ3JpZDsKfQoKLl81SkRGTVdfZmllbGRzZXQgbGVnZW5kIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXNlY29uZGFyeSk7CiAgcGFkZGluZzogMCA0cHg7CiAgZm9udC1zaXplOiAxMnB4OwogIGZvbnQtd2VpZ2h0OiA2MDA7CiAgbGluZS1oZWlnaHQ6IDE4cHg7Cn0KCi5fNUpERk1XX2ZpZWxkc2V0ID4gLl81SkRGTVdfaGludCwgLl81SkRGTVdfZmllbGRzZXQgPiAuXzVKREZNV19mdWxsIHsKICBncmlkLWNvbHVtbjogMSAvIC0xOwp9CgouXzVKREZNV19wcmV2aWV3Qm94IHsKICBib3JkZXI6IDFweCBzb2xpZCB2YXIoLS1kc3ctYWxpYXMtYm9yZGVyLWwyKTsKICBib3gtc2l6aW5nOiBib3JkZXItYm94OwogIGJvcmRlci1yYWRpdXM6IDhweDsKICBtaW4taGVpZ2h0OiAzMDBweDsKICBwYWRkaW5nOiAxMnB4IDE0cHg7CiAgb3ZlcmZsb3cteTogYXV0bzsKfQoKLl81SkRGTVdfZm9vdGVyIHsKICBmbGV4OiAxOwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiA4cHg7CiAgZGlzcGxheTogZmxleDsKfQoKLl81SkRGTVdfZm9vdGVySGludCB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC10ZXJ0aWFyeSk7CiAgZm9udC1zaXplOiAxMnB4Owp9CgouXzVKREZNV19ncm93IHsKICBmbGV4OiBhdXRvOwp9CgouXzVKREZNV19mb290ZXJFcnJvciB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1zdGF0ZS1lcnJvci1wcmltYXJ5KTsKICBmb250LXNpemU6IDEycHg7Cn0KCkBtZWRpYSAocHJlZmVycy1yZWR1Y2VkLW1vdGlvbjogcmVkdWNlKSB7CiAgLl81SkRGTVdfc2VnIGJ1dHRvbiwgLl81SkRGTVdfYWRkSWNvbiwgLl81SkRGTVdfaWNvbkJ0biB7CiAgICB0cmFuc2l0aW9uOiBub25lOwogIH0KfQoKQGNvbnRhaW5lciAod2lkdGggPD0gNzAwcHgpIHsKICAuXzVKREZNV19mb3JtR3JpZCwgLl81SkRGTVdfZmllbGRzZXQgewogICAgZ3JpZC10ZW1wbGF0ZS1jb2x1bW5zOiBtaW5tYXgoMCwgMWZyKTsKICB9Cn0KLklneWpJcV9jYXJkW2RhdGEtcmVzb3VyY2Utc3RhdGVdIHsKICBib3gtc2l6aW5nOiBib3JkZXItYm94OwogIGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWRzdy1hbGlhcy1ib3JkZXItbDIpOwogIGJhY2tncm91bmQ6IHZhcigtLWRzdy1hbGlhcy1iZy1sYXllci0xKTsKICBtaW4td2lkdGg6IDA7CiAgbWF4LXdpZHRoOiAxMDAlOwogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtcHJpbWFyeSk7CiAgYm94LXNoYWRvdzogbm9uZTsKICBjdXJzb3I6IHBvaW50ZXI7CiAgYm9yZGVyLWxlZnQtd2lkdGg6IDNweDsKICBib3JkZXItcmFkaXVzOiAxMHB4OwogIGdhcDogNHB4IDEwcHg7CiAgcGFkZGluZzogMTFweCAxMnB4IDExcHggMTNweDsKICB0cmFuc2l0aW9uOiBib3JkZXItY29sb3IgLjE0cywgYmFja2dyb3VuZCAuMTRzOwogIGRpc3BsYXk6IGdyaWQ7CiAgcG9zaXRpb246IHJlbGF0aXZlOwogIG92ZXJmbG93OiBoaWRkZW47Cn0KCi5JZ3lqSXFfY2FyZFtkYXRhLXJlc291cmNlLXN0YXRlPSJhY3RpdmUiXSB7CiAgYm9yZGVyLWxlZnQtY29sb3I6IHZhcigtLWRzdy1hbGlhcy1zdGF0ZS1zdWNjZXNzLXByaW1hcnkpOwp9CgouSWd5aklxX2NhcmRbZGF0YS1yZXNvdXJjZS1zdGF0ZT0iZGlzYWJsZWQiXSB7CiAgYm9yZGVyLWxlZnQtY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC10ZXJ0aWFyeSk7Cn0KCi5JZ3lqSXFfY2FyZFtkYXRhLXJlc291cmNlLXN0YXRlPSJ3YXJuaW5nIl0gewogIGJvcmRlci1sZWZ0LWNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtc3RhdGUtd2Fybi1wcmltYXJ5KTsKfQoKLklneWpJcV9jYXJkW2RhdGEtcmVzb3VyY2Utc3RhdGU9ImVycm9yIl0gewogIGJvcmRlci1sZWZ0LWNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtc3RhdGUtZXJyb3ItcHJpbWFyeSk7Cn0KCi5JZ3lqSXFfY2FyZFtkYXRhLXJlc291cmNlLXN0YXRlXTpob3ZlciB7CiAgYmFja2dyb3VuZDogdmFyKC0tZHN3LWFsaWFzLWludGVyYWN0aXZlLWJnLWhvdmVyKTsKfQoKLklneWpJcV9jb2xsZWN0aW9uW2RhdGEtcmVzb3VyY2Utdmlldz0iZ3JpZCJdID4gLklneWpJcV9jYXJkW2RhdGEtcmVzb3VyY2Utc3RhdGVdOmhvdmVyIC5JZ3lqSXFfcm93QWN0aW9ucywgLklneWpJcV9jb2xsZWN0aW9uW2RhdGEtcmVzb3VyY2Utdmlldz0iZ3JpZCJdID4gLklneWpJcV9jYXJkW2RhdGEtcmVzb3VyY2Utc3RhdGVdOmZvY3VzLXdpdGhpbiAuSWd5aklxX3Jvd0FjdGlvbnMgewogIHotaW5kZXg6IDE7Cn0KCi5JZ3lqSXFfY29sbGVjdGlvbltkYXRhLXJlc291cmNlLXZpZXddIHsKICBib3gtc2l6aW5nOiBib3JkZXItYm94OwogIHNjcm9sbGJhci1ndXR0ZXI6IHN0YWJsZTsKICBhbGlnbi1jb250ZW50OiBzdGFydDsKICBhbGlnbi1pdGVtczogc3RyZXRjaDsKICB3aWR0aDogMTAwJTsKICBtaW4td2lkdGg6IDA7CiAgbWluLWhlaWdodDogMDsKICBvdmVyZmxvdy15OiBhdXRvOwp9CgouSWd5aklxX2NvbGxlY3Rpb25bZGF0YS1yZXNvdXJjZS12aWV3PSJncmlkIl0gewogIGdyaWQtdGVtcGxhdGUtY29sdW1uczogcmVwZWF0KGF1dG8tZmlsbCwgbWlubWF4KDI4MHB4LCAxZnIpKTsKICBncmlkLWF1dG8tcm93czogMTIycHg7CiAgZ2FwOiAxMHB4OwogIHBhZGRpbmctcmlnaHQ6IDRweDsKICBkaXNwbGF5OiBncmlkOwp9CgouSWd5aklxX2NvbGxlY3Rpb25bZGF0YS1yZXNvdXJjZS12aWV3PSJsaXN0Il0gewogIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47CiAgZ2FwOiA2cHg7CiAgcGFkZGluZy1yaWdodDogNHB4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5JZ3lqSXFfY29sbGVjdGlvbltkYXRhLXJlc291cmNlLXZpZXc9Imxpc3QiXSA+IC5JZ3lqSXFfY2FyZCB7CiAgZmxleC1zaHJpbms6IDA7Cn0KCi5JZ3lqSXFfY29sbGVjdGlvbltkYXRhLXJlc291cmNlLXZpZXc9ImdyaWQiXSA+IC5JZ3lqSXFfY2FyZFtkYXRhLXJlc291cmNlLXN0YXRlXSB7CiAgZ3JpZC10ZW1wbGF0ZTogIklneWpJcV9pZCBJZ3lqSXFfYWN0IgogICAgICAgICAgICAgICAgICJJZ3lqSXFfYm9keSBJZ3lqSXFfYm9keSIgbWlubWF4KDAsIDFmcikKICAgICAgICAgICAgICAgICAiSWd5aklxX2Zvb3QgSWd5aklxX2Zvb3QiCiAgICAgICAgICAgICAgICAgLyBtaW5tYXgoMCwgMWZyKSBhdXRvOwp9CgouSWd5aklxX2NvbGxlY3Rpb25bZGF0YS1yZXNvdXJjZS12aWV3PSJsaXN0Il0gPiAuSWd5aklxX2NhcmRbZGF0YS1yZXNvdXJjZS1zdGF0ZV0gewogIGJveC1zaXppbmc6IGJvcmRlci1ib3g7CiAgZ3JpZC10ZW1wbGF0ZS1jb2x1bW5zOiBtaW5tYXgoMTYwcHgsIC44NWZyKSBtaW5tYXgoMjEwcHgsIDEuMDVmcikgbWlubWF4KDAsIDEuNWZyKSBhdXRvOwogIGdyaWQtdGVtcGxhdGUtYXJlYXM6ICJJZ3lqSXFfaWQgSWd5aklxX2Zvb3QgSWd5aklxX2JvZHkgSWd5aklxX2FjdCI7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBnYXA6IDE2cHg7CiAgaGVpZ2h0OiA1NnB4Owp9CgpAY29udGFpbmVyICh3aWR0aCA8PSA3MDBweCkgewogIC5JZ3lqSXFfY29sbGVjdGlvbltkYXRhLXJlc291cmNlLXZpZXc9ImdyaWQiXSB7CiAgICBncmlkLXRlbXBsYXRlLWNvbHVtbnM6IHJlcGVhdCgyLCBtaW5tYXgoMCwgMWZyKSk7CiAgICBncmlkLWF1dG8tcm93czogbWF4LWNvbnRlbnQ7CiAgICBnYXA6IDRweDsKICB9CgogIC5JZ3lqSXFfY29sbGVjdGlvbltkYXRhLXJlc291cmNlLXZpZXc9ImdyaWQiXSA+IC5JZ3lqSXFfY2FyZFtkYXRhLXJlc291cmNlLXN0YXRlXSB7CiAgICBncmlkLXRlbXBsYXRlOiAiSWd5aklxX2lkIgogICAgICAgICAgICAgICAgICAgIklneWpJcV9ib2R5IgogICAgICAgICAgICAgICAgICAgIklneWpJcV9mb290IgogICAgICAgICAgICAgICAgICAgLyBtaW5tYXgoMCwgMWZyKTsKICAgIGFsaWduLWNvbnRlbnQ6IHN0YXJ0OwogICAgZ2FwOiA0cHg7CiAgICBwYWRkaW5nOiAxMHB4IDEwcHggMTBweCAxM3B4OwogIH0KCiAgLklneWpJcV9jb2xsZWN0aW9uW2RhdGEtcmVzb3VyY2Utdmlldz0iZ3JpZCJdID4gLklneWpJcV9jYXJkW2RhdGEtcmVzb3VyY2Utc3RhdGVdIC5JZ3lqSXFfcm93SWQsIC5JZ3lqSXFfY29sbGVjdGlvbltkYXRhLXJlc291cmNlLXZpZXc9ImdyaWQiXSA+IC5JZ3lqSXFfY2FyZFtkYXRhLXJlc291cmNlLXN0YXRlXSAuSWd5aklxX3Jvd0JvZHkgewogICAgb3ZlcmZsb3c6IGhpZGRlbjsKICB9CgogIC5JZ3lqSXFfY29sbGVjdGlvbltkYXRhLXJlc291cmNlLXZpZXc9ImdyaWQiXSA+IC5JZ3lqSXFfY2FyZFtkYXRhLXJlc291cmNlLXN0YXRlXSAuSWd5aklxX3Jvd0FjdGlvbnMgewogICAgYmFja2dyb3VuZDogdmFyKC0tZHN3LWFsaWFzLWJnLWxheWVyLTEpOwogICAgYm94LXNoYWRvdzogMCAwIDZweCA4cHggdmFyKC0tZHN3LWFsaWFzLWJnLWxheWVyLTEpOwogICAgb3BhY2l0eTogMDsKICAgIGJvcmRlci1yYWRpdXM6IDE2cHg7CiAgICBnYXA6IDRweDsKICAgIG1hcmdpbi1sZWZ0OiAwOwogICAgcGFkZGluZzogNHB4IDZweDsKICAgIHRyYW5zaXRpb246IG9wYWNpdHkgLjE0czsKICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTsKICAgIHRvcDogOHB4OwogICAgYm90dG9tOiBhdXRvOwogICAgcmlnaHQ6IDhweDsKICB9CgogIC5JZ3lqSXFfY29sbGVjdGlvbltkYXRhLXJlc291cmNlLXZpZXc9ImdyaWQiXSA+IC5JZ3lqSXFfY2FyZFtkYXRhLXJlc291cmNlLXN0YXRlXTpob3ZlciAuSWd5aklxX3Jvd0FjdGlvbnMsIC5JZ3lqSXFfY29sbGVjdGlvbltkYXRhLXJlc291cmNlLXZpZXc9ImdyaWQiXSA+IC5JZ3lqSXFfY2FyZFtkYXRhLXJlc291cmNlLXN0YXRlXTpmb2N1cy13aXRoaW4gLklneWpJcV9yb3dBY3Rpb25zIHsKICAgIG9wYWNpdHk6IDE7CiAgfQoKICAuSWd5aklxX2NvbGxlY3Rpb25bZGF0YS1yZXNvdXJjZS12aWV3PSJncmlkIl0gPiAuSWd5aklxX2NhcmRbZGF0YS1yZXNvdXJjZS1zdGF0ZV06aG92ZXIsIC5JZ3lqSXFfY29sbGVjdGlvbltkYXRhLXJlc291cmNlLXZpZXc9ImdyaWQiXSA+IC5JZ3lqSXFfY2FyZFtkYXRhLXJlc291cmNlLXN0YXRlXTpmb2N1cy13aXRoaW4gewogICAgYmFja2dyb3VuZDogdmFyKC0tZHN3LWFsaWFzLWJnLWxheWVyLTEpOwogIH0KCiAgLklneWpJcV9jb2xsZWN0aW9uW2RhdGEtcmVzb3VyY2Utdmlldz0iZ3JpZCJdID4gLklneWpJcV9jYXJkW2RhdGEtcmVzb3VyY2Utc3VyZmFjZT0ibWNwIl0gLklneWpJcV9wcm92ZW5hbmNlQ2hpcCwgLklneWpJcV9jb2xsZWN0aW9uW2RhdGEtcmVzb3VyY2Utdmlldz0iZ3JpZCJdID4gLklneWpJcV9jYXJkW2RhdGEtcmVzb3VyY2Utc3VyZmFjZT0ibHNwIl0gLklneWpJcV9wcm92ZW5hbmNlQ2hpcCB7CiAgICBkaXNwbGF5OiBub25lOwogIH0KCiAgLklneWpJcV9jb2xsZWN0aW9uW2RhdGEtcmVzb3VyY2Utdmlldz0ibGlzdCJdID4gLklneWpJcV9jYXJkW2RhdGEtcmVzb3VyY2Utc3RhdGVdIHsKICAgIGdyaWQtdGVtcGxhdGUtY29sdW1uczogbWlubWF4KDAsIDFmcikgYXV0bzsKICAgIGdyaWQtdGVtcGxhdGUtYXJlYXM6ICJJZ3lqSXFfaWQgSWd5aklxX2FjdCIKICAgICAgICAgICAgICAgICAgICAgICAgICJJZ3lqSXFfZm9vdCBJZ3lqSXFfYWN0IgogICAgICAgICAgICAgICAgICAgICAgICAgIklneWpJcV9ib2R5IElneWpJcV9hY3QiOwogICAgaGVpZ2h0OiBhdXRvOwogICAgcGFkZGluZy1ibG9jazogMTBweDsKICB9Cn0KCkBjb250YWluZXIgKHdpZHRoIDw9IDQyMHB4KSB7CiAgLklneWpJcV9jb2xsZWN0aW9uW2RhdGEtcmVzb3VyY2Utdmlldz0iZ3JpZCJdIHsKICAgIGdyaWQtdGVtcGxhdGUtY29sdW1uczogbWlubWF4KDAsIDFmcik7CiAgfQp9CgouSWd5aklxX3Jvd0lkIHsKICBncmlkLWFyZWE6IElneWpJcV9pZDsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGdhcDogN3B4OwogIG1pbi13aWR0aDogMDsKICBtaW4taGVpZ2h0OiAyNHB4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5JZ3lqSXFfcm93Qm9keSB7CiAgZ3JpZC1hcmVhOiBJZ3lqSXFfYm9keTsKICBtaW4td2lkdGg6IDA7CiAgb3ZlcmZsb3c6IGhpZGRlbjsKfQoKLklneWpJcV9yb3dGb290IHsKICBncmlkLWFyZWE6IElneWpJcV9mb290OwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiA3cHg7CiAgbWluLXdpZHRoOiAwOwogIG1pbi1oZWlnaHQ6IDE2cHg7CiAgZGlzcGxheTogZmxleDsKICBvdmVyZmxvdzogaGlkZGVuOwp9CgouSWd5aklxX3Jvd0FjdGlvbnMgewogIGJvcmRlci1yYWRpdXM6IDhweDsKICBmbGV4OiBub25lOwogIGdyaWQtYXJlYTogSWd5aklxX2FjdDsKICBqdXN0aWZ5LWNvbnRlbnQ6IGZsZXgtZW5kOwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiAycHg7CiAgbWFyZ2luLWxlZnQ6IGF1dG87CiAgZGlzcGxheTogZmxleDsKICBwb3NpdGlvbjogcmVsYXRpdmU7Cn0KCi5JZ3lqSXFfbmFtZSB7CiAgbWluLXdpZHRoOiAwOwogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtcHJpbWFyeSk7CiAgd2hpdGUtc3BhY2U6IG5vd3JhcDsKICBmb250LXNpemU6IDEzcHg7CiAgZm9udC13ZWlnaHQ6IDYwMDsKICBsaW5lLWhlaWdodDogMjBweDsKfQoKLklneWpJcV9uYW1lTW9ubyB7CiAgbGV0dGVyLXNwYWNpbmc6IC0uMDFlbTsKICBmb250LWZhbWlseTogdWktbW9ub3NwYWNlLCBNZW5sbywgQ29uc29sYXMsIG1vbm9zcGFjZTsKICBmb250LXNpemU6IDEyLjVweDsKfQoKLklneWpJcV92ZXJzaW9uIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXRlcnRpYXJ5KTsKICBmb250LXZhcmlhbnQtbnVtZXJpYzogdGFidWxhci1udW1zOwogIGZsZXg6IG5vbmU7CiAgZm9udC1zaXplOiAxMXB4Owp9CgouSWd5aklxX2Rlc2MgewogIG1heC1oZWlnaHQ6IDM0cHg7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1zZWNvbmRhcnkpOwogIG1hcmdpbjogMDsKICBmb250LXNpemU6IDEycHg7CiAgbGluZS1oZWlnaHQ6IDE3cHg7CiAgb3ZlcmZsb3c6IGhpZGRlbjsKfQoKLklneWpJcV9tb25vTGluZSB7CiAgbWF4LWhlaWdodDogMzRweDsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXRlcnRpYXJ5KTsKICBvdmVyZmxvdy13cmFwOiBhbnl3aGVyZTsKICBtYXJnaW46IDA7CiAgZm9udC1mYW1pbHk6IHVpLW1vbm9zcGFjZSwgTWVubG8sIENvbnNvbGFzLCBtb25vc3BhY2U7CiAgZm9udC1zaXplOiAxMS41cHg7CiAgbGluZS1oZWlnaHQ6IDE3cHg7CiAgb3ZlcmZsb3c6IGhpZGRlbjsKfQoKLklneWpJcV9wcm92ZW5hbmNlLCAuSWd5aklxX3BhdGggewogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtdGVydGlhcnkpOwogIHRleHQtb3ZlcmZsb3c6IGVsbGlwc2lzOwogIHdoaXRlLXNwYWNlOiBub3dyYXA7CiAgZmxleDogMCBhdXRvOwogIGZvbnQtZmFtaWx5OiB1aS1tb25vc3BhY2UsIE1lbmxvLCBDb25zb2xhcywgbW9ub3NwYWNlOwogIGZvbnQtc2l6ZTogMTFweDsKICBvdmVyZmxvdzogaGlkZGVuOwp9CgouSWd5aklxX2NvdW50IHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXRlcnRpYXJ5KTsKICB3aGl0ZS1zcGFjZTogbm93cmFwOwogIGZsZXg6IG5vbmU7CiAgZm9udC1zaXplOiAxMXB4Owp9CgouSWd5aklxX2NvdW50VmFsdWUgewogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtc2Vjb25kYXJ5KTsKICBmb250LXZhcmlhbnQtbnVtZXJpYzogdGFidWxhci1udW1zOwogIGZvbnQtd2VpZ2h0OiA2MDA7Cn0KCi5JZ3lqSXFfc2VwYXJhdG9yIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLWRpbW1lZCk7CiAgZmxleDogbm9uZTsKICBmb250LXNpemU6IDExcHg7Cn0KCi5JZ3lqSXFfaWNvbkJ0biB7CiAgd2lkdGg6IDI0cHg7CiAgaGVpZ2h0OiAyNHB4OwogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtYnJhbmQtcHJpbWFyeSk7CiAgY3Vyc29yOiBwb2ludGVyOwogIGJhY2tncm91bmQ6IG5vbmU7CiAgYm9yZGVyOiBub25lOwogIGJvcmRlci1yYWRpdXM6IDZweDsKICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIHBhZGRpbmc6IDA7CiAgZGlzcGxheTogaW5saW5lLWZsZXg7Cn0KCi5JZ3lqSXFfaWNvbkJ0bjpob3Zlcjpub3QoOmRpc2FibGVkKSB7CiAgYmFja2dyb3VuZDogdmFyKC0tZHN3LWFsaWFzLWludGVyYWN0aXZlLWJnLWhvdmVyKTsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnkpOwp9CgouSWd5aklxX2ljb25CdG46ZGlzYWJsZWQgewogIGN1cnNvcjogZGVmYXVsdDsKICBvcGFjaXR5OiAuNDsKfQoKLklneWpJcV9pY29uQnRuRGFuZ2VyOmhvdmVyOm5vdCg6ZGlzYWJsZWQpIHsKICBiYWNrZ3JvdW5kOiB2YXIoLS1kc3ctYWxpYXMtaW50ZXJhY3RpdmUtYmctaG92ZXItZGFuZ2VyKTsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLXN0YXRlLWVycm9yLXByaW1hcnkpOwp9CgouSWd5aklxX2ljb25CdG46Zm9jdXMtdmlzaWJsZSwgLklneWpJcV9yb3dBY3Rpb25zIDpmb2N1cy12aXNpYmxlLCAuSWd5aklxX2NhcmRbZGF0YS1yZXNvdXJjZS1zdGF0ZV06Zm9jdXMtdmlzaWJsZSB7CiAgb3V0bGluZTogMnB4IHNvbGlkIHZhcigtLWRzdy1hbGlhcy1icmFuZC1wcmltYXJ5KTsKICBvdXRsaW5lLW9mZnNldDogMnB4Owp9CgouSWd5aklxX3JldmVhbE9uSG92ZXIgewogIG9wYWNpdHk6IDA7CiAgdHJhbnNpdGlvbjogb3BhY2l0eSAuMTRzOwp9CgouSWd5aklxX2NhcmRbZGF0YS1yZXNvdXJjZS1zdGF0ZV06aG92ZXIgLklneWpJcV9yZXZlYWxPbkhvdmVyLCAuSWd5aklxX2NhcmRbZGF0YS1yZXNvdXJjZS1zdGF0ZV06Zm9jdXMtd2l0aGluIC5JZ3lqSXFfcmV2ZWFsT25Ib3ZlciB7CiAgb3BhY2l0eTogMTsKfQoKLklneWpJcV9jb2xsZWN0aW9uW2RhdGEtcmVzb3VyY2Utdmlldz0ibGlzdCJdIC5JZ3lqSXFfZGVzYywgLklneWpJcV9jb2xsZWN0aW9uW2RhdGEtcmVzb3VyY2Utdmlldz0ibGlzdCJdIC5JZ3lqSXFfbW9ub0xpbmUgewogIG1heC1oZWlnaHQ6IDE4cHg7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC10ZXJ0aWFyeSk7CiAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7CiAgd2hpdGUtc3BhY2U6IG5vd3JhcDsKICBmb250LXNpemU6IDExLjVweDsKICBkaXNwbGF5OiBibG9jazsKICBvdmVyZmxvdzogaGlkZGVuOwp9CgouSWd5aklxX2NvbGxlY3Rpb25bZGF0YS1yZXNvdXJjZS12aWV3PSJsaXN0Il0gLklneWpJcV9yZXZlYWxPbkhvdmVyIHsKICBvcGFjaXR5OiAxOwp9CgouSWd5aklxX3N3aXRjaFdyYXAsIC5JZ3lqSXFfd2FybldyYXAgewogIGZsZXg6IG5vbmU7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBkaXNwbGF5OiBpbmxpbmUtZmxleDsKfQoKQG1lZGlhIChwcmVmZXJzLXJlZHVjZWQtbW90aW9uOiByZWR1Y2UpIHsKICAuSWd5aklxX2NhcmRbZGF0YS1yZXNvdXJjZS1zdGF0ZV0sIC5JZ3lqSXFfcmV2ZWFsT25Ib3ZlciwgLklneWpJcV9yb3dBY3Rpb25zIHsKICAgIHRyYW5zaXRpb246IG5vbmU7CiAgfQp9Ci5zQlh3Z1dfZGlhbG9nW3JvbGU9ImRpYWxvZyJdIHsKICBib3gtc2l6aW5nOiBib3JkZXItYm94OwogIG1heC13aWR0aDogY2FsYygxMDB2dyAtIDQ4cHgpOwogIG1heC1oZWlnaHQ6IGNhbGMoMTAwZHZoIC0gNDhweCk7Cn0KCi5zQlh3Z1dfZGlhbG9nW3JvbGU9ImRpYWxvZyJdLnNCWHdnV19zaXplU20gewogIHdpZHRoOiBtaW4oNDYwcHgsIDEwMHZ3IC0gNDhweCk7Cn0KCi5zQlh3Z1dfZGlhbG9nW3JvbGU9ImRpYWxvZyJdLnNCWHdnV19zaXplTWQgewogIHdpZHRoOiBtaW4oNjQwcHgsIDEwMHZ3IC0gNDhweCk7Cn0KCi5zQlh3Z1dfZGlhbG9nW3JvbGU9ImRpYWxvZyJdLnNCWHdnV19zaXplTGcgewogIHdpZHRoOiBtaW4oODgwcHgsIDEwMHZ3IC0gNDhweCk7Cn0KCi5zQlh3Z1dfYm9keSB7CiAgb3ZlcmZsb3ctd3JhcDogYW55d2hlcmU7CiAgbWluLXdpZHRoOiAwOwogIG1pbi1oZWlnaHQ6IDA7CiAgbWF4LWhlaWdodDogY2FsYygxMDBkdmggLSAyMDBweCk7CiAgb3ZlcmZsb3cteTogYXV0bzsKfQoKLnNCWHdnV19mb290ZXIgewogIGp1c3RpZnktY29udGVudDogZmxleC1lbmQ7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBnYXA6IDhweDsKICB3aWR0aDogMTAwJTsKICBkaXNwbGF5OiBmbGV4Owp9Cgouc0JYd2dXX2Zvb3RlclNsb3Q6ZW1wdHkgewogIGRpc3BsYXk6IG5vbmU7Cn0KCi5zQlh3Z1dfZnJvbnRtYXR0ZXIgewogIGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWRzdy1hbGlhcy1ib3JkZXItbDIpOwogIGJhY2tncm91bmQ6IHZhcigtLWRzdy1hbGlhcy1tYXJrZG93bi1jb2RlLWJsb2NrKTsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXRlcnRpYXJ5KTsKICBvdmVyZmxvdy13cmFwOiBhbnl3aGVyZTsKICB3aGl0ZS1zcGFjZTogcHJlLXdyYXA7CiAgYm9yZGVyLXJhZGl1czogOHB4OwogIG1hcmdpbjogMCAwIDEwcHg7CiAgcGFkZGluZzogOHB4IDEwcHg7CiAgZm9udC1mYW1pbHk6IHVpLW1vbm9zcGFjZSwgU0ZNb25vLVJlZ3VsYXIsIE1lbmxvLCBDb25zb2xhcywgbW9ub3NwYWNlOwogIGZvbnQtc2l6ZTogMTEuNXB4OwogIGxpbmUtaGVpZ2h0OiAxOHB4Owp9Cgouc0JYd2dXX3ByZXZpZXcgewogIG1pbi13aWR0aDogMDsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnkpOwogIGZvbnQtc2l6ZTogMTRweDsKICBsaW5lLWhlaWdodDogMS42Owp9Cgouc0JYd2dXX3ByZXZpZXcgcHJlLCAuc0JYd2dXX3ByZXZpZXcgdGFibGUgewogIG1heC13aWR0aDogMTAwJTsKICBvdmVyZmxvdzogYXV0bzsKfQoKLnNCWHdnV19wcmV2aWV3IGltZyB7CiAgbWF4LXdpZHRoOiAxMDAlOwogIGhlaWdodDogYXV0bzsKfQoKLnNCWHdnV19lcnJvciB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1zdGF0ZS1lcnJvci1wcmltYXJ5KTsKICBtYXJnaW46IDhweCAwOwogIGZvbnQtc2l6ZTogMTNweDsKfQoKLnNCWHdnV19wYWlyIHsKICBncmlkLXRlbXBsYXRlLWNvbHVtbnM6IHJlcGVhdCgyLCBtaW5tYXgoMCwgMWZyKSk7CiAgZ2FwOiAxNnB4OwogIGRpc3BsYXk6IGdyaWQ7Cn0KCi5zQlh3Z1dfcm93IHsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGdhcDogNnB4OwogIG1pbi13aWR0aDogMDsKICBkaXNwbGF5OiBmbGV4Owp9Cgouc0JYd2dXX3JvdyBpbnB1dCB7CiAgZmxleDogMTsKICB3aWR0aDogMDsKfQoKLnNCWHdnV19yb3cgYnV0dG9uIHsKICBmbGV4OiBub25lOwp9CgpAbWVkaWEgKHdpZHRoIDw9IDY0MHB4KSB7CiAgLnNCWHdnV19kaWFsb2dbcm9sZT0iZGlhbG9nIl0gewogICAgd2lkdGg6IGNhbGMoMTAwdncgLSAxNnB4KTsKICAgIG1heC13aWR0aDogY2FsYygxMDB2dyAtIDE2cHgpOwogICAgbWF4LWhlaWdodDogY2FsYygxMDBkdmggLSAxNnB4KTsKICB9CgogIC5zQlh3Z1dfZm9ybSB7CiAgICBncmlkLXRlbXBsYXRlLWNvbHVtbnM6IG1pbm1heCgwLCAxZnIpOwogIH0KfQouXzlMdWpyYV9yb3dzIHsKICBib3JkZXI6IDFweCBzb2xpZCB2YXIoLS1kc3ctYWxpYXMtYm9yZGVyLWwyKTsKICBib3JkZXItcmFkaXVzOiAxMHB4OwogIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47CiAgbWluLXdpZHRoOiAwOwogIGRpc3BsYXk6IGZsZXg7CiAgb3ZlcmZsb3c6IGhpZGRlbjsKfQoKLl85THVqcmFfZ3JvdXAgewogIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47CiAgbWluLXdpZHRoOiAwOwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5fOUx1anJhX2dyb3VwICsgLl85THVqcmFfZ3JvdXAgLl85THVqcmFfcm93IHsKICBib3JkZXItdG9wOiAxcHggc29saWQgdmFyKC0tZHN3LWFsaWFzLWJvcmRlci1sMSk7Cn0KCi5fOUx1anJhX3JvdyB7CiAgYm94LXNpemluZzogYm9yZGVyLWJveDsKICB3aWR0aDogMTAwJTsKICBjb2xvcjogaW5oZXJpdDsKICB0ZXh0LWFsaWduOiBsZWZ0OwogIGZvbnQ6IGluaGVyaXQ7CiAgYmFja2dyb3VuZDogbm9uZTsKICBib3JkZXI6IG5vbmU7CiAgZ3JpZC10ZW1wbGF0ZS1jb2x1bW5zOiBtaW5tYXgoMTEwcHgsIG1heC1jb250ZW50KSBtaW5tYXgoMCwgMWZyKSAxNHB4OwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiAxMnB4OwogIHBhZGRpbmc6IDlweCAxMnB4OwogIGRpc3BsYXk6IGdyaWQ7Cn0KCmJ1dHRvbi5fOUx1anJhX3JvdyB7CiAgY3Vyc29yOiBwb2ludGVyOwp9CgouXzlMdWpyYV9yb3c6aG92ZXIgewogIGJhY2tncm91bmQ6IHZhcigtLWRzdy1hbGlhcy1pbnRlcmFjdGl2ZS1iZy1ob3Zlcik7Cn0KCi5fOUx1anJhX3Jvd1thcmlhLWV4cGFuZGVkPSJ0cnVlIl0gewogIGJhY2tncm91bmQ6IHZhcigtLWRzdy1hbGlhcy1zdGF0ZS1idXNpbmVzcy10ZXJ0aWFyeSk7Cn0KCi5fOUx1anJhX3Jvdzpmb2N1cy12aXNpYmxlIHsKICBvdXRsaW5lOiAycHggc29saWQgdmFyKC0tZHN3LWFsaWFzLWJyYW5kLXByaW1hcnkpOwogIG91dGxpbmUtb2Zmc2V0OiAtMnB4Owp9CgouXzlMdWpyYV9uYW1lIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnkpOwogIHRleHQtb3ZlcmZsb3c6IGVsbGlwc2lzOwogIHdoaXRlLXNwYWNlOiBub3dyYXA7CiAgZm9udC1mYW1pbHk6IHVpLW1vbm9zcGFjZSwgU0ZNb25vLVJlZ3VsYXIsIE1lbmxvLCBDb25zb2xhcywgbW9ub3NwYWNlOwogIGZvbnQtc2l6ZTogMTEuNXB4OwogIGZvbnQtd2VpZ2h0OiA2MDA7CiAgb3ZlcmZsb3c6IGhpZGRlbjsKfQoKLl85THVqcmFfc3VtbWFyeSB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC10ZXJ0aWFyeSk7CiAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7CiAgd2hpdGUtc3BhY2U6IG5vd3JhcDsKICBmb250LXNpemU6IDExLjVweDsKICBvdmVyZmxvdzogaGlkZGVuOwp9CgouXzlMdWpyYV9jaGV2cm9uIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXRlcnRpYXJ5KTsKICBqdXN0aWZ5LXNlbGY6IGVuZDsKICBkaXNwbGF5OiBpbmxpbmUtZmxleDsKfQoKLl85THVqcmFfY2hldnJvbiBzdmcgewogIGRpc3BsYXk6IGJsb2NrOwp9CgouXzlMdWpyYV9ib2R5IHsKICBib3JkZXItdG9wOiAxcHggc29saWQgdmFyKC0tZHN3LWFsaWFzLWJvcmRlci1sMik7CiAgYmFja2dyb3VuZDogdmFyKC0tZHN3LWFsaWFzLWludGVyYWN0aXZlLWJnLWhvdmVyKTsKICBwYWRkaW5nOiAxMnB4IDE0cHg7Cn0KLkhKOXg3YV9zaGVsbCB7CiAgbWluLXdpZHRoOiAwOwogIG1pbi1oZWlnaHQ6IDA7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1wcmltYXJ5LCAjMWYyMzI4KTsKICBmbGV4LWRpcmVjdGlvbjogY29sdW1uOwogIGZsZXg6IDE7CiAgZ2FwOiAxNnB4OwogIGRpc3BsYXk6IGZsZXg7CiAgY29udGFpbmVyLXR5cGU6IGlubGluZS1zaXplOwp9CgouSEo5eDdhX2hlYWRlciB7CiAgZmxleC1kaXJlY3Rpb246IHJvdzsKICBmbGV4OiBub25lOwogIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGdhcDogMTJweDsKICBtaW4taGVpZ2h0OiA0NnB4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5ISjl4N2FfaGVhZGVyVGV4dCB7CiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjsKICBnYXA6IDJweDsKICBtaW4td2lkdGg6IDA7CiAgZGlzcGxheTogZmxleDsKfQoKLkhKOXg3YV90aXRsZSB7CiAgbWFyZ2luOiAwOwogIGZvbnQtc2l6ZTogMTZweDsKICBmb250LXdlaWdodDogNjAwOwogIGxpbmUtaGVpZ2h0OiAyNHB4Owp9CgouSEo5eDdhX3N1YnRpdGxlIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXNlY29uZGFyeSk7CiAgbWFyZ2luOiAwOwogIGZvbnQtc2l6ZTogMTNweDsKICBsaW5lLWhlaWdodDogMjBweDsKfQoKLkhKOXg3YV9oZWFkZXJBY3Rpb25zIHsKICBmbGV4LWRpcmVjdGlvbjogcm93OwogIGZsZXg6IG5vbmU7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBnYXA6IDZweDsKICBkaXNwbGF5OiBmbGV4Owp9CgouSEo5eDdhX2JvZHkgewogIHNjcm9sbGJhci1ndXR0ZXI6IHN0YWJsZTsKICBmbGV4LWRpcmVjdGlvbjogY29sdW1uOwogIGZsZXg6IDE7CiAgZ2FwOiAxMnB4OwogIG1pbi1oZWlnaHQ6IDA7CiAgZGlzcGxheTogZmxleDsKICBvdmVyZmxvdy15OiBhdXRvOwp9CgouSEo5eDdhX2J1c3lMaW5lIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXNlY29uZGFyeSwgIzZiNzI4MCk7CiAgZmxleC1kaXJlY3Rpb246IHJvdzsKICBmbGV4OiBub25lOwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiA4cHg7CiAgZm9udC1zaXplOiAxMnB4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5ISjl4N2FfYnVzeUxhYmVsIHsKICB0ZXh0LW92ZXJmbG93OiBlbGxpcHNpczsKICB3aGl0ZS1zcGFjZTogbm93cmFwOwogIG1pbi13aWR0aDogMDsKICBvdmVyZmxvdzogaGlkZGVuOwp9CgouSEo5eDdhX3NwaW5uZXIgewogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtc2Vjb25kYXJ5LCAjNmI3MjgwKTsKICBmbGV4OiBub25lOwogIGZvbnQtc2l6ZTogMTNweDsKICBkaXNwbGF5OiBpbmxpbmUtZmxleDsKfQoKLkhKOXg3YV9zcGlubmluZyB7CiAgYW5pbWF0aW9uOiAuOXMgbGluZWFyIGluZmluaXRlIEhKOXg3YV9wYW5lbC1zcGluOwp9CgpAa2V5ZnJhbWVzIEhKOXg3YV9wYW5lbC1zcGluIHsKICBmcm9tIHsKICAgIHRyYW5zZm9ybTogcm90YXRlKDApOwogIH0KCiAgdG8gewogICAgdHJhbnNmb3JtOiByb3RhdGUoMzYwZGVnKTsKICB9Cn0KCkBtZWRpYSAocHJlZmVycy1yZWR1Y2VkLW1vdGlvbjogcmVkdWNlKSB7CiAgLkhKOXg3YV9zcGlubmluZyB7CiAgICBhbmltYXRpb24tZHVyYXRpb246IDIuNHM7CiAgfQp9CgouSEo5eDdhX2VkaXRvckRpYWxvZyB7CiAgZ2FwOiAxMnB4OwogIG1heC13aWR0aDogNzIwcHg7Cn0KCi5ISjl4N2FfZWRpdG9yRGlhbG9nIFtjbGFzcyo9ImNvbnRlbnQiXSA+IFtjbGFzcyo9ImJvZHkiXSB7CiAgbWFyZ2luLXRvcDogMDsKfQoKLkhKOXg3YV9lZGl0b3JCb2R5IHsKICBmbGV4LWRpcmVjdGlvbjogY29sdW1uOwogIGdhcDogMTJweDsKICBkaXNwbGF5OiBmbGV4Owp9CgouSEo5eDdhX2VkaXRvckZvb3RlciB7CiAgZmxleC1kaXJlY3Rpb246IHJvdzsKICBmbGV4OiAxOwogIGp1c3RpZnktY29udGVudDogZmxleC1lbmQ7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBnYXA6IDhweDsKICBkaXNwbGF5OiBmbGV4Owp9CgouSEo5eDdhX2VkaXRvckVycm9yIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLXN0YXRlLWVycm9yLXByaW1hcnksICNjODFlMWUpOwogIG1hcmdpbi1yaWdodDogYXV0bzsKICBmb250LXNpemU6IDEycHg7Cn0KCi5ISjl4N2FfY29uZmlybUNoZWNrIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnksICMxZjIzMjgpOwogIGZsZXgtZGlyZWN0aW9uOiByb3c7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBnYXA6IDhweDsKICBmb250LXNpemU6IDEycHg7CiAgZGlzcGxheTogZmxleDsKfQoKLkhKOXg3YV9lbXB0eSB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC10ZXJ0aWFyeSwgIzZiNzI4MCk7CiAgdGV4dC1hbGlnbjogY2VudGVyOwogIHBhZGRpbmc6IDI0cHggMTJweDsKICBmb250LXNpemU6IDEycHg7Cn0KCkBjb250YWluZXIgKHdpZHRoIDw9IDU0MHB4KSB7CiAgLkhKOXg3YV9lbnRyeUdyaWQgewogICAgZ3JpZC10ZW1wbGF0ZS1jb2x1bW5zOiBtaW5tYXgoMCwgMWZyKTsKICB9CgogIC5ISjl4N2FfZW50cnlSb3cgewogICAgZmxleC13cmFwOiB3cmFwOwogIH0KCiAgLkhKOXg3YV9lbnRyeUFjdGlvbnMgewogICAgbWFyZ2luLWxlZnQ6IGF1dG87CiAgfQoKICAuSEo5eDdhX2VudHJ5TWFpbiB7CiAgICBmbGV4LWJhc2lzOiAxMDAlOwogIH0KfQoKLkhKOXg3YV9oZXJvIHsKICBiYWNrZ3JvdW5kOiB2YXIoLS1kc3ctYWxpYXMtaW50ZXJhY3RpdmUtYmctaG92ZXIpOwogIGJvcmRlci1yYWRpdXM6IDEwcHg7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBnYXA6IDEwcHg7CiAgcGFkZGluZzogMTJweCAxNHB4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5ISjl4N2FfaGVyb1RleHQgewogIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47CiAgZ2FwOiA1cHg7CiAgbWluLXdpZHRoOiAwOwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5ISjl4N2FfaGVyb0xpbmUgewogIGZsZXgtd3JhcDogd3JhcDsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGdhcDogN3B4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5ISjl4N2FfaGVyb01vbm8gewogIG92ZXJmbG93LXdyYXA6IGFueXdoZXJlOwogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtc2Vjb25kYXJ5KTsKICBtYXJnaW46IDA7CiAgZm9udDogMTJweCAvIDE4cHggdWktbW9ub3NwYWNlLCBNZW5sbywgQ29uc29sYXMsIG1vbm9zcGFjZTsKfQoKLkhKOXg3YV9ibG9jayB7CiAgbWFyZ2luLXRvcDogMThweDsKfQoKLkhKOXg3YV9ibG9ja0hlYWQgewogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtc2Vjb25kYXJ5KTsKICBsZXR0ZXItc3BhY2luZzogLjA0ZW07CiAgdGV4dC10cmFuc2Zvcm06IHVwcGVyY2FzZTsKICBtYXJnaW46IDAgMCA4cHg7CiAgZm9udC1zaXplOiAxMXB4OwogIGZvbnQtd2VpZ2h0OiA2MDA7Cn0KCi5ISjl4N2Ffa3ZHcmlkIHsKICBncmlkLXRlbXBsYXRlLWNvbHVtbnM6IHJlcGVhdChhdXRvLWZpdCwgbWlubWF4KDE3MHB4LCAxZnIpKTsKICBnYXA6IDEwcHggMTZweDsKICBtYXJnaW46IDA7CiAgZGlzcGxheTogZ3JpZDsKfQoKLkhKOXg3YV9rdktleSB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC10ZXJ0aWFyeSk7CiAgZm9udC1zaXplOiAxMXB4OwogIGxpbmUtaGVpZ2h0OiAxNnB4Owp9CgouSEo5eDdhX2t2VmFsdWUgewogIHRleHQtb3ZlcmZsb3c6IGVsbGlwc2lzOwogIHdoaXRlLXNwYWNlOiBub3dyYXA7CiAgbWFyZ2luOiAzcHggMCAwOwogIGZvbnQtc2l6ZTogMTIuNXB4OwogIGxpbmUtaGVpZ2h0OiAxOHB4OwogIG92ZXJmbG93OiBoaWRkZW47Cn0KCi5ISjl4N2FfbW9ub0Jsb2NrIHsKICBib3JkZXI6IDFweCBzb2xpZCB2YXIoLS1kc3ctYWxpYXMtYm9yZGVyLWwyKTsKICBiYWNrZ3JvdW5kOiB2YXIoLS1kc3ctYWxpYXMtbWFya2Rvd24tY29kZS1ibG9jayk7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1zZWNvbmRhcnkpOwogIGJvcmRlci1yYWRpdXM6IDEwcHg7CiAgbWFyZ2luOiAwOwogIHBhZGRpbmc6IDEycHggMTRweDsKICBmb250OiAxMS41cHggLyAxOHB4IHVpLW1vbm9zcGFjZSwgTWVubG8sIENvbnNvbGFzLCBtb25vc3BhY2U7CiAgb3ZlcmZsb3cteDogYXV0bzsKfQoKLkhKOXg3YV9kZXRhaWxQcm9zZSB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1zZWNvbmRhcnkpOwogIG1hcmdpbjogMDsKICBmb250LXNpemU6IDEzcHg7CiAgbGluZS1oZWlnaHQ6IDIxcHg7Cn0KCi5ISjl4N2Ffa3ZWYWx1ZU1vbm8gewogIGZvbnQtZmFtaWx5OiB1aS1tb25vc3BhY2UsIE1lbmxvLCBDb25zb2xhcywgbW9ub3NwYWNlOwp9Ci5fNEpMOHFxX3Rvb2xiYXIgewogIGZsZXg6IG5vbmU7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBnYXA6IDhweDsKICBtaW4td2lkdGg6IDA7CiAgZGlzcGxheTogZmxleDsKfQoKLl80Skw4cXFfc2VhcmNoIHsKICBmbGV4OiBhdXRvOwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgbWluLXdpZHRoOiAwOwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5fNEpMOHFxX3NlYXJjaElucHV0IHsKICBmbGV4OiBhdXRvOwogIG1pbi13aWR0aDogMDsKfQoKLl80Skw4cXFfc2VhcmNoSW5wdXQgaW5wdXQgewogIGZvbnQtc2l6ZTogMTJweDsKICBsaW5lLWhlaWdodDogMjBweDsKfQoKLl80Skw4cXFfc2VnbWVudCB7CiAgZmxleDogbm9uZTsKfQoKQGNvbnRhaW5lciAod2lkdGggPD0gNDgwcHgpIHsKICAuXzRKTDhxcV90b29sYmFyIHsKICAgIGZsZXgtd3JhcDogd3JhcDsKICAgIGp1c3RpZnktY29udGVudDogZmxleC1lbmQ7CiAgfQoKICAuXzRKTDhxcV9zZWFyY2ggewogICAgZmxleC1iYXNpczogMTAwJTsKICB9Cn0KLl81Qm9LUkdfZWRpdG9yIHsKICBib3JkZXI6IDFweCBzb2xpZCB2YXIoLS1kc3ctYWxpYXMtYm9yZGVyLWwyKTsKICBiYWNrZ3JvdW5kOiB2YXIoLS1kc3ctYWxpYXMtYmctbGF5ZXItMSk7CiAgYm94LXNpemluZzogYm9yZGVyLWJveDsKICBib3JkZXItcmFkaXVzOiA4cHg7CiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjsKICBkaXNwbGF5OiBmbGV4OwogIG92ZXJmbG93OiBoaWRkZW47Cn0KCi5fNUJvS1JHX2VkaXRvciAuY20tZWRpdG9yIHsKICBmbGV4OiAxOwogIG1pbi1oZWlnaHQ6IDA7Cn0KCi5fNUJvS1JHX2VkaXRvciAuY20tc2Nyb2xsZXIgewogIG92ZXJmbG93OiBhdXRvOwp9Ci5BSm40eWFfYmFuZCB7CiAgYm9yZGVyLWxlZnQ6IDNweCBzb2xpZCB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtdGVydGlhcnkpOwogIGJhY2tncm91bmQ6IHZhcigtLWRzdy1hbGlhcy1pbnRlcmFjdGl2ZS1iZy1ob3Zlcik7CiAgYm9yZGVyLXJhZGl1czogMTBweDsKICBmbGV4LWRpcmVjdGlvbjogY29sdW1uOwogIGdhcDogNnB4OwogIHBhZGRpbmc6IDEycHggMTRweDsKICBkaXNwbGF5OiBmbGV4Owp9CgouQUpuNHlhX2JhbmRbZGF0YS1iYW5kLXRvbmU9InN1Y2Nlc3MiXSB7CiAgYm9yZGVyLWxlZnQtY29sb3I6IHZhcigtLWRzdy1hbGlhcy1zdGF0ZS1zdWNjZXNzLXByaW1hcnkpOwp9CgouQUpuNHlhX2JhbmRbZGF0YS1iYW5kLXRvbmU9Indhcm4iXSB7CiAgYm9yZGVyLWxlZnQtY29sb3I6IHZhcigtLWRzdy1hbGlhcy1zdGF0ZS13YXJuLXByaW1hcnkpOwp9CgouQUpuNHlhX2JhbmRbZGF0YS1iYW5kLXRvbmU9ImVycm9yIl0gewogIGJvcmRlci1sZWZ0LWNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtc3RhdGUtZXJyb3ItcHJpbWFyeSk7Cn0KCi5BSm40eWFfdG9wIHsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGdhcDogMTBweDsKICBkaXNwbGF5OiBmbGV4Owp9CgouQUpuNHlhX2xhYmVscyB7CiAgZmxleC13cmFwOiB3cmFwOwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiA3cHg7CiAgbWluLXdpZHRoOiAwOwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5BSm40eWFfYWN0aW9ucyB7CiAgZmxleDogbm9uZTsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGdhcDogOHB4OwogIG1hcmdpbi1sZWZ0OiBhdXRvOwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5BSm40eWFfZWNobyB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1wcmltYXJ5KTsKICBvdmVyZmxvdy13cmFwOiBhbnl3aGVyZTsKICBtYXJnaW46IDA7CiAgZm9udC1zaXplOiAxMnB4OwogIGxpbmUtaGVpZ2h0OiAxOHB4Owp9CgouQUpuNHlhX2VjaG9TdWNjZXNzIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLXN0YXRlLXN1Y2Nlc3MtcHJpbWFyeSk7Cn0KCi5BSm40eWFfcmVhc29uIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnkpOwogIG92ZXJmbG93LXdyYXA6IGFueXdoZXJlOwogIG1hcmdpbjogMDsKICBmb250LXNpemU6IDEycHg7CiAgbGluZS1oZWlnaHQ6IDE4cHg7Cn0KCi5BSm40eWFfZGlhZ25vc3RpYyB7CiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjsKICBnYXA6IDJweDsKICBwYWRkaW5nOiAycHggMCAycHggMjJweDsKICBkaXNwbGF5OiBmbGV4Owp9CgouQUpuNHlhX2RpYWdub3N0aWNMaW5lIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXRlcnRpYXJ5KTsKICBvdmVyZmxvdy13cmFwOiBhbnl3aGVyZTsKICBtYXJnaW46IDA7CiAgZm9udC1mYW1pbHk6IHVpLW1vbm9zcGFjZSwgU0ZNb25vLVJlZ3VsYXIsIE1lbmxvLCBDb25zb2xhcywgbW9ub3NwYWNlOwogIGZvbnQtc2l6ZTogMTFweDsKICBsaW5lLWhlaWdodDogMTZweDsKfQoKLkFKbjR5YV9tb25vIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXNlY29uZGFyeSk7CiAgb3ZlcmZsb3ctd3JhcDogYW55d2hlcmU7CiAgbWFyZ2luOiAwOwogIGZvbnQ6IDEycHggLyAxOHB4IHVpLW1vbm9zcGFjZSwgTWVubG8sIENvbnNvbGFzLCBtb25vc3BhY2U7Cn0KLkhKOXg3YV9zaGVsbCB7CiAgbWluLXdpZHRoOiAwOwogIG1pbi1oZWlnaHQ6IDA7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1wcmltYXJ5LCAjMWYyMzI4KTsKICBmbGV4LWRpcmVjdGlvbjogY29sdW1uOwogIGZsZXg6IDE7CiAgZ2FwOiAxNnB4OwogIGRpc3BsYXk6IGZsZXg7CiAgY29udGFpbmVyLXR5cGU6IGlubGluZS1zaXplOwp9CgouSEo5eDdhX2hlYWRlciB7CiAgZmxleC1kaXJlY3Rpb246IHJvdzsKICBmbGV4OiBub25lOwogIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGdhcDogMTJweDsKICBtaW4taGVpZ2h0OiA0NnB4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5ISjl4N2FfaGVhZGVyVGV4dCB7CiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjsKICBnYXA6IDJweDsKICBtaW4td2lkdGg6IDA7CiAgZGlzcGxheTogZmxleDsKfQoKLkhKOXg3YV90aXRsZSB7CiAgbWFyZ2luOiAwOwogIGZvbnQtc2l6ZTogMTZweDsKICBmb250LXdlaWdodDogNjAwOwogIGxpbmUtaGVpZ2h0OiAyNHB4Owp9CgouSEo5eDdhX3N1YnRpdGxlIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXNlY29uZGFyeSk7CiAgbWFyZ2luOiAwOwogIGZvbnQtc2l6ZTogMTNweDsKICBsaW5lLWhlaWdodDogMjBweDsKfQoKLkhKOXg3YV9oZWFkZXJBY3Rpb25zIHsKICBmbGV4LWRpcmVjdGlvbjogcm93OwogIGZsZXg6IG5vbmU7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBnYXA6IDZweDsKICBkaXNwbGF5OiBmbGV4Owp9CgouSEo5eDdhX2JvZHkgewogIHNjcm9sbGJhci1ndXR0ZXI6IHN0YWJsZTsKICBmbGV4LWRpcmVjdGlvbjogY29sdW1uOwogIGZsZXg6IDE7CiAgZ2FwOiAxMnB4OwogIG1pbi1oZWlnaHQ6IDA7CiAgZGlzcGxheTogZmxleDsKICBvdmVyZmxvdy15OiBhdXRvOwp9CgouSEo5eDdhX2J1c3lMaW5lIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXNlY29uZGFyeSwgIzZiNzI4MCk7CiAgZmxleC1kaXJlY3Rpb246IHJvdzsKICBmbGV4OiBub25lOwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiA4cHg7CiAgZm9udC1zaXplOiAxMnB4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5ISjl4N2FfYnVzeUxhYmVsIHsKICB0ZXh0LW92ZXJmbG93OiBlbGxpcHNpczsKICB3aGl0ZS1zcGFjZTogbm93cmFwOwogIG1pbi13aWR0aDogMDsKICBvdmVyZmxvdzogaGlkZGVuOwp9CgouSEo5eDdhX3NwaW5uZXIgewogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtc2Vjb25kYXJ5LCAjNmI3MjgwKTsKICBmbGV4OiBub25lOwogIGZvbnQtc2l6ZTogMTNweDsKICBkaXNwbGF5OiBpbmxpbmUtZmxleDsKfQoKLkhKOXg3YV9zcGlubmluZyB7CiAgYW5pbWF0aW9uOiAuOXMgbGluZWFyIGluZmluaXRlIEhKOXg3YV9wYW5lbC1zcGluOwp9CgpAa2V5ZnJhbWVzIEhKOXg3YV9wYW5lbC1zcGluIHsKICBmcm9tIHsKICAgIHRyYW5zZm9ybTogcm90YXRlKDApOwogIH0KCiAgdG8gewogICAgdHJhbnNmb3JtOiByb3RhdGUoMzYwZGVnKTsKICB9Cn0KCkBtZWRpYSAocHJlZmVycy1yZWR1Y2VkLW1vdGlvbjogcmVkdWNlKSB7CiAgLkhKOXg3YV9zcGlubmluZyB7CiAgICBhbmltYXRpb24tZHVyYXRpb246IDIuNHM7CiAgfQp9CgouSEo5eDdhX2VkaXRvckRpYWxvZyB7CiAgZ2FwOiAxMnB4OwogIG1heC13aWR0aDogNzIwcHg7Cn0KCi5ISjl4N2FfZWRpdG9yRGlhbG9nIFtjbGFzcyo9ImNvbnRlbnQiXSA+IFtjbGFzcyo9ImJvZHkiXSB7CiAgbWFyZ2luLXRvcDogMDsKfQoKLkhKOXg3YV9lZGl0b3JCb2R5IHsKICBmbGV4LWRpcmVjdGlvbjogY29sdW1uOwogIGdhcDogMTJweDsKICBkaXNwbGF5OiBmbGV4Owp9CgouSEo5eDdhX2VkaXRvckZvb3RlciB7CiAgZmxleC1kaXJlY3Rpb246IHJvdzsKICBmbGV4OiAxOwogIGp1c3RpZnktY29udGVudDogZmxleC1lbmQ7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBnYXA6IDhweDsKICBkaXNwbGF5OiBmbGV4Owp9CgouSEo5eDdhX2VkaXRvckVycm9yIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLXN0YXRlLWVycm9yLXByaW1hcnksICNjODFlMWUpOwogIG1hcmdpbi1yaWdodDogYXV0bzsKICBmb250LXNpemU6IDEycHg7Cn0KCi5ISjl4N2FfY29uZmlybUNoZWNrIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnksICMxZjIzMjgpOwogIGZsZXgtZGlyZWN0aW9uOiByb3c7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBnYXA6IDhweDsKICBmb250LXNpemU6IDEycHg7CiAgZGlzcGxheTogZmxleDsKfQoKLkhKOXg3YV9lbXB0eSB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC10ZXJ0aWFyeSwgIzZiNzI4MCk7CiAgdGV4dC1hbGlnbjogY2VudGVyOwogIHBhZGRpbmc6IDI0cHggMTJweDsKICBmb250LXNpemU6IDEycHg7Cn0KCkBjb250YWluZXIgKHdpZHRoIDw9IDU0MHB4KSB7CiAgLkhKOXg3YV9lbnRyeUdyaWQgewogICAgZ3JpZC10ZW1wbGF0ZS1jb2x1bW5zOiBtaW5tYXgoMCwgMWZyKTsKICB9CgogIC5ISjl4N2FfZW50cnlSb3cgewogICAgZmxleC13cmFwOiB3cmFwOwogIH0KCiAgLkhKOXg3YV9lbnRyeUFjdGlvbnMgewogICAgbWFyZ2luLWxlZnQ6IGF1dG87CiAgfQoKICAuSEo5eDdhX2VudHJ5TWFpbiB7CiAgICBmbGV4LWJhc2lzOiAxMDAlOwogIH0KfQoKLkhKOXg3YV9oZXJvIHsKICBiYWNrZ3JvdW5kOiB2YXIoLS1kc3ctYWxpYXMtaW50ZXJhY3RpdmUtYmctaG92ZXIpOwogIGJvcmRlci1yYWRpdXM6IDEwcHg7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBnYXA6IDEwcHg7CiAgcGFkZGluZzogMTJweCAxNHB4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5ISjl4N2FfaGVyb1RleHQgewogIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47CiAgZ2FwOiA1cHg7CiAgbWluLXdpZHRoOiAwOwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5ISjl4N2FfaGVyb0xpbmUgewogIGZsZXgtd3JhcDogd3JhcDsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGdhcDogN3B4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5ISjl4N2FfaGVyb01vbm8gewogIG92ZXJmbG93LXdyYXA6IGFueXdoZXJlOwogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtc2Vjb25kYXJ5KTsKICBtYXJnaW46IDA7CiAgZm9udDogMTJweCAvIDE4cHggdWktbW9ub3NwYWNlLCBNZW5sbywgQ29uc29sYXMsIG1vbm9zcGFjZTsKfQoKLkhKOXg3YV9ibG9jayB7CiAgbWFyZ2luLXRvcDogMThweDsKfQoKLkhKOXg3YV9ibG9ja0hlYWQgewogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtc2Vjb25kYXJ5KTsKICBsZXR0ZXItc3BhY2luZzogLjA0ZW07CiAgdGV4dC10cmFuc2Zvcm06IHVwcGVyY2FzZTsKICBtYXJnaW46IDAgMCA4cHg7CiAgZm9udC1zaXplOiAxMXB4OwogIGZvbnQtd2VpZ2h0OiA2MDA7Cn0KCi5ISjl4N2Ffa3ZHcmlkIHsKICBncmlkLXRlbXBsYXRlLWNvbHVtbnM6IHJlcGVhdChhdXRvLWZpdCwgbWlubWF4KDE3MHB4LCAxZnIpKTsKICBnYXA6IDEwcHggMTZweDsKICBtYXJnaW46IDA7CiAgZGlzcGxheTogZ3JpZDsKfQoKLkhKOXg3YV9rdktleSB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC10ZXJ0aWFyeSk7CiAgZm9udC1zaXplOiAxMXB4OwogIGxpbmUtaGVpZ2h0OiAxNnB4Owp9CgouSEo5eDdhX2t2VmFsdWUgewogIHRleHQtb3ZlcmZsb3c6IGVsbGlwc2lzOwogIHdoaXRlLXNwYWNlOiBub3dyYXA7CiAgbWFyZ2luOiAzcHggMCAwOwogIGZvbnQtc2l6ZTogMTIuNXB4OwogIGxpbmUtaGVpZ2h0OiAxOHB4OwogIG92ZXJmbG93OiBoaWRkZW47Cn0KCi5ISjl4N2FfbW9ub0Jsb2NrIHsKICBib3JkZXI6IDFweCBzb2xpZCB2YXIoLS1kc3ctYWxpYXMtYm9yZGVyLWwyKTsKICBiYWNrZ3JvdW5kOiB2YXIoLS1kc3ctYWxpYXMtbWFya2Rvd24tY29kZS1ibG9jayk7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1zZWNvbmRhcnkpOwogIGJvcmRlci1yYWRpdXM6IDEwcHg7CiAgbWFyZ2luOiAwOwogIHBhZGRpbmc6IDEycHggMTRweDsKICBmb250OiAxMS41cHggLyAxOHB4IHVpLW1vbm9zcGFjZSwgTWVubG8sIENvbnNvbGFzLCBtb25vc3BhY2U7CiAgb3ZlcmZsb3cteDogYXV0bzsKfQoKLkhKOXg3YV9kZXRhaWxQcm9zZSB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1zZWNvbmRhcnkpOwogIG1hcmdpbjogMDsKICBmb250LXNpemU6IDEzcHg7CiAgbGluZS1oZWlnaHQ6IDIxcHg7Cn0KCi5ISjl4N2Ffa3ZWYWx1ZU1vbm8gewogIGZvbnQtZmFtaWx5OiB1aS1tb25vc3BhY2UsIE1lbmxvLCBDb25zb2xhcywgbW9ub3NwYWNlOwp9CgouXzNmMjJtcV9zdXJmYWNlIHsKICBtaW4td2lkdGg6IDA7CiAgbWluLWhlaWdodDogMDsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnksICMxZjIzMjgpOwogIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47CiAgZmxleDogMTsKICBkaXNwbGF5OiBmbGV4Owp9CgouXzNmMjJtcV90b29sYmFyIHsKICBmbGV4OiBub25lOwp9CgpAbWVkaWEgKHdpZHRoIDw9IDc2MHB4KSB7CiAgLl8zZjIybXFfZ3JpZCB7CiAgICBncmlkLXRlbXBsYXRlLWNvbHVtbnM6IG1pbm1heCgwLCAxZnIpOwogIH0KfQoKLl8zZjIybXFfZW1wdHksIC5fM2YyMm1xX2RldGFpbEVtcHR5IHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXRlcnRpYXJ5LCAjOGI5M2ExKTsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgcGFkZGluZzogMjRweDsKICBmb250LXNpemU6IDEycHg7Cn0KCi5fM2YyMm1xX2Vycm9yIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLXN0YXRlLWVycm9yLXByaW1hcnksICNkYzI2MjYpOwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiA4cHg7CiAgbWFyZ2luOiAxNnB4IDA7CiAgZm9udC1zaXplOiAxMnB4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5fM2YyMm1xX2RldGFpbEJvZHkgewogIG1heC1oZWlnaHQ6IDcydmg7CiAgb3ZlcmZsb3cteTogYXV0bzsKfQoKLl8zZjIybXFfbW9kYWxGb290ZXIgewogIGp1c3RpZnktY29udGVudDogZmxleC1lbmQ7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBnYXA6IDhweDsKICB3aWR0aDogMTAwJTsKICBkaXNwbGF5OiBmbGV4Owp9CgouXzNmMjJtcV9tb2RhbEZvb3RlckhpbnQgewogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtdGVydGlhcnkpOwogIGZvbnQtc2l6ZTogMTJweDsKfQoKLl8zZjIybXFfbW9kYWxGb290ZXJHcm93IHsKICBmbGV4OiBhdXRvOwp9CgouXzNmMjJtcV9kZXRhaWwgewogIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47CiAgZ2FwOiAxNnB4OwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5fM2YyMm1xX3JlYXV0aENvbmZpcm0gewogIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47CiAgZ2FwOiA4cHg7CiAgbWFyZ2luLXRvcDogMTBweDsKICBkaXNwbGF5OiBmbGV4Owp9CgouXzNmMjJtcV9yZWF1dGhFeHBsYWluIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXNlY29uZGFyeSwgIzRlNTk2OSk7CiAgbWFyZ2luOiAwOwogIGZvbnQtc2l6ZTogMTJweDsKICBsaW5lLWhlaWdodDogMThweDsKfQoKLl8zZjIybXFfcmVhdXRoQWN0aW9ucyB7CiAganVzdGlmeS1jb250ZW50OiBmbGV4LWVuZDsKICBnYXA6IDhweDsKICBkaXNwbGF5OiBmbGV4Owp9CgouXzNmMjJtcV9ibG9ja0hlYWRSb3cgewogIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGdhcDogMTJweDsKICBkaXNwbGF5OiBmbGV4Owp9CgouXzNmMjJtcV9ibG9ja1N1YiB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC10ZXJ0aWFyeSwgIzhiOTNhMSk7CiAgbWFyZ2luOiAwIDAgNnB4OwogIGZvbnQtc2l6ZTogMTFweDsKICBsaW5lLWhlaWdodDogMTZweDsKfQoKLl8zZjIybXFfdG9vbFNlYXJjaCB7CiAgZmxleDogMCAyMjBweDsKICBtaW4td2lkdGg6IDA7CiAgZGlzcGxheTogYmxvY2s7Cn0KCi5fM2YyMm1xX3Rvb2xMaXN0IHsKICBmbGV4LWRpcmVjdGlvbjogY29sdW1uOwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5fM2YyMm1xX3Rvb2wgewogIGJvcmRlci1ib3R0b206IDFweCBzb2xpZCB2YXIoLS1kc3ctYWxpYXMtYm9yZGVyLWwxLCAjZWVmMWY1KTsKICBncmlkLXRlbXBsYXRlLWNvbHVtbnM6IG1pbm1heCgxNDBweCwgbWF4LWNvbnRlbnQpIG1pbm1heCgwLCAxZnIpIG1heC1jb250ZW50OwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiAxMnB4OwogIHBhZGRpbmc6IDdweCAwIDdweCAycHg7CiAgZGlzcGxheTogZ3JpZDsKfQoKLl8zZjIybXFfdG9vbDpsYXN0LWNoaWxkIHsKICBib3JkZXItYm90dG9tOiBub25lOwp9CgouXzNmMjJtcV90b29sSWRlbnRpdHkgewogIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgZ2FwOiA4cHg7CiAgbWluLXdpZHRoOiAwOwogIGRpc3BsYXk6IGZsZXg7Cn0KCi5fM2YyMm1xX3Rvb2xOYW1lIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnksICMxZjIzMjgpOwogIHRleHQtb3ZlcmZsb3c6IGVsbGlwc2lzOwogIHdoaXRlLXNwYWNlOiBub3dyYXA7CiAgZm9udDogMTFweCAvIDE2cHggdWktbW9ub3NwYWNlLCBNZW5sbywgQ29uc29sYXMsIG1vbm9zcGFjZTsKICBvdmVyZmxvdzogaGlkZGVuOwp9CgouXzNmMjJtcV90b29sRGVzY3JpcHRpb24sIC5fM2YyMm1xX3Rvb2xOb3RlIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXRlcnRpYXJ5LCAjOGI5M2ExKTsKICB0ZXh0LW92ZXJmbG93OiBlbGxpcHNpczsKICB3aGl0ZS1zcGFjZTogbm93cmFwOwogIGZvbnQtc2l6ZTogMTBweDsKICBvdmVyZmxvdzogaGlkZGVuOwp9CgouXzNmMjJtcV90b29sTmFtZUJ1dHRvbiB7CiAgY3Vyc29yOiBwb2ludGVyOwogIHRleHQtYWxpZ246IGxlZnQ7CiAgYmFja2dyb3VuZDogbm9uZTsKICBib3JkZXI6IG5vbmU7CiAgcGFkZGluZzogMDsKfQoKLl8zZjIybXFfdG9vbE5hbWVCdXR0b246aG92ZXIgewogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtYnJhbmQtcHJpbWFyeSwgIzRmNmVmNyk7Cn0KCi5fM2YyMm1xX3Rvb2xQYXJhbXMgewogIGdyaWQtY29sdW1uOiAxIC8gLTE7CiAgcGFkZGluZzogOHB4IDAgMnB4IDExcHg7Cn0KCi5fM2YyMm1xX3Rvb2xQYXJhbXNHcmlkIHsKICBncmlkLXRlbXBsYXRlLWNvbHVtbnM6IG1pbm1heCgxMjBweCwgbWF4LWNvbnRlbnQpIG1pbm1heCg2MHB4LCBtYXgtY29udGVudCkgbWF4LWNvbnRlbnQgbWlubWF4KDAsIDFmcik7CiAgYWxpZ24taXRlbXM6IGJhc2VsaW5lOwogIGdhcDogNnB4IDEycHg7CiAgZGlzcGxheTogZ3JpZDsKfQoKLl8zZjIybXFfdG9vbFBhcmFtIHsKICBkaXNwbGF5OiBjb250ZW50czsKfQoKLl8zZjIybXFfdG9vbFBhcmFtTmFtZSB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1wcmltYXJ5LCAjMWYyMzI4KTsKICBmb250OiAxMXB4IC8gMTZweCB1aS1tb25vc3BhY2UsIE1lbmxvLCBDb25zb2xhcywgbW9ub3NwYWNlOwp9CgouXzNmMjJtcV90b29sUGFyYW1UeXBlIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXRlcnRpYXJ5LCAjOGI5M2ExKTsKICBmb250OiAxMHB4IC8gMTZweCB1aS1tb25vc3BhY2UsIE1lbmxvLCBDb25zb2xhcywgbW9ub3NwYWNlOwp9CgouXzNmMjJtcV90b29sUGFyYW1SZXF1aXJlZCB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1zdGF0ZS13YXJuLXByaW1hcnksICNiNDUzMDkpOwogIGZvbnQtc2l6ZTogMTBweDsKICBsaW5lLWhlaWdodDogMTZweDsKfQoKLl8zZjIybXFfdG9vbFBhcmFtRGVzYyB7CiAgb3ZlcmZsb3ctd3JhcDogYW55d2hlcmU7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC10ZXJ0aWFyeSwgIzhiOTNhMSk7CiAgZm9udC1zaXplOiAxMHB4OwogIGxpbmUtaGVpZ2h0OiAxNnB4Owp9CgouXzNmMjJtcV90b29sUGFyYW1zRW1wdHkgewogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtdGVydGlhcnksICM4YjkzYTEpOwogIG1hcmdpbjogMDsKICBmb250LXNpemU6IDEwcHg7CiAgbGluZS1oZWlnaHQ6IDE2cHg7Cn0KCi5fM2YyMm1xX3Rvb2xNb3JlIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXNlY29uZGFyeSwgIzY2NzA4NSk7CiAgY3Vyc29yOiBwb2ludGVyOwogIGJhY2tncm91bmQ6IG5vbmU7CiAgYm9yZGVyOiBub25lOwogIGJvcmRlci1yYWRpdXM6IDZweDsKICBhbGlnbi1zZWxmOiBmbGV4LXN0YXJ0OwogIG1hcmdpbi10b3A6IDhweDsKICBwYWRkaW5nOiA0cHggOHB4OwogIGZvbnQtc2l6ZTogMTFweDsKICBsaW5lLWhlaWdodDogMTdweDsKfQoKLl8zZjIybXFfdG9vbE1vcmU6aG92ZXIgewogIGJhY2tncm91bmQ6IHZhcigtLWRzdy1hbGlhcy1pbnRlcmFjdGl2ZS1iZy1ob3Zlcik7Cn0KCkBtZWRpYSAod2lkdGggPD0gNzYwcHgpIHsKICAuXzNmMjJtcV90b29sYmFyIHsKICAgIHBhZGRpbmctbGVmdDogMDsKICAgIHBhZGRpbmctcmlnaHQ6IDA7CiAgfQoKICAuXzNmMjJtcV9ncmlkIHsKICAgIGdyaWQtdGVtcGxhdGUtY29sdW1uczogbWlubWF4KDAsIDFmcik7CiAgfQoKICAuXzNmMjJtcV9saXN0IC5fM2YyMm1xX2NhcmRUb3AgewogICAgbWF4LXdpZHRoOiAxMDAlOwogIH0KCiAgLl8zZjIybXFfdG9vbCB7CiAgICBncmlkLXRlbXBsYXRlLWNvbHVtbnM6IG1pbm1heCgwLCAxZnIpOwogIH0KCiAgLl8zZjIybXFfdG9vbERlc2NyaXB0aW9uIHsKICAgIGRpc3BsYXk6IG5vbmU7CiAgfQp9CgpAa2V5ZnJhbWVzIF8zZjIybXFfbHNwU3RhcnRpbmdQdWxzZSB7CiAgNTAlIHsKICAgIG9wYWNpdHk6IC4zNTsKICB9Cn0KCi5fM2YyMm1xX3NlYW1CYW5uZXIgewogIGJvcmRlci1sZWZ0OiAzcHggc29saWQgdmFyKC0tZHN3LWFsaWFzLXN0YXRlLXdhcm4tcHJpbWFyeSwgI2I0NTMwOSk7CiAgYmFja2dyb3VuZDogdmFyKC0tZHN3LWFsaWFzLXN0YXRlLXdhcm4tdGVydGlhcnksICNiNDUzMDkxNCk7CiAgYm9yZGVyLXJhZGl1czogOHB4OwogIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47CiAgZ2FwOiA4cHg7CiAgbWFyZ2luOiAwIDAgMTJweDsKICBwYWRkaW5nOiAxMnB4IDE0cHg7CiAgZGlzcGxheTogZmxleDsKfQoKLl8zZjIybXFfc2VhbVRpdGxlIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLWxhYmVsLXByaW1hcnksICMxZjIzMjkpOwogIGZvbnQtc2l6ZTogMTNweDsKICBmb250LXdlaWdodDogNjAwOwp9CgouXzNmMjJtcV9zZWFtQm9keSB7CiAgY29sb3I6IHZhcigtLWRzdy1hbGlhcy1sYWJlbC1zZWNvbmRhcnksICM0ZTU5NjkpOwogIG1hcmdpbjogMDsKICBmb250LXNpemU6IDEycHg7CiAgbGluZS1oZWlnaHQ6IDE4cHg7Cn0KCi5fM2YyMm1xX3NlYW1QYXRoTGFiZWwgewogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtdGVydGlhcnksICM4YjkzYTEpOwogIGZvbnQtc2l6ZTogMTFweDsKfQoKLl8zZjIybXFfc2VhbVBhdGggewogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtc2Vjb25kYXJ5LCAjNGU1OTY5KTsKICBvdmVyZmxvdy13cmFwOiBhbnl3aGVyZTsKICBtYXJnaW46IDA7CiAgZm9udC1mYW1pbHk6IHVpLW1vbm9zcGFjZSwgU0ZNb25vLVJlZ3VsYXIsIE1lbmxvLCBtb25vc3BhY2U7CiAgZm9udC1zaXplOiAxMXB4OwogIGxpbmUtaGVpZ2h0OiAxNnB4Owp9CgouXzNmMjJtcV9zZWFtT3RoZXIgewogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtdGVydGlhcnksICM4YjkzYTEpOwogIG1hcmdpbjogMDsKICBmb250LXNpemU6IDExcHg7CiAgbGluZS1oZWlnaHQ6IDE2cHg7Cn0KCi5fM2YyMm1xX3NlYW1Eb25lIHsKICBjb2xvcjogdmFyKC0tZHN3LWFsaWFzLXN0YXRlLXN1Y2Nlc3MtcHJpbWFyeSwgIzE1ODAzZCk7CiAgbWFyZ2luOiAwOwogIGZvbnQtc2l6ZTogMTJweDsKICBsaW5lLWhlaWdodDogMThweDsKfQoucjV5Y3RHX3dvcmtzcGFjZSB7CiAgbWluLXdpZHRoOiAwOwogIGhlaWdodDogMTAwJTsKICBtaW4taGVpZ2h0OiAwOwogIGNvbG9yOiB2YXIoLS1kc3ctYWxpYXMtbGFiZWwtcHJpbWFyeSwgIzFmMjMyOCk7CiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjsKICBmbGV4OiAxOwogIGdhcDogMTJweDsKICBkaXNwbGF5OiBmbGV4Owp9CgoucjV5Y3RHX3BhZ2VNb2RlIHsKICBib3gtc2l6aW5nOiBib3JkZXItYm94OwogIHBhZGRpbmc6IDRweCAwOwp9CgoucjV5Y3RHX3RhYlJvdyB7CiAgc2Nyb2xsYmFyLXdpZHRoOiBub25lOwogIGZsZXg6IG5vbmU7CiAgbWluLXdpZHRoOiAwOwogIG92ZXJmbG93LXg6IGF1dG87Cn0KCi5yNXljdEdfdGFiUGFuZWwgewogIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47CiAgZmxleDogMTsKICBtaW4taGVpZ2h0OiAwOwogIGRpc3BsYXk6IGZsZXg7Cn0K"),function(c){return c.charCodeAt(0)}));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
|
-
|
|
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
|
-
|
|
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
|
|
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": "
|
|
1538
|
-
"cardActions": "
|
|
1539
|
-
"cardTop": "
|
|
1540
|
-
"confirmCheck": "
|
|
1541
|
-
"detailItemOpen": "
|
|
1542
|
-
"detailItemRow": "
|
|
1543
|
-
"dshApmSpin": "
|
|
1544
|
-
"editorDialog": "
|
|
1545
|
-
"empty": "
|
|
1546
|
-
"grid": "
|
|
1547
|
-
"header": "
|
|
1548
|
-
"installConfirmBody": "
|
|
1549
|
-
"installConfirmCommit": "
|
|
1550
|
-
"installConfirmMeta": "
|
|
1551
|
-
"installConfirmSuite": "
|
|
1552
|
-
"installConfirmTags": "
|
|
1553
|
-
"installConfirmWarn": "
|
|
1554
|
-
"list": "
|
|
1555
|
-
"market": "
|
|
1556
|
-
"market-config": "
|
|
1557
|
-
"marketControls": "
|
|
1558
|
-
"meta": "
|
|
1559
|
-
"modalFooter": "
|
|
1560
|
-
"modalFooterLeft": "
|
|
1561
|
-
"pageEntry": "
|
|
1562
|
-
"pageMode": "
|
|
1563
|
-
"pageView": "
|
|
1564
|
-
"pluginCard": "
|
|
1565
|
-
"pluginCardBody": "
|
|
1566
|
-
"pluginCardDesc": "
|
|
1567
|
-
"pluginCardDiscard": "
|
|
1568
|
-
"pluginCardError": "
|
|
1569
|
-
"pluginCardFooter": "
|
|
1570
|
-
"pluginCardHeader": "
|
|
1571
|
-
"pluginCardOpen": "
|
|
1572
|
-
"pluginCardReadonly": "
|
|
1573
|
-
"pluginCardRow": "
|
|
1574
|
-
"pluginCardRowLabel": "
|
|
1575
|
-
"
|
|
1576
|
-
"
|
|
1577
|
-
"
|
|
1578
|
-
"
|
|
1579
|
-
"
|
|
1580
|
-
"
|
|
1581
|
-
"
|
|
1582
|
-
"
|
|
1583
|
-
"
|
|
1584
|
-
"
|
|
1585
|
-
"
|
|
1586
|
-
"
|
|
1587
|
-
"
|
|
1588
|
-
"
|
|
1589
|
-
"
|
|
1590
|
-
"
|
|
1591
|
-
"
|
|
1592
|
-
"
|
|
1593
|
-
"
|
|
1594
|
-
"
|
|
1595
|
-
"
|
|
1596
|
-
"
|
|
1597
|
-
"
|
|
1598
|
-
"
|
|
1599
|
-
"
|
|
1600
|
-
"
|
|
1601
|
-
"
|
|
1602
|
-
"
|
|
1603
|
-
"
|
|
1604
|
-
"
|
|
1605
|
-
"
|
|
1606
|
-
"
|
|
1607
|
-
"
|
|
1608
|
-
"
|
|
1609
|
-
"
|
|
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/
|
|
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/
|
|
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 },
|
|
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
|
|
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
|
|
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"))
|
|
8310
|
-
|
|
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
|
-
"
|
|
8331
|
-
"
|
|
8332
|
-
"
|
|
8333
|
-
"
|
|
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
|
|
8342
|
-
*
|
|
8343
|
-
*
|
|
8344
|
-
*
|
|
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)(
|
|
8366
|
-
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8370
|
-
|
|
8371
|
-
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
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
|
-
/**
|
|
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:
|
|
8394
|
-
y:
|
|
8363
|
+
x: 3,
|
|
8364
|
+
y: 3,
|
|
8395
8365
|
width: 4,
|
|
8396
8366
|
height: 4,
|
|
8397
|
-
rx:
|
|
8367
|
+
rx: 1
|
|
8398
8368
|
}), (0, react.createElement)("rect", {
|
|
8399
|
-
x: 9
|
|
8400
|
-
y:
|
|
8369
|
+
x: 9,
|
|
8370
|
+
y: 3,
|
|
8401
8371
|
width: 4,
|
|
8402
8372
|
height: 4,
|
|
8403
|
-
rx:
|
|
8373
|
+
rx: 1
|
|
8404
8374
|
}), (0, react.createElement)("rect", {
|
|
8405
|
-
x:
|
|
8406
|
-
y: 9
|
|
8375
|
+
x: 3,
|
|
8376
|
+
y: 9,
|
|
8407
8377
|
width: 4,
|
|
8408
8378
|
height: 4,
|
|
8409
|
-
rx:
|
|
8379
|
+
rx: 1
|
|
8410
8380
|
}), (0, react.createElement)("rect", {
|
|
8411
|
-
x: 9
|
|
8412
|
-
y: 9
|
|
8381
|
+
x: 9,
|
|
8382
|
+
y: 9,
|
|
8413
8383
|
width: 4,
|
|
8414
8384
|
height: 4,
|
|
8415
|
-
rx:
|
|
8385
|
+
rx: 1
|
|
8416
8386
|
}));
|
|
8417
8387
|
}
|
|
8418
8388
|
//#endregion
|
|
@@ -8487,7 +8457,7 @@ function codePointSize$1(code) {
|
|
|
8487
8457
|
return code < 65536 ? 1 : 2;
|
|
8488
8458
|
}
|
|
8489
8459
|
//#endregion
|
|
8490
|
-
//#region node_modules/.pnpm/@codemirror+state@6.7.
|
|
8460
|
+
//#region node_modules/.pnpm/@codemirror+state@6.7.6/node_modules/@codemirror/state/dist/index.js
|
|
8491
8461
|
/**
|
|
8492
8462
|
The data structure for documents. @nonabstract
|
|
8493
8463
|
*/
|
|
@@ -10784,7 +10754,7 @@ var EditorState = class EditorState {
|
|
|
10784
10754
|
to: range.to,
|
|
10785
10755
|
insert: text
|
|
10786
10756
|
},
|
|
10787
|
-
range: EditorSelection.cursor(range.from + text.length)
|
|
10757
|
+
range: EditorSelection.cursor(range.from + text.length, -1)
|
|
10788
10758
|
}));
|
|
10789
10759
|
}
|
|
10790
10760
|
/**
|
|
@@ -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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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}
|
|
35035
|
+
label: `${source.id} ${source.suiteIds.length}`,
|
|
35066
35036
|
...noteHint === void 0 ? {} : { title: noteHint },
|
|
35067
|
-
editable:
|
|
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, {
|
|
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)(
|
|
35778
|
-
|
|
35779
|
-
|
|
35780
|
-
|
|
35781
|
-
|
|
35782
|
-
|
|
35783
|
-
|
|
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
|
|
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
|
-
|
|
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)(
|
|
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
|
|
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", {
|
|
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", {
|
|
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
|
|
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)(
|
|
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/
|
|
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
|
-
|
|
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
|
-
|
|
37695
|
-
|
|
37696
|
-
|
|
37697
|
-
|
|
37698
|
-
|
|
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", {
|
|
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": "
|
|
38027
|
-
"
|
|
38028
|
-
"
|
|
38029
|
-
"
|
|
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)(
|
|
37987
|
+
}, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.SegmentedTabs, {
|
|
38088
37988
|
className: workspace_module_default.tabRow,
|
|
38089
|
-
|
|
38090
|
-
|
|
38091
|
-
|
|
38092
|
-
|
|
38093
|
-
|
|
38094
|
-
|
|
38095
|
-
|
|
38096
|
-
|
|
38097
|
-
|
|
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,28 +38060,190 @@ function renderTab(tab, t, credentials, mode) {
|
|
|
38125
38060
|
}
|
|
38126
38061
|
}
|
|
38127
38062
|
//#endregion
|
|
38128
|
-
//#region src/client/
|
|
38063
|
+
//#region src/client/features/settings-card/market-card-form.ts
|
|
38064
|
+
/**
|
|
38065
|
+
* The market settings card's binding onto the host's published settings-form
|
|
38066
|
+
* model (`@deepseek-ai/dsh-client-ui-primitives.SettingsFormModel`).
|
|
38067
|
+
*
|
|
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.
|
|
38077
|
+
*
|
|
38078
|
+
* @module client/market-card-form
|
|
38079
|
+
*/
|
|
38080
|
+
/** The boolean switches this card renders, in display order. */
|
|
38081
|
+
const MARKET_SWITCH_FIELDS = [
|
|
38082
|
+
"mcpEnhanced",
|
|
38083
|
+
"scanProjectLayouts",
|
|
38084
|
+
"autoUpdateSources",
|
|
38085
|
+
"feedbackEnabled"
|
|
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
|
|
38129
38229
|
/**
|
|
38130
38230
|
* The Agent Plugins Market page on the host's Plugins panel: the market
|
|
38131
38231
|
* feature's configuration entry, named after the market itself.
|
|
38132
38232
|
*
|
|
38133
38233
|
* The page's Plugins panel renders every `plugins.item` entry twice: a
|
|
38134
38234
|
* `summary` one-liner on the official card, and the `page` form on the
|
|
38135
|
-
* entry's detail page. This component answers both views.
|
|
38136
|
-
*
|
|
38137
|
-
*
|
|
38138
|
-
*
|
|
38139
|
-
*
|
|
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.
|
|
38140
38242
|
*
|
|
38141
38243
|
* @module client/McpPluginCard
|
|
38142
38244
|
*/
|
|
38143
38245
|
/** Copy of the boolean switches, in display order. */
|
|
38144
|
-
const SWITCH_FIELDS =
|
|
38145
|
-
"mcpEnhanced",
|
|
38146
|
-
"scanProjectLayouts",
|
|
38147
|
-
"autoUpdateSources",
|
|
38148
|
-
"feedbackEnabled"
|
|
38149
|
-
];
|
|
38246
|
+
const SWITCH_FIELDS = MARKET_SWITCH_FIELDS;
|
|
38150
38247
|
/** Copy keys of each switch. */
|
|
38151
38248
|
const SWITCH_COPY = {
|
|
38152
38249
|
mcpEnhanced: {
|
|
@@ -38177,343 +38274,110 @@ function OverrideBadge(props) {
|
|
|
38177
38274
|
onClick: props.onReset
|
|
38178
38275
|
}, props.t("settingReset")));
|
|
38179
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
|
+
}
|
|
38180
38281
|
/** One boolean switch row: its copy, the control, and the reset when it is overridden. */
|
|
38181
38282
|
function SwitchRow(props) {
|
|
38182
38283
|
const copy = SWITCH_COPY[props.field];
|
|
38183
38284
|
const label = props.t(copy.label);
|
|
38184
|
-
return (0, react.createElement)("div", { className: market_module_default.pluginCardRow }, (0, react.createElement)("div", { className: market_module_default.pluginCardText }, (0, react.createElement)(
|
|
38185
|
-
|
|
38186
|
-
|
|
38187
|
-
|
|
38188
|
-
props.
|
|
38189
|
-
|
|
38190
|
-
|
|
38191
|
-
|
|
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",
|
|
38192
38297
|
label,
|
|
38193
38298
|
disabled: props.disabled,
|
|
38194
38299
|
onChange: () => {
|
|
38195
|
-
props.
|
|
38300
|
+
props.onEdit(props.field, props.state.text === "true" ? "false" : "true");
|
|
38196
38301
|
}
|
|
38197
38302
|
}));
|
|
38198
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
|
+
];
|
|
38199
38319
|
function McpPluginCard(props) {
|
|
38200
|
-
const { t, useMarketCard,
|
|
38320
|
+
const { t, useMarketCard, edit, resetField, save, discard, refreshProbe } = props;
|
|
38201
38321
|
const state = useMarketCard((current) => current);
|
|
38202
38322
|
(0, react.useEffect)(() => {
|
|
38203
|
-
refreshProbe();
|
|
38204
|
-
}, [refreshProbe]);
|
|
38205
|
-
if (
|
|
38206
|
-
|
|
38207
|
-
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;
|
|
38208
38327
|
const region = state.downloadRegion;
|
|
38209
|
-
const effectiveRegion = state.probe?.downloadRegion.effective ?? (region.
|
|
38210
|
-
return (0, react.createElement)(
|
|
38211
|
-
|
|
38212
|
-
|
|
38213
|
-
|
|
38214
|
-
|
|
38215
|
-
|
|
38216
|
-
|
|
38217
|
-
|
|
38218
|
-
|
|
38219
|
-
|
|
38220
|
-
|
|
38221
|
-
|
|
38222
|
-
|
|
38223
|
-
|
|
38224
|
-
|
|
38225
|
-
|
|
38226
|
-
|
|
38227
|
-
|
|
38228
|
-
|
|
38229
|
-
"
|
|
38230
|
-
|
|
38231
|
-
|
|
38232
|
-
|
|
38233
|
-
|
|
38234
|
-
|
|
38235
|
-
|
|
38236
|
-
|
|
38237
|
-
disabled: blocked,
|
|
38238
|
-
className: selected ? market_module_default.regionSegOn : resolved ? market_module_default.regionSegEffective : market_module_default.regionSegBtn,
|
|
38239
|
-
onClick: () => {
|
|
38240
|
-
if (option === "auto") {
|
|
38241
|
-
if (region.overridden) resetField("downloadRegion");
|
|
38242
|
-
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");
|
|
38243
38356
|
}
|
|
38244
|
-
|
|
38245
|
-
|
|
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);
|
|
38246
38370
|
}
|
|
38247
|
-
},
|
|
38248
|
-
|
|
38249
|
-
|
|
38250
|
-
|
|
38251
|
-
|
|
38252
|
-
|
|
38253
|
-
|
|
38254
|
-
disabled: !state.dirty || state.saving,
|
|
38255
|
-
onClick: discard
|
|
38256
|
-
}, t("settingDiscard")), (0, react.createElement)("button", {
|
|
38257
|
-
type: "button",
|
|
38258
|
-
className: market_module_default.pluginCardSave,
|
|
38259
|
-
disabled: !state.dirty || state.invalid || state.saving,
|
|
38260
|
-
onClick: save
|
|
38261
|
-
}, t(state.saving ? "settingSaving" : "settingSave"))));
|
|
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
|
+
});
|
|
38262
38378
|
}
|
|
38263
38379
|
//#endregion
|
|
38264
|
-
//#region src/client/
|
|
38265
|
-
/**
|
|
38266
|
-
* Staged form behind the Agent Plugins Market card on the host's plugin
|
|
38267
|
-
* configuration tab.
|
|
38268
|
-
*
|
|
38269
|
-
* The card's controls edit the market's host settings namespace, so every write
|
|
38270
|
-
* is a durable, revision-fenced document mutation the node half reacts to —
|
|
38271
|
-
* flipping the MCP switch tears down and remounts suite servers. The form
|
|
38272
|
-
* therefore stages what the user picks and writes it on save, which is the
|
|
38273
|
-
* contract every card in this slot follows: what is on screen is exactly what a
|
|
38274
|
-
* save would store, one save is one committed change, and a field the user
|
|
38275
|
-
* never touched stays untouched.
|
|
38276
|
-
*
|
|
38277
|
-
* Every default the card renders comes from the contract module, which is the
|
|
38278
|
-
* single place a default is written; the card never restates one. A field still
|
|
38279
|
-
* carrying no user-layer entry is marked overridable rather than overridden, and
|
|
38280
|
-
* resetting it clears the entry instead of writing today's default in, so the
|
|
38281
|
-
* field goes back to following the plugin rather than pinning the value it
|
|
38282
|
-
* happened to have.
|
|
38283
|
-
*
|
|
38284
|
-
* @module client/plugin-card-controller
|
|
38285
|
-
*/
|
|
38286
|
-
/** Bridges the market settings scope onto the card's staged form. */
|
|
38287
|
-
var MarketPluginCardController = class {
|
|
38288
|
-
scope;
|
|
38289
|
-
probeSource;
|
|
38290
|
-
store;
|
|
38291
|
-
unsubscribe;
|
|
38292
|
-
staged = /* @__PURE__ */ new Map();
|
|
38293
|
-
probe;
|
|
38294
|
-
probeStatus = "idle";
|
|
38295
|
-
/** Bumped by every probe read so a late answer cannot overwrite a newer one. */
|
|
38296
|
-
probeGeneration = 0;
|
|
38297
|
-
/** Bumped by every save and every dispose so a late write cannot publish over a newer state. */
|
|
38298
|
-
saveGeneration = 0;
|
|
38299
|
-
saving = false;
|
|
38300
|
-
failed = false;
|
|
38301
|
-
disposed = false;
|
|
38302
|
-
/**
|
|
38303
|
-
* @param scope - the host configuration form for the market namespace.
|
|
38304
|
-
* @param probe - reads the live host-client and region state from the market API.
|
|
38305
|
-
*/
|
|
38306
|
-
constructor(scope, probeSource) {
|
|
38307
|
-
this.scope = scope;
|
|
38308
|
-
this.probeSource = probeSource;
|
|
38309
|
-
this.store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(this.projection());
|
|
38310
|
-
this.unsubscribe = scope.subscribe(() => {
|
|
38311
|
-
this.publish();
|
|
38312
|
-
});
|
|
38313
|
-
}
|
|
38314
|
-
/** Stop observing settings and suppress late probe/write settlements. */
|
|
38315
|
-
dispose() {
|
|
38316
|
-
this.disposed = true;
|
|
38317
|
-
this.saveGeneration += 1;
|
|
38318
|
-
this.probeGeneration += 1;
|
|
38319
|
-
this.unsubscribe();
|
|
38320
|
-
}
|
|
38321
|
-
/**
|
|
38322
|
-
* Build the renderer face for this card.
|
|
38323
|
-
* @returns the card snapshot and its staged form actions.
|
|
38324
|
-
*/
|
|
38325
|
-
inject() {
|
|
38326
|
-
return {
|
|
38327
|
-
hooks: { marketCard: this.store },
|
|
38328
|
-
toggle: (field) => {
|
|
38329
|
-
this.toggle(field);
|
|
38330
|
-
},
|
|
38331
|
-
setRegion: (next) => {
|
|
38332
|
-
this.stageSet("downloadRegion", next);
|
|
38333
|
-
},
|
|
38334
|
-
resetField: (field) => {
|
|
38335
|
-
this.stageClear(field);
|
|
38336
|
-
},
|
|
38337
|
-
save: () => {
|
|
38338
|
-
this.save();
|
|
38339
|
-
},
|
|
38340
|
-
discard: () => {
|
|
38341
|
-
this.discard();
|
|
38342
|
-
},
|
|
38343
|
-
refreshProbe: () => {
|
|
38344
|
-
this.loadProbe();
|
|
38345
|
-
}
|
|
38346
|
-
};
|
|
38347
|
-
}
|
|
38348
|
-
/** Read the host-client probe once; a second call while one is in flight is a no-op. */
|
|
38349
|
-
async loadProbe() {
|
|
38350
|
-
if (this.disposed || this.probeStatus === "loading") return;
|
|
38351
|
-
this.probeStatus = "loading";
|
|
38352
|
-
const generation = this.probeGeneration;
|
|
38353
|
-
try {
|
|
38354
|
-
const info = await this.probeSource();
|
|
38355
|
-
if (generation !== this.probeGeneration || this.disposed) return;
|
|
38356
|
-
this.probe = info;
|
|
38357
|
-
} catch {} finally {
|
|
38358
|
-
if (generation === this.probeGeneration) this.probeStatus = "idle";
|
|
38359
|
-
this.publish();
|
|
38360
|
-
}
|
|
38361
|
-
}
|
|
38362
|
-
/** Stage the opposite of one switch's shown value. */
|
|
38363
|
-
toggle(field) {
|
|
38364
|
-
if (!this.editable()) return;
|
|
38365
|
-
this.stageSet(field, !this.fieldValue(field));
|
|
38366
|
-
}
|
|
38367
|
-
stageSet(field, value) {
|
|
38368
|
-
if (!this.editable()) return;
|
|
38369
|
-
this.staged.set(field, {
|
|
38370
|
-
kind: "set",
|
|
38371
|
-
value
|
|
38372
|
-
});
|
|
38373
|
-
this.failed = false;
|
|
38374
|
-
this.publish();
|
|
38375
|
-
}
|
|
38376
|
-
stageClear(field) {
|
|
38377
|
-
if (!this.editable()) return;
|
|
38378
|
-
this.staged.set(field, { kind: "clear" });
|
|
38379
|
-
this.failed = false;
|
|
38380
|
-
this.publish();
|
|
38381
|
-
}
|
|
38382
|
-
discard() {
|
|
38383
|
-
if (this.saving || this.staged.size === 0 && !this.failed) return;
|
|
38384
|
-
this.staged.clear();
|
|
38385
|
-
this.failed = false;
|
|
38386
|
-
this.publish();
|
|
38387
|
-
}
|
|
38388
|
-
/**
|
|
38389
|
-
* Write every staged edit, then re-read what the host accepted.
|
|
38390
|
-
*
|
|
38391
|
-
* The host is the only authority on whether a write landed — it owns the
|
|
38392
|
-
* document, its validation, and any concurrent writer — so the outcome is read
|
|
38393
|
-
* back rather than predicted. A save that did not land keeps its edits so the
|
|
38394
|
-
* user can correct them instead of retyping.
|
|
38395
|
-
*/
|
|
38396
|
-
async save() {
|
|
38397
|
-
const plan = this.plan();
|
|
38398
|
-
if (plan.length === 0 || this.saving || this.invalid()) return;
|
|
38399
|
-
const generation = this.saveGeneration;
|
|
38400
|
-
this.saving = true;
|
|
38401
|
-
this.failed = false;
|
|
38402
|
-
this.publish();
|
|
38403
|
-
let landed = true;
|
|
38404
|
-
for (const write of plan) try {
|
|
38405
|
-
landed = await write.run() && landed;
|
|
38406
|
-
} catch {
|
|
38407
|
-
landed = false;
|
|
38408
|
-
}
|
|
38409
|
-
if (generation !== this.saveGeneration) return;
|
|
38410
|
-
if (landed) this.staged.clear();
|
|
38411
|
-
this.saving = false;
|
|
38412
|
-
this.failed = !landed;
|
|
38413
|
-
this.publish();
|
|
38414
|
-
}
|
|
38415
|
-
/**
|
|
38416
|
-
* Every staged edit a save would write. An edit that would leave the document
|
|
38417
|
-
* exactly as it already is carries no write, which is what keeps `dirty` from
|
|
38418
|
-
* reporting a save that would do nothing.
|
|
38419
|
-
*/
|
|
38420
|
-
plan() {
|
|
38421
|
-
const plan = [];
|
|
38422
|
-
for (const [field, edit] of this.staged) {
|
|
38423
|
-
if (edit.kind === "clear") {
|
|
38424
|
-
if (this.overridden(field)) plan.push({
|
|
38425
|
-
field,
|
|
38426
|
-
run: () => this.clear(field)
|
|
38427
|
-
});
|
|
38428
|
-
continue;
|
|
38429
|
-
}
|
|
38430
|
-
if (edit.value === this.storedValue(field)) continue;
|
|
38431
|
-
plan.push({
|
|
38432
|
-
field,
|
|
38433
|
-
run: () => this.storeValue(field, edit.value)
|
|
38434
|
-
});
|
|
38435
|
-
}
|
|
38436
|
-
return plan;
|
|
38437
|
-
}
|
|
38438
|
-
async clear(field) {
|
|
38439
|
-
await this.scope.unset(field);
|
|
38440
|
-
return !this.overridden(field);
|
|
38441
|
-
}
|
|
38442
|
-
async storeValue(field, value) {
|
|
38443
|
-
await this.scope.set(field, value);
|
|
38444
|
-
return this.overridden(field) && this.fieldValue(field) === value;
|
|
38445
|
-
}
|
|
38446
|
-
/** Whether the form accepts edits at all: served, writable, and not mid-save. */
|
|
38447
|
-
editable() {
|
|
38448
|
-
const snapshot = this.scope.getSnapshot();
|
|
38449
|
-
return !this.disposed && snapshot.status === "ready" && snapshot.writable && !this.saving;
|
|
38450
|
-
}
|
|
38451
|
-
/** The document's resolved value for one field. */
|
|
38452
|
-
storedValue(field) {
|
|
38453
|
-
return this.scope.getSnapshot().value?.[field] ?? MARKET_SETTINGS_DEFAULTS[field];
|
|
38454
|
-
}
|
|
38455
|
-
/** The value the card shows: the staged edit when one stands, else the document's. */
|
|
38456
|
-
fieldValue(field) {
|
|
38457
|
-
const edit = this.staged.get(field);
|
|
38458
|
-
if (edit !== void 0 && edit.kind === "set") return edit.value;
|
|
38459
|
-
return this.storedValue(field);
|
|
38460
|
-
}
|
|
38461
|
-
/** Whether a user-layer entry stands for this field, which is what marks it overridden. */
|
|
38462
|
-
overridden(field) {
|
|
38463
|
-
const user = this.scope.getSnapshot().user;
|
|
38464
|
-
return typeof user === "object" && user !== null && Object.hasOwn(user, field);
|
|
38465
|
-
}
|
|
38466
|
-
switchState(field) {
|
|
38467
|
-
const edit = this.staged.get(field);
|
|
38468
|
-
return {
|
|
38469
|
-
value: this.fieldValue(field),
|
|
38470
|
-
overridden: edit === void 0 ? this.overridden(field) : edit.kind === "set",
|
|
38471
|
-
staged: edit !== void 0
|
|
38472
|
-
};
|
|
38473
|
-
}
|
|
38474
|
-
/** Whether the host client is known to be missing, which blocks compat mode. */
|
|
38475
|
-
hostClientMissing() {
|
|
38476
|
-
return this.probe !== void 0 && !this.probe.hostClient.available;
|
|
38477
|
-
}
|
|
38478
|
-
/**
|
|
38479
|
-
* Whether the form is in a state a save must refuse: compat mode asks for the
|
|
38480
|
-
* host's MCP client, and a deployment that does not resolve it would leave MCP
|
|
38481
|
-
* servers with no mount path at all.
|
|
38482
|
-
*/
|
|
38483
|
-
invalid() {
|
|
38484
|
-
return !this.fieldValue("mcpEnhanced") && this.hostClientMissing();
|
|
38485
|
-
}
|
|
38486
|
-
projection() {
|
|
38487
|
-
const snapshot = this.scope.getSnapshot();
|
|
38488
|
-
const plan = this.plan();
|
|
38489
|
-
const regionEdit = this.staged.get("downloadRegion");
|
|
38490
|
-
return {
|
|
38491
|
-
available: snapshot.status === "ready",
|
|
38492
|
-
writable: snapshot.writable,
|
|
38493
|
-
dirty: plan.length > 0,
|
|
38494
|
-
invalid: this.invalid(),
|
|
38495
|
-
saving: this.saving,
|
|
38496
|
-
failed: this.failed,
|
|
38497
|
-
mcpEnhanced: this.switchState("mcpEnhanced"),
|
|
38498
|
-
scanProjectLayouts: this.switchState("scanProjectLayouts"),
|
|
38499
|
-
autoUpdateSources: this.switchState("autoUpdateSources"),
|
|
38500
|
-
feedbackEnabled: this.switchState("feedbackEnabled"),
|
|
38501
|
-
downloadRegion: {
|
|
38502
|
-
value: this.fieldValue("downloadRegion"),
|
|
38503
|
-
overridden: regionEdit === void 0 ? this.overridden("downloadRegion") : regionEdit.kind === "set",
|
|
38504
|
-
staged: regionEdit !== void 0
|
|
38505
|
-
},
|
|
38506
|
-
probe: this.probe,
|
|
38507
|
-
hostClientMissing: this.hostClientMissing()
|
|
38508
|
-
};
|
|
38509
|
-
}
|
|
38510
|
-
publish() {
|
|
38511
|
-
if (this.disposed) return;
|
|
38512
|
-
this.store.set(this.projection());
|
|
38513
|
-
}
|
|
38514
|
-
};
|
|
38515
|
-
//#endregion
|
|
38516
|
-
//#region src/client/page-mode-selection.ts
|
|
38380
|
+
//#region src/client/workspace/page-mode-selection.ts
|
|
38517
38381
|
/** Pure capability decision for the legacy page-mode fallback. */
|
|
38518
38382
|
/**
|
|
38519
38383
|
* Use the DOM page fallback only when the host has no settings page and does
|
|
@@ -38527,7 +38391,7 @@ function shouldUseLegacyPageMode(settingsSurfaceAvailable, pageShellAvailable) {
|
|
|
38527
38391
|
return !settingsSurfaceAvailable && pageShellAvailable;
|
|
38528
38392
|
}
|
|
38529
38393
|
//#endregion
|
|
38530
|
-
//#region src/client/page-mode.tsx
|
|
38394
|
+
//#region src/client/workspace/page-mode.tsx
|
|
38531
38395
|
/**
|
|
38532
38396
|
* Legacy Web page-mode adapter.
|
|
38533
38397
|
*
|
|
@@ -38810,17 +38674,18 @@ function apply(ctx) {
|
|
|
38810
38674
|
if (service === void 0 || slots === void 0) return;
|
|
38811
38675
|
let card;
|
|
38812
38676
|
service.whileServed([NS], () => {
|
|
38813
|
-
|
|
38677
|
+
const bound = bindMarketCardForm(service.get(NS), fetchMcpBackend);
|
|
38678
|
+
card = bound.face;
|
|
38814
38679
|
const dispose = slots.register({
|
|
38815
38680
|
name: "plugins.item",
|
|
38816
38681
|
id: NS,
|
|
38817
38682
|
order: 50,
|
|
38818
38683
|
label: () => t("nav"),
|
|
38819
38684
|
locale: NS,
|
|
38820
|
-
inject: () => card
|
|
38685
|
+
inject: () => card
|
|
38821
38686
|
}, McpPluginCard);
|
|
38822
38687
|
return () => {
|
|
38823
|
-
|
|
38688
|
+
bound.dispose();
|
|
38824
38689
|
card = void 0;
|
|
38825
38690
|
if (typeof dispose === "function") dispose();
|
|
38826
38691
|
};
|