dsh-plugin-mcp-toggles 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -46
- package/lib/client.js +90 -56
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,55 +1,41 @@
|
|
|
1
1
|
# dsh-plugin-mcp-toggles
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/dsh-plugin-mcp-toggles)
|
|
4
|
+
[](https://www.npmjs.com/package/dsh-plugin-mcp-toggles)
|
|
4
5
|
[](LICENSE)
|
|
5
6
|
[](package.json)
|
|
6
7
|
|
|
7
8
|
为**每个会话**单独开关已安装的 MCP 服务器。
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
MCP 服务器在 DSH profile 里是进程级的:`@deepseek-ai/dsh-mcp-client` 每行连一个
|
|
12
|
-
服务器,把 `mcp__<serverName>__<tool>` 注册进**全局**工具层。于是每个会话都看到
|
|
13
|
-
同一批 MCP 工具 —— 想让 A 会话只用 REA、B 会话只用别的服务器,原生做不到。
|
|
14
|
-
|
|
15
|
-
装上本插件后:会话标题栏右侧出现一个 **MCP** 按钮,点开列出已安装的 MCP 服务器,
|
|
16
|
-
每行一个开关,**只影响当前会话**。新会话默认全部开启(装上插件不会悄悄改变任何
|
|
17
|
-
人现有的能力)。
|
|
10
|
+
装好之后,会话标题栏右侧(新会话页则是输入卡片上方那一行)会出现一个 **MCP**
|
|
11
|
+
按钮,点开列出已安装的 MCP 服务器,每行一个开关,**只影响当前会话**。
|
|
18
12
|
|
|
19
13
|
## 安装
|
|
20
14
|
|
|
21
|
-
|
|
22
|
-
插件行,用 `dsh.client` 声明 Web 端入口,没有依赖、没有构建步骤,装上即可用。
|
|
15
|
+
用 DSH 自带的插件命令,装进你要用的 profile:
|
|
23
16
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
plugin_manager action=install_bundle target=dsh-plugin-mcp-toggles
|
|
17
|
+
```bash
|
|
18
|
+
dsh plugin --profile web add dsh-plugin-mcp-toggles
|
|
28
19
|
```
|
|
29
20
|
|
|
30
|
-
`
|
|
21
|
+
把 `web` 换成你的 profile 名(`desktop`、`tui`、`headless` 等)。这条命令会
|
|
22
|
+
把它加入该 profile 的依赖与 bundle 列表,然后重启 DSH 即可。
|
|
31
23
|
|
|
32
|
-
|
|
33
|
-
plugin_manager action=install_bundle target=dsh-plugin-mcp-toggles@0.1.0
|
|
34
|
-
plugin_manager action=install_bundle target=github:ZhaoHanshao/dsh-plugin-mcp-toggles
|
|
35
|
-
```
|
|
24
|
+
指定版本或改用 GitHub 源:
|
|
36
25
|
|
|
37
|
-
|
|
26
|
+
```bash
|
|
27
|
+
dsh plugin --profile web add dsh-plugin-mcp-toggles@0.1.0
|
|
28
|
+
dsh plugin --profile web add github:ZhaoHanshao/dsh-plugin-mcp-toggles
|
|
29
|
+
```
|
|
38
30
|
|
|
39
|
-
|
|
31
|
+
卸载:
|
|
40
32
|
|
|
41
33
|
```bash
|
|
42
|
-
|
|
43
|
-
npm pack dsh-plugin-mcp-toggles --dry-run # 只打印将要发布的文件
|
|
34
|
+
dsh plugin --profile web remove dsh-plugin-mcp-toggles
|
|
44
35
|
```
|
|
45
36
|
|
|
46
|
-
|
|
47
|
-
`
|
|
48
|
-
`@deepseek-ai/dsh-client-ui-conversation`(运行时 **0.2.1-rc.3**)。这条约束写进了
|
|
49
|
-
`peerDependencies`,但标记为可选 —— DSH 把这些包内置在自己的安装目录里,普通 npm
|
|
50
|
-
安装不该为它再拉一份副本。
|
|
51
|
-
|
|
52
|
-
Node 版本要求 `^22.19.0 || >=24.0.0`,与 DSH 官方下限一致。
|
|
37
|
+
> 在 DSH 会话里,也可以让 agent 用 `plugin_manager action=install_bundle
|
|
38
|
+
> target=dsh-plugin-mcp-toggles` 完成同样的安装。
|
|
53
39
|
|
|
54
40
|
## 用法
|
|
55
41
|
|
|
@@ -59,29 +45,39 @@ Node 版本要求 `^22.19.0 || >=24.0.0`,与 DSH 官方下限一致。
|
|
|
59
45
|
|
|
60
46
|
按钮上的徽标显示当前状态:`全部开启`、`n/m`、`全部关闭`;部分关闭时按钮转为警示色。
|
|
61
47
|
|
|
62
|
-
|
|
48
|
+
开关立即生效,无需重启会话或重开服务器。
|
|
63
49
|
|
|
64
|
-
|
|
65
|
-
|---|---|
|
|
66
|
-
| `conversation.session.header.utilities` | 已有会话的标题栏右侧 |
|
|
67
|
-
| `conversation.hero.options` | 新会话落地页,紧跟 workspace 与模式控件之后 |
|
|
50
|
+
## 它解决什么
|
|
68
51
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
52
|
+
MCP 服务器在 DSH profile 里是进程级的:`@deepseek-ai/dsh-mcp-client` 每行连一个
|
|
53
|
+
服务器,把 `mcp__<serverName>__<tool>` 注册进**全局**工具层。于是每个会话都看到
|
|
54
|
+
同一批 MCP 工具 —— 想让 A 会话只用 REA、B 会话只用别的服务器,原生做不到。
|
|
55
|
+
|
|
56
|
+
本插件把这份「全局可见」变成「按会话可见」。**新会话默认全部开启**,所以装上它
|
|
57
|
+
不会悄悄改变任何人现有的能力;只有你亲手关掉的服务器才会在该会话里消失。
|
|
74
58
|
|
|
75
59
|
## 它怎么工作
|
|
76
60
|
|
|
77
|
-
`agent.ctx.tools.restrict({ deny })`
|
|
78
|
-
|
|
79
|
-
|
|
61
|
+
`agent.ctx.tools.restrict({ deny })` 是**作用域内**生效的全局工具掩码。可见性、
|
|
62
|
+
schema 投影与派发都走同一个解析器,因此被关掉的工具模型既看不到也调不到,其他
|
|
63
|
+
会话完全不受影响。
|
|
80
64
|
|
|
81
65
|
- 关闭某服务器 → 把它的 `mcp__<server>__*` 工具加进该会话的 deny 集。
|
|
82
66
|
- 全部服务器都关闭时,共享的 `list_mcp_resources` 等资源工具一并隐藏
|
|
83
67
|
(`sharedResourceTools: false` 可关掉这个联动)。
|
|
84
|
-
-
|
|
68
|
+
- 掩码按 deny 指纹幂等:工具集变化时只重算、不重复叠加。
|
|
69
|
+
|
|
70
|
+
## 两个入口,同一个开关集合
|
|
71
|
+
|
|
72
|
+
| 槽位 | 出现位置 |
|
|
73
|
+
|---|---|
|
|
74
|
+
| `conversation.session.header.utilities` | 已有会话的标题栏右侧 |
|
|
75
|
+
| `conversation.hero.options` | 新会话落地页,紧跟 workspace 与模式控件之后 |
|
|
76
|
+
|
|
77
|
+
两处**必须都有**:新会话页的会话页头带 `hideChrome`
|
|
78
|
+
(`blank && composerPhase === 'blank'`),此时整个 header 都不渲染,只挂标题栏会让
|
|
79
|
+
按钮在新会话页上完全消失。两个槽都提供同一个 `sessionId`,所以在哪一处切换都是
|
|
80
|
+
同一个会话的开关 —— 在新会话页关掉的服务器,进入对话后依然关着。
|
|
85
81
|
|
|
86
82
|
## 开关存在哪
|
|
87
83
|
|
|
@@ -96,16 +92,36 @@ header 都不渲染,只挂标题栏会让按钮在新会话页上完全消失
|
|
|
96
92
|
|
|
97
93
|
## 配置
|
|
98
94
|
|
|
99
|
-
`cordis.patch.yml`
|
|
95
|
+
在 profile 的 `cordis.patch.yml` 里覆盖 `mcp-toggles` 这一行的 `config`:
|
|
100
96
|
|
|
101
97
|
| 字段 | 默认 | 含义 |
|
|
102
98
|
|---|---|---|
|
|
103
99
|
| `sharedResourceTools` | `true` | 关闭全部 MCP 时是否连共享资源工具一起隐藏。 |
|
|
104
100
|
| `extraServers` | `[]` | 额外要认作 MCP 服务器的名字;用于服务器暂时没有注册任何工具时也能列出来。 |
|
|
105
101
|
|
|
102
|
+
## 兼容性
|
|
103
|
+
|
|
104
|
+
- **DSH**:需要 `@deepseek-ai/dsh-client-ui-conversation` ≥ `0.2.1-rc.3`
|
|
105
|
+
(提供上述两个槽位与 `webServer` 服务)。这条写进了 `peerDependencies` 并标记为
|
|
106
|
+
可选 —— DSH 把这些包内置在安装目录里,普通 npm 安装不该再拉一份副本。
|
|
107
|
+
- **Node**:`^22.19.0 || >=24.0.0`,与 DSH 官方下限一致。
|
|
108
|
+
|
|
106
109
|
## 已知限制
|
|
107
110
|
|
|
108
111
|
- 只管理 **MCP** 工具(`mcp__*` 前缀与共享资源工具),不动其他工具。
|
|
109
112
|
- 服务器列表来自 `configEditor.entries()` 里的 `@deepseek-ai/dsh-mcp-client` 行;
|
|
110
113
|
`configEditor` 不可用时退回当前工具名前缀,此时**没有工具**的服务器不会出现在列表里。
|
|
111
114
|
- 开关按会话 id 保存;会话被删除后对应记录会保留(无害,不会影响其他会话)。
|
|
115
|
+
|
|
116
|
+
## 开发
|
|
117
|
+
|
|
118
|
+
没有依赖、没有构建步骤,`lib/` 就是发布内容。改完直接检查:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
npm run prepublishOnly # node --check 两个入口
|
|
122
|
+
npm pack --dry-run # 查看将要发布的文件
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
MIT
|
package/lib/client.js
CHANGED
|
@@ -38,6 +38,7 @@ window.__ModuleLoader__.load({
|
|
|
38
38
|
'picker.summary.all': '全部开启',
|
|
39
39
|
'picker.summary.none': '全部关闭',
|
|
40
40
|
'picker.summary.pending': '选择 MCP',
|
|
41
|
+
'picker.summary.empty': '无',
|
|
41
42
|
'picker.saving': '保存中…',
|
|
42
43
|
'picker.unsaved': '未写入磁盘',
|
|
43
44
|
}
|
|
@@ -61,6 +62,7 @@ window.__ModuleLoader__.load({
|
|
|
61
62
|
'picker.summary.all': 'All on',
|
|
62
63
|
'picker.summary.none': 'All off',
|
|
63
64
|
'picker.summary.pending': 'MCP',
|
|
65
|
+
'picker.summary.empty': 'None',
|
|
64
66
|
'picker.saving': 'Saving…',
|
|
65
67
|
'picker.unsaved': 'not written to disk',
|
|
66
68
|
}
|
|
@@ -130,7 +132,7 @@ window.__ModuleLoader__.load({
|
|
|
130
132
|
/** 小箭头。 */
|
|
131
133
|
function Caret() {
|
|
132
134
|
return React.createElement('svg', {
|
|
133
|
-
width:
|
|
135
|
+
width: 12, height: 12, viewBox: '0 0 24 24', fill: 'none', 'aria-hidden': true,
|
|
134
136
|
}, React.createElement('path', {
|
|
135
137
|
d: 'm6 9 6 6 6-6',
|
|
136
138
|
stroke: 'currentColor', strokeWidth: 2.2, strokeLinecap: 'round', strokeLinejoin: 'round',
|
|
@@ -139,90 +141,120 @@ window.__ModuleLoader__.load({
|
|
|
139
141
|
|
|
140
142
|
// #endregion
|
|
141
143
|
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
+
// 样式基准取自 DSH 自身,数值与相邻控件对齐:
|
|
145
|
+
// · 标题栏正文 14px/20px、圆角 12px、hover 用 --dsw-alias-interactive-bg-hover
|
|
146
|
+
// (ui-conversation/ConversationRoot.module.css 的 .crumb)
|
|
147
|
+
// · hero 行控件 28px 高、24px 圆角、13px 字号、透明底
|
|
148
|
+
// (ui-conversation/PermissionSelect.module.css 的 .trigger)
|
|
149
|
+
// · 开关 20×10、thumb 6px、缓动 --ds-ease-in-out
|
|
150
|
+
// (ui-trajectory/TrajectoryToolbar.module.css 的 .controlTrack)
|
|
151
|
+
// · 浮层阴影用 --dsw-shadow-lv3,不写死 rgba
|
|
152
|
+
// 只用主题 token,不引入任何硬编码颜色。
|
|
144
153
|
const STYLE = `
|
|
145
154
|
.mt-wrap { position: relative; display: inline-flex; flex: none; align-self: center; }
|
|
146
155
|
.mt-trigger {
|
|
147
|
-
box-sizing: border-box; display: inline-flex; align-items: center; gap:
|
|
148
|
-
height:
|
|
149
|
-
border:
|
|
150
|
-
background:
|
|
151
|
-
font-family: var(--dsw-font-family); font-size:
|
|
156
|
+
box-sizing: border-box; display: inline-flex; align-items: center; gap: 6px;
|
|
157
|
+
height: 28px; padding: 0 8px; max-width: 220px;
|
|
158
|
+
border: none; border-radius: 24px; outline: none;
|
|
159
|
+
background: transparent; color: var(--dsw-alias-label-secondary);
|
|
160
|
+
font-family: var(--dsw-font-family); font-size: 13px; line-height: 20px; font-weight: 500;
|
|
152
161
|
white-space: nowrap; cursor: pointer;
|
|
153
162
|
}
|
|
154
|
-
.mt-trigger:hover { background: var(--dsw-alias-interactive-bg-hover); }
|
|
155
|
-
.mt-trigger:focus-visible {
|
|
156
|
-
.mt-trigger[data-open="true"] {
|
|
157
|
-
.mt-trigger[data-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
.mt-trigger[data-
|
|
161
|
-
|
|
162
|
-
.mt-
|
|
163
|
+
.mt-trigger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
|
|
164
|
+
.mt-trigger:focus-visible { box-shadow: 0 0 0 2px var(--dsw-alias-border-l3); }
|
|
165
|
+
.mt-trigger[data-open="true"] { background: var(--dsw-alias-interactive-bg-hover); }
|
|
166
|
+
.mt-trigger[data-none="true"] { color: var(--dsw-alias-label-dimmed); }
|
|
167
|
+
/* 部分关闭:用状态色点出「本会话少了东西」,而不是整块文字变色。 */
|
|
168
|
+
.mt-trigger[data-partial="true"] .mt-name { color: var(--dsw-alias-label-primary); }
|
|
169
|
+
.mt-trigger[data-partial="true"] .mt-badge { color: var(--dsw-alias-state-warn-primary); }
|
|
170
|
+
/* hero 行比标题栏紧凑,与相邻的 workspace/模式控件同高。 */
|
|
171
|
+
.mt-trigger[data-compact="true"] { height: 28px; padding: 0 8px; font-size: 13px; }
|
|
172
|
+
.mt-icon { flex: none; display: inline-flex; align-items: center; }
|
|
163
173
|
.mt-name { overflow: hidden; text-overflow: ellipsis; }
|
|
164
|
-
.mt-caret {
|
|
174
|
+
.mt-caret {
|
|
175
|
+
flex: none; display: inline-flex; align-items: center;
|
|
176
|
+
color: var(--dsw-alias-label-caption);
|
|
177
|
+
transition: transform 120ms var(--ds-ease-in-out);
|
|
178
|
+
}
|
|
165
179
|
.mt-trigger[data-open="true"] .mt-caret { transform: rotate(180deg); }
|
|
180
|
+
.mt-badge {
|
|
181
|
+
flex: none; padding: 0 6px; border-radius: 6px;
|
|
182
|
+
font-size: 12px; line-height: 18px; font-weight: 500;
|
|
183
|
+
background: var(--dsw-alias-bg-layer-2); color: var(--dsw-alias-label-secondary);
|
|
184
|
+
}
|
|
185
|
+
.mt-badge[data-tone="warn"] { color: var(--dsw-alias-state-warn-primary); }
|
|
186
|
+
|
|
187
|
+
/* 浮层:与 DSH 弹层同源 —— overlay 底、lv3 阴影、12px 圆角。 */
|
|
166
188
|
.mt-menu {
|
|
167
|
-
position: absolute; top: calc(100% +
|
|
168
|
-
width:
|
|
169
|
-
border:
|
|
170
|
-
background: var(--dsw-alias-bg-overlay); box-shadow:
|
|
189
|
+
position: absolute; top: calc(100% + 6px); right: 0; z-index: 60;
|
|
190
|
+
width: 340px; max-height: 60vh; overflow-y: auto; padding: 6px;
|
|
191
|
+
border: 1px solid var(--dsw-alias-border-l1); border-radius: 12px;
|
|
192
|
+
background: var(--dsw-alias-bg-overlay); box-shadow: var(--dsw-shadow-lv3);
|
|
171
193
|
}
|
|
172
194
|
.mt-head {
|
|
173
195
|
display: flex; align-items: center; justify-content: space-between; gap: 8px;
|
|
174
|
-
padding:
|
|
196
|
+
padding: 6px 8px 8px;
|
|
197
|
+
font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-secondary);
|
|
198
|
+
}
|
|
199
|
+
.mt-headActions { display: inline-flex; align-items: center; gap: 10px; flex: none; }
|
|
200
|
+
.mt-link {
|
|
201
|
+
cursor: pointer; border-radius: 6px; padding: 0 2px;
|
|
175
202
|
color: var(--dsw-alias-label-secondary);
|
|
203
|
+
transition: color 120ms var(--ds-ease-in-out);
|
|
176
204
|
}
|
|
177
|
-
.mt-headActions { display: inline-flex; align-items: center; gap: 8px; flex: none; }
|
|
178
|
-
.mt-link { cursor: pointer; color: var(--dsw-alias-label-secondary); }
|
|
179
205
|
.mt-link:hover { color: var(--dsw-alias-brand-primary); }
|
|
206
|
+
.mt-link:focus-visible { outline: 2px solid var(--dsw-alias-border-l3); outline-offset: 1px; }
|
|
207
|
+
.mt-link[data-disabled="true"] { opacity: .5; cursor: default; pointer-events: none; }
|
|
180
208
|
.mt-item {
|
|
181
|
-
display: flex; align-items: center; gap:
|
|
182
|
-
border-radius:
|
|
209
|
+
display: flex; align-items: center; gap: 10px; padding: 8px;
|
|
210
|
+
border-radius: 8px; cursor: default;
|
|
183
211
|
}
|
|
184
212
|
.mt-item:hover { background: var(--dsw-alias-interactive-bg-hover); }
|
|
185
|
-
.mt-item[data-busy="true"] { opacity: .6;
|
|
213
|
+
.mt-item[data-busy="true"] { opacity: .6; }
|
|
186
214
|
.mt-body { flex: 1; min-width: 0; }
|
|
187
|
-
.mt-title {
|
|
215
|
+
.mt-title {
|
|
216
|
+
display: flex; align-items: center; gap: 6px;
|
|
217
|
+
font-size: 13px; line-height: 20px; font-weight: 500;
|
|
218
|
+
color: var(--dsw-alias-label-primary);
|
|
219
|
+
}
|
|
188
220
|
.mt-sub {
|
|
189
|
-
margin-top:
|
|
221
|
+
margin-top: 2px; font-size: 12px; line-height: 18px;
|
|
190
222
|
color: var(--dsw-alias-label-secondary);
|
|
191
223
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
192
224
|
}
|
|
193
|
-
.mt-badge {
|
|
194
|
-
flex: none; padding: 0 4px; border-radius: var(--dsw-radius-xs);
|
|
195
|
-
font-size: 9.5px; line-height: 14px;
|
|
196
|
-
background: var(--dsw-alias-bg-layer-2); color: var(--dsw-alias-label-secondary);
|
|
197
|
-
}
|
|
198
|
-
.mt-badge[data-tone="warn"] { color: var(--dsw-alias-state-warn-primary); }
|
|
199
225
|
.mt-switch {
|
|
200
226
|
flex: none; position: relative; box-sizing: border-box;
|
|
201
|
-
width:
|
|
202
|
-
border:
|
|
203
|
-
background: var(--dsw-alias-
|
|
227
|
+
width: 32px; height: 18px; padding: 0;
|
|
228
|
+
border: none; border-radius: 9px;
|
|
229
|
+
background: var(--dsw-alias-border-l2); cursor: pointer;
|
|
230
|
+
transition: background-color 120ms var(--ds-ease-in-out);
|
|
204
231
|
}
|
|
205
232
|
.mt-switch::after {
|
|
206
|
-
content: ""; position: absolute; top:
|
|
207
|
-
width:
|
|
208
|
-
background: var(--dsw-alias-
|
|
233
|
+
content: ""; position: absolute; top: 3px; left: 3px;
|
|
234
|
+
width: 12px; height: 12px; border-radius: 50%;
|
|
235
|
+
background: var(--dsw-alias-bg-layer-1);
|
|
236
|
+
transition: transform 120ms var(--ds-ease-in-out);
|
|
209
237
|
}
|
|
210
|
-
.mt-switch[aria-checked="true"] { background: var(--dsw-alias-brand-primary);
|
|
211
|
-
.mt-switch[aria-checked="true"]::after { transform: translateX(
|
|
212
|
-
.mt-switch:focus-visible { outline: 2px solid var(--dsw-alias-
|
|
238
|
+
.mt-switch[aria-checked="true"] { background: var(--dsw-alias-brand-primary); }
|
|
239
|
+
.mt-switch[aria-checked="true"]::after { transform: translateX(14px); }
|
|
240
|
+
.mt-switch:focus-visible { outline: 2px solid var(--dsw-alias-border-l3); outline-offset: 2px; }
|
|
213
241
|
.mt-switch:disabled { opacity: .5; cursor: default; }
|
|
214
|
-
.mt-sep { height: .5px; margin: 4px 2px; background: var(--dsw-alias-border-l1); }
|
|
215
242
|
.mt-foot {
|
|
216
|
-
display: flex; align-items: center; gap: 6px; padding:
|
|
217
|
-
font-size:
|
|
243
|
+
display: flex; align-items: center; gap: 6px; padding: 6px 8px;
|
|
244
|
+
font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-secondary);
|
|
245
|
+
}
|
|
246
|
+
.mt-err {
|
|
247
|
+
padding: 4px 8px 6px; font-size: 12px; line-height: 18px;
|
|
248
|
+
color: var(--dsw-alias-state-error-primary);
|
|
218
249
|
}
|
|
219
|
-
.mt-err { padding: 3px 8px 6px; font-size: 10.5px; line-height: 15px; color: var(--dsw-alias-state-error-primary); }
|
|
220
250
|
.mt-btn {
|
|
221
|
-
padding:
|
|
222
|
-
background:
|
|
223
|
-
font-family: var(--dsw-font-family); font-size:
|
|
251
|
+
padding: 4px 10px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px;
|
|
252
|
+
background: transparent; color: var(--dsw-alias-label-primary);
|
|
253
|
+
font-family: var(--dsw-font-family); font-size: 12px; line-height: 18px;
|
|
254
|
+
cursor: pointer; transition: background-color 120ms var(--ds-ease-in-out);
|
|
224
255
|
}
|
|
225
|
-
.mt-btn:hover { background: var(--dsw-alias-interactive-bg-hover); }
|
|
256
|
+
.mt-btn:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
|
|
257
|
+
.mt-btn:focus-visible { outline: 2px solid var(--dsw-alias-border-l3); outline-offset: 1px; }
|
|
226
258
|
.mt-btn:disabled { opacity: .5; cursor: default; }
|
|
227
259
|
`
|
|
228
260
|
|
|
@@ -301,12 +333,14 @@ window.__ModuleLoader__.load({
|
|
|
301
333
|
const servers = data?.servers ?? []
|
|
302
334
|
const enabledCount = data?.enabledCount ?? 0
|
|
303
335
|
|
|
336
|
+
// 徽标只放短状态:长句(无服务器/读取中)会把 220px 的触发器撑破,
|
|
337
|
+
// 完整说明留在弹层里。
|
|
304
338
|
const label = !scoped
|
|
305
339
|
? t('picker.summary.pending')
|
|
306
340
|
: data === undefined
|
|
307
|
-
?
|
|
341
|
+
? '…'
|
|
308
342
|
: servers.length === 0
|
|
309
|
-
? t('picker.empty')
|
|
343
|
+
? t('picker.summary.empty')
|
|
310
344
|
: enabledCount === servers.length
|
|
311
345
|
? t('picker.summary.all')
|
|
312
346
|
: enabledCount === 0
|
|
@@ -378,7 +412,7 @@ window.__ModuleLoader__.load({
|
|
|
378
412
|
'aria-expanded': open,
|
|
379
413
|
onClick: () => { setOpen((value) => !value) },
|
|
380
414
|
},
|
|
381
|
-
React.createElement('span', { className: 'mt-icon' }, React.createElement(PlugGlyph, { size:
|
|
415
|
+
React.createElement('span', { className: 'mt-icon' }, React.createElement(PlugGlyph, { size: 14 })),
|
|
382
416
|
React.createElement('span', { className: 'mt-name' }, 'MCP'),
|
|
383
417
|
React.createElement('span', {
|
|
384
418
|
className: 'mt-badge',
|