@dawn0608/dsh-mcp-manager 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +74 -2
- package/README.zh.md +75 -0
- package/cordis.patch.yml +3 -0
- package/icon.svg +6 -0
- package/lib/client.js +590 -0
- package/lib/client.js.map +7 -0
- package/lib/index.js +8774 -0
- package/lib/index.js.map +7 -0
- package/locale/en.json +7 -0
- package/locale/zh.json +7 -0
- package/package.json +73 -4
package/lib/client.js
ADDED
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "@dawn0608/dsh-mcp-manager",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
var __create = Object.create;
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
9
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
10
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
11
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
16
|
+
var __copyProps = (to, from, except, desc) => {
|
|
17
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
18
|
+
for (let key of __getOwnPropNames(from))
|
|
19
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
20
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
21
|
+
}
|
|
22
|
+
return to;
|
|
23
|
+
};
|
|
24
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
25
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
26
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
27
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
28
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
29
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
30
|
+
mod
|
|
31
|
+
));
|
|
32
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
33
|
+
|
|
34
|
+
// src/client/index.js
|
|
35
|
+
var index_exports = {};
|
|
36
|
+
__export(index_exports, {
|
|
37
|
+
apply: () => apply,
|
|
38
|
+
inject: () => inject
|
|
39
|
+
});
|
|
40
|
+
module.exports = __toCommonJS(index_exports);
|
|
41
|
+
var React3 = __toESM(require("react"), 1);
|
|
42
|
+
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
43
|
+
|
|
44
|
+
// icon.svg
|
|
45
|
+
var icon_default = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" width="36" height="36">%0A <path d="M15 9v4m6-4v4M13 13h10v2a5 5 0 0 1-10 0zM18 20v4m-8 2v-2h16v2"%0A fill="none" stroke="%23527ee8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>%0A <circle cx="10" cy="26" r="2" fill="%23527ee8"/>%0A <circle cx="26" cy="26" r="2" fill="%23527ee8"/>%0A</svg>%0A';
|
|
46
|
+
|
|
47
|
+
// src/client/i18n.js
|
|
48
|
+
var NS = "mcpManager";
|
|
49
|
+
var DICTS = {
|
|
50
|
+
zh: {
|
|
51
|
+
title: "MCP \u7BA1\u7406",
|
|
52
|
+
loadFailed: "\u8BFB\u53D6\u914D\u7F6E\u5931\u8D25",
|
|
53
|
+
emptyTitle: "\u8FD8\u6CA1\u6709 MCP \u670D\u52A1",
|
|
54
|
+
duplicate: "\u91CD\u540D",
|
|
55
|
+
duplicateHint: "\u540C\u4E00\u670D\u52A1\u540D\u51FA\u73B0\u591A\u6B21\uFF0CHarness \u53EA\u4F1A\u52A0\u8F7D\u5176\u4E2D\u4E00\u4E2A\u3002",
|
|
56
|
+
readOnly: "\u53EA\u8BFB",
|
|
57
|
+
readOnlyFailure: "\u8BE5\u6761\u76EE\u4E3A\u53EA\u8BFB\uFF0C\u65E0\u6CD5\u5728\u9762\u677F\u4E2D\u4FEE\u6539\u3002",
|
|
58
|
+
unknownName: "\u672A\u547D\u540D\u6761\u76EE",
|
|
59
|
+
readOnlyNotInsert: "\u8BE5 MCP \u6761\u76EE\u4E0D\u5728 insert \u5217\u8868\u4E2D\u3002",
|
|
60
|
+
readOnlyBlockShape: "\u6240\u5728\u7684 patch \u5757\u5305\u542B\u5176\u4ED6\u5B57\u6BB5\u3002",
|
|
61
|
+
readOnlyRowShape: "\u6761\u76EE\u5305\u542B\u9762\u677F\u4E0D\u652F\u6301\u7684\u5B57\u6BB5\u3002",
|
|
62
|
+
readOnlyMissingId: "\u6761\u76EE\u7F3A\u5C11 id\u3002",
|
|
63
|
+
readOnlyDuplicateId: "\u6761\u76EE id \u91CD\u590D\u6216\u88AB\u8986\u76D6\u3002",
|
|
64
|
+
readOnlyConditional: "\u542F\u7528\u72B6\u6001\u662F\u6761\u4EF6\u8868\u8FBE\u5F0F\u3002",
|
|
65
|
+
readOnlyMissingName: "\u6761\u76EE\u7F3A\u5C11 serverName\u3002",
|
|
66
|
+
readOnlyConfig: "\u914D\u7F6E\u7ED3\u6784\u4E0D\u53D7\u652F\u6301\u3002",
|
|
67
|
+
readOnlyConfigEnabled: "\u6761\u76EE\u5728 config \u4E2D\u4F7F\u7528\u4E86 enabled\uFF0C\u65E0\u6CD5\u5B89\u5168\u6539\u5199\u3002",
|
|
68
|
+
transportStdio: "STDIO",
|
|
69
|
+
transportHttp: "Streamable HTTP",
|
|
70
|
+
switchLabel: "\u542F\u7528 {name}",
|
|
71
|
+
saving: "\u6B63\u5728\u4FDD\u5B58\u2026",
|
|
72
|
+
invalid: "\u8BF7\u6C42\u65E0\u6548\u3002",
|
|
73
|
+
internal: "\u64CD\u4F5C\u672A\u5B8C\u6210\uFF0C\u8BF7\u67E5\u770B Harness \u65E5\u5FD7\u3002",
|
|
74
|
+
conflict: "\u914D\u7F6E\u6587\u4EF6\u5DF2\u88AB\u5176\u4ED6\u7A0B\u5E8F\u4FEE\u6539\uFF0C\u5DF2\u5237\u65B0\u5217\u8868\uFF0C\u8BF7\u91CD\u8BD5\u3002",
|
|
75
|
+
locked: "\u914D\u7F6E\u6587\u4EF6\u6B63\u88AB\u5176\u4ED6\u64CD\u4F5C\u5360\u7528\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002",
|
|
76
|
+
profileUnavailable: "\u65E0\u6CD5\u5B9A\u4F4D\u6216\u8BFB\u5199\u5F53\u524D profile \u8865\u4E01\u6587\u4EF6\u3002",
|
|
77
|
+
network: "\u65E0\u6CD5\u8FDE\u63A5 Harness\u3002",
|
|
78
|
+
unauthorized: "\u5F53\u524D\u9875\u9762\u6CA1\u6709\u8BBF\u95EE Host \u7684\u6743\u9650\u3002"
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
DICTS.en = {
|
|
82
|
+
title: "MCP Management",
|
|
83
|
+
loadFailed: "Could not read the configuration",
|
|
84
|
+
emptyTitle: "No MCP servers yet",
|
|
85
|
+
duplicate: "Duplicate name",
|
|
86
|
+
duplicateHint: "The same server name appears more than once; Harness loads only one of them.",
|
|
87
|
+
readOnly: "Read-only",
|
|
88
|
+
readOnlyFailure: "This entry is read-only and cannot be changed from the panel.",
|
|
89
|
+
unknownName: "Unnamed entry",
|
|
90
|
+
readOnlyNotInsert: "This MCP entry is outside an insert list.",
|
|
91
|
+
readOnlyBlockShape: "Its patch block contains other fields.",
|
|
92
|
+
readOnlyRowShape: "The entry contains fields this panel does not manage.",
|
|
93
|
+
readOnlyMissingId: "The entry has no id.",
|
|
94
|
+
readOnlyDuplicateId: "The entry id is duplicated or overridden.",
|
|
95
|
+
readOnlyConditional: "Enablement is a conditional expression.",
|
|
96
|
+
readOnlyMissingName: "The entry has no serverName.",
|
|
97
|
+
readOnlyConfig: "The configuration shape is unsupported.",
|
|
98
|
+
readOnlyConfigEnabled: "The entry uses enabled inside config and cannot be rewritten safely.",
|
|
99
|
+
transportStdio: "STDIO",
|
|
100
|
+
transportHttp: "Streamable HTTP",
|
|
101
|
+
switchLabel: "Enable {name}",
|
|
102
|
+
saving: "Saving\u2026",
|
|
103
|
+
invalid: "The request is invalid.",
|
|
104
|
+
internal: "The operation did not complete; check the Harness logs.",
|
|
105
|
+
conflict: "The configuration changed on disk. The list was refreshed; try again.",
|
|
106
|
+
locked: "The profile is being written by another operation. Try again shortly.",
|
|
107
|
+
profileUnavailable: "The profile patch for this desktop profile cannot be located or written.",
|
|
108
|
+
network: "Could not reach Harness.",
|
|
109
|
+
unauthorized: "This page is not authorized to call the Host."
|
|
110
|
+
};
|
|
111
|
+
function format(template, params) {
|
|
112
|
+
return String(template).replace(/\{(\w+)\}/g, (match, key) => params && Object.prototype.hasOwnProperty.call(params, key) ? String(params[key]) : match);
|
|
113
|
+
}
|
|
114
|
+
function registerLocale(ctx) {
|
|
115
|
+
return ctx.effect(() => {
|
|
116
|
+
try {
|
|
117
|
+
return ctx.locale.register(NS, DICTS);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
return () => {
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}, "mcp-manager: dictionaries");
|
|
123
|
+
}
|
|
124
|
+
function createTranslator(ctx) {
|
|
125
|
+
let bound;
|
|
126
|
+
try {
|
|
127
|
+
bound = ctx.locale.bind(NS);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
bound = null;
|
|
130
|
+
}
|
|
131
|
+
const fallback = () => {
|
|
132
|
+
let active = "en";
|
|
133
|
+
try {
|
|
134
|
+
active = ctx.locale.getSnapshot().active || "en";
|
|
135
|
+
} catch (error) {
|
|
136
|
+
active = "en";
|
|
137
|
+
}
|
|
138
|
+
return String(active).toLowerCase().startsWith("zh") ? DICTS.zh : DICTS.en;
|
|
139
|
+
};
|
|
140
|
+
return (key, params) => {
|
|
141
|
+
let text;
|
|
142
|
+
if (bound !== null) {
|
|
143
|
+
try {
|
|
144
|
+
text = bound(key, params);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
text = void 0;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (typeof text !== "string" || text === key) {
|
|
150
|
+
const dict = fallback();
|
|
151
|
+
text = format(dict[key] !== void 0 ? dict[key] : DICTS.en[key], params);
|
|
152
|
+
}
|
|
153
|
+
return text;
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// src/client/page.js
|
|
158
|
+
var React2 = __toESM(require("react"), 1);
|
|
159
|
+
|
|
160
|
+
// src/client/api.js
|
|
161
|
+
var CONNECTION_PATH = "api/mcp-manager";
|
|
162
|
+
var PLAIN_PATH = "/plugin/mcp-manager";
|
|
163
|
+
var ApiError = class extends Error {
|
|
164
|
+
constructor(code, status) {
|
|
165
|
+
super(code);
|
|
166
|
+
this.name = "ApiError";
|
|
167
|
+
this.code = code;
|
|
168
|
+
this.status = status;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
function streamOrigin() {
|
|
172
|
+
const transport = globalThis.window && globalThis.window.__DSH_TRANSPORT__;
|
|
173
|
+
if (!transport || typeof transport.streamBaseUrl !== "string" || transport.streamBaseUrl === "") return void 0;
|
|
174
|
+
try {
|
|
175
|
+
const url = new URL(transport.streamBaseUrl, globalThis.location && globalThis.location.href);
|
|
176
|
+
return `${url.protocol === "wss:" ? "https:" : url.protocol === "ws:" ? "http:" : url.protocol}//${url.host}`;
|
|
177
|
+
} catch {
|
|
178
|
+
return void 0;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function documentBase() {
|
|
182
|
+
const location = globalThis.location;
|
|
183
|
+
if (!location || location.protocol !== "http:" && location.protocol !== "https:") return void 0;
|
|
184
|
+
return location.origin;
|
|
185
|
+
}
|
|
186
|
+
function candidatesFor(method) {
|
|
187
|
+
const urls = [];
|
|
188
|
+
if (method !== "POST") {
|
|
189
|
+
const stream = streamOrigin();
|
|
190
|
+
if (stream) urls.push(`${stream}${PLAIN_PATH}`);
|
|
191
|
+
const document2 = documentBase();
|
|
192
|
+
if (document2) urls.push(`${document2}${PLAIN_PATH}`);
|
|
193
|
+
}
|
|
194
|
+
urls.push(CONNECTION_PATH);
|
|
195
|
+
if (method === "POST") {
|
|
196
|
+
const document2 = documentBase();
|
|
197
|
+
if (document2) urls.push(`${document2}${PLAIN_PATH}`);
|
|
198
|
+
}
|
|
199
|
+
return urls.filter((value, index) => urls.indexOf(value) === index);
|
|
200
|
+
}
|
|
201
|
+
function isResult(payload) {
|
|
202
|
+
return Boolean(payload) && typeof payload === "object" && typeof payload.ok === "boolean";
|
|
203
|
+
}
|
|
204
|
+
async function request(input) {
|
|
205
|
+
const method = input.method || "GET";
|
|
206
|
+
const fetchImpl = input.fetchImpl || globalThis.fetch;
|
|
207
|
+
const headers = { accept: "application/json" };
|
|
208
|
+
let body;
|
|
209
|
+
if (input.body !== void 0) {
|
|
210
|
+
headers["content-type"] = "application/json";
|
|
211
|
+
headers["x-dsh-mcp-manager"] = "1";
|
|
212
|
+
body = JSON.stringify(input.body);
|
|
213
|
+
}
|
|
214
|
+
let lastCode = "network";
|
|
215
|
+
for (const url of candidatesFor(method)) {
|
|
216
|
+
let response;
|
|
217
|
+
try {
|
|
218
|
+
response = await fetchImpl(url, {
|
|
219
|
+
method,
|
|
220
|
+
headers,
|
|
221
|
+
body,
|
|
222
|
+
cache: "no-store",
|
|
223
|
+
credentials: "same-origin",
|
|
224
|
+
signal: input.signal
|
|
225
|
+
});
|
|
226
|
+
} catch (error) {
|
|
227
|
+
if (error && error.name === "AbortError") throw new ApiError("aborted", 0);
|
|
228
|
+
lastCode = "network";
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
let payload;
|
|
232
|
+
try {
|
|
233
|
+
payload = await response.json();
|
|
234
|
+
} catch {
|
|
235
|
+
payload = void 0;
|
|
236
|
+
}
|
|
237
|
+
if (isResult(payload)) return { status: response.status, payload };
|
|
238
|
+
if (response.status === 401 || response.status === 403) {
|
|
239
|
+
lastCode = "unauthorized";
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
if (response.status === 404) {
|
|
243
|
+
lastCode = "network";
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
lastCode = "network";
|
|
247
|
+
}
|
|
248
|
+
throw new ApiError(lastCode, 0);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// src/client/controller.js
|
|
252
|
+
var POLL_DELAY_MS = 2e3;
|
|
253
|
+
var READ_TIMEOUT_MS = 8e3;
|
|
254
|
+
function createController(options = {}) {
|
|
255
|
+
const fetchImpl = options.fetchImpl;
|
|
256
|
+
let snapshot = {
|
|
257
|
+
status: "idle",
|
|
258
|
+
state: null,
|
|
259
|
+
error: null,
|
|
260
|
+
busy: false,
|
|
261
|
+
action: null
|
|
262
|
+
};
|
|
263
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
264
|
+
let generation = 0;
|
|
265
|
+
let pollTimer;
|
|
266
|
+
let polling;
|
|
267
|
+
let disposed = false;
|
|
268
|
+
function publish(patch) {
|
|
269
|
+
if (disposed) return;
|
|
270
|
+
snapshot = { ...snapshot, ...patch };
|
|
271
|
+
for (const listener of listeners) listener();
|
|
272
|
+
}
|
|
273
|
+
function subscribe(listener) {
|
|
274
|
+
listeners.add(listener);
|
|
275
|
+
return () => {
|
|
276
|
+
listeners.delete(listener);
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
function getSnapshot() {
|
|
280
|
+
return snapshot;
|
|
281
|
+
}
|
|
282
|
+
function failure(error) {
|
|
283
|
+
if (error instanceof ApiError) return { code: error.code };
|
|
284
|
+
return { code: "network" };
|
|
285
|
+
}
|
|
286
|
+
async function load(lifecycleSignal) {
|
|
287
|
+
if (disposed) return;
|
|
288
|
+
const current = ++generation;
|
|
289
|
+
if (snapshot.status === "idle") publish({ status: "loading" });
|
|
290
|
+
const timeout = AbortSignal.timeout(READ_TIMEOUT_MS);
|
|
291
|
+
const signal = lifecycleSignal ? AbortSignal.any([lifecycleSignal, timeout]) : timeout;
|
|
292
|
+
try {
|
|
293
|
+
const { payload } = await request({ method: "GET", fetchImpl, signal });
|
|
294
|
+
if (current !== generation || disposed) return;
|
|
295
|
+
if (payload.ok === true) {
|
|
296
|
+
publish({ status: "ready", state: payload, error: null });
|
|
297
|
+
} else {
|
|
298
|
+
publish({
|
|
299
|
+
status: snapshot.state === null ? "error" : "ready",
|
|
300
|
+
error: { code: payload.code || "internal", params: payload.params }
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
} catch (error) {
|
|
304
|
+
if (current !== generation || disposed) return;
|
|
305
|
+
publish({ status: snapshot.state === null ? "error" : "ready", error: failure(error) });
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
function start() {
|
|
309
|
+
if (polling || disposed) return;
|
|
310
|
+
const session = new AbortController();
|
|
311
|
+
polling = session;
|
|
312
|
+
async function poll() {
|
|
313
|
+
if (!snapshot.busy) await load(session.signal);
|
|
314
|
+
if (!session.signal.aborted) pollTimer = setTimeout(poll, POLL_DELAY_MS);
|
|
315
|
+
}
|
|
316
|
+
void poll();
|
|
317
|
+
}
|
|
318
|
+
async function setEnabled(target, enabled) {
|
|
319
|
+
if (snapshot.busy) return { ok: false, code: "locked" };
|
|
320
|
+
const action = { id: target.id, name: target.name };
|
|
321
|
+
generation += 1;
|
|
322
|
+
publish({ busy: true, action });
|
|
323
|
+
try {
|
|
324
|
+
const { payload } = await request({
|
|
325
|
+
method: "POST",
|
|
326
|
+
fetchImpl,
|
|
327
|
+
body: { action: "setEnabled", id: target.id, name: target.name, rowHash: target.rowHash, enabled }
|
|
328
|
+
});
|
|
329
|
+
if (payload.ok === true) {
|
|
330
|
+
publish({ busy: false, action: null, status: "ready", state: payload, error: null });
|
|
331
|
+
return { ok: true };
|
|
332
|
+
}
|
|
333
|
+
if (payload.code === "conflict" || payload.code === "not-found") await load();
|
|
334
|
+
const error = { code: payload.code, params: payload.params };
|
|
335
|
+
publish({ busy: false, action: { ...action, error } });
|
|
336
|
+
return { ok: false, ...error };
|
|
337
|
+
} catch (error) {
|
|
338
|
+
const details = failure(error);
|
|
339
|
+
publish({ busy: false, action: { ...action, error: details } });
|
|
340
|
+
return { ok: false, ...details };
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
function stop() {
|
|
344
|
+
generation += 1;
|
|
345
|
+
polling?.abort();
|
|
346
|
+
polling = void 0;
|
|
347
|
+
clearTimeout(pollTimer);
|
|
348
|
+
pollTimer = void 0;
|
|
349
|
+
}
|
|
350
|
+
function dispose() {
|
|
351
|
+
disposed = true;
|
|
352
|
+
stop();
|
|
353
|
+
listeners.clear();
|
|
354
|
+
}
|
|
355
|
+
return { subscribe, getSnapshot, load, setEnabled, start, stop, dispose };
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/client/row.js
|
|
359
|
+
var React = __toESM(require("react"), 1);
|
|
360
|
+
|
|
361
|
+
// src/client/model.js
|
|
362
|
+
function serverLabel(server, translate) {
|
|
363
|
+
if (server && typeof server.name === "string" && server.name !== "") return server.name;
|
|
364
|
+
if (server && typeof server.id === "string" && server.id !== "") return server.id;
|
|
365
|
+
return translate("unknownName");
|
|
366
|
+
}
|
|
367
|
+
function transportLabel(server, translate) {
|
|
368
|
+
if (server && server.transport === "stdio") return translate("transportStdio");
|
|
369
|
+
if (server && server.transport === "streamable-http") return translate("transportHttp");
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// src/client/row.js
|
|
374
|
+
var h = React.createElement;
|
|
375
|
+
var READ_ONLY_KEYS = {
|
|
376
|
+
"not-insert": "readOnlyNotInsert",
|
|
377
|
+
"block-shape": "readOnlyBlockShape",
|
|
378
|
+
"row-shape": "readOnlyRowShape",
|
|
379
|
+
"missing-id": "readOnlyMissingId",
|
|
380
|
+
"duplicate-id": "readOnlyDuplicateId",
|
|
381
|
+
"conditional-disabled": "readOnlyConditional",
|
|
382
|
+
"missing-name": "readOnlyMissingName",
|
|
383
|
+
"config-invalid": "readOnlyConfig",
|
|
384
|
+
"config-enabled": "readOnlyConfigEnabled"
|
|
385
|
+
};
|
|
386
|
+
function ServerRow({ server, translate, busy, saving, failure, Switch: Switch2, Tag: Tag2, onToggle }) {
|
|
387
|
+
const name = serverLabel(server, translate);
|
|
388
|
+
const readOnlyText = server.editable ? null : translate(READ_ONLY_KEYS[server.readOnlyCode] || "readOnlyConfig");
|
|
389
|
+
const canToggle = server.editable && server.enabled !== null;
|
|
390
|
+
return h(
|
|
391
|
+
"li",
|
|
392
|
+
{ className: "dshmcp_row" },
|
|
393
|
+
h(
|
|
394
|
+
"span",
|
|
395
|
+
{ className: "dshmcp_identity" },
|
|
396
|
+
h("span", { className: "dshmcp_name" }, name),
|
|
397
|
+
server.duplicate ? h(
|
|
398
|
+
"span",
|
|
399
|
+
{ title: translate("duplicateHint") },
|
|
400
|
+
h(Tag2, { tone: "warning" }, translate("duplicate"))
|
|
401
|
+
) : null,
|
|
402
|
+
readOnlyText ? h(Tag2, { tone: "neutral" }, translate("readOnly")) : null
|
|
403
|
+
),
|
|
404
|
+
h("span", { className: "dshmcp_transport" }, transportLabel(server, translate)),
|
|
405
|
+
canToggle ? h(Switch2, {
|
|
406
|
+
className: "dshmcp_switch",
|
|
407
|
+
checked: server.enabled === true,
|
|
408
|
+
label: translate("switchLabel", { name }),
|
|
409
|
+
disabled: Boolean(busy),
|
|
410
|
+
onChange: (enabled) => onToggle(server, enabled)
|
|
411
|
+
}) : null,
|
|
412
|
+
saving ? h("p", { className: "dshmcp_reason", role: "status" }, translate("saving")) : null,
|
|
413
|
+
failure ? h("p", { className: "dshmcp_reason dshmcp_notice_error", role: "alert" }, failure) : null,
|
|
414
|
+
readOnlyText ? h("span", { className: "dshmcp_reason" }, readOnlyText) : null
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// src/client/page.js
|
|
419
|
+
var h2 = React2.createElement;
|
|
420
|
+
var CODE_KEYS = {
|
|
421
|
+
conflict: "conflict",
|
|
422
|
+
locked: "locked",
|
|
423
|
+
"profile-unavailable": "profileUnavailable",
|
|
424
|
+
network: "network",
|
|
425
|
+
unauthorized: "unauthorized",
|
|
426
|
+
"read-only": "readOnlyFailure",
|
|
427
|
+
"not-found": "conflict",
|
|
428
|
+
"parse-failed": "loadFailed",
|
|
429
|
+
"verify-failed": "internal",
|
|
430
|
+
"write-failed": "internal",
|
|
431
|
+
invalid: "invalid",
|
|
432
|
+
internal: "internal"
|
|
433
|
+
};
|
|
434
|
+
function failureText(translate, failure) {
|
|
435
|
+
const key = CODE_KEYS[failure && failure.code || "internal"] || "internal";
|
|
436
|
+
return translate(key, failure && failure.params ? failure.params : void 0);
|
|
437
|
+
}
|
|
438
|
+
function Notice({ children }) {
|
|
439
|
+
return h2("p", { className: "dshmcp_notice dshmcp_notice_error", role: "alert" }, children);
|
|
440
|
+
}
|
|
441
|
+
function Skeleton() {
|
|
442
|
+
return h2(
|
|
443
|
+
"div",
|
|
444
|
+
{ className: "dshmcp_rows", "aria-hidden": true },
|
|
445
|
+
h2(
|
|
446
|
+
"div",
|
|
447
|
+
{ className: "dshmcp_skeletonRow" },
|
|
448
|
+
h2("span", { className: "dshmcp_skeletonLine", "data-w": "34" })
|
|
449
|
+
),
|
|
450
|
+
h2(
|
|
451
|
+
"div",
|
|
452
|
+
{ className: "dshmcp_skeletonRow" },
|
|
453
|
+
h2("span", { className: "dshmcp_skeletonLine", "data-w": "46" })
|
|
454
|
+
)
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
var Boundary = class extends React2.Component {
|
|
458
|
+
constructor(props) {
|
|
459
|
+
super(props);
|
|
460
|
+
this.state = { failed: false };
|
|
461
|
+
}
|
|
462
|
+
static getDerivedStateFromError() {
|
|
463
|
+
return { failed: true };
|
|
464
|
+
}
|
|
465
|
+
render() {
|
|
466
|
+
if (this.state.failed) return h2("p", { className: "dshmcp_notice dshmcp_notice_error" }, this.props.fallback);
|
|
467
|
+
return this.props.children;
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
function createPage(options) {
|
|
471
|
+
const { translate, subscribeLocale, localeVersion, Switch: Switch2, Tag: Tag2 } = options;
|
|
472
|
+
const createStore = options.createStore || createController;
|
|
473
|
+
function Page() {
|
|
474
|
+
const storeRef = React2.useRef(null);
|
|
475
|
+
if (storeRef.current === null) storeRef.current = createStore();
|
|
476
|
+
const store = storeRef.current;
|
|
477
|
+
const snapshot = React2.useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
478
|
+
React2.useSyncExternalStore(subscribeLocale, localeVersion, localeVersion);
|
|
479
|
+
const servers = snapshot.state && Array.isArray(snapshot.state.servers) ? snapshot.state.servers : [];
|
|
480
|
+
const { busy, action } = snapshot;
|
|
481
|
+
const loading = snapshot.state === null && snapshot.status !== "error";
|
|
482
|
+
const loadFailure = snapshot.error ? failureText(translate, snapshot.error) : null;
|
|
483
|
+
const actionServer = action && servers.find((server) => server.id === action.id && server.name === action.name);
|
|
484
|
+
const actionFailureText = action?.error ? failureText(translate, action.error) : null;
|
|
485
|
+
React2.useEffect(() => {
|
|
486
|
+
store.start();
|
|
487
|
+
return () => store.stop();
|
|
488
|
+
}, [store]);
|
|
489
|
+
return h2(
|
|
490
|
+
"section",
|
|
491
|
+
{
|
|
492
|
+
className: "dshmcp_page",
|
|
493
|
+
"aria-labelledby": "dshmcp-title",
|
|
494
|
+
"aria-busy": loading ? "true" : void 0
|
|
495
|
+
},
|
|
496
|
+
h2("h2", { className: "dshmcp_title", id: "dshmcp-title" }, translate("title")),
|
|
497
|
+
loading ? h2(Skeleton) : null,
|
|
498
|
+
loadFailure && snapshot.state === null ? h2(
|
|
499
|
+
"div",
|
|
500
|
+
{ className: "dshmcp_group dshmcp_messagePanel", role: "alert" },
|
|
501
|
+
h2("p", { className: "dshmcp_messageTitle" }, translate("loadFailed")),
|
|
502
|
+
loadFailure === translate("loadFailed") ? null : h2("p", { className: "dshmcp_hint" }, loadFailure)
|
|
503
|
+
) : null,
|
|
504
|
+
snapshot.state !== null ? h2(
|
|
505
|
+
React2.Fragment,
|
|
506
|
+
null,
|
|
507
|
+
loadFailure ? h2(Notice, null, loadFailure) : null,
|
|
508
|
+
actionFailureText && !actionServer ? h2(Notice, null, action.name, " \u2014 ", actionFailureText) : null,
|
|
509
|
+
servers.length > 0 ? h2(
|
|
510
|
+
"ul",
|
|
511
|
+
{ className: "dshmcp_rows", role: "list" },
|
|
512
|
+
servers.map((server, index) => h2(ServerRow, {
|
|
513
|
+
key: server.editable ? `service:${server.id}` : `readonly:${index}`,
|
|
514
|
+
server,
|
|
515
|
+
Switch: Switch2,
|
|
516
|
+
Tag: Tag2,
|
|
517
|
+
translate,
|
|
518
|
+
busy,
|
|
519
|
+
saving: busy && server === actionServer,
|
|
520
|
+
failure: server === actionServer ? actionFailureText : null,
|
|
521
|
+
onToggle: store.setEnabled
|
|
522
|
+
}))
|
|
523
|
+
) : h2(
|
|
524
|
+
"div",
|
|
525
|
+
{ className: "dshmcp_group dshmcp_messagePanel" },
|
|
526
|
+
h2("p", { className: "dshmcp_messageTitle" }, translate("emptyTitle"))
|
|
527
|
+
)
|
|
528
|
+
) : null
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
function SafePage() {
|
|
532
|
+
return h2(Boundary, { fallback: translate("internal") }, h2(Page));
|
|
533
|
+
}
|
|
534
|
+
SafePage.displayName = "McpManagerPage";
|
|
535
|
+
return SafePage;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// src/client/style.css
|
|
539
|
+
var style_default = "/* Match the host's settings typography, controls and surfaces. */\n\n.dshmcp_navIcon {\n display: inline-block;\n flex-shrink: 0;\n background-color: currentColor;\n mask-position: center;\n mask-repeat: no-repeat;\n mask-size: 150%;\n}\n\n.dshmcp_page {\n display: flex;\n flex-direction: column;\n gap: 16px;\n width: 100%;\n min-width: 0;\n padding-top: 16px;\n color: var(--dsw-alias-label-primary);\n font-size: 14px;\n line-height: 22px;\n}\n\n.dshmcp_title {\n min-width: 0;\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n overflow-wrap: anywhere;\n}\n\n.dshmcp_group {\n box-sizing: border-box;\n min-width: 0;\n margin: 0;\n border: 0.5px solid var(--dsw-alias-settings-card-stroke, var(--dsw-alias-border-l4));\n border-radius: var(--dsw-radius-xl);\n background: var(--dsw-alias-settings-card-fill, var(--dsw-alias-bg-layer-2));\n}\n\n.dshmcp_rows {\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.dshmcp_row,\n.dshmcp_skeletonRow {\n padding-block: 10px;\n}\n\n.dshmcp_row {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto minmax(36px, max-content);\n align-items: center;\n gap: 2px 12px;\n}\n\n.dshmcp_row + .dshmcp_row,\n.dshmcp_skeletonRow + .dshmcp_skeletonRow {\n border-top: 0.5px solid var(--dsw-alias-border-l3);\n}\n\n.dshmcp_identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 0 8px;\n min-width: 0;\n}\n\n.dshmcp_name {\n min-width: 0;\n font-weight: 500;\n overflow-wrap: anywhere;\n}\n\n.dshmcp_transport,\n.dshmcp_reason {\n margin: 0;\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n line-height: 18px;\n overflow-wrap: anywhere;\n}\n\n.dshmcp_transport {\n white-space: nowrap;\n}\n\n/* Composite the native off track over the same base surface as the Plugins page. */\n.dshmcp_switch[aria-checked='false'] {\n background-color: var(--dsw-alias-bg-base);\n background-image: linear-gradient(var(--dsw-alias-border-l3), var(--dsw-alias-border-l3));\n}\n\n.dshmcp_reason {\n grid-column: 1 / -1;\n}\n\n.dshmcp_notice,\n.dshmcp_hint {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n overflow-wrap: anywhere;\n}\n\n.dshmcp_notice_error {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.dshmcp_hint {\n color: var(--dsw-alias-label-tertiary);\n}\n\n.dshmcp_messagePanel {\n display: grid;\n justify-items: start;\n gap: 6px;\n padding: 16px;\n}\n\n.dshmcp_messageTitle {\n margin: 0;\n font-weight: 500;\n}\n\n.dshmcp_skeletonRow {\n display: grid;\n align-items: center;\n min-height: 22px;\n}\n\n.dshmcp_skeletonLine {\n display: block;\n height: 12px;\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-skeleton);\n}\n\n.dshmcp_skeletonLine[data-w='34'] { width: 34%; }\n.dshmcp_skeletonLine[data-w='46'] { width: 46%; }\n\n@media (prefers-reduced-motion: no-preference) {\n .dshmcp_skeletonLine {\n animation: dshmcp-pulse 1.6s ease-in-out infinite;\n }\n}\n\n@keyframes dshmcp-pulse {\n 50% { opacity: 0.55; }\n}\n";
|
|
540
|
+
|
|
541
|
+
// src/client/index.js
|
|
542
|
+
var h3 = React3.createElement;
|
|
543
|
+
function McpIcon({ size = 18, active = false } = {}) {
|
|
544
|
+
return h3("span", {
|
|
545
|
+
className: "dshmcp_navIcon",
|
|
546
|
+
"aria-hidden": true,
|
|
547
|
+
"data-active": active ? "true" : void 0,
|
|
548
|
+
style: { width: size, height: size, maskImage: `url(${JSON.stringify(icon_default)})` }
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
var inject = ["slots", "locale"];
|
|
552
|
+
function apply(ctx) {
|
|
553
|
+
registerLocale(ctx);
|
|
554
|
+
ctx.effect(() => {
|
|
555
|
+
const tag = document.createElement("style");
|
|
556
|
+
tag.dataset.plugin = "@dawn0608/dsh-mcp-manager";
|
|
557
|
+
tag.textContent = style_default;
|
|
558
|
+
document.head.appendChild(tag);
|
|
559
|
+
return () => {
|
|
560
|
+
tag.remove();
|
|
561
|
+
};
|
|
562
|
+
}, "mcp-manager: styles");
|
|
563
|
+
const translate = createTranslator(ctx);
|
|
564
|
+
const subscribeLocale = (listener) => ctx.locale.subscribe(listener);
|
|
565
|
+
const localeVersion = () => {
|
|
566
|
+
try {
|
|
567
|
+
const snapshot = ctx.locale.getSnapshot();
|
|
568
|
+
return typeof snapshot.revision === "number" ? snapshot.revision : 0;
|
|
569
|
+
} catch (error) {
|
|
570
|
+
return 0;
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
const Page = createPage({ translate, subscribeLocale, localeVersion, Switch: import_dsh_client_ui_primitives.Switch, Tag: import_dsh_client_ui_primitives.Tag });
|
|
574
|
+
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
575
|
+
name: "settings.section",
|
|
576
|
+
id: "mcp-manager",
|
|
577
|
+
order: 17,
|
|
578
|
+
label: () => translate("title")
|
|
579
|
+
}, Page));
|
|
580
|
+
ctx.slots.inject("settings.section.icon", () => ctx.slots.register({
|
|
581
|
+
name: "settings.section.icon",
|
|
582
|
+
id: "mcp-manager",
|
|
583
|
+
order: 17
|
|
584
|
+
}, McpIcon));
|
|
585
|
+
}
|
|
586
|
+
Object.defineProperty(module.exports, Symbol.toStringTag, { value: "Module" });
|
|
587
|
+
return module.exports;
|
|
588
|
+
},
|
|
589
|
+
});
|
|
590
|
+
//# sourceMappingURL=client.js.map
|