@sunshaobei/dsh-mcp-manager 0.4.0 → 0.6.1
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.en.md +6 -0
- package/README.md +6 -0
- package/lib/client/float/float.d.ts +2 -2
- package/lib/client/float/panel.d.ts +2 -0
- package/lib/client/float/servers.d.ts +6 -0
- package/lib/client.js +137 -236
- package/lib/index.js +779 -516
- package/lib/server/api/routes.d.ts +2 -2
- package/lib/server/catalog/search.d.ts +3 -3
- package/lib/server/config/sources-sync.d.ts +2 -2
- package/lib/server/connection/interface.d.ts +9 -0
- package/lib/server/connection/orchestrator/manager.d.ts +28 -10
- package/lib/server/connection/runtime/deps.d.ts +1 -0
- package/lib/server/connection/runtime/middleware.d.ts +3 -1
- package/package.json +3 -4
package/lib/client.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// 契约外壳(scripts/build-client.ts 生成):external 依赖(React 等)经 factory 注入的 require 解析
|
|
3
3
|
window.__ModuleLoader__.load({
|
|
4
|
-
id: "
|
|
4
|
+
id: "dsh-mcp-manager",
|
|
5
5
|
factory: function (require) {
|
|
6
6
|
var module = { exports: {} }
|
|
7
7
|
var exports = module.exports
|
|
@@ -44,7 +44,7 @@ window.__ModuleLoader__.load({
|
|
|
44
44
|
module.exports = __toCommonJS(index_exports);
|
|
45
45
|
|
|
46
46
|
// src/client/style.css
|
|
47
|
-
var style_default = '/* dsh-mcp-manager — 客户端样式(独立 .css 文件)。\n *\n * 由 build-client 的 .css text-loader 构建期内联进 client.js(产物仍自包含单文件、\n * 零运行时依赖、无独立请求)。前缀 dm-(防与 shell / 其他插件样式冲突)。\n *\n * 浮窗视觉:Apple Liquid Glass(半透明毛玻璃 + 0.5px subtle border)。\n * 固体文字/状态色走 --dsw-alias-* + 浅色回退;玻璃底/光边双主题 rgba\n * (light ≈ white/76,dark ≈ zinc-900/74),并经 color-mix 跟随宿主主题变量。\n * 动效:Apple Fluid Curve cubic-bezier(0.16, 1, 0.3, 1)。\n * 浮窗 origin=胶囊锚点→对角 scale 0.72→1;模态 origin=中心→四周 scale 0.78→1。\n * 可点元素 Active Press Feedback;中英混排系统中文字体栈 + line-height ≥1.5。 */\n\n:root {\n --dm-fluid: cubic-bezier(0.16, 1, 0.3, 1);\n --dm-press-scale: 0.96;\n --dm-glass-blur: 28px;\n --dm-glass-saturate: 220%;\n --dm-glass-bg: rgba(255, 255, 255, 0.76);\n --dm-glass-bg-strong: rgba(255, 255, 255, 0.84);\n --dm-glass-bg-solid: var(--dsw-alias-bg-base, #fdfdfd);\n /* 主题跟随 wash:浅色用墨 8%,深色用白 12%(M1:禁止深色下写死浅色 wash) */\n --dm-wash: color-mix(in srgb, #1c1e26 8%, transparent);\n /* 卡片底:浅色白 42% 霜,深色白 7% 霜(配 zinc-900/74 玻璃底) */\n --dm-card-bg: color-mix(in srgb, #ffffff 42%, transparent);\n /* 行 hover:浅色黑 3%,深色白 7%(深色下黑 3% 近不可见) */\n --dm-row-hover: color-mix(in srgb, #000000 3%, transparent);\n --dm-glass-edge: rgba(20, 30, 50, 0.1);\n --dm-glass-rim: rgba(255, 255, 255, 0.92);\n --dm-glass-shadow:\n inset 0 0.5px 0 rgba(255, 255, 255, 0.95), inset 0 0 0 0.5px rgba(255, 255, 255, 0.45),\n 0 1px 1px rgba(20, 30, 50, 0.04), 0 6px 16px rgba(30, 45, 80, 0.08),\n 0 20px 48px rgba(30, 45, 80, 0.12);\n --dm-glass-spec: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 0.72) 0%,\n rgba(255, 255, 255, 0.22) 22%,\n rgba(255, 255, 255, 0.04) 48%,\n rgba(255, 255, 255, 0) 100%\n );\n --dm-font-ui:\n system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",\n "Noto Sans SC", sans-serif;\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n --dm-glass-bg: rgba(24, 24, 27, 0.74);\n --dm-glass-bg-strong: rgba(24, 24, 27, 0.86);\n --dm-wash: color-mix(in srgb, #ffffff 12%, transparent);\n --dm-card-bg: color-mix(in srgb, #ffffff 7%, transparent);\n --dm-row-hover: color-mix(in srgb, #ffffff 7%, transparent);\n --dm-glass-edge: rgba(255, 255, 255, 0.14);\n --dm-glass-rim: rgba(255, 255, 255, 0.12);\n --dm-glass-shadow:\n inset 0 0.5px 0 rgba(255, 255, 255, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.1),\n 0 24px 64px rgba(0, 0, 0, 0.5), 0 4px 16px rgba(0, 0, 0, 0.28);\n --dm-glass-spec: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 0.16) 0%,\n rgba(255, 255, 255, 0.03) 30%,\n rgba(255, 255, 255, 0) 100%\n );\n }\n}\nhtml.dark,\n[data-theme="dark"],\n[data-color-mode="dark"] {\n --dm-glass-bg: rgba(24, 24, 27, 0.74);\n --dm-glass-bg-strong: rgba(24, 24, 27, 0.86);\n --dm-wash: color-mix(in srgb, #ffffff 12%, transparent);\n --dm-card-bg: color-mix(in srgb, #ffffff 7%, transparent);\n --dm-row-hover: color-mix(in srgb, #ffffff 7%, transparent);\n --dm-glass-edge: rgba(255, 255, 255, 0.14);\n --dm-glass-rim: rgba(255, 255, 255, 0.12);\n --dm-glass-shadow:\n inset 0 0.5px 0 rgba(255, 255, 255, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.1),\n 0 24px 64px rgba(0, 0, 0, 0.5), 0 4px 16px rgba(0, 0, 0, 0.28);\n --dm-glass-spec: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 0.16) 0%,\n rgba(255, 255, 255, 0.03) 30%,\n rgba(255, 255, 255, 0) 100%\n );\n}\n\n@media (prefers-contrast: more) {\n :root {\n --dm-glass-bg: rgba(255, 255, 255, 0.94);\n --dm-glass-bg-strong: #ffffff;\n --dm-glass-edge: rgba(20, 30, 50, 0.22);\n /* 高对比下关闭高光 wash,wash 走纯色 */\n --dm-glass-spec: none;\n --dm-wash: #eceff3;\n --dm-card-bg: #ffffff;\n --dm-row-hover: #eef1f5;\n }\n html.dark,\n [data-theme="dark"],\n [data-color-mode="dark"] {\n --dm-glass-bg: rgba(18, 18, 20, 0.96);\n --dm-glass-bg-strong: #121214;\n --dm-glass-edge: rgba(255, 255, 255, 0.28);\n --dm-glass-spec: none;\n --dm-wash: #2a2d34;\n --dm-card-bg: #17171a;\n --dm-row-hover: #26282f;\n }\n /* 高对比下隐藏装饰性高光层,失败行保留纯色语义底 */\n .dm-glass::before {\n display: none;\n }\n .dm-float-row.dm-float-row--fail,\n .dm-server.dm-server--fail {\n background: color-mix(in srgb, #e0483e 12%, var(--dm-glass-bg-strong));\n }\n}\n\n[data-conversation-scroll] {\n position: relative;\n}\n[data-pane="conversation"] {\n position: relative;\n}\n\n/* 毛玻璃公共层 */\n.dm-glass {\n position: relative;\n color: var(--dsw-alias-label-primary, #1c1e26);\n border: 0.5px solid var(--dm-glass-edge);\n background: var(--dm-glass-bg);\n backdrop-filter: blur(var(--dm-glass-blur)) saturate(var(--dm-glass-saturate));\n -webkit-backdrop-filter: blur(var(--dm-glass-blur)) saturate(var(--dm-glass-saturate));\n box-shadow: var(--dm-glass-shadow);\n font-family: var(--dm-font-ui);\n letter-spacing: 0;\n}\n.dm-glass::before {\n content: "";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n background: var(--dm-glass-spec);\n pointer-events: none;\n}\n.dm-glass > * {\n position: relative;\n z-index: 1;\n}\n@media (prefers-reduced-transparency: reduce) {\n .dm-float,\n .dm-float-panel,\n .dm-card,\n .dm-float-action,\n .dm-float-head button,\n .dm-head button,\n .dm-actions button,\n .dm-form-actions button,\n .dm-server,\n .dm-tab[data-active] {\n background: var(--dm-glass-bg-solid, var(--dsw-alias-bg-base, #fdfdfd));\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n }\n /* 失败行保留语义底,但以纯色混合(相对实底)代替透明罩染 */\n .dm-float-row.dm-float-row--fail,\n .dm-server.dm-server--fail {\n background: color-mix(\n in srgb,\n #e0483e 8%,\n var(--dm-glass-bg-solid, var(--dsw-alias-bg-base, #fdfdfd))\n );\n }\n /* 装饰性高光层在减透明下隐藏 */\n .dm-glass::before {\n display: none;\n }\n}\n\n/* —— 胶囊(高度契约约 26–30px,供 provider-usage offsetY 避让)—— */\n.dm-float {\n position: absolute;\n top: 44px;\n right: 14px;\n z-index: 10;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 5px 11px;\n border: 0.5px solid var(--dm-glass-edge);\n border-radius: 99px;\n background: var(--dm-glass-bg);\n color: var(--dsw-alias-label-primary, #1c1e26);\n font-size: 12px;\n line-height: 1.4;\n letter-spacing: 0;\n cursor: pointer;\n font-family: var(--dm-font-ui);\n backdrop-filter: blur(var(--dm-glass-blur)) saturate(var(--dm-glass-saturate));\n -webkit-backdrop-filter: blur(var(--dm-glass-blur)) saturate(var(--dm-glass-saturate));\n box-shadow:\n inset 0 0.5px 0 var(--dm-glass-rim),\n 0 2px 10px rgba(15, 18, 28, 0.08);\n transition:\n transform 160ms var(--dm-fluid),\n box-shadow 160ms var(--dm-fluid);\n transform-origin: center;\n -webkit-tap-highlight-color: transparent;\n}\n/* 触控热区(#128,WCAG 2.2 AA ≥24px;外扩至约 44px) */\n.dm-float::after {\n content: "";\n position: absolute;\n inset: -7px;\n border-radius: 99px;\n}\n.dm-float .dm-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n display: inline-block;\n flex: none;\n /* 缺省中性灰;renderPill 按健康态写 inline 色 */\n background: var(--dsw-alias-label-tertiary, #9aa1ad);\n}\n.dm-float.dm-float--fail .dm-dot {\n background: var(--dsw-alias-state-error-primary, #e0483e) !important;\n box-shadow: 0 0 0 2px color-mix(in srgb, #e0483e 22%, transparent);\n}\n.dm-float .dm-float-fail {\n display: none;\n font-size: 10px;\n font-weight: 700;\n color: var(--dsw-alias-state-error-primary, #e0483e);\n line-height: 1;\n}\n.dm-float.dm-float--fail .dm-float-fail {\n display: inline;\n}\n.dm-float:active {\n transform: scale(var(--dm-press-scale));\n transition-duration: 80ms;\n}\n.dm-float.dm-float--open {\n box-shadow:\n inset 0 0.5px 0 var(--dm-glass-rim),\n 0 0 0 1.5px color-mix(in srgb, #2f7bf6 35%, transparent),\n 0 2px 10px rgba(15, 18, 28, 0.08);\n}\n.dm-float:focus-visible {\n outline: 2px solid var(--dsw-alias-state-info-primary, #3b82f6);\n outline-offset: 2px;\n}\n\n/* —— 浮窗下拉面板:锚点(胶囊)→ 对角展开 —— */\n@keyframes dm-float-in {\n from {\n opacity: 0;\n transform: scale(0.72);\n filter: blur(10px);\n }\n to {\n opacity: 1;\n transform: scale(1);\n filter: blur(0px);\n }\n}\n@keyframes dm-float-out {\n from {\n opacity: 1;\n transform: scale(1);\n filter: blur(0px);\n }\n to {\n opacity: 0;\n transform: scale(0.78);\n filter: blur(8px);\n }\n}\n@keyframes dm-row-in {\n from {\n opacity: 0;\n transform: translateY(6px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.dm-float-panel {\n position: fixed;\n top: 44px;\n right: 14px;\n width: min(400px, calc(100vw - 36px));\n max-height: min(70vh, 560px);\n max-height: min(70dvh, 560px);\n overflow: auto;\n overscroll-behavior: contain;\n color: var(--dsw-alias-label-primary, #1c1e26);\n border: 0.5px solid var(--dm-glass-edge);\n border-radius: 20px;\n background: var(--dm-glass-bg);\n z-index: 10;\n padding: 14px 14px 12px;\n font-family: var(--dm-font-ui);\n font-size: 12px;\n line-height: 1.55;\n letter-spacing: 0;\n backdrop-filter: blur(var(--dm-glass-blur)) saturate(var(--dm-glass-saturate));\n -webkit-backdrop-filter: blur(var(--dm-glass-blur)) saturate(var(--dm-glass-saturate));\n box-shadow: var(--dm-glass-shadow);\n opacity: 0;\n transform: scale(0.72);\n filter: blur(10px);\n visibility: hidden;\n pointer-events: none;\n /* 缺省 top-right 锚点;placePanel 按四角改写 inline transform-origin */\n transform-origin: top right;\n will-change: opacity, transform, filter;\n}\n.dm-float-panel.dm-float-panel--open {\n visibility: visible;\n pointer-events: auto;\n opacity: 1;\n transform: scale(1);\n filter: blur(0);\n animation: dm-float-in 480ms var(--dm-fluid) both;\n}\n.dm-float-panel.dm-float-panel--closing {\n visibility: visible;\n pointer-events: none;\n animation: dm-float-out 300ms var(--dm-fluid) both;\n}\n.dm-float-panel.dm-float-panel--open .dm-float-row.dm-stagger {\n animation: dm-row-in 320ms var(--dm-fluid) both;\n}\n.dm-float-panel[hidden] {\n display: none !important;\n}\n\n/* #128 移动端档位 */\n.dm-float-panel[data-dm-bp="narrow"] {\n width: calc(100vw - 16px);\n max-height: calc(85vh - 88px);\n max-height: calc(85dvh - 88px);\n padding: 12px 10px 10px;\n border-radius: 14px;\n}\n.dm-float-panel[data-dm-bp="tablet"] {\n width: min(400px, calc(100vw - 24px));\n}\n.dm-float-panel[data-dm-bp="narrow"] .dm-float-row {\n flex-wrap: wrap;\n row-gap: 2px;\n padding: 10px 8px;\n}\n.dm-float-panel[data-dm-bp="narrow"] .dm-float-row .dm-float-meta {\n flex-basis: 100%;\n white-space: normal;\n line-height: 1.5;\n}\n.dm-float-panel[data-dm-bp="narrow"] .dm-float-actions {\n flex: 1;\n justify-content: flex-end;\n}\n.dm-float-action {\n position: relative;\n}\n.dm-float-panel[data-dm-bp="narrow"] .dm-float-action {\n min-height: 36px;\n padding: 6px 14px;\n font-size: 12.5px;\n}\n.dm-float-panel[data-dm-bp="narrow"] .dm-float-action::before {\n content: "";\n position: absolute;\n inset: -4px;\n}\n.dm-float-panel[data-dm-bp="tablet"] .dm-float-action {\n min-height: 30px;\n padding: 4px 11px;\n}\n.dm-float-panel[data-dm-bp="narrow"] .dm-float-head button {\n min-height: 36px;\n padding: 5px 12px;\n font-size: 12.5px;\n}\n\n.dm-float-head {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n margin-bottom: 10px;\n padding: 2px 4px 0;\n}\n.dm-float-head-text {\n flex: 1;\n min-width: 0;\n}\n.dm-float-title {\n font-weight: 600;\n font-size: 13px;\n line-height: 1.4;\n letter-spacing: 0;\n color: var(--dsw-alias-label-primary, #1c1e26);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dm-float-health {\n margin-top: 3px;\n font-size: 11px;\n line-height: 1.45;\n color: var(--dsw-alias-label-secondary, #6b7280);\n font-variant-numeric: tabular-nums;\n}\n.dm-float-health .dm-health-ok {\n color: var(--dsw-alias-state-success-primary, #0f9d6e);\n}\n.dm-float-health .dm-health-bad {\n color: var(--dsw-alias-state-error-primary, #e0483e);\n font-weight: 600;\n}\n.dm-float-head button {\n flex: none;\n border: 0.5px solid var(--dm-glass-edge);\n background: color-mix(in srgb, var(--dsw-alias-bg-base, #fff) 55%, transparent);\n color: var(--dsw-alias-label-primary, #1c1e26);\n border-radius: 99px;\n min-height: 28px;\n padding: 4px 11px;\n font-size: 11px;\n line-height: 1.4;\n font-family: inherit;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n transition:\n transform 160ms var(--dm-fluid),\n background-color 160ms var(--dm-fluid),\n opacity 160ms var(--dm-fluid);\n}\n.dm-float-head button:active,\n.dm-float-action:active,\n.dm-head button:active,\n.dm-actions button:active,\n.dm-form-actions button:active,\n.dm-set-save:active {\n transform: scale(var(--dm-press-scale));\n transition-duration: 80ms;\n opacity: 0.88;\n}\n.dm-float-head button:focus-visible,\n.dm-float-action:focus-visible,\n.dm-head button:focus-visible {\n outline: 2px solid var(--dsw-alias-state-info-primary, #3b82f6);\n outline-offset: 2px;\n}\n\n.dm-float-group {\n margin: 0 0 4px;\n padding: 0;\n}\n.dm-float-group + .dm-float-group {\n margin-top: 14px;\n}\n.dm-float-group-title {\n font-size: 11px;\n line-height: 1.4;\n letter-spacing: 0.04em;\n color: var(--dsw-alias-label-secondary, #8a8f9c);\n font-weight: 600;\n margin: 0 0 6px;\n padding: 0 6px;\n}\n.dm-float-group-title.dm-float-group-title--alert {\n color: var(--dsw-alias-state-error-primary, #e0483e);\n}\n\n.dm-float-row {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 6px 8px;\n padding: 8px 8px 10px;\n border: none;\n border-radius: 14px;\n margin-bottom: 2px;\n background: transparent;\n line-height: 1.5;\n transition: background-color 160ms var(--dm-fluid);\n}\n.dm-float-row.dm-float-row--fail {\n background: color-mix(in srgb, #e0483e 6%, transparent);\n}\n.dm-float-row .dm-float-name {\n font-weight: 600;\n font-family: ui-monospace, "SF Mono", Consolas, "PingFang SC", monospace;\n font-size: 12px;\n line-height: 1.4;\n letter-spacing: 0;\n max-width: 150px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--dsw-alias-label-primary, #1c1e26);\n}\n.dm-float-row .dm-float-meta {\n flex: 1;\n min-width: 0;\n font-size: 11px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary, #8a8f9c);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n}\n.dm-float-actions {\n flex: none;\n display: flex;\n gap: 4px;\n margin-left: auto;\n flex-wrap: wrap;\n}\n.dm-float-action {\n border: 0.5px solid var(--dm-glass-edge);\n background: color-mix(in srgb, var(--dsw-alias-bg-base, #fff) 50%, transparent);\n color: var(--dsw-alias-label-primary, #1c1e26);\n border-radius: 99px;\n min-height: 28px;\n padding: 3px 10px;\n font-size: 11px;\n line-height: 1.4;\n font-family: inherit;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n transition:\n transform 160ms var(--dm-fluid),\n background-color 160ms var(--dm-fluid),\n opacity 160ms var(--dm-fluid);\n}\n.dm-float-action.dm-primary,\n.dm-actions button.dm-primary,\n.dm-form-actions button.dm-primary {\n font-weight: 600;\n border-color: color-mix(in srgb, #2f7bf6 35%, transparent);\n background: color-mix(in srgb, #2f7bf6 12%, transparent);\n color: var(--dsw-alias-state-business-primary, #2f6fe0);\n}\n.dm-float-action.dm-danger,\n.dm-actions button.dm-danger {\n color: var(--dsw-alias-state-error-primary, #b42318);\n border-color: color-mix(in srgb, #b42318 30%, transparent);\n}\n\n/* —— 模态管理面板:中心 → 四周 —— */\n@keyframes dm-modal-in {\n from {\n opacity: 0;\n transform: scale(0.78);\n filter: blur(12px);\n }\n to {\n opacity: 1;\n transform: scale(1);\n filter: blur(0px);\n }\n}\n@keyframes dm-modal-out {\n from {\n opacity: 1;\n transform: scale(1);\n filter: blur(0px);\n }\n to {\n opacity: 0;\n transform: scale(0.82);\n filter: blur(10px);\n }\n}\n@keyframes dm-overlay-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes dm-overlay-out {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n}\n.dm-overlay {\n position: fixed;\n inset: 0;\n background: var(--dsw-alias-bg-mask-2, rgba(8, 10, 16, 0.28));\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 9999;\n font-family: var(--dm-font-ui);\n opacity: 0;\n visibility: hidden;\n pointer-events: none;\n backdrop-filter: blur(8px) saturate(120%);\n -webkit-backdrop-filter: blur(8px) saturate(120%);\n}\n.dm-overlay.dm-overlay--open {\n opacity: 1;\n visibility: visible;\n pointer-events: auto;\n animation: dm-overlay-in 360ms var(--dm-fluid) both;\n}\n.dm-overlay.dm-overlay--closing {\n visibility: visible;\n pointer-events: none;\n animation: dm-overlay-out 280ms var(--dm-fluid) both;\n}\n.dm-overlay[hidden] {\n display: none !important;\n}\n.dm-card {\n width: min(860px, 94vw);\n max-height: 86vh;\n display: flex;\n flex-direction: column;\n color: var(--dsw-alias-label-primary, #1c1e26);\n border: 0.5px solid var(--dm-glass-edge);\n border-radius: 22px;\n background: var(--dm-glass-bg-strong);\n box-shadow: var(--dm-glass-shadow);\n backdrop-filter: blur(var(--dm-glass-blur)) saturate(var(--dm-glass-saturate));\n -webkit-backdrop-filter: blur(var(--dm-glass-blur)) saturate(var(--dm-glass-saturate));\n overflow: hidden;\n opacity: 0;\n transform: scale(0.78);\n filter: blur(12px);\n transform-origin: center center;\n will-change: opacity, transform, filter;\n}\n.dm-overlay.dm-overlay--open .dm-card {\n opacity: 1;\n transform: scale(1);\n filter: blur(0);\n transform-origin: center center;\n animation: dm-modal-in 520ms var(--dm-fluid) both;\n}\n.dm-overlay.dm-overlay--closing .dm-card {\n transform-origin: center center;\n animation: dm-modal-out 300ms var(--dm-fluid) both;\n}\n.dm-head {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 16px 18px 10px;\n border-bottom: none;\n background: transparent;\n}\n.dm-head h2 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 1.35;\n}\n.dm-head .dm-counts {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary, #8a8f9c);\n flex: 1;\n line-height: 1.5;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n}\n.dm-head .dm-counts .dm-health-bad {\n color: var(--dsw-alias-state-error-primary, #e0483e);\n font-weight: 600;\n}\n.dm-head button {\n border: 0.5px solid var(--dm-glass-edge);\n background: color-mix(in srgb, var(--dsw-alias-bg-base, #fff) 55%, transparent);\n color: var(--dsw-alias-label-primary, #3a3f4b);\n border-radius: 99px;\n min-height: 28px;\n padding: 4px 11px;\n font-size: 12px;\n font-family: inherit;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n transition:\n transform 160ms var(--dm-fluid),\n background-color 160ms var(--dm-fluid);\n}\n.dm-tabs {\n display: flex;\n gap: 4px;\n padding: 0 18px 8px;\n border-bottom: none;\n background: transparent;\n}\n.dm-tab {\n border: none;\n background: transparent;\n color: var(--dsw-alias-label-secondary, #6b7280);\n min-height: 34px;\n padding: 8px 14px;\n font-size: 13px;\n line-height: 1.4;\n font-family: inherit;\n cursor: pointer;\n border-radius: 99px;\n -webkit-tap-highlight-color: transparent;\n transition:\n background 160ms var(--dm-fluid),\n color 160ms var(--dm-fluid),\n transform 160ms var(--dm-fluid);\n}\n.dm-tab:active {\n transform: scale(var(--dm-press-scale));\n transition-duration: 80ms;\n}\n.dm-tab[data-active] {\n color: var(--dsw-alias-label-primary, #1c1e26);\n font-weight: 600;\n background: var(--dm-wash);\n box-shadow: 0 0 0 0.5px var(--dm-glass-edge);\n}\n.dm-body {\n padding: 4px 18px 18px;\n overflow: auto;\n min-height: 200px;\n overscroll-behavior: contain;\n}\n.dm-status {\n padding: 28px 16px;\n color: var(--dsw-alias-label-secondary, #6b7280);\n font-size: 13px;\n text-align: center;\n line-height: 1.6;\n}\n\n.dm-group {\n margin-bottom: 8px;\n}\n.dm-group > h3 {\n position: sticky;\n top: 0;\n z-index: 1;\n margin: 8px 0 6px;\n font-size: 12px;\n font-weight: 600;\n letter-spacing: 0.04em;\n color: var(--dsw-alias-label-secondary, #525866);\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 0 6px;\n line-height: 1.4;\n background: linear-gradient(\n color-mix(in srgb, var(--dsw-alias-bg-base, #fdfdfd) 88%, transparent) 70%,\n transparent\n );\n}\n.dm-group > h3.dm-group-alert {\n color: var(--dsw-alias-state-error-primary, #e0483e);\n}\n.dm-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n display: inline-block;\n}\n.dm-group > .dm-hint {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, #8a8f9c);\n margin: 0 0 8px;\n line-height: 1.5;\n}\n.dm-count {\n font-weight: 400;\n color: var(--dsw-alias-label-secondary, #8a8f9c);\n margin-left: 2px;\n font-size: 11px;\n}\n.dm-server {\n border: 0.5px solid var(--dm-glass-edge);\n border-radius: 16px;\n padding: 12px 14px;\n margin-bottom: 10px;\n background: var(--dm-card-bg);\n line-height: 1.5;\n}\n.dm-server.dm-server--fail {\n border-color: color-mix(in srgb, #e0483e 28%, var(--dm-glass-edge));\n background: color-mix(in srgb, #e0483e 5%, transparent);\n}\n.dm-server header {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n.dm-server .dm-name {\n font-weight: 600;\n font-size: 13px;\n color: var(--dsw-alias-label-primary, #111827);\n font-family: ui-monospace, Consolas, "PingFang SC", monospace;\n overflow-wrap: anywhere;\n word-break: break-word;\n line-height: 1.4;\n}\n.dm-badge {\n font-size: 10px;\n line-height: 1.3;\n padding: 1px 7px;\n border-radius: 99px;\n background: var(--dsw-alias-bg-layer-2, #f1f2f5);\n color: var(--dsw-alias-label-secondary, #525866);\n border: 1px solid var(--dsw-alias-border-l2, #e2e4ea);\n}\n.dm-badge.dm-http {\n background: var(--dsw-alias-state-business-secondary, #eef2ff);\n color: var(--dsw-alias-state-business-primary, #4353a3);\n border-color: var(--dsw-alias-state-business-tertiary, #dde3f8);\n}\n.dm-badge.dm-stdio {\n background: var(--dsw-alias-bg-layer-2, #f5f0ff);\n color: var(--dsw-alias-label-secondary, #6d4bb8);\n border-color: var(--dsw-alias-border-l2, #e6dcf8);\n}\n.dm-badge.dm-st-connected {\n /* 绿底白字:运行中是唯一「正向强状态」,用实底与未连接/失败的中性、红底拉开层级 */\n background: #10b981;\n color: #ffffff;\n border-color: #10b981;\n font-weight: 600;\n}\n.dm-badge.dm-st-connecting,\n.dm-badge.dm-st-reconnecting {\n background: var(--dsw-alias-state-business-secondary, #eff6ff);\n color: var(--dsw-alias-state-business-primary, #1d66b8);\n border-color: var(--dsw-alias-state-business-tertiary, #d3e5fb);\n}\n.dm-badge.dm-st-failed {\n /* 红底白字:失败与运行中同为强状态,实底保证可读性 */\n background: #dc2626;\n color: #ffffff;\n border-color: #dc2626;\n font-weight: 600;\n}\n.dm-badge.dm-st-disabled,\n.dm-badge.dm-st-stopped {\n background: var(--dsw-alias-bg-layer-2, #f1f2f5);\n color: var(--dsw-alias-label-secondary, #6b7280);\n border-color: var(--dsw-alias-border-l2, #e2e4ea);\n}\n.dm-server .dm-endpoint {\n margin: 6px 0 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, #8a8f9c);\n font-family: ui-monospace, Consolas, "PingFang SC", monospace;\n word-break: break-all;\n line-height: 1.5;\n}\n.dm-server .dm-err {\n margin: 6px 0 0;\n font-size: 11px;\n color: var(--dsw-alias-state-error-primary, #b42318);\n line-height: 1.5;\n}\n.dm-server .dm-tools {\n margin: 8px 0 0;\n}\n.dm-server .dm-tools summary {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, #525866);\n cursor: pointer;\n user-select: none;\n line-height: 1.5;\n}\n.dm-server .dm-tools ul {\n margin: 4px 0 0;\n padding-left: 16px;\n font-size: 11px;\n color: var(--dsw-alias-label-primary, #3a3f4b);\n font-family: ui-monospace, Consolas, "PingFang SC", monospace;\n line-height: 1.55;\n}\n.dm-actions {\n display: flex;\n gap: 6px;\n margin-top: 10px;\n flex-wrap: wrap;\n}\n.dm-actions button {\n border: 0.5px solid var(--dm-glass-edge);\n background: color-mix(in srgb, var(--dsw-alias-bg-base, #fff) 55%, transparent);\n color: var(--dsw-alias-label-primary, #3a3f4b);\n border-radius: 99px;\n min-height: 28px;\n padding: 3px 10px;\n font-size: 11px;\n font-family: inherit;\n line-height: 1.4;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n transition:\n transform 160ms var(--dm-fluid),\n background-color 160ms var(--dm-fluid);\n}\n.dm-actions button.dm-danger {\n color: var(--dsw-alias-state-error-primary, #b42318);\n border-color: var(--dsw-alias-state-error-tertiary, #f0c4c1);\n}\n.dm-actions button.dm-primary {\n color: var(--dsw-alias-state-business-primary, #1d4ed8);\n border-color: var(--dsw-alias-state-business-tertiary, #bcd1fb);\n background: var(--dsw-alias-state-business-secondary, #f5f8ff);\n font-weight: 600;\n}\n.dm-actions button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.dm-section {\n margin-bottom: 18px;\n}\n.dm-section > h3 {\n margin: 0 0 8px;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, #2f3542);\n line-height: 1.4;\n}\n.dm-form {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px 12px;\n max-width: 640px;\n}\n.dm-form .dm-full {\n grid-column: 1/-1;\n}\n.dm-field {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.dm-field label {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, #525866);\n font-weight: 600;\n line-height: 1.4;\n}\n.dm-field input,\n.dm-field select,\n.dm-field textarea {\n border: 0.5px solid var(--dm-glass-edge);\n border-radius: 10px;\n padding: 8px 10px;\n min-height: 36px;\n font-size: 12px;\n color: var(--dsw-alias-label-primary, #1c1e26);\n background: color-mix(in srgb, #ffffff 55%, transparent);\n font-family: ui-monospace, Consolas, "PingFang SC", monospace;\n line-height: 1.45;\n}\n.dm-field textarea {\n min-height: 64px;\n resize: vertical;\n line-height: 1.55;\n}\n.dm-field input[type="checkbox"] {\n width: auto;\n min-height: 0;\n}\n.dm-check {\n flex-direction: row;\n align-items: center;\n gap: 8px;\n}\n.dm-check label {\n margin: 0;\n}\n.dm-form-actions {\n grid-column: 1/-1;\n display: flex;\n gap: 8px;\n}\n.dm-form-actions button {\n border: 0.5px solid var(--dm-glass-edge);\n background: color-mix(in srgb, var(--dsw-alias-bg-base, #fff) 55%, transparent);\n color: var(--dsw-alias-label-primary, #3a3f4b);\n border-radius: 99px;\n min-height: 32px;\n padding: 6px 14px;\n font-size: 12px;\n font-family: inherit;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n transition:\n transform 160ms var(--dm-fluid),\n background-color 160ms var(--dm-fluid);\n}\n.dm-form-actions button.dm-primary {\n background: var(--dsw-alias-button-primary-fill, #4f6ef7);\n color: var(--dsw-alias-label-primary-foreground, #fff);\n border-color: var(--dsw-alias-button-primary-fill, #4f6ef7);\n font-weight: 600;\n}\n.dm-hint {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, #8a8f9c);\n line-height: 1.5;\n}\n.dm-paste-box {\n border: 0.5px solid var(--dm-glass-edge);\n border-radius: 16px;\n padding: 12px;\n background: color-mix(in srgb, #ffffff 40%, transparent);\n max-width: 640px;\n}\n.dm-result {\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary, #0f7a50);\n margin-top: 8px;\n line-height: 1.6;\n}\n.dm-result .dm-skip {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n/* 设置页插件卡(settings.plugin.item)——视觉锚点测试 #219 不变 */\n.dm-set-card {\n list-style: none;\n margin: 0;\n padding: 0;\n border: 1px solid var(--dsw-alias-border-l2, #e2e5ea);\n border-radius: 12px;\n background: var(--dsw-alias-bg-layer-3, #fbfbfc);\n overflow: hidden;\n transition:\n border-color 0.16s,\n background 0.16s;\n}\n.dm-set-head {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 14px 16px;\n background: transparent;\n border: none;\n cursor: pointer;\n text-align: left;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n.dm-set-headText {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n min-width: 0;\n}\n.dm-set-name {\n display: block;\n font-size: 15px;\n font-weight: 600;\n line-height: 1.4;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n.dm-set-description {\n display: block;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary, #8a919c);\n}\n.dm-set-chevron {\n flex: none;\n color: var(--dsw-alias-label-tertiary, #5f6672);\n transition: transform 0.16s ease;\n}\n.dm-set-chevronOpen {\n transform: rotate(180deg);\n}\n.dm-set-body {\n padding: 4px 14px 14px;\n border-top: 1px solid var(--dsw-alias-border-l1, #e2e5ea);\n display: flex;\n flex-direction: column;\n gap: 9px;\n}\n.dm-set-row {\n display: flex;\n align-items: center;\n gap: 12px;\n margin: 0;\n flex-wrap: wrap;\n}\n.dm-set-row > label {\n font-size: 12.5px;\n color: var(--dsw-alias-label-secondary, #5f6672);\n font-weight: 600;\n white-space: nowrap;\n}\n.dm-set-field {\n display: inline-flex;\n flex-direction: column;\n gap: 3px;\n font-size: 11.5px;\n color: var(--dsw-alias-label-secondary, #5f6672);\n font-weight: 600;\n}\n.dm-set-input {\n min-width: 88px;\n padding: 5px 8px;\n border: 1px solid var(--dsw-alias-border-l1, #e2e5ea);\n border-radius: 6px;\n font-size: 12.5px;\n color: var(--dsw-alias-label-primary, #1f2329);\n background: var(--dsw-alias-bg-layer-1, #fff);\n box-sizing: border-box;\n}\n.dm-set-input:focus {\n outline: none;\n border-color: var(--dsw-alias-state-info-primary, #3b82f6);\n}\n.dm-set-hint {\n margin-top: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-tertiary, #8a919c);\n line-height: 1.5;\n}\n.dm-set-foot {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 10px;\n margin-top: 10px;\n}\n.dm-set-foot .dm-set-saved {\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary, #16a34a);\n}\n.dm-set-foot .dm-set-error {\n font-size: 12px;\n color: var(--dsw-alias-state-danger-primary, #dc2626);\n}\n.dm-set-save {\n border: 1px solid var(--dsw-alias-border-l1, #e2e5ea);\n background: var(--dsw-alias-bg-base, #fff);\n color: var(--dsw-alias-label-primary, #3a3f4b);\n border-radius: 6px;\n padding: 5px 14px;\n font-size: 12px;\n cursor: pointer;\n transition:\n transform 160ms var(--dm-fluid),\n background-color 160ms var(--dm-fluid);\n}\n.dm-set-save:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* #128 悬停态统一包裹 @media(hover:hover) */\n@media (hover: hover) {\n .dm-float:hover {\n background: color-mix(in srgb, var(--dsw-alias-interactive-bg-hover, #f2f4f8) 70%, transparent);\n }\n .dm-float-head button:hover {\n background: var(--dsw-alias-interactive-bg-hover, #eef1f5);\n }\n .dm-float-action:hover {\n background: var(--dsw-alias-interactive-bg-hover, #eef1f5);\n }\n .dm-float-row:hover {\n background: var(--dm-row-hover);\n }\n .dm-head button:hover {\n background: var(--dsw-alias-interactive-bg-hover, #eef1f5);\n }\n .dm-actions button:hover {\n background: var(--dsw-alias-interactive-bg-hover, #eef1f5);\n }\n .dm-form-actions button:hover {\n background: var(--dsw-alias-interactive-bg-hover, #eef1f5);\n }\n .dm-set-card:hover {\n border-color: var(--dsw-alias-label-dimmed, #9ba1a6);\n }\n .dm-set-head:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, 0.04));\n }\n .dm-set-save:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, 0.06));\n }\n}\n\n/* #362 工具级禁用 checkbox(#401 勾选=禁用,红色 ×) */\n.dm-float-tools {\n margin: 4px 0 0 16px;\n width: 100%;\n}\n.dm-float-tools summary {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, #525866);\n cursor: pointer;\n user-select: none;\n line-height: 1.5;\n}\n.dm-float-tool-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin: 4px 0 0;\n max-height: 140px;\n overflow: auto;\n}\n.dm-float-tool,\n.dm-tool {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: var(--dsw-alias-label-primary, #3a3f4b);\n font-family: ui-monospace, Consolas, monospace;\n cursor: pointer;\n line-height: 1.6;\n overflow-wrap: anywhere;\n word-break: break-word;\n min-width: 0;\n max-width: 100%;\n}\n.dm-float-tool input,\n.dm-tool input {\n width: 13px;\n height: 13px;\n margin: 0;\n flex: none;\n appearance: none;\n -webkit-appearance: none;\n border: 1px solid var(--dsw-alias-border-l2, #c3c8d2);\n border-radius: 3px;\n background: var(--dsw-alias-bg-base, #fff);\n cursor: pointer;\n position: relative;\n box-sizing: border-box;\n}\n.dm-float-tool input:checked,\n.dm-tool input:checked {\n border-color: var(--dsw-alias-state-error-primary, #b42318);\n background: var(--dsw-alias-state-error-secondary, #fef2f2);\n}\n.dm-float-tool input:checked::after,\n.dm-tool input:checked::after {\n content: "";\n position: absolute;\n left: 50%;\n top: 50%;\n width: 8px;\n height: 8px;\n transform: translate(-50%, -50%);\n background:\n linear-gradient(\n 45deg,\n transparent 43%,\n var(--dsw-alias-state-error-primary, #b42318) 43%,\n var(--dsw-alias-state-error-primary, #b42318) 57%,\n transparent 57%\n ),\n linear-gradient(\n -45deg,\n transparent 43%,\n var(--dsw-alias-state-error-primary, #b42318) 43%,\n var(--dsw-alias-state-error-primary, #b42318) 57%,\n transparent 57%\n );\n}\n.dm-float-tool input:hover,\n.dm-tool input:hover {\n border-color: var(--dsw-alias-state-info-primary, #3b82f6);\n}\n.dm-float-tool input:checked:hover,\n.dm-tool input:checked:hover {\n border-color: var(--dsw-alias-state-error-primary, #b42318);\n}\n.dm-float-tool input:focus-visible,\n.dm-tool input:focus-visible {\n outline: 2px solid var(--dsw-alias-state-info-primary, #3b82f6);\n outline-offset: 1px;\n}\n.dm-float-tool:has(input:checked),\n.dm-tool:has(input:checked) {\n color: var(--dsw-alias-state-error-primary, #b42318);\n}\n.dm-float-hint {\n font-size: 10.5px;\n color: var(--dsw-alias-label-tertiary, #8a919c);\n line-height: 1.5;\n padding: 4px 8px 2px;\n}\n.dm-subgroup {\n margin: 6px 0 10px;\n}\n.dm-subgroup-title {\n margin: 0 0 4px;\n font-size: 11px;\n font-weight: 600;\n color: var(--dsw-alias-label-secondary, #525866);\n line-height: 1.4;\n}\n.dm-group > h3 .dm-count {\n font-size: 11px;\n color: var(--dsw-alias-label-tertiary, #8a919c);\n font-weight: 600;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dm-float,\n .dm-float-panel,\n .dm-float-panel.dm-float-panel--open,\n .dm-float-panel.dm-float-panel--closing,\n .dm-float-panel.dm-float-panel--open .dm-float-row.dm-stagger,\n .dm-overlay,\n .dm-overlay.dm-overlay--open,\n .dm-overlay.dm-overlay--closing,\n .dm-card,\n .dm-overlay.dm-overlay--open .dm-card,\n .dm-overlay.dm-overlay--closing .dm-card,\n .dm-float-action,\n .dm-float-head button,\n .dm-head button,\n .dm-actions button,\n .dm-form-actions button,\n .dm-tab {\n animation: none !important;\n transition-duration: 1ms !important;\n }\n .dm-float-panel.dm-float-panel--open,\n .dm-overlay.dm-overlay--open .dm-card {\n transform: none;\n filter: none;\n }\n}\n';
|
|
47
|
+
var style_default = '/* dsh-mcp-manager — 客户端样式(独立 .css 文件)。\n *\n * 由 build-client 的 .css text-loader 构建期内联进 client.js(产物仍自包含单文件、\n * 零运行时依赖、无独立请求)。前缀 dm-(防与 shell / 其他插件样式冲突)。\n *\n * 浮窗视觉:Apple Liquid Glass(半透明毛玻璃 + 0.5px subtle border)。\n * 固体文字/状态色走 --dsw-alias-* + 浅色回退;玻璃底/光边双主题 rgba\n * (light ≈ white/76,dark ≈ zinc-900/74),并经 color-mix 跟随宿主主题变量。\n * 动效:Apple Fluid Curve cubic-bezier(0.16, 1, 0.3, 1)。\n * 浮窗 origin=胶囊锚点→对角 scale 0.72→1;模态 origin=中心→四周 scale 0.78→1。\n * 可点元素 Active Press Feedback;中英混排系统中文字体栈 + line-height ≥1.5。 */\n\n:root {\n --dm-fluid: cubic-bezier(0.16, 1, 0.3, 1);\n --dm-press-scale: 0.96;\n --dm-glass-blur: 28px;\n --dm-glass-saturate: 220%;\n --dm-glass-bg: rgba(255, 255, 255, 0.76);\n --dm-glass-bg-strong: rgba(255, 255, 255, 0.84);\n --dm-glass-bg-solid: var(--dsw-alias-bg-base, #fdfdfd);\n /* 主题跟随 wash:浅色用墨 8%,深色用白 12%(M1:禁止深色下写死浅色 wash) */\n --dm-wash: color-mix(in srgb, #1c1e26 8%, transparent);\n /* 卡片底:浅色白 42% 霜,深色白 7% 霜(配 zinc-900/74 玻璃底) */\n --dm-card-bg: color-mix(in srgb, #ffffff 42%, transparent);\n /* 行 hover:浅色黑 3%,深色白 7%(深色下黑 3% 近不可见) */\n --dm-row-hover: color-mix(in srgb, #000000 3%, transparent);\n --dm-glass-edge: rgba(20, 30, 50, 0.1);\n --dm-glass-rim: rgba(255, 255, 255, 0.92);\n --dm-glass-shadow:\n inset 0 0.5px 0 rgba(255, 255, 255, 0.95), inset 0 0 0 0.5px rgba(255, 255, 255, 0.45),\n 0 1px 1px rgba(20, 30, 50, 0.04), 0 6px 16px rgba(30, 45, 80, 0.08),\n 0 20px 48px rgba(30, 45, 80, 0.12);\n --dm-glass-spec: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 0.72) 0%,\n rgba(255, 255, 255, 0.22) 22%,\n rgba(255, 255, 255, 0.04) 48%,\n rgba(255, 255, 255, 0) 100%\n );\n --dm-font-ui:\n system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",\n "Noto Sans SC", sans-serif;\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n --dm-glass-bg: rgba(24, 24, 27, 0.74);\n --dm-glass-bg-strong: rgba(24, 24, 27, 0.86);\n --dm-wash: color-mix(in srgb, #ffffff 12%, transparent);\n --dm-card-bg: color-mix(in srgb, #ffffff 7%, transparent);\n --dm-row-hover: color-mix(in srgb, #ffffff 7%, transparent);\n --dm-glass-edge: rgba(255, 255, 255, 0.14);\n --dm-glass-rim: rgba(255, 255, 255, 0.12);\n --dm-glass-shadow:\n inset 0 0.5px 0 rgba(255, 255, 255, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.1),\n 0 24px 64px rgba(0, 0, 0, 0.5), 0 4px 16px rgba(0, 0, 0, 0.28);\n --dm-glass-spec: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 0.16) 0%,\n rgba(255, 255, 255, 0.03) 30%,\n rgba(255, 255, 255, 0) 100%\n );\n }\n}\nhtml.dark,\n[data-theme="dark"],\n[data-color-mode="dark"] {\n --dm-glass-bg: rgba(24, 24, 27, 0.74);\n --dm-glass-bg-strong: rgba(24, 24, 27, 0.86);\n --dm-wash: color-mix(in srgb, #ffffff 12%, transparent);\n --dm-card-bg: color-mix(in srgb, #ffffff 7%, transparent);\n --dm-row-hover: color-mix(in srgb, #ffffff 7%, transparent);\n --dm-glass-edge: rgba(255, 255, 255, 0.14);\n --dm-glass-rim: rgba(255, 255, 255, 0.12);\n --dm-glass-shadow:\n inset 0 0.5px 0 rgba(255, 255, 255, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.1),\n 0 24px 64px rgba(0, 0, 0, 0.5), 0 4px 16px rgba(0, 0, 0, 0.28);\n --dm-glass-spec: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 0.16) 0%,\n rgba(255, 255, 255, 0.03) 30%,\n rgba(255, 255, 255, 0) 100%\n );\n}\n\n@media (prefers-contrast: more) {\n :root {\n --dm-glass-bg: rgba(255, 255, 255, 0.94);\n --dm-glass-bg-strong: #ffffff;\n --dm-glass-edge: rgba(20, 30, 50, 0.22);\n /* 高对比下关闭高光 wash,wash 走纯色 */\n --dm-glass-spec: none;\n --dm-wash: #eceff3;\n --dm-card-bg: #ffffff;\n --dm-row-hover: #eef1f5;\n }\n html.dark,\n [data-theme="dark"],\n [data-color-mode="dark"] {\n --dm-glass-bg: rgba(18, 18, 20, 0.96);\n --dm-glass-bg-strong: #121214;\n --dm-glass-edge: rgba(255, 255, 255, 0.28);\n --dm-glass-spec: none;\n --dm-wash: #2a2d34;\n --dm-card-bg: #17171a;\n --dm-row-hover: #26282f;\n }\n /* 高对比下隐藏装饰性高光层,失败行保留纯色语义底 */\n .dm-glass::before {\n display: none;\n }\n .dm-float-row.dm-float-row--fail,\n .dm-server.dm-server--fail {\n background: color-mix(in srgb, #e0483e 12%, var(--dm-glass-bg-strong));\n }\n}\n\n[data-conversation-scroll] {\n position: relative;\n}\n[data-pane="conversation"] {\n position: relative;\n}\n\n/* 毛玻璃公共层 */\n.dm-glass {\n position: relative;\n color: var(--dsw-alias-label-primary, #1c1e26);\n border: 0.5px solid var(--dm-glass-edge);\n background: var(--dm-glass-bg);\n backdrop-filter: blur(var(--dm-glass-blur)) saturate(var(--dm-glass-saturate));\n -webkit-backdrop-filter: blur(var(--dm-glass-blur)) saturate(var(--dm-glass-saturate));\n box-shadow: var(--dm-glass-shadow);\n font-family: var(--dm-font-ui);\n letter-spacing: 0;\n}\n.dm-glass::before {\n content: "";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n background: var(--dm-glass-spec);\n pointer-events: none;\n}\n.dm-glass > * {\n position: relative;\n z-index: 1;\n}\n@media (prefers-reduced-transparency: reduce) {\n .dm-float,\n .dm-float-panel,\n .dm-card,\n .dm-float-action,\n .dm-float-head button,\n .dm-head button,\n .dm-actions button,\n .dm-form-actions button,\n .dm-server,\n .dm-tab[data-active] {\n background: var(--dm-glass-bg-solid, var(--dsw-alias-bg-base, #fdfdfd));\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n }\n /* 失败行保留语义底,但以纯色混合(相对实底)代替透明罩染 */\n .dm-float-row.dm-float-row--fail,\n .dm-server.dm-server--fail {\n background: color-mix(\n in srgb,\n #e0483e 8%,\n var(--dm-glass-bg-solid, var(--dsw-alias-bg-base, #fdfdfd))\n );\n }\n /* 装饰性高光层在减透明下隐藏 */\n .dm-glass::before {\n display: none;\n }\n}\n\n/* —— 胶囊(高度契约约 26–30px,供 provider-usage offsetY 避让)—— */\n.dm-float {\n position: fixed;\n pointer-events: auto;\n top: 44px;\n right: 14px;\n z-index: 10;\n display: flex;\n align-items: center;\n gap: 6px;\n /* 胶囊固定单行:会话切换瞬间容器变窄时禁止换行/收缩,避免「MCP / 0/12」折成两行 */\n white-space: nowrap;\n flex-wrap: nowrap;\n flex: none;\n width: max-content;\n padding: 5px 11px;\n border: 0.5px solid var(--dm-glass-edge);\n border-radius: 99px;\n background: var(--dm-glass-bg);\n color: var(--dsw-alias-label-primary, #1c1e26);\n font-size: 12px;\n line-height: 1.4;\n letter-spacing: 0;\n cursor: pointer;\n font-family: var(--dm-font-ui);\n backdrop-filter: blur(var(--dm-glass-blur)) saturate(var(--dm-glass-saturate));\n -webkit-backdrop-filter: blur(var(--dm-glass-blur)) saturate(var(--dm-glass-saturate));\n box-shadow:\n inset 0 0.5px 0 var(--dm-glass-rim),\n 0 2px 10px rgba(15, 18, 28, 0.08);\n transition:\n transform 160ms var(--dm-fluid),\n box-shadow 160ms var(--dm-fluid);\n transform-origin: center;\n -webkit-tap-highlight-color: transparent;\n}\n/* 触控热区(#128,WCAG 2.2 AA ≥24px;外扩至约 44px) */\n.dm-float::after {\n content: "";\n position: absolute;\n inset: -7px;\n border-radius: 99px;\n}\n.dm-float .dm-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n display: inline-block;\n flex: none;\n /* 缺省中性灰;renderPill 按健康态写 inline 色 */\n background: var(--dsw-alias-label-tertiary, #9aa1ad);\n}\n.dm-float.dm-float--fail .dm-dot {\n background: var(--dsw-alias-state-error-primary, #e0483e) !important;\n box-shadow: 0 0 0 2px color-mix(in srgb, #e0483e 22%, transparent);\n}\n.dm-float .dm-float-fail {\n display: none;\n font-size: 10px;\n font-weight: 700;\n color: var(--dsw-alias-state-error-primary, #e0483e);\n line-height: 1;\n}\n.dm-float.dm-float--fail .dm-float-fail {\n display: inline;\n}\n.dm-float:active {\n transform: scale(var(--dm-press-scale));\n transition-duration: 80ms;\n}\n.dm-float.dm-float--open {\n box-shadow:\n inset 0 0.5px 0 var(--dm-glass-rim),\n 0 0 0 1.5px color-mix(in srgb, #2f7bf6 35%, transparent),\n 0 2px 10px rgba(15, 18, 28, 0.08);\n}\n.dm-float:focus-visible {\n outline: 2px solid var(--dsw-alias-state-info-primary, #3b82f6);\n outline-offset: 2px;\n}\n\n/* —— 浮窗下拉面板:锚点(胶囊)→ 对角展开 —— */\n@keyframes dm-float-in {\n from {\n opacity: 0;\n transform: scale(0.72);\n filter: blur(10px);\n }\n to {\n opacity: 1;\n transform: scale(1);\n filter: blur(0px);\n }\n}\n@keyframes dm-float-out {\n from {\n opacity: 1;\n transform: scale(1);\n filter: blur(0px);\n }\n to {\n opacity: 0;\n transform: scale(0.78);\n filter: blur(8px);\n }\n}\n@keyframes dm-row-in {\n from {\n opacity: 0;\n transform: translateY(6px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.dm-float-panel {\n box-sizing: border-box;\n min-width: 0;\n min-height: 0;\n position: fixed;\n top: 44px;\n right: 14px;\n width: min(400px, var(--dm-float-available-width, calc(100vw - 16px)));\n max-width: var(--dm-float-available-width, calc(100vw - 16px));\n max-height: min(70vh, 560px, var(--dm-float-available-height, 100vh));\n max-height: min(70dvh, 560px, var(--dm-float-available-height, 100dvh));\n overflow: auto;\n overscroll-behavior: contain;\n color: var(--dsw-alias-label-primary, #1c1e26);\n border: 0.5px solid var(--dm-glass-edge);\n border-radius: 20px;\n background: var(--dm-glass-bg);\n z-index: 10;\n padding: 14px 14px 12px;\n font-family: var(--dm-font-ui);\n font-size: 12px;\n line-height: 1.55;\n letter-spacing: 0;\n backdrop-filter: blur(var(--dm-glass-blur)) saturate(var(--dm-glass-saturate));\n -webkit-backdrop-filter: blur(var(--dm-glass-blur)) saturate(var(--dm-glass-saturate));\n box-shadow: var(--dm-glass-shadow);\n opacity: 0;\n transform: scale(0.72);\n filter: blur(10px);\n visibility: hidden;\n pointer-events: none;\n /* 缺省 top-right 锚点;placePanel 按四角改写 inline transform-origin */\n transform-origin: top right;\n will-change: opacity, transform, filter;\n}\n.dm-float-panel.dm-float-panel--open {\n visibility: visible;\n pointer-events: auto;\n opacity: 1;\n transform: scale(1);\n filter: blur(0);\n animation: dm-float-in 480ms var(--dm-fluid) both;\n}\n.dm-float-panel.dm-float-panel--closing {\n visibility: visible;\n pointer-events: none;\n animation: dm-float-out 300ms var(--dm-fluid) both;\n}\n.dm-float-panel.dm-float-panel--open .dm-float-row.dm-stagger {\n animation: dm-row-in 320ms var(--dm-fluid) both;\n}\n.dm-float-panel[hidden] {\n display: none !important;\n}\n\n/* #128 移动端档位 */\n.dm-float-panel[data-dm-bp="narrow"] {\n width: min(400px, var(--dm-float-available-width, calc(100vw - 16px)));\n padding: 12px 10px 10px;\n border-radius: 14px;\n}\n.dm-float-panel[data-dm-bp="tablet"] {\n width: min(400px, var(--dm-float-available-width, calc(100vw - 16px)));\n}\n.dm-float-panel[data-dm-bp="narrow"] .dm-float-row {\n flex-wrap: wrap;\n row-gap: 2px;\n padding: 10px 8px;\n}\n.dm-float-panel[data-dm-bp="narrow"] .dm-float-row .dm-float-meta {\n flex-basis: 100%;\n white-space: normal;\n line-height: 1.5;\n}\n.dm-float-panel[data-dm-bp="narrow"] .dm-float-actions {\n flex: 1;\n justify-content: flex-end;\n}\n.dm-float-action {\n position: relative;\n}\n.dm-float-panel[data-dm-bp="narrow"] .dm-float-action {\n min-height: 36px;\n padding: 6px 14px;\n font-size: 12.5px;\n}\n.dm-float-panel[data-dm-bp="narrow"] .dm-float-action::before {\n content: "";\n position: absolute;\n inset: -4px;\n}\n.dm-float-panel[data-dm-bp="tablet"] .dm-float-action {\n min-height: 30px;\n padding: 4px 11px;\n}\n.dm-float-panel[data-dm-bp="narrow"] .dm-float-head button {\n min-height: 36px;\n padding: 5px 12px;\n font-size: 12.5px;\n}\n\n.dm-float-head {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n margin-bottom: 10px;\n padding: 2px 4px 0;\n}\n.dm-float-head-text {\n flex: 1;\n min-width: 0;\n}\n.dm-float-title {\n font-weight: 600;\n font-size: 13px;\n line-height: 1.4;\n letter-spacing: 0;\n color: var(--dsw-alias-label-primary, #1c1e26);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dm-float-health {\n margin-top: 3px;\n font-size: 11px;\n line-height: 1.45;\n color: var(--dsw-alias-label-secondary, #6b7280);\n font-variant-numeric: tabular-nums;\n}\n.dm-float-health .dm-health-ok {\n color: var(--dsw-alias-state-success-primary, #0f9d6e);\n}\n.dm-float-health .dm-health-bad {\n color: var(--dsw-alias-state-error-primary, #e0483e);\n font-weight: 600;\n}\n.dm-float-head button {\n flex: none;\n border: 0.5px solid var(--dm-glass-edge);\n background: color-mix(in srgb, var(--dsw-alias-bg-base, #fff) 55%, transparent);\n color: var(--dsw-alias-label-primary, #1c1e26);\n border-radius: 99px;\n min-height: 28px;\n padding: 4px 11px;\n font-size: 11px;\n line-height: 1.4;\n font-family: inherit;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n transition:\n transform 160ms var(--dm-fluid),\n background-color 160ms var(--dm-fluid),\n opacity 160ms var(--dm-fluid);\n}\n.dm-float-head button:active,\n.dm-float-action:active,\n.dm-head button:active,\n.dm-actions button:active,\n.dm-form-actions button:active,\n.dm-set-save:active {\n transform: scale(var(--dm-press-scale));\n transition-duration: 80ms;\n opacity: 0.88;\n}\n.dm-float-head button:focus-visible,\n.dm-float-action:focus-visible,\n.dm-head button:focus-visible {\n outline: 2px solid var(--dsw-alias-state-info-primary, #3b82f6);\n outline-offset: 2px;\n}\n\n.dm-float-group {\n margin: 0 0 4px;\n padding: 0;\n}\n.dm-float-group + .dm-float-group {\n margin-top: 14px;\n}\n.dm-float-group-title {\n font-size: 11px;\n line-height: 1.4;\n letter-spacing: 0.04em;\n color: var(--dsw-alias-label-secondary, #8a8f9c);\n font-weight: 600;\n margin: 0 0 6px;\n padding: 0 6px;\n}\n.dm-float-group-title.dm-float-group-title--alert {\n color: var(--dsw-alias-state-error-primary, #e0483e);\n}\n\n.dm-float-row {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 6px 8px;\n padding: 8px 8px 10px;\n border: none;\n border-radius: 14px;\n margin-bottom: 2px;\n background: transparent;\n line-height: 1.5;\n transition: background-color 160ms var(--dm-fluid);\n}\n.dm-float-row.dm-float-row--fail {\n background: color-mix(in srgb, #e0483e 6%, transparent);\n}\n.dm-float-row .dm-float-name {\n font-weight: 600;\n font-family: ui-monospace, "SF Mono", Consolas, "PingFang SC", monospace;\n font-size: 12px;\n line-height: 1.4;\n letter-spacing: 0;\n max-width: 150px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--dsw-alias-label-primary, #1c1e26);\n}\n.dm-float-row .dm-float-meta {\n flex: 1;\n min-width: 0;\n font-size: 11px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary, #8a8f9c);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n}\n.dm-float-actions {\n flex: none;\n display: flex;\n gap: 4px;\n margin-left: auto;\n flex-wrap: wrap;\n}\n.dm-float-action {\n border: 0.5px solid var(--dm-glass-edge);\n background: color-mix(in srgb, var(--dsw-alias-bg-base, #fff) 50%, transparent);\n color: var(--dsw-alias-label-primary, #1c1e26);\n border-radius: 99px;\n min-height: 28px;\n padding: 3px 10px;\n font-size: 11px;\n line-height: 1.4;\n font-family: inherit;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n transition:\n transform 160ms var(--dm-fluid),\n background-color 160ms var(--dm-fluid),\n opacity 160ms var(--dm-fluid);\n}\n.dm-float-action.dm-primary,\n.dm-actions button.dm-primary,\n.dm-form-actions button.dm-primary {\n font-weight: 600;\n border-color: color-mix(in srgb, #2f7bf6 35%, transparent);\n background: color-mix(in srgb, #2f7bf6 12%, transparent);\n color: var(--dsw-alias-state-business-primary, #2f6fe0);\n}\n.dm-float-action.dm-danger,\n.dm-actions button.dm-danger {\n color: var(--dsw-alias-state-error-primary, #b42318);\n border-color: color-mix(in srgb, #b42318 30%, transparent);\n}\n\n/* —— 模态管理面板:中心 → 四周 —— */\n@keyframes dm-modal-in {\n from {\n opacity: 0;\n transform: scale(0.78);\n filter: blur(12px);\n }\n to {\n opacity: 1;\n transform: scale(1);\n filter: blur(0px);\n }\n}\n@keyframes dm-modal-out {\n from {\n opacity: 1;\n transform: scale(1);\n filter: blur(0px);\n }\n to {\n opacity: 0;\n transform: scale(0.82);\n filter: blur(10px);\n }\n}\n@keyframes dm-overlay-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes dm-overlay-out {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n}\n.dm-overlay {\n position: fixed;\n inset: 0;\n background: var(--dsw-alias-bg-mask-2, rgba(8, 10, 16, 0.28));\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 9999;\n font-family: var(--dm-font-ui);\n opacity: 0;\n visibility: hidden;\n pointer-events: none;\n backdrop-filter: blur(8px) saturate(120%);\n -webkit-backdrop-filter: blur(8px) saturate(120%);\n}\n.dm-overlay.dm-overlay--open {\n opacity: 1;\n visibility: visible;\n pointer-events: auto;\n animation: dm-overlay-in 360ms var(--dm-fluid) both;\n}\n.dm-overlay.dm-overlay--closing {\n visibility: visible;\n pointer-events: none;\n animation: dm-overlay-out 280ms var(--dm-fluid) both;\n}\n.dm-overlay[hidden] {\n display: none !important;\n}\n.dm-card {\n width: min(860px, 94vw);\n max-height: 86vh;\n display: flex;\n flex-direction: column;\n color: var(--dsw-alias-label-primary, #1c1e26);\n border: 0.5px solid var(--dm-glass-edge);\n border-radius: 22px;\n background: var(--dm-glass-bg-strong);\n box-shadow: var(--dm-glass-shadow);\n backdrop-filter: blur(var(--dm-glass-blur)) saturate(var(--dm-glass-saturate));\n -webkit-backdrop-filter: blur(var(--dm-glass-blur)) saturate(var(--dm-glass-saturate));\n overflow: hidden;\n opacity: 0;\n transform: scale(0.78);\n filter: blur(12px);\n transform-origin: center center;\n will-change: opacity, transform, filter;\n}\n.dm-overlay.dm-overlay--open .dm-card {\n opacity: 1;\n transform: scale(1);\n filter: blur(0);\n transform-origin: center center;\n animation: dm-modal-in 520ms var(--dm-fluid) both;\n}\n.dm-overlay.dm-overlay--closing .dm-card {\n transform-origin: center center;\n animation: dm-modal-out 300ms var(--dm-fluid) both;\n}\n.dm-head {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 16px 18px 10px;\n border-bottom: none;\n background: transparent;\n}\n.dm-head h2 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 1.35;\n}\n.dm-head .dm-counts {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary, #8a8f9c);\n flex: 1;\n line-height: 1.5;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n}\n.dm-head .dm-counts .dm-health-bad {\n color: var(--dsw-alias-state-error-primary, #e0483e);\n font-weight: 600;\n}\n.dm-head button {\n border: 0.5px solid var(--dm-glass-edge);\n background: color-mix(in srgb, var(--dsw-alias-bg-base, #fff) 55%, transparent);\n color: var(--dsw-alias-label-primary, #3a3f4b);\n border-radius: 99px;\n min-height: 28px;\n padding: 4px 11px;\n font-size: 12px;\n font-family: inherit;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n transition:\n transform 160ms var(--dm-fluid),\n background-color 160ms var(--dm-fluid);\n}\n.dm-tabs {\n display: flex;\n gap: 4px;\n padding: 0 18px 8px;\n border-bottom: none;\n background: transparent;\n}\n.dm-tab {\n border: none;\n background: transparent;\n color: var(--dsw-alias-label-secondary, #6b7280);\n min-height: 34px;\n padding: 8px 14px;\n font-size: 13px;\n line-height: 1.4;\n font-family: inherit;\n cursor: pointer;\n border-radius: 99px;\n -webkit-tap-highlight-color: transparent;\n transition:\n background 160ms var(--dm-fluid),\n color 160ms var(--dm-fluid),\n transform 160ms var(--dm-fluid);\n}\n.dm-tab:active {\n transform: scale(var(--dm-press-scale));\n transition-duration: 80ms;\n}\n.dm-tab[data-active] {\n color: var(--dsw-alias-label-primary, #1c1e26);\n font-weight: 600;\n background: var(--dm-wash);\n box-shadow: 0 0 0 0.5px var(--dm-glass-edge);\n}\n.dm-body {\n padding: 4px 18px 18px;\n overflow: auto;\n min-height: 200px;\n overscroll-behavior: contain;\n}\n.dm-status {\n padding: 28px 16px;\n color: var(--dsw-alias-label-secondary, #6b7280);\n font-size: 13px;\n text-align: center;\n line-height: 1.6;\n}\n\n.dm-group {\n margin-bottom: 8px;\n}\n.dm-group > h3 {\n position: sticky;\n top: 0;\n z-index: 1;\n margin: 8px 0 6px;\n font-size: 12px;\n font-weight: 600;\n letter-spacing: 0.04em;\n color: var(--dsw-alias-label-secondary, #525866);\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 0 6px;\n line-height: 1.4;\n background: linear-gradient(\n color-mix(in srgb, var(--dsw-alias-bg-base, #fdfdfd) 88%, transparent) 70%,\n transparent\n );\n}\n.dm-group > h3.dm-group-alert {\n color: var(--dsw-alias-state-error-primary, #e0483e);\n}\n.dm-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n display: inline-block;\n}\n.dm-group > .dm-hint {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, #8a8f9c);\n margin: 0 0 8px;\n line-height: 1.5;\n}\n.dm-count {\n font-weight: 400;\n color: var(--dsw-alias-label-secondary, #8a8f9c);\n margin-left: 2px;\n font-size: 11px;\n}\n.dm-server {\n border: 0.5px solid var(--dm-glass-edge);\n border-radius: 16px;\n padding: 12px 14px;\n margin-bottom: 10px;\n background: var(--dm-card-bg);\n line-height: 1.5;\n}\n.dm-server.dm-server--fail {\n border-color: color-mix(in srgb, #e0483e 28%, var(--dm-glass-edge));\n background: color-mix(in srgb, #e0483e 5%, transparent);\n}\n.dm-server header {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n.dm-server .dm-name {\n font-weight: 600;\n font-size: 13px;\n color: var(--dsw-alias-label-primary, #111827);\n font-family: ui-monospace, Consolas, "PingFang SC", monospace;\n overflow-wrap: anywhere;\n word-break: break-word;\n line-height: 1.4;\n}\n.dm-badge {\n font-size: 10px;\n line-height: 1.3;\n padding: 1px 7px;\n border-radius: 99px;\n background: var(--dsw-alias-bg-layer-2, #f1f2f5);\n color: var(--dsw-alias-label-secondary, #525866);\n border: 1px solid var(--dsw-alias-border-l2, #e2e4ea);\n}\n.dm-badge.dm-http {\n background: var(--dsw-alias-state-business-secondary, #eef2ff);\n color: var(--dsw-alias-state-business-primary, #4353a3);\n border-color: var(--dsw-alias-state-business-tertiary, #dde3f8);\n}\n.dm-badge.dm-stdio {\n background: var(--dsw-alias-bg-layer-2, #f5f0ff);\n color: var(--dsw-alias-label-secondary, #6d4bb8);\n border-color: var(--dsw-alias-border-l2, #e6dcf8);\n}\n.dm-badge.dm-st-connected {\n /* 绿底白字:运行中是唯一「正向强状态」,用实底与未连接/失败的中性、红底拉开层级 */\n background: #10b981;\n color: #ffffff;\n border-color: #10b981;\n font-weight: 600;\n}\n.dm-badge.dm-st-connecting,\n.dm-badge.dm-st-reconnecting {\n background: var(--dsw-alias-state-business-secondary, #eff6ff);\n color: var(--dsw-alias-state-business-primary, #1d66b8);\n border-color: var(--dsw-alias-state-business-tertiary, #d3e5fb);\n}\n.dm-badge.dm-st-failed {\n /* 红底白字:失败与运行中同为强状态,实底保证可读性 */\n background: #dc2626;\n color: #ffffff;\n border-color: #dc2626;\n font-weight: 600;\n}\n.dm-badge.dm-st-disabled,\n.dm-badge.dm-st-stopped {\n background: var(--dsw-alias-bg-layer-2, #f1f2f5);\n color: var(--dsw-alias-label-secondary, #6b7280);\n border-color: var(--dsw-alias-border-l2, #e2e4ea);\n}\n.dm-server .dm-endpoint {\n margin: 6px 0 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, #8a8f9c);\n font-family: ui-monospace, Consolas, "PingFang SC", monospace;\n word-break: break-all;\n line-height: 1.5;\n}\n.dm-server .dm-err {\n margin: 6px 0 0;\n font-size: 11px;\n color: var(--dsw-alias-state-error-primary, #b42318);\n line-height: 1.5;\n}\n.dm-server .dm-tools {\n margin: 8px 0 0;\n}\n.dm-server .dm-tools summary {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, #525866);\n cursor: pointer;\n user-select: none;\n line-height: 1.5;\n}\n.dm-server .dm-tools ul {\n margin: 4px 0 0;\n padding-left: 16px;\n font-size: 11px;\n color: var(--dsw-alias-label-primary, #3a3f4b);\n font-family: ui-monospace, Consolas, "PingFang SC", monospace;\n line-height: 1.55;\n}\n.dm-actions {\n display: flex;\n gap: 6px;\n margin-top: 10px;\n flex-wrap: wrap;\n}\n.dm-actions button {\n border: 0.5px solid var(--dm-glass-edge);\n background: color-mix(in srgb, var(--dsw-alias-bg-base, #fff) 55%, transparent);\n color: var(--dsw-alias-label-primary, #3a3f4b);\n border-radius: 99px;\n min-height: 28px;\n padding: 3px 10px;\n font-size: 11px;\n font-family: inherit;\n line-height: 1.4;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n transition:\n transform 160ms var(--dm-fluid),\n background-color 160ms var(--dm-fluid);\n}\n.dm-actions button.dm-danger {\n color: var(--dsw-alias-state-error-primary, #b42318);\n border-color: var(--dsw-alias-state-error-tertiary, #f0c4c1);\n}\n.dm-actions button.dm-primary {\n color: var(--dsw-alias-state-business-primary, #1d4ed8);\n border-color: var(--dsw-alias-state-business-tertiary, #bcd1fb);\n background: var(--dsw-alias-state-business-secondary, #f5f8ff);\n font-weight: 600;\n}\n.dm-actions button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.dm-section {\n margin-bottom: 18px;\n}\n.dm-section > h3 {\n margin: 0 0 8px;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, #2f3542);\n line-height: 1.4;\n}\n.dm-form {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px 12px;\n max-width: 640px;\n}\n.dm-form .dm-full {\n grid-column: 1/-1;\n}\n.dm-field {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.dm-field label {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, #525866);\n font-weight: 600;\n line-height: 1.4;\n}\n.dm-field input,\n.dm-field select,\n.dm-field textarea {\n border: 0.5px solid var(--dm-glass-edge);\n border-radius: 10px;\n padding: 8px 10px;\n min-height: 36px;\n font-size: 12px;\n color: var(--dsw-alias-label-primary, #1c1e26);\n background: color-mix(in srgb, #ffffff 55%, transparent);\n font-family: ui-monospace, Consolas, "PingFang SC", monospace;\n line-height: 1.45;\n}\n.dm-field textarea {\n min-height: 64px;\n resize: vertical;\n line-height: 1.55;\n}\n.dm-field input[type="checkbox"] {\n width: auto;\n min-height: 0;\n}\n.dm-check {\n flex-direction: row;\n align-items: center;\n gap: 8px;\n}\n.dm-check label {\n margin: 0;\n}\n.dm-form-actions {\n grid-column: 1/-1;\n display: flex;\n gap: 8px;\n}\n.dm-form-actions button {\n border: 0.5px solid var(--dm-glass-edge);\n background: color-mix(in srgb, var(--dsw-alias-bg-base, #fff) 55%, transparent);\n color: var(--dsw-alias-label-primary, #3a3f4b);\n border-radius: 99px;\n min-height: 32px;\n padding: 6px 14px;\n font-size: 12px;\n font-family: inherit;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n transition:\n transform 160ms var(--dm-fluid),\n background-color 160ms var(--dm-fluid);\n}\n.dm-form-actions button.dm-primary {\n background: var(--dsw-alias-button-primary-fill, #4f6ef7);\n color: var(--dsw-alias-label-primary-foreground, #fff);\n border-color: var(--dsw-alias-button-primary-fill, #4f6ef7);\n font-weight: 600;\n}\n.dm-hint {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, #8a8f9c);\n line-height: 1.5;\n}\n.dm-paste-box {\n border: 0.5px solid var(--dm-glass-edge);\n border-radius: 16px;\n padding: 12px;\n background: color-mix(in srgb, #ffffff 40%, transparent);\n max-width: 640px;\n}\n.dm-result {\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary, #0f7a50);\n margin-top: 8px;\n line-height: 1.6;\n}\n.dm-result .dm-skip {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n}\n\n/* 设置页插件卡(settings.plugin.item)——视觉锚点测试 #219 不变 */\n.dm-set-card {\n list-style: none;\n margin: 0;\n padding: 0;\n border: 1px solid var(--dsw-alias-border-l2, #e2e5ea);\n border-radius: 12px;\n background: var(--dsw-alias-bg-layer-3, #fbfbfc);\n overflow: hidden;\n transition:\n border-color 0.16s,\n background 0.16s;\n}\n.dm-set-head {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 14px 16px;\n background: transparent;\n border: none;\n cursor: pointer;\n text-align: left;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n.dm-set-headText {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n min-width: 0;\n}\n.dm-set-name {\n display: block;\n font-size: 15px;\n font-weight: 600;\n line-height: 1.4;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n.dm-set-description {\n display: block;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary, #8a919c);\n}\n.dm-set-chevron {\n flex: none;\n color: var(--dsw-alias-label-tertiary, #5f6672);\n transition: transform 0.16s ease;\n}\n.dm-set-chevronOpen {\n transform: rotate(180deg);\n}\n.dm-set-body {\n padding: 4px 14px 14px;\n border-top: 1px solid var(--dsw-alias-border-l1, #e2e5ea);\n display: flex;\n flex-direction: column;\n gap: 9px;\n}\n.dm-set-row {\n display: flex;\n align-items: center;\n gap: 12px;\n margin: 0;\n flex-wrap: wrap;\n}\n.dm-set-row > label {\n font-size: 12.5px;\n color: var(--dsw-alias-label-secondary, #5f6672);\n font-weight: 600;\n white-space: nowrap;\n}\n.dm-set-field {\n display: inline-flex;\n flex-direction: column;\n gap: 3px;\n font-size: 11.5px;\n color: var(--dsw-alias-label-secondary, #5f6672);\n font-weight: 600;\n}\n.dm-set-input {\n min-width: 88px;\n padding: 5px 8px;\n border: 1px solid var(--dsw-alias-border-l1, #e2e5ea);\n border-radius: 6px;\n font-size: 12.5px;\n color: var(--dsw-alias-label-primary, #1f2329);\n background: var(--dsw-alias-bg-layer-1, #fff);\n box-sizing: border-box;\n}\n.dm-set-input:focus {\n outline: none;\n border-color: var(--dsw-alias-state-info-primary, #3b82f6);\n}\n.dm-set-hint {\n margin-top: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-tertiary, #8a919c);\n line-height: 1.5;\n}\n.dm-set-foot {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 10px;\n margin-top: 10px;\n}\n.dm-set-foot .dm-set-saved {\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary, #16a34a);\n}\n.dm-set-foot .dm-set-error {\n font-size: 12px;\n color: var(--dsw-alias-state-danger-primary, #dc2626);\n}\n.dm-set-save {\n border: 1px solid var(--dsw-alias-border-l1, #e2e5ea);\n background: var(--dsw-alias-bg-base, #fff);\n color: var(--dsw-alias-label-primary, #3a3f4b);\n border-radius: 6px;\n padding: 5px 14px;\n font-size: 12px;\n cursor: pointer;\n transition:\n transform 160ms var(--dm-fluid),\n background-color 160ms var(--dm-fluid);\n}\n.dm-set-save:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* #128 悬停态统一包裹 @media(hover:hover) */\n@media (hover: hover) {\n .dm-float:hover {\n background: color-mix(in srgb, var(--dsw-alias-interactive-bg-hover, #f2f4f8) 70%, transparent);\n }\n .dm-float-head button:hover {\n background: var(--dsw-alias-interactive-bg-hover, #eef1f5);\n }\n .dm-float-action:hover {\n background: var(--dsw-alias-interactive-bg-hover, #eef1f5);\n }\n .dm-float-row:hover {\n background: var(--dm-row-hover);\n }\n .dm-head button:hover {\n background: var(--dsw-alias-interactive-bg-hover, #eef1f5);\n }\n .dm-actions button:hover {\n background: var(--dsw-alias-interactive-bg-hover, #eef1f5);\n }\n .dm-form-actions button:hover {\n background: var(--dsw-alias-interactive-bg-hover, #eef1f5);\n }\n .dm-set-card:hover {\n border-color: var(--dsw-alias-label-dimmed, #9ba1a6);\n }\n .dm-set-head:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, 0.04));\n }\n .dm-set-save:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, 0.06));\n }\n}\n\n/* #362 工具级禁用 checkbox(#401 勾选=禁用,红色 ×) */\n.dm-float-tools {\n margin: 4px 0 0 16px;\n width: 100%;\n}\n.dm-float-tools summary {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, #525866);\n cursor: pointer;\n user-select: none;\n line-height: 1.5;\n}\n.dm-float-tool-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin: 4px 0 0;\n max-height: 140px;\n overflow: auto;\n}\n.dm-float-tool,\n.dm-tool {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: var(--dsw-alias-label-primary, #3a3f4b);\n font-family: ui-monospace, Consolas, monospace;\n cursor: pointer;\n line-height: 1.6;\n overflow-wrap: anywhere;\n word-break: break-word;\n min-width: 0;\n max-width: 100%;\n}\n.dm-float-tool input,\n.dm-tool input {\n width: 13px;\n height: 13px;\n margin: 0;\n flex: none;\n appearance: none;\n -webkit-appearance: none;\n border: 1px solid var(--dsw-alias-border-l2, #c3c8d2);\n border-radius: 3px;\n background: var(--dsw-alias-bg-base, #fff);\n cursor: pointer;\n position: relative;\n box-sizing: border-box;\n}\n.dm-float-tool input:checked,\n.dm-tool input:checked {\n border-color: var(--dsw-alias-state-error-primary, #b42318);\n background: var(--dsw-alias-state-error-secondary, #fef2f2);\n}\n.dm-float-tool input:checked::after,\n.dm-tool input:checked::after {\n content: "";\n position: absolute;\n left: 50%;\n top: 50%;\n width: 8px;\n height: 8px;\n transform: translate(-50%, -50%);\n background:\n linear-gradient(\n 45deg,\n transparent 43%,\n var(--dsw-alias-state-error-primary, #b42318) 43%,\n var(--dsw-alias-state-error-primary, #b42318) 57%,\n transparent 57%\n ),\n linear-gradient(\n -45deg,\n transparent 43%,\n var(--dsw-alias-state-error-primary, #b42318) 43%,\n var(--dsw-alias-state-error-primary, #b42318) 57%,\n transparent 57%\n );\n}\n.dm-float-tool input:hover,\n.dm-tool input:hover {\n border-color: var(--dsw-alias-state-info-primary, #3b82f6);\n}\n.dm-float-tool input:checked:hover,\n.dm-tool input:checked:hover {\n border-color: var(--dsw-alias-state-error-primary, #b42318);\n}\n.dm-float-tool input:focus-visible,\n.dm-tool input:focus-visible {\n outline: 2px solid var(--dsw-alias-state-info-primary, #3b82f6);\n outline-offset: 1px;\n}\n.dm-float-tool:has(input:checked),\n.dm-tool:has(input:checked) {\n color: var(--dsw-alias-state-error-primary, #b42318);\n}\n.dm-float-hint {\n font-size: 10.5px;\n color: var(--dsw-alias-label-tertiary, #8a919c);\n line-height: 1.5;\n padding: 4px 8px 2px;\n}\n.dm-subgroup {\n margin: 6px 0 10px;\n}\n.dm-subgroup-title {\n margin: 0 0 4px;\n font-size: 11px;\n font-weight: 600;\n color: var(--dsw-alias-label-secondary, #525866);\n line-height: 1.4;\n}\n.dm-group > h3 .dm-count {\n font-size: 11px;\n color: var(--dsw-alias-label-tertiary, #8a919c);\n font-weight: 600;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dm-float,\n .dm-float-panel,\n .dm-float-panel.dm-float-panel--open,\n .dm-float-panel.dm-float-panel--closing,\n .dm-float-panel.dm-float-panel--open .dm-float-row.dm-stagger,\n .dm-overlay,\n .dm-overlay.dm-overlay--open,\n .dm-overlay.dm-overlay--closing,\n .dm-card,\n .dm-overlay.dm-overlay--open .dm-card,\n .dm-overlay.dm-overlay--closing .dm-card,\n .dm-float-action,\n .dm-float-head button,\n .dm-head button,\n .dm-actions button,\n .dm-form-actions button,\n .dm-tab {\n animation: none !important;\n transition-duration: 1ms !important;\n }\n .dm-float-panel.dm-float-panel--open,\n .dm-overlay.dm-overlay--open .dm-card {\n transform: none;\n filter: none;\n }\n}\n\n/* ── 启用开关(dm-switch):弹窗卡片与浮层行共用的「启用/停用」滑块 ── */\n/* 对齐官方 ui-primitives/Switch:36×20 轨道、16px 圆点、主题色及 120ms 动效。\n 显式使用 round,避免宿主全局 superellipse 将轨道和圆点变成方圆形。\n 保留强规则,防止浮层/表单的通用 label、span 样式覆盖开关。 */\n.dm-switch {\n box-sizing: border-box !important;\n position: relative !important;\n display: inline-block !important;\n width: 36px !important;\n height: 20px !important;\n min-width: 36px !important;\n max-width: 36px !important;\n min-height: 20px !important;\n max-height: 20px !important;\n padding: 0 !important;\n margin: 0 !important;\n border: none !important;\n border-radius: 999px !important;\n corner-shape: round !important;\n background: var(--dsw-alias-border-l3, rgb(0 0 0 / 0.12)) !important;\n box-shadow: none !important;\n cursor: pointer;\n flex: 0 0 auto !important;\n line-height: normal !important;\n font-size: 0 !important;\n}\n.dm-switch input[type="checkbox"] {\n position: absolute !important;\n opacity: 0 !important;\n width: 1px !important;\n height: 1px !important;\n margin: 0 !important;\n padding: 0 !important;\n pointer-events: none !important;\n}\n.dm-switch .dm-switch-slider {\n box-sizing: border-box !important;\n position: absolute !important;\n top: 2px !important;\n left: 2px !important;\n display: block !important;\n width: 16px !important;\n height: 16px !important;\n min-width: 16px !important;\n min-height: 16px !important;\n max-width: 16px !important;\n max-height: 16px !important;\n padding: 0 !important;\n margin: 0 !important;\n border: none !important;\n border-radius: 50% !important;\n corner-shape: round !important;\n background: var(--dsw-alias-label-primary-foreground, #ffffff) !important;\n box-shadow: none !important;\n transform: translateX(0) !important;\n transition: transform 120ms ease !important;\n}\n.dm-switch input[type="checkbox"]:checked + .dm-switch-slider {\n transform: translateX(16px) !important;\n}\n.dm-switch input[type="checkbox"]:not(:checked) + .dm-switch-slider {\n background: var(--dsw-alias-switch-thumb, #ffffff) !important;\n}\n.dm-switch:has(input[type="checkbox"]:checked) {\n background: var(--dsw-alias-brand-primary, #111827) !important;\n}\n.dm-switch--busy {\n opacity: 0.5 !important;\n pointer-events: none !important;\n}\n.dm-switch:has(input:focus-visible) {\n outline: var(--dsw-focus-ring-width, 2px) solid\n var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary, #2f6fe0)) !important;\n outline-offset: 2px !important;\n}\n\n/* 胶囊计数小圆点(绿=连通 / 红=失败) */\n.dm-pill-dot {\n display: inline-block;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n flex: none;\n}\n';
|
|
48
48
|
|
|
49
49
|
// src/vendor/shared/client/ui/ui.css
|
|
50
50
|
var ui_default = '/* ================= T1 五原语层(dsu-*)唯一副本 =================\n * 职责:Surface / Field / SegmentedControl / Status+Badge 的唯一表现面。\n * Button 的视觉本体由**调用点自带的领域类**承担(见块尾说明),本块不出 dsu-btn 规则。\n *\n * 【怎么进到浏览器:ts 侧拼接,不是 @import】\n * 各包 src/client/index.ts 两行接缝:\n * import UI_CSS from "<到仓库根的相对路径>/shared/client/ui/ui.css";\n * ensureStyle({ id: STYLE_ID, cssText: UI_CSS + STYLE, version: CSS_VERSION });\n * **顺序不可颠倒**:原语层在前(当底座),各包 style.css 在后,这样包内针对原语钩子的\n * 窄屏/领域覆盖(同优先级靠后者胜)才压得住——provider-usage 的 @media 480px 段正是\n * 靠这条把 .dsu-badge 的 max-width 放宽到 100%、.dsu-surface-pane 的 padding 收到 10px。\n * 写成 STYLE + UI_CSS 时这两条覆盖会变死规则,build 仍 exit 0、窄屏却悄悄变回原样。\n * build-client 的 .css text-loader(scripts/build/build-client.ts)把本文件当**纯文本**\n * 内联进各包 client.js,产物仍自包含单文件、零运行时依赖、无独立请求。\n *\n * 【为什么不是 @import:R3 实测证伪,勿再提】\n * 试过在各包 style.css 顶部写 @import 指向本文件:text-loader 不解析 CSS,@import 会\n * 原样留在产物字符串里(实测 `grep -c \'@import\' lib/client.js` → 1),而探针规则\n * `grep -c \'dsu-probe\' lib/client.js` → 0;浏览器随后按**页面相对 URL** 去请求那个\n * 路径 → 404 → 规则静默消失,**而 build 仍 exit 0、测试仍全绿**。这是最坏的失败模式。\n *\n * 【与「各包 style.css 单文件」约定的关系】\n * DEVELOPMENT §3 要求样式不写进 ts、留在各包 style.css。本文件不违反它:本文件**不含\n * 任何包的领域样式**,只是跨包共享的那一段原语规则的单一事实源,由 ts 侧拼接注入;\n * 各包 style.css 仍是该包领域样式的唯一位置。\n *\n * 纪律:颜色全走 --dsw-alias-* + 浅色回退(禁裸 hex);悬停一律 @media (hover: hover)\n * 包裹(#128 规格第 7 条),断点机制全仓只有这一套;禁 role="navigation"(语义层在\n * shared/client/ui/index.tsx 冻结,本块只管表现,结构不冻结)。\n * 消费包不必逐档消费:未消费的档位在本包是死规则,属有意接受的冗余——宁可一段没人用的\n * 规则,也不要给原语层开出「按包裁剪规则块」这条会立刻分叉的机制。\n */\n.dsu-surface-pane {\n margin-bottom: 16px;\n padding: 12px;\n border: 1px solid var(--dsw-alias-border-l1, #e2e5ea);\n border-radius: 10px;\n background: var(--dsw-alias-bg-base, #ffffff);\n font-size: 12px;\n line-height: 1.7;\n}\n/* 极窄容器降级(#1015 A+C 的 C-3 配套):宿主设置弹窗在 375px 下不折叠左侧导航,\n 内容列被压到约 139px,再经 pane padding 12px×2 层层扣减后趋势区只剩 56px——\n 实测装 dsh-web-mobile@3.0.3 亦然(nav 仍 flex:0 0 auto 固定 188px),故根因在宿主\n 布局、插件侧无法获得更多宽度。此处能做的唯一有效动作是**把容器自身的 padding 让给内容**:\n 收掉 padding 后可用宽度翻倍(56px → 104px 量级),标题/控件不再逐词竖排。\n 断点判据用 trend.tsx 已有的 data-dou-col(由 ResizeObserver 量**本窗格实测宽**写入),\n 不用视口断点也不依赖 container-type:宿主把内容列压到多窄与视口宽度无关,\n 桌面窄窗同样会命中,这是刻意的。 */\n.dou-trend-body[data-dou-col="s"] .dsu-surface-pane {\n padding: 6px 4px;\n border-radius: 8px;\n}\n/* 极窄档再让出设置区外壳的 padding:实测宿主 375px 下 content 仅 139px,经 set-body\n padding 14 与 pane padding 各扣一轮后,内容实得 34px——不足一行中文。窄档下这些\n padding 是纯损失(外壳描边已提供视觉边界),一并收掉。 */\n/* set-body 是所有设置区窗格共用的外壳,:has() 把作用域限死在「含窄档趋势窗格」的那一个,\n 不影响 usage/report/history/providers 等其他窗格(宿主与本仓均已在用 :has())。 */\n.dou-set-body:has(.dou-trend-body[data-dou-col="s"]) {\n padding: 4px 2px;\n}\n.dsu-surface-card {\n /* 壳宽 560px 是外壳卡独有的约束(原 settings/index.tsx 内联 maxWidth,行为不变收敛进样式表) */\n max-width: 560px;\n border: 1px solid var(--dsw-alias-border-l1, #e2e5ea);\n border-radius: 12px;\n overflow: hidden;\n background: var(--dsw-alias-bg-base, #ffffff);\n box-shadow: 0 1px 3px rgba(15, 23, 42, 0.05);\n}\n\n/* ---- Field:标签 + 控件 ----\n 行内字段 nowrap 横排,换行能力由 .dsu-field-row 的 flex-wrap 承担\n (约 350px 内容宽度下 nowrap 横排必然溢出,四个数字输入行必须能折行)。 */\n.dsu-field {\n margin-right: 12px;\n white-space: nowrap;\n}\n.dsu-field-block {\n /* 标签在上、控件在下:与 .dsu-field(行内标签)并存会让同一行里出现两种排版结构,\n 跨字段换行时左边缘对不齐。此处统一为竖排,行内字段若需保持原样走 .dsu-field。 */\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n margin-bottom: 8px;\n}\n/* 标签文本是 <label> 内的裸文本节点(隐式关联 select),不是子元素——\n 故只能用 font/ ::first-line 类手段无法精确命中。改为给 label 本身定排版,\n 并让 select 独占一行:裸文本节点会生成匿名 flex item,与 select 同行。\n 这里把 label 设为 flex column,裸文本成为它的匿名 item,select 成为第二个。 */\n.dsu-field-block > select {\n margin-top: 4px;\n align-self: flex-start;\n}\n.dsu-field-block {\n font-size: 11px;\n color: var(--dsw-alias-label-tertiary, #6d7480);\n}\n.dsu-field-block > select {\n font-size: 12px;\n color: var(--dsw-alias-label-primary, #1f2329);\n}\n.dsu-field-row {\n display: flex;\n flex-wrap: wrap;\n row-gap: 6px;\n margin-bottom: 8px;\n}\n.dsu-input {\n margin-left: 6px;\n padding: 2px 6px;\n border: 1px solid var(--dsw-alias-border-l2, #e8eaf0);\n border-radius: 4px;\n}\n.dsu-input-number {\n width: 64px;\n}\n\n/* ---- SegmentedControl:bar=顶部导航条 / pill=行内药丸组 / plain=朴素按钮组 ----\n * 窄屏:bar 靠 overflow-x + nowrap 横滑(与收敛前一致),pill/plain 靠 flex-wrap 折行。\n * 激活项由 [data-dsu-seg-active] 定位而非类名,换实现不会打坏「激活档滚进视野」。 */\n.dsu-seg {\n display: flex;\n}\n.dsu-seg-bar {\n gap: 4px;\n padding: 10px 14px;\n border-bottom: 1px solid var(--dsw-alias-border-l1, #e2e5ea);\n background: var(--dsw-alias-bg-layer-1, #f5f6f8);\n overflow-x: auto;\n white-space: nowrap;\n scrollbar-width: none;\n}\n.dsu-seg-bar::-webkit-scrollbar {\n display: none;\n}\n.dsu-seg-bar .dsu-seg-item {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-height: 32px;\n padding: 5px 14px;\n flex: none;\n white-space: nowrap;\n border: 1px solid transparent;\n border-radius: 8px;\n background: transparent;\n color: var(--dsw-alias-label-secondary, #5f6672);\n font-size: 12px;\n cursor: pointer;\n font-family: inherit;\n}\n.dsu-seg-bar .dsu-seg-item[data-dsu-seg-active="true"] {\n background: var(--dsw-alias-bg-base, #ffffff);\n border-color: var(--dsw-alias-border-l1, #e2e5ea);\n color: var(--dsw-alias-label-primary, #1f2329);\n font-weight: 600;\n box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08);\n}\n.dsu-seg-bar .dsu-seg-item:focus-visible {\n outline: 2px solid var(--dsw-alias-state-info-primary, #4a7dd6);\n outline-offset: 2px;\n}\n@media (hover: hover) {\n .dsu-seg-bar .dsu-seg-item:hover {\n color: var(--dsw-alias-label-primary, #1f2329);\n }\n}\n.dsu-seg-pill {\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n margin-bottom: 10px;\n}\n.dsu-seg-pill .dsu-seg-item {\n border: 1px solid var(--dsw-alias-border-l1, #e2e5ea);\n background: var(--dsw-alias-bg-layer-1, #f5f6f8);\n color: var(--dsw-alias-label-tertiary, #6d7480);\n border-radius: 999px;\n padding: 3px 12px;\n min-height: 28px;\n font-size: 11px;\n cursor: pointer;\n font-family: inherit;\n}\n.dsu-seg-pill .dsu-seg-item[data-dsu-seg-active="true"] {\n background: var(--dsw-alias-state-info-soft, rgba(47, 111, 237, 0.1));\n border-color: var(--dsw-alias-state-info-primary, #4a7dd6);\n color: var(--dsw-alias-state-info-primary, #4a7dd6);\n font-weight: 600;\n}\n.dsu-seg-plain {\n gap: 6px;\n flex-wrap: wrap;\n /* 档内项距 6px、档与档之间靠外层 .dou-trend-controls 的 row-gap 拉开——\n 两级间距必须分层:项距 6 太挤会让「日/周/月」和「7d/30d/90d」读成一串。 */\n margin-bottom: 6px;\n}\n/* 段内项的视觉分组:给「粒度/范围」这类**同类单选**加一个共同的浅底槽,\n 与「口径/指标」这类**独立选择器**在形状上分开——此前四组控件全是同样的\n 透明圆角按钮平铺,视觉上分不出哪几个是一组。槽只描边不填色,\n 保持与设置页底色同调、不与已选态的 brand 底色抢注意力。 */\n.dsu-seg-plain > .dsu-seg-item {\n border: 1px solid var(--dsw-alias-border-l3, #d7dae0);\n background: var(--dsw-alias-bg-layer-1, #f5f6f8);\n color: var(--dsw-alias-label-secondary, #5f6672);\n padding: 3px 12px;\n border-radius: 6px;\n font-size: 12.5px;\n min-height: 26px;\n}\n.dsu-seg-plain > .dsu-seg-item:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, 0.04));\n}\n.dsu-seg-plain > .dsu-seg-item[data-dsu-seg-active="true"] {\n background: var(--dsw-alias-bg-base, #ffffff);\n color: var(--dsw-alias-label-primary, #1f2329);\n font-weight: 600;\n border-color: var(--dsw-alias-border-l3, #d7dae0);\n box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);\n}\n/* plain 档的项**不出规则**:视觉与触控热区由消费包自己的按钮类承担——\n 本包调用点传 itemClassName="dou-btn",命中 #128 触控热区\n (.dou-panel[data-dou-bp="narrow"] .dou-btn::before 外扩)与既有按钮规则。 */\n\n/* ---- Status:状态点(无 label 时为装饰点,语义由 aria-hidden 承担)---- */\n.dsu-status {\n display: inline-block;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n margin-right: 6px;\n vertical-align: middle;\n flex: none;\n}\n.dsu-status[data-dsu-tone="ok"] {\n background: var(--dsw-alias-state-success-primary, #0f9d6e);\n}\n.dsu-status[data-dsu-tone="warn"] {\n background: var(--dsw-alias-state-warn-primary, #c9820b);\n}\n.dsu-status[data-dsu-tone="err"] {\n background: var(--dsw-alias-state-error-primary, #d64545);\n}\n.dsu-status[data-dsu-tone="off"],\n.dsu-status[data-dsu-tone="neutral"] {\n background: var(--dsw-alias-label-tertiary, #9aa0ab);\n}\n\n/* ---- Badge:状态徽标 ----\n * 色与边由两个自定义属性承载,尺寸档与色调档各改其一,避免 tone×size 组合爆炸。\n * 规则顺序即优先级:size(定中性底)→ tone(定色)→ muted(定弱化,末位覆盖 tone)。\n * sm 档承载 provider 身份药丸(含窄屏 100% 让位,由既有 480px 段改写本选择器)。 */\n.dsu-badge {\n --dsu-badge-fg: inherit;\n --dsu-badge-bd: var(--dsw-alias-border-l1, #d7dae0);\n flex: none;\n line-height: 1.5;\n color: var(--dsu-badge-fg);\n border: 1px solid var(--dsu-badge-bd);\n}\n.dsu-badge[data-dsu-size="sm"] {\n max-width: 55%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 11px;\n padding: 0 8px;\n border-radius: 99px;\n background: var(--dsw-alias-bg-layer-1, #f8f9fb);\n}\n.dsu-badge[data-dsu-size="xs"] {\n --dsu-badge-bd: transparent;\n font-size: 10px;\n padding: 1px 6px;\n border-radius: 8px;\n background: transparent;\n}\n.dsu-badge[data-dsu-tone="ok"] {\n --dsu-badge-fg: var(--dsw-alias-state-success-primary, #3f9d63);\n --dsu-badge-bd: var(--dsw-alias-state-success-primary, #3f9d63);\n}\n.dsu-badge[data-dsu-tone="warn"] {\n --dsu-badge-fg: var(--dsw-alias-state-warn-primary, #c9820b);\n --dsu-badge-bd: var(--dsw-alias-state-warn-primary, #c9820b);\n}\n.dsu-badge[data-dsu-tone="err"] {\n --dsu-badge-fg: var(--dsw-alias-state-error-primary, #d64545);\n --dsu-badge-bd: var(--dsw-alias-state-error-primary, #d64545);\n}\n.dsu-badge[data-dsu-tone="off"] {\n --dsu-badge-fg: var(--dsw-alias-label-tertiary, #9aa0ab);\n}\n.dsu-badge[data-dsu-muted="true"] {\n --dsu-badge-fg: var(--dsw-alias-label-tertiary, #9aa0ab);\n border-style: dashed;\n}\n\n/* ---- Button:本块不出规则 ----\n Button 原语只出 dsu-btn 钩子与恒定的 type="button" 语义;视觉与触控热区由**调用点\n 传入的领域类**承担(provider-usage 传 .dou-btn、lan-proxy 传 .lp-set-save……)。\n R1 时 Button 曾硬编码 .dou-btn,但原语层上提到档 C 后,那条类名就成了「provider-usage\n 的领域契约写在跨包层里」——别的包挂上去只会得到一条永远命不中的死类。#128 触控目标\n 契约又是按**类名**选中的(.dou-panel[data-dou-bp="narrow"] .dou-btn::before 的\n inset:-4px 把 narrow 档的 min-height:36px 外扩到约 44px 命中区),所以各包的按钮类\n 必须仍挂在按钮元素上;在这里重复一份 dsu-btn 规则只会制造第二事实源。 */\n';
|
|
@@ -266,7 +266,7 @@ window.__ModuleLoader__.load({
|
|
|
266
266
|
return `@${root}/${server.name}`;
|
|
267
267
|
}
|
|
268
268
|
function cwdQueryOf(state) {
|
|
269
|
-
return typeof state.currentCwd === "string" && state.currentCwd !== "" ? `&cwd=${encodeURIComponent(state.currentCwd)}` : "";
|
|
269
|
+
return typeof state.currentCwd === "string" && state.currentCwd !== "" ? `&cwd=${encodeURIComponent(state.currentCwd)}` : state.sessionResolved ? "&cwd=" : "";
|
|
270
270
|
}
|
|
271
271
|
function resumeBodyOf(state) {
|
|
272
272
|
if (!state.sessionResolved) return void 0;
|
|
@@ -435,19 +435,6 @@ window.__ModuleLoader__.load({
|
|
|
435
435
|
details.appendChild(list);
|
|
436
436
|
return details;
|
|
437
437
|
}
|
|
438
|
-
function jsonPatchInit(enabled) {
|
|
439
|
-
return {
|
|
440
|
-
method: "PATCH",
|
|
441
|
-
headers: { "content-type": "application/json" },
|
|
442
|
-
body: JSON.stringify({ enabled })
|
|
443
|
-
};
|
|
444
|
-
}
|
|
445
|
-
function postThenRefresh(state, actions, url) {
|
|
446
|
-
return async () => {
|
|
447
|
-
await api(url, { method: "POST" });
|
|
448
|
-
await actions.refresh();
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
438
|
function activateSourceRun(server, state, actions) {
|
|
452
439
|
return async () => {
|
|
453
440
|
const q = cwdQueryOf(state).replace(/^&/, "");
|
|
@@ -459,81 +446,6 @@ window.__ModuleLoader__.load({
|
|
|
459
446
|
await actions.refresh();
|
|
460
447
|
};
|
|
461
448
|
}
|
|
462
|
-
function statusActions(server, state, actions, scopeQuery, cwdQuery) {
|
|
463
|
-
const name = encodeURIComponent(server.name);
|
|
464
|
-
if (server.shadowedBy !== void 0) {
|
|
465
|
-
return [
|
|
466
|
-
{
|
|
467
|
-
label: t("connect"),
|
|
468
|
-
primary: true,
|
|
469
|
-
run: activateSourceRun(server, state, actions)
|
|
470
|
-
}
|
|
471
|
-
];
|
|
472
|
-
}
|
|
473
|
-
if (server.status === "connected") {
|
|
474
|
-
return [
|
|
475
|
-
{
|
|
476
|
-
label: t("disconnect"),
|
|
477
|
-
primary: false,
|
|
478
|
-
run: postThenRefresh(
|
|
479
|
-
state,
|
|
480
|
-
actions,
|
|
481
|
-
`${state.API.disconnect}?name=${name}${scopeQuery}${cwdQuery}`
|
|
482
|
-
)
|
|
483
|
-
},
|
|
484
|
-
{
|
|
485
|
-
label: t("reconnect"),
|
|
486
|
-
primary: false,
|
|
487
|
-
run: postThenRefresh(
|
|
488
|
-
state,
|
|
489
|
-
actions,
|
|
490
|
-
`${state.API.reconnect}?name=${name}${scopeQuery}${cwdQuery}`
|
|
491
|
-
)
|
|
492
|
-
}
|
|
493
|
-
];
|
|
494
|
-
}
|
|
495
|
-
if (server.status === "disabled") {
|
|
496
|
-
return [
|
|
497
|
-
{
|
|
498
|
-
label: t("enableAndConnect"),
|
|
499
|
-
primary: true,
|
|
500
|
-
run: async () => {
|
|
501
|
-
await api(`${state.API.servers}?name=${name}${scopeQuery}`, jsonPatchInit(true));
|
|
502
|
-
await api(`${state.API.connect}?name=${name}${scopeQuery}${cwdQuery}`, {
|
|
503
|
-
method: "POST"
|
|
504
|
-
});
|
|
505
|
-
await actions.refresh();
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
];
|
|
509
|
-
}
|
|
510
|
-
return [
|
|
511
|
-
{
|
|
512
|
-
label: t("connect"),
|
|
513
|
-
primary: true,
|
|
514
|
-
run: postThenRefresh(
|
|
515
|
-
state,
|
|
516
|
-
actions,
|
|
517
|
-
`${state.API.connect}?name=${name}${scopeQuery}${cwdQuery}`
|
|
518
|
-
)
|
|
519
|
-
}
|
|
520
|
-
];
|
|
521
|
-
}
|
|
522
|
-
function disableAction(server, state, actions, scopeQuery, cwdQuery) {
|
|
523
|
-
const name = encodeURIComponent(server.name);
|
|
524
|
-
return {
|
|
525
|
-
label: t("disable"),
|
|
526
|
-
primary: false,
|
|
527
|
-
run: async () => {
|
|
528
|
-
await api(
|
|
529
|
-
`${state.API.servers}?name=${name}${scopeQuery}${cwdQuery}`,
|
|
530
|
-
jsonPatchInit(false)
|
|
531
|
-
);
|
|
532
|
-
if (state.editingName === server.name) actions.resetForm();
|
|
533
|
-
await actions.refresh();
|
|
534
|
-
}
|
|
535
|
-
};
|
|
536
|
-
}
|
|
537
449
|
function deleteAction(server, state, actions, scopeQuery) {
|
|
538
450
|
const name = encodeURIComponent(server.name);
|
|
539
451
|
return {
|
|
@@ -593,39 +505,53 @@ window.__ModuleLoader__.load({
|
|
|
593
505
|
const busy = server.status === "connecting" || server.status === "reconnecting";
|
|
594
506
|
const scopeQuery = `&scope=${server.scope}`;
|
|
595
507
|
const cwdQuery = cwdQueryOf(state);
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
const disable = disableAction(server, state, actions, scopeQuery, cwdQuery);
|
|
601
|
-
actionsEl.appendChild(actionButton(disable.label, disable.run, disable.primary));
|
|
602
|
-
}
|
|
603
|
-
if (server.shadowedBy !== void 0) {
|
|
604
|
-
const shadowedBy = server.shadowedBy ?? "";
|
|
508
|
+
actionsEl.appendChild(enabledSwitch(server, state, actions, cwdQuery));
|
|
509
|
+
if (server.shadowedBy === void 0) {
|
|
510
|
+
actionsEl.appendChild(actionButton(t("edit"), () => actions.beginEdit(server)));
|
|
511
|
+
const remove = deleteAction(server, state, actions, scopeQuery);
|
|
605
512
|
actionsEl.appendChild(
|
|
606
|
-
actionButton(
|
|
607
|
-
try {
|
|
608
|
-
await activateSourceRun(server, state, actions)();
|
|
609
|
-
} catch (error) {
|
|
610
|
-
window.alert(t("importFail", { msg: error instanceof Error ? error.message : String(error) }));
|
|
611
|
-
}
|
|
612
|
-
})
|
|
513
|
+
actionButton(remove.label, remove.run, remove.primary, remove.danger === true)
|
|
613
514
|
);
|
|
614
|
-
actionsEl.
|
|
615
|
-
void actions.refresh();
|
|
616
|
-
}));
|
|
617
|
-
article.appendChild(actionsEl);
|
|
618
|
-
return article;
|
|
515
|
+
actionsEl.children[actionsEl.children.length - 1].disabled = busy;
|
|
619
516
|
}
|
|
620
|
-
actionsEl.appendChild(actionButton(t("edit"), () => actions.beginEdit(server)));
|
|
621
|
-
const remove = deleteAction(server, state, actions, scopeQuery);
|
|
622
|
-
actionsEl.appendChild(
|
|
623
|
-
actionButton(remove.label, remove.run, remove.primary, remove.danger === true)
|
|
624
|
-
);
|
|
625
|
-
actionsEl.children[actionsEl.children.length - 1].disabled = busy;
|
|
626
517
|
article.appendChild(actionsEl);
|
|
627
518
|
return article;
|
|
628
519
|
}
|
|
520
|
+
function enabledSwitch(server, state, actions, cwdQuery) {
|
|
521
|
+
const shadowed = server.shadowedBy !== void 0;
|
|
522
|
+
const checked = shadowed ? false : server.enabled !== false;
|
|
523
|
+
const wrap = el("label", {
|
|
524
|
+
class: "dm-switch",
|
|
525
|
+
role: "switch",
|
|
526
|
+
"aria-checked": String(checked),
|
|
527
|
+
title: shadowed ? t("srcActivateThis") : checked ? t("disable") : t("enable")
|
|
528
|
+
});
|
|
529
|
+
const box = document.createElement("input");
|
|
530
|
+
box.type = "checkbox";
|
|
531
|
+
box.checked = checked;
|
|
532
|
+
const slider = el("span", { class: "dm-switch-slider" });
|
|
533
|
+
wrap.appendChild(box);
|
|
534
|
+
wrap.appendChild(slider);
|
|
535
|
+
const name = encodeURIComponent(server.name);
|
|
536
|
+
box.addEventListener("change", () => {
|
|
537
|
+
wrap.setAttribute("aria-checked", String(box.checked));
|
|
538
|
+
wrap.classList.add("dm-switch--busy");
|
|
539
|
+
const run = shadowed && box.checked ? activateSourceRun(server, state, actions) : async () => {
|
|
540
|
+
await api(
|
|
541
|
+
`${state.API.servers}?name=${name}&scope=${server.scope}${cwdQuery}`,
|
|
542
|
+
{ method: "PATCH", headers: { "content-type": "application/json" }, body: JSON.stringify({ enabled: box.checked }) }
|
|
543
|
+
);
|
|
544
|
+
await actions.refresh();
|
|
545
|
+
};
|
|
546
|
+
run().catch((error) => {
|
|
547
|
+
box.checked = checked;
|
|
548
|
+
window.alert(
|
|
549
|
+
t("actionFail", { msg: error instanceof Error ? error.message : String(error) })
|
|
550
|
+
);
|
|
551
|
+
}).finally(() => wrap.classList.remove("dm-switch--busy"));
|
|
552
|
+
});
|
|
553
|
+
return wrap;
|
|
554
|
+
}
|
|
629
555
|
var groupFoldOpen = /* @__PURE__ */ new Map();
|
|
630
556
|
function renderServers(state, actions) {
|
|
631
557
|
if (state.bodyEl === void 0) return;
|
|
@@ -980,7 +906,7 @@ window.__ModuleLoader__.load({
|
|
|
980
906
|
onclick: async () => {
|
|
981
907
|
try {
|
|
982
908
|
const payload2 = await api(
|
|
983
|
-
state.API.sourceSave
|
|
909
|
+
`${state.API.sourceSave}?${cwdQueryOf(state).replace(/^&/, "")}`,
|
|
984
910
|
{
|
|
985
911
|
method: "POST",
|
|
986
912
|
headers: { "content-type": "application/json" },
|
|
@@ -1056,11 +982,6 @@ window.__ModuleLoader__.load({
|
|
|
1056
982
|
void node.offsetWidth;
|
|
1057
983
|
style.animation = "";
|
|
1058
984
|
}
|
|
1059
|
-
function pillDotColor(fail, connected) {
|
|
1060
|
-
if (fail) return "var(--dsw-alias-state-error-primary,#e0483e)";
|
|
1061
|
-
if (connected > 0) return "var(--dsw-alias-state-success-primary,#0f9d6e)";
|
|
1062
|
-
return "var(--dsw-alias-label-tertiary,#9aa1ad)";
|
|
1063
|
-
}
|
|
1064
985
|
function pillHints(total, bad, connected) {
|
|
1065
986
|
const failed = t("healthFailed", { n: bad });
|
|
1066
987
|
return {
|
|
@@ -1076,11 +997,15 @@ window.__ModuleLoader__.load({
|
|
|
1076
997
|
const fail = bad > 0;
|
|
1077
998
|
state.floatPill.classList.toggle("dm-float--fail", fail);
|
|
1078
999
|
state.floatPill.textContent = "";
|
|
1079
|
-
state.floatPill.appendChild(
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1000
|
+
state.floatPill.appendChild(el("span", { text: "MCP" }));
|
|
1001
|
+
if (total > 0) {
|
|
1002
|
+
state.floatPill.appendChild(el("span", { class: "dm-pill-dot", style: "background:#10b981" }));
|
|
1003
|
+
state.floatPill.appendChild(el("span", { text: String(ok) }));
|
|
1004
|
+
if (bad > 0) {
|
|
1005
|
+
state.floatPill.appendChild(el("span", { class: "dm-pill-dot", style: "background:#dc2626" }));
|
|
1006
|
+
state.floatPill.appendChild(el("span", { text: String(bad) }));
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1084
1009
|
if (total === 0) return;
|
|
1085
1010
|
const hints = pillHints(total, bad, ok);
|
|
1086
1011
|
state.floatPill.title = hints.title;
|
|
@@ -1130,90 +1055,6 @@ window.__ModuleLoader__.load({
|
|
|
1130
1055
|
details.appendChild(list);
|
|
1131
1056
|
return details;
|
|
1132
1057
|
}
|
|
1133
|
-
function floatActionClass(server) {
|
|
1134
|
-
if (server.status === "failed" || server.status === "stopped")
|
|
1135
|
-
return "dm-float-action dm-primary";
|
|
1136
|
-
return "dm-float-action";
|
|
1137
|
-
}
|
|
1138
|
-
function primaryRowAction(server, state, cwdQuery) {
|
|
1139
|
-
const query = `name=${encodeURIComponent(server.name)}&scope=${server.scope}${cwdQuery}`;
|
|
1140
|
-
const className = floatActionClass(server);
|
|
1141
|
-
if (server.status === "connected") {
|
|
1142
|
-
return {
|
|
1143
|
-
className,
|
|
1144
|
-
label: t("disconnect"),
|
|
1145
|
-
url: `${state.API.disconnect}?${query}`,
|
|
1146
|
-
method: "POST",
|
|
1147
|
-
tag: "disconnect"
|
|
1148
|
-
};
|
|
1149
|
-
}
|
|
1150
|
-
if (server.status === "disabled") {
|
|
1151
|
-
return {
|
|
1152
|
-
className,
|
|
1153
|
-
label: t("enable"),
|
|
1154
|
-
url: `${state.API.servers}?${query}`,
|
|
1155
|
-
method: "PATCH",
|
|
1156
|
-
tag: "enable",
|
|
1157
|
-
body: JSON.stringify({ enabled: true })
|
|
1158
|
-
};
|
|
1159
|
-
}
|
|
1160
|
-
if (server.shadowedBy !== void 0) {
|
|
1161
|
-
return {
|
|
1162
|
-
className,
|
|
1163
|
-
label: t("connect"),
|
|
1164
|
-
url: `${state.API.sourceActivate}?${cwdQuery.replace(/^&/, "")}`,
|
|
1165
|
-
method: "POST",
|
|
1166
|
-
tag: "activate",
|
|
1167
|
-
body: JSON.stringify({ name: server.name, id: server.source })
|
|
1168
|
-
};
|
|
1169
|
-
}
|
|
1170
|
-
return {
|
|
1171
|
-
className,
|
|
1172
|
-
label: t("connect"),
|
|
1173
|
-
url: `${state.API.connect}?${query}`,
|
|
1174
|
-
method: "POST",
|
|
1175
|
-
tag: "connect"
|
|
1176
|
-
};
|
|
1177
|
-
}
|
|
1178
|
-
function disableRowAction(server, state) {
|
|
1179
|
-
return {
|
|
1180
|
-
className: "dm-float-action",
|
|
1181
|
-
label: t("disable"),
|
|
1182
|
-
url: `${state.API.servers}?name=${encodeURIComponent(server.name)}&scope=${server.scope}`,
|
|
1183
|
-
method: "PATCH",
|
|
1184
|
-
tag: "disable",
|
|
1185
|
-
body: JSON.stringify({ enabled: false })
|
|
1186
|
-
};
|
|
1187
|
-
}
|
|
1188
|
-
function rowRequestInit(action) {
|
|
1189
|
-
if (action.body === void 0) return { method: action.method };
|
|
1190
|
-
return {
|
|
1191
|
-
method: action.method,
|
|
1192
|
-
headers: { "content-type": "application/json" },
|
|
1193
|
-
body: action.body
|
|
1194
|
-
};
|
|
1195
|
-
}
|
|
1196
|
-
function rowActionButton(action, actions) {
|
|
1197
|
-
const button = el("button", { class: action.className });
|
|
1198
|
-
button.textContent = action.label;
|
|
1199
|
-
button.addEventListener("click", () => {
|
|
1200
|
-
const original = button.textContent ?? "";
|
|
1201
|
-
focusGuardSuppressUntil = Date.now() + 800;
|
|
1202
|
-
button.disabled = true;
|
|
1203
|
-
button.style.opacity = "0.6";
|
|
1204
|
-
button.textContent = `${original}…`;
|
|
1205
|
-
const done = () => {
|
|
1206
|
-
button.disabled = false;
|
|
1207
|
-
button.style.opacity = "";
|
|
1208
|
-
button.textContent = original;
|
|
1209
|
-
};
|
|
1210
|
-
void api(action.url, rowRequestInit(action)).then(() => actions.refresh()).catch((error) => {
|
|
1211
|
-
console.warn(`[dsh-mcp-manager] ${action.tag} failed:`, error);
|
|
1212
|
-
window.alert(`${action.tag} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1213
|
-
}).finally(done);
|
|
1214
|
-
});
|
|
1215
|
-
return button;
|
|
1216
|
-
}
|
|
1217
1058
|
function renderFloatRow(server, state, actions, opts = { tools: true }) {
|
|
1218
1059
|
const failed = server.status === "failed" || server.status === "reconnecting";
|
|
1219
1060
|
const row = el("div", {
|
|
@@ -1231,13 +1072,13 @@ window.__ModuleLoader__.load({
|
|
|
1231
1072
|
text: pangu(t("serverMeta", { status: tStatus(server.status), tools }))
|
|
1232
1073
|
})
|
|
1233
1074
|
);
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
if (server.status !== "disabled") {
|
|
1239
|
-
actionsEl.appendChild(rowActionButton(disableRowAction(server, state), actions));
|
|
1075
|
+
if ((server.status === "failed" || server.status === "reconnecting") && server.error !== void 0 && server.error !== "") {
|
|
1076
|
+
row.appendChild(
|
|
1077
|
+
el("div", { class: "dm-err", style: "margin:2px 0 0 23px;", text: server.error })
|
|
1078
|
+
);
|
|
1240
1079
|
}
|
|
1080
|
+
const actionsEl = el("div", { class: "dm-float-actions" });
|
|
1081
|
+
actionsEl.appendChild(enabledSwitch(server, state, actions, cwdQueryOf(state)));
|
|
1241
1082
|
row.appendChild(actionsEl);
|
|
1242
1083
|
if (opts.tools)
|
|
1243
1084
|
row.appendChild(renderFloatTools(server, state, actions, opts.openTools ?? /* @__PURE__ */ new Set()));
|
|
@@ -1479,6 +1320,18 @@ window.__ModuleLoader__.load({
|
|
|
1479
1320
|
const pillRect = state.floatPill.getBoundingClientRect();
|
|
1480
1321
|
if (pillRect.width === 0 && pillRect.height === 0) return;
|
|
1481
1322
|
const panel = state.floatPanel;
|
|
1323
|
+
const host = conversationHost();
|
|
1324
|
+
const rect = host.getBoundingClientRect();
|
|
1325
|
+
const constrained = host !== document.body && rect.width > 0 && rect.height > 0;
|
|
1326
|
+
const margin = constrained ? 8 : 0;
|
|
1327
|
+
const bounds = constrained ? {
|
|
1328
|
+
left: Math.max(0, rect.left),
|
|
1329
|
+
top: Math.max(0, rect.top),
|
|
1330
|
+
right: Math.min(window.innerWidth, rect.right),
|
|
1331
|
+
bottom: Math.min(window.innerHeight, rect.bottom)
|
|
1332
|
+
} : { left: 0, top: 0, right: window.innerWidth, bottom: window.innerHeight };
|
|
1333
|
+
panel.style.setProperty("--dm-float-available-width", `${Math.max(0, bounds.right - bounds.left - Math.max(16, margin * 2))}px`);
|
|
1334
|
+
panel.style.setProperty("--dm-float-available-height", `${Math.max(0, bounds.bottom - bounds.top - Math.max(16, margin * 2))}px`);
|
|
1482
1335
|
const position = state.mcpUiConfig?.position;
|
|
1483
1336
|
const anchorBottom = panelAnchorForPosition(position) === "bottom";
|
|
1484
1337
|
const isLeft = anchorsLeft(position);
|
|
@@ -1493,8 +1346,10 @@ window.__ModuleLoader__.load({
|
|
|
1493
1346
|
window.innerWidth,
|
|
1494
1347
|
window.innerHeight
|
|
1495
1348
|
);
|
|
1496
|
-
|
|
1497
|
-
|
|
1349
|
+
const x = Math.min(Math.max(point.x, bounds.left + margin), Math.max(bounds.left + margin, bounds.right - panel.offsetWidth - margin));
|
|
1350
|
+
const y = Math.min(Math.max(point.y, bounds.top + margin), Math.max(bounds.top + margin, bounds.bottom - panel.offsetHeight - margin));
|
|
1351
|
+
panel.style.left = `${Math.round(x)}px`;
|
|
1352
|
+
panel.style.top = `${Math.round(y)}px`;
|
|
1498
1353
|
panel.style.right = "auto";
|
|
1499
1354
|
panel.style.transformOrigin = transformOriginFor(isLeft, anchorBottom);
|
|
1500
1355
|
}
|
|
@@ -1634,7 +1489,17 @@ window.__ModuleLoader__.load({
|
|
|
1634
1489
|
window.addEventListener("resize", scheduleUpdate);
|
|
1635
1490
|
window.addEventListener("orientationchange", onOrientationChange);
|
|
1636
1491
|
window.visualViewport?.addEventListener("resize", onVisualViewportResize);
|
|
1492
|
+
const onDragMove = (event) => {
|
|
1493
|
+
if (event.buttons !== 0) scheduleUpdate();
|
|
1494
|
+
};
|
|
1495
|
+
window.addEventListener("pointermove", onDragMove, { capture: true, passive: true });
|
|
1496
|
+
const resizeObserver = typeof ResizeObserver === "function" ? new ResizeObserver(scheduleUpdate) : void 0;
|
|
1497
|
+
for (let node = target; node !== null; node = node.parentElement) resizeObserver?.observe(node);
|
|
1498
|
+
resizeObserver?.observe(pill);
|
|
1499
|
+
resizeObserver?.observe(panel);
|
|
1637
1500
|
listeners.push(() => {
|
|
1501
|
+
resizeObserver?.disconnect();
|
|
1502
|
+
window.removeEventListener("pointermove", onDragMove, true);
|
|
1638
1503
|
target.removeEventListener("scroll", scheduleUpdate);
|
|
1639
1504
|
window.removeEventListener("resize", scheduleUpdate);
|
|
1640
1505
|
window.removeEventListener("orientationchange", onOrientationChange);
|
|
@@ -1645,10 +1510,11 @@ window.__ModuleLoader__.load({
|
|
|
1645
1510
|
const place = () => {
|
|
1646
1511
|
const best = conversationHost();
|
|
1647
1512
|
if (best === null || best === void 0) return false;
|
|
1648
|
-
|
|
1513
|
+
const root = panelHost();
|
|
1514
|
+
if (pill.parentElement !== root) root.appendChild(pill);
|
|
1515
|
+
if (panel.parentElement !== root) root.appendChild(panel);
|
|
1516
|
+
if (host !== best) {
|
|
1649
1517
|
host = best;
|
|
1650
|
-
if (pill.parentElement !== null) pill.remove();
|
|
1651
|
-
best.appendChild(pill);
|
|
1652
1518
|
attachListeners(best);
|
|
1653
1519
|
}
|
|
1654
1520
|
return true;
|
|
@@ -1661,14 +1527,17 @@ window.__ModuleLoader__.load({
|
|
|
1661
1527
|
place();
|
|
1662
1528
|
});
|
|
1663
1529
|
};
|
|
1664
|
-
const observer = new MutationObserver(
|
|
1530
|
+
const observer = new MutationObserver((records) => {
|
|
1531
|
+
if (records.some((record) => record.type === "childList")) schedulePlace();
|
|
1532
|
+
if (records.some((record) => record.type === "attributes" && record.target instanceof Element && record.target !== pill && record.target !== panel && host !== void 0 && host !== null && (record.target === host || record.target.contains(host)))) scheduleUpdate();
|
|
1533
|
+
});
|
|
1665
1534
|
if (place()) {
|
|
1666
|
-
observer.observe(document.body, { childList: true, subtree: true });
|
|
1535
|
+
observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["style", "class"] });
|
|
1667
1536
|
} else {
|
|
1668
1537
|
const wait = new MutationObserver(() => {
|
|
1669
1538
|
if (place()) {
|
|
1670
1539
|
wait.disconnect();
|
|
1671
|
-
observer.observe(document.body, { childList: true, subtree: true });
|
|
1540
|
+
observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["style", "class"] });
|
|
1672
1541
|
}
|
|
1673
1542
|
});
|
|
1674
1543
|
wait.observe(document.body, { childList: true, subtree: true });
|
|
@@ -1697,14 +1566,40 @@ window.__ModuleLoader__.load({
|
|
|
1697
1566
|
}
|
|
1698
1567
|
|
|
1699
1568
|
// src/client/float/panel.ts
|
|
1700
|
-
var inflight;
|
|
1569
|
+
var inflight = /* @__PURE__ */ new WeakMap();
|
|
1570
|
+
var snapshots = /* @__PURE__ */ new WeakMap();
|
|
1571
|
+
function activateWorkspace(state, actions, previous) {
|
|
1572
|
+
let cache = snapshots.get(state);
|
|
1573
|
+
if (cache === void 0) snapshots.set(state, cache = /* @__PURE__ */ new Map());
|
|
1574
|
+
if (Array.isArray(state.servers) && previous !== void 0) {
|
|
1575
|
+
cache.set(previous, { servers: state.servers, counts: state.counts, projectRoot: state.projectRoot });
|
|
1576
|
+
}
|
|
1577
|
+
const next = state.sessionResolved ? cache.get(state.currentCwd ?? "") : void 0;
|
|
1578
|
+
state.servers = next?.servers ?? [];
|
|
1579
|
+
state.counts = next?.counts ?? {};
|
|
1580
|
+
state.projectRoot = next?.projectRoot;
|
|
1581
|
+
renderPill(state);
|
|
1582
|
+
renderCountsBadge(state);
|
|
1583
|
+
if (state.bodyEl !== void 0 && state.activeTab === "servers") state.bodyEl.textContent = "";
|
|
1584
|
+
if (state.floatOpen && state.floatPanel !== void 0) state.floatPanel.textContent = "";
|
|
1585
|
+
const cwd = state.currentCwd;
|
|
1586
|
+
setTimeout(() => {
|
|
1587
|
+
if (state.currentCwd !== cwd) return;
|
|
1588
|
+
if (state.floatOpen) renderFloatPanel(state, actions);
|
|
1589
|
+
if (state.bodyEl !== void 0 && state.activeTab === "servers") renderServers(state, actions);
|
|
1590
|
+
}, 0);
|
|
1591
|
+
}
|
|
1701
1592
|
var keydownCleanups = /* @__PURE__ */ new WeakMap();
|
|
1702
1593
|
function refresh(state, actions) {
|
|
1703
|
-
if (
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1594
|
+
if (!state.sessionResolved) return Promise.resolve(true);
|
|
1595
|
+
const key = state.currentCwd ?? "";
|
|
1596
|
+
let pending = inflight.get(state);
|
|
1597
|
+
if (pending === void 0) inflight.set(state, pending = /* @__PURE__ */ new Map());
|
|
1598
|
+
const existing = pending.get(key);
|
|
1599
|
+
if (existing !== void 0) return existing;
|
|
1600
|
+
const request = doRefresh(state, actions, key).finally(() => pending.delete(key));
|
|
1601
|
+
pending.set(key, request);
|
|
1602
|
+
return request;
|
|
1708
1603
|
}
|
|
1709
1604
|
function countsSummaryText(state) {
|
|
1710
1605
|
const parts = [];
|
|
@@ -1716,6 +1611,7 @@ window.__ModuleLoader__.load({
|
|
|
1716
1611
|
return parts.length > 0 ? t("countsSummary", { n: state.servers.length, parts: parts.join(" · ") }) : t("countsSummaryOnly", { n: state.servers.length });
|
|
1717
1612
|
}
|
|
1718
1613
|
function renderCountsBadge(state) {
|
|
1614
|
+
if (typeof document === "undefined") return;
|
|
1719
1615
|
const countsEl = document.querySelector(".dm-counts");
|
|
1720
1616
|
if (countsEl === null) return;
|
|
1721
1617
|
const summary = countsSummaryText(state);
|
|
@@ -1733,9 +1629,10 @@ window.__ModuleLoader__.load({
|
|
|
1733
1629
|
}
|
|
1734
1630
|
countsEl.textContent = summary;
|
|
1735
1631
|
}
|
|
1736
|
-
async function doRefresh(state, actions) {
|
|
1632
|
+
async function doRefresh(state, actions, cwd) {
|
|
1737
1633
|
try {
|
|
1738
|
-
const payload = await api(state.API.servers);
|
|
1634
|
+
const payload = await api(`${state.API.servers}?cwd=${encodeURIComponent(cwd)}`);
|
|
1635
|
+
if (!state.sessionResolved || (state.currentCwd ?? "") !== cwd) return true;
|
|
1739
1636
|
state.servers = payload.servers ?? [];
|
|
1740
1637
|
state.counts = payload.counts ?? {};
|
|
1741
1638
|
state.projectRoot = payload.projectRoot;
|
|
@@ -1745,6 +1642,7 @@ window.__ModuleLoader__.load({
|
|
|
1745
1642
|
if (state.bodyEl !== void 0 && state.activeTab === "servers") renderServers(state, actions);
|
|
1746
1643
|
return true;
|
|
1747
1644
|
} catch (error) {
|
|
1645
|
+
if ((state.currentCwd ?? "") !== cwd) return false;
|
|
1748
1646
|
if (state.bodyEl !== void 0 && state.activeTab === "servers") {
|
|
1749
1647
|
state.bodyEl.textContent = "";
|
|
1750
1648
|
state.bodyEl.appendChild(
|
|
@@ -1906,6 +1804,7 @@ window.__ModuleLoader__.load({
|
|
|
1906
1804
|
if (read.kind === "unknown") {
|
|
1907
1805
|
state.currentCwd = void 0;
|
|
1908
1806
|
state.sessionResolved = false;
|
|
1807
|
+
if (prevResolved) activateWorkspace(state, actions, prevCwd ?? "");
|
|
1909
1808
|
state.unknownSessionFrames += 1;
|
|
1910
1809
|
state.updateFloatState?.();
|
|
1911
1810
|
if (prevResolved || state.unknownSessionFrames >= 2) warnUnknownOnce(state);
|
|
@@ -1917,11 +1816,13 @@ window.__ModuleLoader__.load({
|
|
|
1917
1816
|
state.warnedUnknownSession = false;
|
|
1918
1817
|
state.updateFloatState?.();
|
|
1919
1818
|
if (prevResolved && read.cwd === prevCwd) return;
|
|
1819
|
+
activateWorkspace(state, actions, prevResolved ? prevCwd ?? "" : void 0);
|
|
1820
|
+
void actions.refresh();
|
|
1920
1821
|
void api(state.API.session, {
|
|
1921
1822
|
method: "POST",
|
|
1922
1823
|
headers: { "content-type": "application/json" },
|
|
1923
1824
|
body: JSON.stringify({ cwd: typeof read.cwd === "string" ? read.cwd : "" })
|
|
1924
|
-
}).
|
|
1825
|
+
}).catch(() => {
|
|
1925
1826
|
});
|
|
1926
1827
|
};
|
|
1927
1828
|
sync();
|