dsh-mcp-panel 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +95 -0
- package/README.es.md +17 -5
- package/README.hi.md +17 -5
- package/README.md +17 -5
- package/README.pt.md +17 -5
- package/README.zh.md +17 -5
- package/THIRD_PARTY_NOTICES.md +11 -0
- package/docs/optimization-plan-v2.zh.md +325 -0
- package/docs/optimization-plan.zh.md +157 -0
- package/docs/research-notes.zh.md +114 -0
- package/docs/upstream-proposal.md +150 -0
- package/lib/client.js +283 -130
- package/lib/client.js.map +1 -1
- package/lib/index.js +87 -19
- package/lib/typert.host.js +2 -1
- package/lib/types/client/McpPanelTab.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +12 -0
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/present.d.ts +29 -1
- package/lib/types/client/present.d.ts.map +1 -1
- package/lib/types/client/remote.d.ts +9 -9
- package/lib/types/command.d.ts +6 -0
- package/lib/types/command.d.ts.map +1 -1
- package/lib/types/probe.d.ts.map +1 -1
- package/lib/types/service.d.ts +11 -2
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/typert.host.d.ts +9 -9
- package/lib/types/wire.d.ts +21 -21
- package/lib/types/wire.d.ts.map +1 -1
- package/package.json +18 -8
- package/src/client/McpPanelTab.tsx +68 -14
- package/src/client/locales.ts +12 -0
- package/src/client/present.ts +49 -1
- package/src/client/styles.ts +32 -0
- package/src/command.ts +39 -4
- package/src/probe.ts +1 -1
- package/src/service.ts +62 -10
- package/src/wire.ts +3 -3
package/lib/client.js
CHANGED
|
@@ -75,6 +75,10 @@ window.__ModuleLoader__.load({
|
|
|
75
75
|
badge: "killed",
|
|
76
76
|
tone: "muted"
|
|
77
77
|
};
|
|
78
|
+
default: return {
|
|
79
|
+
badge: "unknown",
|
|
80
|
+
tone: "muted"
|
|
81
|
+
};
|
|
78
82
|
}
|
|
79
83
|
}
|
|
80
84
|
/**
|
|
@@ -112,6 +116,39 @@ window.__ModuleLoader__.load({
|
|
|
112
116
|
refreshIntervalMs: snapshot.refreshIntervalMs
|
|
113
117
|
};
|
|
114
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Count the summary facts for the tab header line. Counting is derived from
|
|
121
|
+
* the same badge codes the cards show, so the line can never disagree with
|
|
122
|
+
* the rows beneath it.
|
|
123
|
+
*
|
|
124
|
+
* @param servers - the presented server rows (typically the filtered list).
|
|
125
|
+
* @returns the summary counts.
|
|
126
|
+
*/
|
|
127
|
+
function summarizePanel(servers) {
|
|
128
|
+
let connected = 0;
|
|
129
|
+
let errored = 0;
|
|
130
|
+
for (const row of servers) if (row.badge === "connected") connected += 1;
|
|
131
|
+
else if (row.badge === "failed" || row.badge === "exhausted") errored += 1;
|
|
132
|
+
return {
|
|
133
|
+
total: servers.length,
|
|
134
|
+
connected,
|
|
135
|
+
errored
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Filter server rows by a case-insensitive substring match against the
|
|
140
|
+
* server name or its display target. An empty query returns the rows
|
|
141
|
+
* unchanged (stable identity, no copies).
|
|
142
|
+
*
|
|
143
|
+
* @param servers - the presented server rows.
|
|
144
|
+
* @param query - the raw filter text.
|
|
145
|
+
* @returns the matching rows.
|
|
146
|
+
*/
|
|
147
|
+
function filterServers(servers, query) {
|
|
148
|
+
const needle = query.trim().toLocaleLowerCase();
|
|
149
|
+
if (needle === "") return servers;
|
|
150
|
+
return servers.filter((row) => row.view.serverName.toLocaleLowerCase().includes(needle) || row.view.target.toLocaleLowerCase().includes(needle));
|
|
151
|
+
}
|
|
115
152
|
//#endregion
|
|
116
153
|
//#region src/client/McpPanelTab.tsx
|
|
117
154
|
/** The read-only MCP management tab: server rows, badges, tools, probes. */
|
|
@@ -136,6 +173,7 @@ window.__ModuleLoader__.load({
|
|
|
136
173
|
case "failed": return t("probeFailed");
|
|
137
174
|
case "killed": return t("probeKilled");
|
|
138
175
|
case "stopping": return t("probeStopping");
|
|
176
|
+
default: return t("probeUnknown");
|
|
139
177
|
}
|
|
140
178
|
}
|
|
141
179
|
/** Local wall-clock range for one probe row; component-layer formatting only. */
|
|
@@ -148,10 +186,11 @@ window.__ModuleLoader__.load({
|
|
|
148
186
|
function McpPanelTab({ status, probe, t }) {
|
|
149
187
|
const listId = (0, react.useId)();
|
|
150
188
|
const [request, setRequest] = (0, react.useState)(0);
|
|
151
|
-
const [expanded, setExpanded] = (0, react.useState)(
|
|
189
|
+
const [expanded, setExpanded] = (0, react.useState)({});
|
|
152
190
|
const [probeError, setProbeError] = (0, react.useState)(null);
|
|
153
191
|
const [state, setState] = (0, react.useState)({ status: "loading" });
|
|
154
192
|
const [toolQueries, setToolQueries] = (0, react.useState)({});
|
|
193
|
+
const [serverQuery, setServerQuery] = (0, react.useState)("");
|
|
155
194
|
const reload = () => {
|
|
156
195
|
setRequest((value) => value + 1);
|
|
157
196
|
};
|
|
@@ -162,8 +201,11 @@ window.__ModuleLoader__.load({
|
|
|
162
201
|
status: "ready",
|
|
163
202
|
snapshot
|
|
164
203
|
});
|
|
165
|
-
}, () => {
|
|
166
|
-
if (current) setState({
|
|
204
|
+
}, (error) => {
|
|
205
|
+
if (current) setState({
|
|
206
|
+
status: "error",
|
|
207
|
+
message: error instanceof Error ? error.message : String(error)
|
|
208
|
+
});
|
|
167
209
|
});
|
|
168
210
|
return () => {
|
|
169
211
|
current = false;
|
|
@@ -185,11 +227,24 @@ window.__ModuleLoader__.load({
|
|
|
185
227
|
document.removeEventListener("visibilitychange", onVisible);
|
|
186
228
|
};
|
|
187
229
|
}, [intervalMs]);
|
|
230
|
+
const model = state.status === "ready" ? presentMcpPanel(state.snapshot) : void 0;
|
|
231
|
+
const visibleServers = model !== void 0 ? filterServers(model.servers, serverQuery) : [];
|
|
232
|
+
const summary = model !== void 0 ? summarizePanel(visibleServers) : null;
|
|
233
|
+
const summaryText = summary === null ? "" : t("summary").replace("{total}", String(summary.total)).replace("{connected}", String(summary.connected)).replace("{errored}", String(summary.errored));
|
|
234
|
+
const probeRunning = model !== void 0 && model.probes.some((probe) => probe.view.status === "running");
|
|
235
|
+
(0, react.useEffect)(() => {
|
|
236
|
+
if (!probeRunning) return void 0;
|
|
237
|
+
const timer = setInterval(() => {
|
|
238
|
+
if (!document.hidden) reload();
|
|
239
|
+
}, 1500);
|
|
240
|
+
return () => {
|
|
241
|
+
clearInterval(timer);
|
|
242
|
+
};
|
|
243
|
+
}, [probeRunning]);
|
|
188
244
|
const retry = () => {
|
|
189
245
|
setState({ status: "loading" });
|
|
190
246
|
reload();
|
|
191
247
|
};
|
|
192
|
-
const model = state.status === "ready" ? presentMcpPanel(state.snapshot) : void 0;
|
|
193
248
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
194
249
|
className: "dmcp-section",
|
|
195
250
|
"data-dsh-mcp-panel": "",
|
|
@@ -201,14 +256,21 @@ window.__ModuleLoader__.load({
|
|
|
201
256
|
}) : null,
|
|
202
257
|
state.status === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
203
258
|
className: "dmcp-failure",
|
|
204
|
-
children: [
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
259
|
+
children: [
|
|
260
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
261
|
+
role: "alert",
|
|
262
|
+
children: t("error")
|
|
263
|
+
}),
|
|
264
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
265
|
+
className: "dmcp-failure-detail",
|
|
266
|
+
children: state.message
|
|
267
|
+
}),
|
|
268
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
269
|
+
type: "button",
|
|
270
|
+
onClick: retry,
|
|
271
|
+
children: t("retry")
|
|
272
|
+
})
|
|
273
|
+
]
|
|
212
274
|
}) : null,
|
|
213
275
|
model !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
214
276
|
className: "dmcp-panel",
|
|
@@ -216,130 +278,177 @@ window.__ModuleLoader__.load({
|
|
|
216
278
|
model.empty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
217
279
|
className: "dmcp-status",
|
|
218
280
|
children: t("empty")
|
|
219
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
"
|
|
232
|
-
|
|
233
|
-
|
|
281
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
282
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
283
|
+
className: "dmcp-heading",
|
|
284
|
+
children: t("servers")
|
|
285
|
+
}),
|
|
286
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
287
|
+
className: "dmcp-summary",
|
|
288
|
+
children: summaryText
|
|
289
|
+
}),
|
|
290
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
291
|
+
className: "dmcp-toolbar",
|
|
292
|
+
children: [
|
|
293
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
294
|
+
type: "search",
|
|
295
|
+
className: "dmcp-tool-filter dmcp-server-filter",
|
|
296
|
+
value: serverQuery,
|
|
297
|
+
placeholder: t("filterServers"),
|
|
298
|
+
"aria-label": t("filterServers"),
|
|
299
|
+
onChange: (event) => {
|
|
300
|
+
setServerQuery(event.currentTarget.value);
|
|
301
|
+
}
|
|
302
|
+
}),
|
|
303
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
234
304
|
type: "button",
|
|
235
|
-
className: "dmcp-
|
|
236
|
-
"aria-expanded": open,
|
|
237
|
-
"aria-controls": detailId,
|
|
305
|
+
className: "dmcp-action",
|
|
238
306
|
onClick: () => {
|
|
239
|
-
setExpanded((
|
|
307
|
+
setExpanded(Object.fromEntries(visibleServers.map((row) => [row.view.serverName, true])));
|
|
240
308
|
},
|
|
241
|
-
children:
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
309
|
+
children: t("expandAll")
|
|
310
|
+
}),
|
|
311
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
312
|
+
type: "button",
|
|
313
|
+
className: "dmcp-action",
|
|
314
|
+
onClick: () => {
|
|
315
|
+
setExpanded({});
|
|
316
|
+
},
|
|
317
|
+
children: t("collapseAll")
|
|
318
|
+
})
|
|
319
|
+
]
|
|
320
|
+
}),
|
|
321
|
+
visibleServers.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
322
|
+
className: "dmcp-status",
|
|
323
|
+
children: t("noMatch")
|
|
324
|
+
}) : null,
|
|
325
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
326
|
+
className: "dmcp-cards",
|
|
327
|
+
children: visibleServers.map((row) => {
|
|
328
|
+
const open = expanded[row.view.serverName] === true;
|
|
329
|
+
const detailId = `${listId}-${encodeURIComponent(row.view.serverName)}`;
|
|
330
|
+
const toolQuery = toolQueries[row.view.serverName] ?? "";
|
|
331
|
+
const rowProbeRunning = model.probes.some((probe) => probe.view.status === "running" && probe.view.serverName === row.view.serverName);
|
|
332
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
333
|
+
className: "dmcp-card",
|
|
334
|
+
"data-mcp-server": row.view.serverName,
|
|
335
|
+
"data-open": open ? "true" : void 0,
|
|
336
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
337
|
+
type: "button",
|
|
338
|
+
className: "dmcp-card-content",
|
|
339
|
+
"aria-expanded": open,
|
|
340
|
+
"aria-controls": detailId,
|
|
341
|
+
onClick: () => {
|
|
342
|
+
setExpanded((current) => {
|
|
343
|
+
const next = { ...current };
|
|
344
|
+
if (next[row.view.serverName] === true) delete next[row.view.serverName];
|
|
345
|
+
else next[row.view.serverName] = true;
|
|
346
|
+
return next;
|
|
347
|
+
});
|
|
348
|
+
},
|
|
349
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
350
|
+
className: "dmcp-card-title",
|
|
351
|
+
children: row.view.serverName
|
|
352
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
353
|
+
className: "dmcp-card-trailing",
|
|
354
|
+
children: [
|
|
355
|
+
row.view.probeState !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
356
|
+
tone: row.view.probeState === "reachable" ? "ok" : "error",
|
|
357
|
+
label: row.view.probeState === "reachable" ? t("probeReachable") : t("probeUnreachable")
|
|
358
|
+
}) : null,
|
|
359
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
360
|
+
tone: row.tone,
|
|
361
|
+
label: badgeLabel(row.badge, t)
|
|
362
|
+
}),
|
|
363
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
364
|
+
className: "dmcp-tool-count",
|
|
365
|
+
children: [
|
|
366
|
+
row.view.toolCount,
|
|
367
|
+
" ",
|
|
368
|
+
t("tools")
|
|
369
|
+
]
|
|
370
|
+
})
|
|
371
|
+
]
|
|
372
|
+
})]
|
|
373
|
+
}), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
374
|
+
className: "dmcp-card-details",
|
|
375
|
+
id: detailId,
|
|
246
376
|
children: [
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
377
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dl", {
|
|
378
|
+
className: "dmcp-details",
|
|
379
|
+
children: [
|
|
380
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("status") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: badgeLabel(row.badge, t) })] }),
|
|
381
|
+
row.hasAttemptBudget ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("attempt") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dd", { children: [
|
|
382
|
+
row.view.attempt < 0 ? t("none") : row.view.attempt,
|
|
383
|
+
"/",
|
|
384
|
+
row.view.maxAttempts < 0 ? t("none") : row.view.maxAttempts
|
|
385
|
+
] })] }) : null,
|
|
386
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("reconnects") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: row.reconnects ?? t("none") })] }),
|
|
387
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("lastError") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
|
|
388
|
+
className: row.hasError ? "dmcp-error-text" : void 0,
|
|
389
|
+
children: row.view.lastError ?? t("none")
|
|
390
|
+
})] }),
|
|
391
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("fiber") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: row.view.fiberPhase ?? t("none") })] }),
|
|
392
|
+
row.view.configuredNote !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("configured") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: row.view.configuredNote })] }) : null,
|
|
393
|
+
row.ageSeconds !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("lastEvent") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dd", { children: [row.ageSeconds, "s"] })] }) : null,
|
|
394
|
+
row.view.delayMs !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("retryIn") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dd", { children: [
|
|
395
|
+
row.view.delayMs,
|
|
396
|
+
" ",
|
|
397
|
+
t("ms")
|
|
398
|
+
] })] }) : null
|
|
399
|
+
]
|
|
254
400
|
}),
|
|
255
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("
|
|
256
|
-
className: "dmcp-
|
|
401
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("code", {
|
|
402
|
+
className: "dmcp-target",
|
|
403
|
+
title: row.view.target,
|
|
257
404
|
children: [
|
|
258
|
-
row.view.
|
|
405
|
+
row.view.transport,
|
|
259
406
|
" ",
|
|
260
|
-
|
|
407
|
+
row.view.target
|
|
261
408
|
]
|
|
262
|
-
})
|
|
409
|
+
}),
|
|
410
|
+
row.view.transport === "streamable-http" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
411
|
+
type: "button",
|
|
412
|
+
className: "dmcp-probe-now",
|
|
413
|
+
disabled: rowProbeRunning,
|
|
414
|
+
onClick: () => {
|
|
415
|
+
setProbeError(null);
|
|
416
|
+
Promise.resolve().then(() => probe(row.view.serverName)).then(() => {
|
|
417
|
+
reload();
|
|
418
|
+
}, (error) => {
|
|
419
|
+
setProbeError(error instanceof Error ? error.message : String(error));
|
|
420
|
+
});
|
|
421
|
+
},
|
|
422
|
+
children: rowProbeRunning ? t("probeRunning") : t("probeNow")
|
|
423
|
+
}) : null,
|
|
424
|
+
row.view.tools.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
425
|
+
className: "dmcp-status",
|
|
426
|
+
children: t("noTools")
|
|
427
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
428
|
+
type: "search",
|
|
429
|
+
className: "dmcp-tool-filter",
|
|
430
|
+
value: toolQuery,
|
|
431
|
+
placeholder: t("filterTools"),
|
|
432
|
+
"aria-label": t("filterTools"),
|
|
433
|
+
onChange: (event) => {
|
|
434
|
+
setToolQueries((current) => ({
|
|
435
|
+
...current,
|
|
436
|
+
[row.view.serverName]: event.currentTarget.value
|
|
437
|
+
}));
|
|
438
|
+
}
|
|
439
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
440
|
+
className: "dmcp-tools",
|
|
441
|
+
children: row.view.tools.filter((tool) => toolQuery.trim() === "" || tool.name.toLocaleLowerCase().includes(toolQuery.trim().toLocaleLowerCase()) || tool.description.toLocaleLowerCase().includes(toolQuery.trim().toLocaleLowerCase())).map((tool) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: tool.name }), tool.description !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
442
|
+
className: "dmcp-tool-description",
|
|
443
|
+
children: tool.description
|
|
444
|
+
}) : null] }, tool.name))
|
|
445
|
+
})] })
|
|
263
446
|
]
|
|
264
|
-
})]
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
id: detailId,
|
|
268
|
-
children: [
|
|
269
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dl", {
|
|
270
|
-
className: "dmcp-details",
|
|
271
|
-
children: [
|
|
272
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("status") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: badgeLabel(row.badge, t) })] }),
|
|
273
|
-
row.hasAttemptBudget ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("attempt") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dd", { children: [
|
|
274
|
-
row.view.attempt < 0 ? t("none") : row.view.attempt,
|
|
275
|
-
"/",
|
|
276
|
-
row.view.maxAttempts < 0 ? t("none") : row.view.maxAttempts
|
|
277
|
-
] })] }) : null,
|
|
278
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("reconnects") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: row.reconnects ?? t("none") })] }),
|
|
279
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("lastError") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
|
|
280
|
-
className: row.hasError ? "dmcp-error-text" : void 0,
|
|
281
|
-
children: row.view.lastError ?? t("none")
|
|
282
|
-
})] }),
|
|
283
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("fiber") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: row.view.fiberPhase ?? t("none") })] }),
|
|
284
|
-
row.view.configuredNote !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("configured") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: row.view.configuredNote })] }) : null,
|
|
285
|
-
row.ageSeconds !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("lastEvent") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dd", { children: [row.ageSeconds, "s"] })] }) : null,
|
|
286
|
-
row.view.delayMs !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("retryIn") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dd", { children: [
|
|
287
|
-
row.view.delayMs,
|
|
288
|
-
" ",
|
|
289
|
-
t("ms")
|
|
290
|
-
] })] }) : null
|
|
291
|
-
]
|
|
292
|
-
}),
|
|
293
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("code", {
|
|
294
|
-
className: "dmcp-target",
|
|
295
|
-
title: row.view.target,
|
|
296
|
-
children: [
|
|
297
|
-
row.view.transport,
|
|
298
|
-
" ",
|
|
299
|
-
row.view.target
|
|
300
|
-
]
|
|
301
|
-
}),
|
|
302
|
-
row.view.transport === "streamable-http" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
303
|
-
type: "button",
|
|
304
|
-
className: "dmcp-probe-now",
|
|
305
|
-
disabled: probeRunning,
|
|
306
|
-
onClick: () => {
|
|
307
|
-
setProbeError(null);
|
|
308
|
-
Promise.resolve().then(() => probe(row.view.serverName)).then(() => {
|
|
309
|
-
reload();
|
|
310
|
-
}, (error) => {
|
|
311
|
-
setProbeError(error instanceof Error ? error.message : String(error));
|
|
312
|
-
});
|
|
313
|
-
},
|
|
314
|
-
children: probeRunning ? t("probeRunning") : t("probeNow")
|
|
315
|
-
}) : null,
|
|
316
|
-
row.view.tools.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
317
|
-
className: "dmcp-status",
|
|
318
|
-
children: t("noTools")
|
|
319
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
320
|
-
type: "search",
|
|
321
|
-
className: "dmcp-tool-filter",
|
|
322
|
-
value: toolQuery,
|
|
323
|
-
placeholder: t("filterTools"),
|
|
324
|
-
"aria-label": t("filterTools"),
|
|
325
|
-
onChange: (event) => {
|
|
326
|
-
setToolQueries((current) => ({
|
|
327
|
-
...current,
|
|
328
|
-
[row.view.serverName]: event.currentTarget.value
|
|
329
|
-
}));
|
|
330
|
-
}
|
|
331
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
332
|
-
className: "dmcp-tools",
|
|
333
|
-
children: row.view.tools.filter((tool) => toolQuery.trim() === "" || tool.name.toLocaleLowerCase().includes(toolQuery.trim().toLocaleLowerCase()) || tool.description.toLocaleLowerCase().includes(toolQuery.trim().toLocaleLowerCase())).map((tool) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: tool.name }), tool.description !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
334
|
-
className: "dmcp-tool-description",
|
|
335
|
-
children: tool.description
|
|
336
|
-
}) : null] }, tool.name))
|
|
337
|
-
})] })
|
|
338
|
-
]
|
|
339
|
-
}) : null]
|
|
340
|
-
}, row.view.serverName);
|
|
447
|
+
}) : null]
|
|
448
|
+
}, row.view.serverName);
|
|
449
|
+
})
|
|
341
450
|
})
|
|
342
|
-
|
|
451
|
+
] }),
|
|
343
452
|
!model.observed && !model.empty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
344
453
|
className: "dmcp-derived-note",
|
|
345
454
|
children: t("derivedNote")
|
|
@@ -398,13 +507,12 @@ window.__ModuleLoader__.load({
|
|
|
398
507
|
]
|
|
399
508
|
});
|
|
400
509
|
}
|
|
401
|
-
/** One tone-colored badge chip.
|
|
510
|
+
/** One tone-colored badge chip. The label is visible text, so no `role="img"`
|
|
511
|
+
* or `aria-label`: screen readers announce it exactly once. */
|
|
402
512
|
function Badge({ tone, label }) {
|
|
403
513
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
404
514
|
className: "dmcp-badge",
|
|
405
515
|
"data-tone": tone,
|
|
406
|
-
role: "img",
|
|
407
|
-
"aria-label": label,
|
|
408
516
|
title: label,
|
|
409
517
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
410
518
|
className: "dmcp-dot",
|
|
@@ -423,6 +531,11 @@ window.__ModuleLoader__.load({
|
|
|
423
531
|
retry: "重试",
|
|
424
532
|
empty: "此 profile 未配置官方 MCP 服务器(@deepseek-ai/dsh-mcp-client 行)。",
|
|
425
533
|
servers: "服务器",
|
|
534
|
+
summary: "服务器 {total} 台:已连接 {connected},错误 {errored}",
|
|
535
|
+
filterServers: "过滤服务器",
|
|
536
|
+
noMatch: "没有匹配的服务器。",
|
|
537
|
+
expandAll: "全部展开",
|
|
538
|
+
collapseAll: "全部折叠",
|
|
426
539
|
tools: "工具",
|
|
427
540
|
noTools: "未注册工具",
|
|
428
541
|
status: "状态",
|
|
@@ -452,6 +565,7 @@ window.__ModuleLoader__.load({
|
|
|
452
565
|
probeFailed: "失败",
|
|
453
566
|
probeKilled: "已取消",
|
|
454
567
|
probeStopping: "取消中",
|
|
568
|
+
probeUnknown: "未知",
|
|
455
569
|
probeNow: "探测",
|
|
456
570
|
probeReachable: "可达",
|
|
457
571
|
probeUnreachable: "不可达",
|
|
@@ -466,6 +580,11 @@ window.__ModuleLoader__.load({
|
|
|
466
580
|
retry: "Retry",
|
|
467
581
|
empty: "This profile configures no official MCP servers (@deepseek-ai/dsh-mcp-client rows).",
|
|
468
582
|
servers: "Servers",
|
|
583
|
+
summary: "{total} servers: {connected} connected, {errored} with errors",
|
|
584
|
+
filterServers: "Filter servers",
|
|
585
|
+
noMatch: "No servers match the filter.",
|
|
586
|
+
expandAll: "Expand all",
|
|
587
|
+
collapseAll: "Collapse all",
|
|
469
588
|
tools: "Tools",
|
|
470
589
|
noTools: "No tools registered",
|
|
471
590
|
status: "Status",
|
|
@@ -495,6 +614,7 @@ window.__ModuleLoader__.load({
|
|
|
495
614
|
probeFailed: "Failed",
|
|
496
615
|
probeKilled: "Killed",
|
|
497
616
|
probeStopping: "Stopping",
|
|
617
|
+
probeUnknown: "Unknown",
|
|
498
618
|
probeNow: "Probe",
|
|
499
619
|
probeReachable: "Reachable",
|
|
500
620
|
probeUnreachable: "Unreachable",
|
|
@@ -4663,7 +4783,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4663
4783
|
literal("stopping"),
|
|
4664
4784
|
literal("completed"),
|
|
4665
4785
|
literal("killed"),
|
|
4666
|
-
literal("failed")
|
|
4786
|
+
literal("failed"),
|
|
4787
|
+
literal("unknown")
|
|
4667
4788
|
]),
|
|
4668
4789
|
startedAt: number().int(),
|
|
4669
4790
|
finishedAt: number().int().nullable(),
|
|
@@ -4788,6 +4909,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4788
4909
|
font: inherit;
|
|
4789
4910
|
cursor: pointer;
|
|
4790
4911
|
}
|
|
4912
|
+
[data-dsh-mcp-panel] .dmcp-failure-detail {
|
|
4913
|
+
margin: 0;
|
|
4914
|
+
color: var(--dsw-alias-label-secondary);
|
|
4915
|
+
overflow-wrap: anywhere;
|
|
4916
|
+
}
|
|
4791
4917
|
[data-dsh-mcp-panel] .dmcp-panel {
|
|
4792
4918
|
display: flex;
|
|
4793
4919
|
flex-direction: column;
|
|
@@ -4799,6 +4925,33 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4799
4925
|
font-size: 1em;
|
|
4800
4926
|
color: var(--dsw-alias-label-primary);
|
|
4801
4927
|
}
|
|
4928
|
+
[data-dsh-mcp-panel] .dmcp-summary {
|
|
4929
|
+
margin: 0;
|
|
4930
|
+
color: var(--dsw-alias-label-secondary);
|
|
4931
|
+
}
|
|
4932
|
+
[data-dsh-mcp-panel] .dmcp-toolbar {
|
|
4933
|
+
display: flex;
|
|
4934
|
+
align-items: center;
|
|
4935
|
+
gap: 8px;
|
|
4936
|
+
flex-wrap: wrap;
|
|
4937
|
+
}
|
|
4938
|
+
[data-dsh-mcp-panel] .dmcp-server-filter {
|
|
4939
|
+
flex: 1 1 180px;
|
|
4940
|
+
min-width: 0;
|
|
4941
|
+
}
|
|
4942
|
+
[data-dsh-mcp-panel] .dmcp-action {
|
|
4943
|
+
font: inherit;
|
|
4944
|
+
cursor: pointer;
|
|
4945
|
+
color: var(--dsw-alias-label-primary);
|
|
4946
|
+
background: var(--dsw-alias-bg-layer-1);
|
|
4947
|
+
border: 1px solid var(--dsw-alias-border-l3);
|
|
4948
|
+
border-radius: 4px;
|
|
4949
|
+
padding: 4px 10px;
|
|
4950
|
+
}
|
|
4951
|
+
[data-dsh-mcp-panel] .dmcp-action:focus-visible {
|
|
4952
|
+
outline: 2px solid var(--dsw-alias-brand-primary);
|
|
4953
|
+
outline-offset: -2px;
|
|
4954
|
+
}
|
|
4802
4955
|
[data-dsh-mcp-panel] .dmcp-cards {
|
|
4803
4956
|
list-style: none;
|
|
4804
4957
|
margin: 0;
|