dsh-plugin-capabilities 0.3.7 → 0.3.9
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 +4 -2
- package/lib/client.js +158 -32
- package/lib/client.js.map +2 -2
- package/lib/index.js +245 -38
- package/lib/index.js.map +2 -2
- package/package.json +1 -1
- package/src/agents.test.ts +47 -1
- package/src/agents.ts +59 -8
- package/src/client/MarketTab.tsx +23 -7
- package/src/client/McpTab.tsx +128 -23
- package/src/client/index.ts +12 -8
- package/src/client/locales.ts +30 -8
- package/src/index.ts +2 -1
- package/src/mcp.test.ts +135 -2
- package/src/mcp.ts +156 -18
- package/src/profile.ts +6 -2
- package/src/routes.ts +116 -26
package/README.md
CHANGED
|
@@ -27,9 +27,11 @@
|
|
|
27
27
|
|
|
28
28
|
「MCP」页管理 profile patch 中的 MCP 服务器行,每行对应一个 `@deepseek-ai/dsh-mcp-client` 实例。stdio 服务器填写命令与参数,streamable-http 服务器填写 URL,编辑、停用、移除都在页面上完成。YAML 读写采用文档级 API,文件中的其他行与注释不受影响。新行写在一个 `- insert:` 块里——加载器只会挂载 insert 形式的行,裸的 `- id:` 条目是对已有行的覆盖,目标不存在时会被跳过;0.1.3 之前写入的裸行会在下一次保存时自动迁入 insert 块。0.3.7 起,若 `cordis.patch.yml` 本身存在语法错误(多见于手工编辑失误),页面会直接报出文件完整路径与出错行列,并且不写入任何内容;此前这种文件会在保存时抛出内部的 "Document with errors cannot be stringified",让人无从下手。
|
|
29
29
|
|
|
30
|
+
服务器行不只存在于 profile 里。dsh 还有一层全局补丁(`DSH_HOME/cordis.patch.yml`),对这台机器上的所有 profile 生效,组合时排在 profile 层之后、同名 id 以全局为准。0.3.8 起,「MCP」页把两层合在一起展示:每行带「全局」或「当前 profile」标记,两层出现同名 id 时 profile 行会注明自己不生效。添加服务器时可以选择写入哪一层,编辑、停用、移除也都落在该行所在的层。每行还有「检查」和「复制到另一层」两个动作:检查不启动服务器——stdio 行在 PATH 里确认命令真实存在(带 Windows 可执行扩展名),http 行发一个短超时的 GET,任何 HTTP 状态都算可达(MCP 端点对普通 GET 回 405 是正常的);复制把整行配置搬去另一层,不用删了重配。全局文件损坏不会连累整个页面:profile 行照常列出,顶部横幅单独报出全局文件的路径与出错行列。
|
|
31
|
+
|
|
30
32
|
添加或编辑服务器时,表单下方有「完整格式与快速填充」区:一边是随表单实时更新的完整 YAML 行(和保存后落进 `cordis.patch.yml` 的一模一样),另一边是等价的 `mcpServers` JSON 写法,可以直接抄去别的工具。反过来也行——把 Claude Code 配置、官方文档或任意 JSON 粘进输入框,点「解析并填充」,服务器名、命令、参数、环境变量、URL、请求头都会自动填好,`{"mcpServers": {...}}` 包装、裸条目、dsh 行三种形状都认。
|
|
31
33
|
|
|
32
|
-
也可以从其他 agent 导入:一键扫描 Claude Code(`~/.claude.json`、`~/.claude/settings.json
|
|
34
|
+
也可以从其他 agent 导入:一键扫描 Claude Code(`~/.claude.json`、`~/.claude/settings.json`)、Codex(`~/.codex/config.toml`)、Cursor(`~/.cursor/mcp.json`)与 Gemini CLI(`~/.gemini/settings.json`)的 MCP 配置,弹窗里先选写入当前 profile 还是全局层,勾选所需条目后转成服务器行。弹窗按来源分组,各自带数量与「全选」;stdio 与 http 两种传输都会处理(Gemini 的 SSE 条目除外,dsh 的客户端不支持),已存在的同名服务器置灰跳过。需要注意的是,Claude 配置里的 `${VAR}` 环境变量引用按字面值导入,如有需要请在导入后手动改回。
|
|
33
35
|
|
|
34
36
|
MCP 行的变更需要重启 dsh 才会进入组合。MCP 页头部有常驻的「重启」按钮,变更后无需离开界面:在 [DSH Desktop](https://github.com/qinyre/dsh-Desktop) 中由桌面壳层重启受监督的 sidecar,完成后窗口自动重载;直接运行 `dsh web` 时插件会拉起一个替代进程再退出自身,页面在恢复后自动刷新——若启动时端口是随机的,按横幅提示在终端查看新地址。重启会中断正在进行的回合,点击后会先弹出确认。
|
|
35
37
|
|
|
@@ -39,7 +41,7 @@ MCP 行的变更需要重启 dsh 才会进入组合。MCP 页头部有常驻的
|
|
|
39
41
|
|
|
40
42
|

|
|
41
43
|
|
|
42
|
-
「市场」页分两栏:「技能市场」是精选的技能仓库(Anthropic 官方技能集、Superpowers 工作流集等),点「安装」走的就是上文 GitHub 仓库的下载解包流程,装完立即出现在「技能」页;「MCP 市场」是一份精选服务器列表(官方 filesystem/memory/git 等,加上 context7
|
|
44
|
+
「市场」页分两栏:「技能市场」是精选的技能仓库(Anthropic 官方技能集、Superpowers 工作流集等),点「安装」走的就是上文 GitHub 仓库的下载解包流程,装完立即出现在「技能」页;「MCP 市场」是一份精选服务器列表(官方 filesystem/memory/git 等,加上 context7 这类常用第三方),点「添加」直接写入一条服务器行,和手工添加完全等价,写入哪一层(当前 profile 还是全局)跟随列表上方的生效范围选择。0.3.0 起点开条目可以看详情:技能仓库列出里面具体有哪些技能,MCP 服务器列出启动命令、需要的环境变量和提供的工具,不必再去 GitHub 主页。列表数据来自[本插件仓库](https://github.com/qinyre/dsh-plugin-capabilities)的在线索引(`market/*.json`),离线时自动回退到包内快照;需要 API 密钥的服务器会在卡片上标出环境变量名,装好后到 MCP 列表里补填即可。已安装的条目可以直接卸载:技能仓库走仓库移除,MCP 行走服务器删除(该行在全局层就删全局层的)。
|
|
43
45
|
|
|
44
46
|
## 安装
|
|
45
47
|
|
package/lib/client.js
CHANGED
|
@@ -187,6 +187,7 @@ function MarketTab(props) {
|
|
|
187
187
|
const [servers, setServers] = (0, import_react.useState)(null);
|
|
188
188
|
const [source, setSource] = (0, import_react.useState)("remote");
|
|
189
189
|
const [busyId, setBusyId] = (0, import_react.useState)(null);
|
|
190
|
+
const [mcpScope, setMcpScope] = (0, import_react.useState)("profile");
|
|
190
191
|
const [outcome, setOutcome] = (0, import_react.useState)(null);
|
|
191
192
|
const [confirmUninstall, setConfirmUninstall] = (0, import_react.useState)(null);
|
|
192
193
|
const [detail, setDetail] = (0, import_react.useState)(null);
|
|
@@ -239,7 +240,7 @@ function MarketTab(props) {
|
|
|
239
240
|
setBusyId(server.id);
|
|
240
241
|
setOutcome(null);
|
|
241
242
|
try {
|
|
242
|
-
await market.installMcp(server.id);
|
|
243
|
+
await market.installMcp(server.id, mcpScope);
|
|
243
244
|
setOutcome({ ok: true, text: t("restartNeeded") });
|
|
244
245
|
refreshMcp();
|
|
245
246
|
} catch (error) {
|
|
@@ -259,7 +260,7 @@ function MarketTab(props) {
|
|
|
259
260
|
setOutcome({ ok: true, text: t("rootRemoved") });
|
|
260
261
|
refreshSkills();
|
|
261
262
|
} else {
|
|
262
|
-
await mcp.remove(target.id);
|
|
263
|
+
await mcp.remove(target.id, target.scope);
|
|
263
264
|
setOutcome({ ok: true, text: t("restartNeeded") });
|
|
264
265
|
refreshMcp();
|
|
265
266
|
}
|
|
@@ -326,6 +327,23 @@ function MarketTab(props) {
|
|
|
326
327
|
] }),
|
|
327
328
|
segment === "mcp" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
328
329
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dpc-intro", children: t("marketMcpIntro") }),
|
|
330
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dpc-cardRow", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: { display: "inline-flex", alignItems: "center", gap: 8 }, children: [
|
|
331
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: t("scopeLabel") }),
|
|
332
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
333
|
+
"select",
|
|
334
|
+
{
|
|
335
|
+
className: "dpc-select",
|
|
336
|
+
style: { width: "auto" },
|
|
337
|
+
value: mcpScope,
|
|
338
|
+
disabled: busyId !== null,
|
|
339
|
+
onChange: (event) => setMcpScope(event.target.value),
|
|
340
|
+
children: [
|
|
341
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "profile", children: t("scopeProfile") }),
|
|
342
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "global", children: t("scopeGlobal") })
|
|
343
|
+
]
|
|
344
|
+
}
|
|
345
|
+
)
|
|
346
|
+
] }) }),
|
|
329
347
|
servers === null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dpc-empty", children: t("loading") }),
|
|
330
348
|
servers !== null && servers.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dpc-empty", children: t("marketEmpty") }),
|
|
331
349
|
servers !== null && servers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "dpc-cards", children: servers.map((server) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "dpc-card", onClick: () => setDetail({ kind: "mcp", id: server.id }), children: [
|
|
@@ -350,7 +368,7 @@ function MarketTab(props) {
|
|
|
350
368
|
void mcp.list().then(
|
|
351
369
|
(body) => {
|
|
352
370
|
const row = body.servers.find((item) => item.serverName === server.id);
|
|
353
|
-
if (row !== void 0) setConfirmUninstall({ kind: "mcp", id: row.id, name: server.id });
|
|
371
|
+
if (row !== void 0) setConfirmUninstall({ kind: "mcp", id: row.id, name: server.id, scope: row.scope });
|
|
354
372
|
},
|
|
355
373
|
(error) => setOutcome({ ok: false, text: `${t("failed")}: ${String(error.message ?? error)}` })
|
|
356
374
|
);
|
|
@@ -382,7 +400,7 @@ function MarketTab(props) {
|
|
|
382
400
|
(body) => {
|
|
383
401
|
const row = body.servers.find((item) => item.serverName === detailServer.id);
|
|
384
402
|
if (row !== void 0) {
|
|
385
|
-
setConfirmUninstall({ kind: "mcp", id: row.id, name: title(detailServer) });
|
|
403
|
+
setConfirmUninstall({ kind: "mcp", id: row.id, name: title(detailServer), scope: row.scope });
|
|
386
404
|
setDetail(null);
|
|
387
405
|
}
|
|
388
406
|
},
|
|
@@ -454,8 +472,8 @@ var import_react2 = require("react");
|
|
|
454
472
|
var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
455
473
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
456
474
|
function importGroups(items) {
|
|
457
|
-
const label = (agent) => agent === "claude-code" ? "Claude Code" : agent === "codex" ? "Codex" : agent;
|
|
458
|
-
const order = ["claude-code", "codex"];
|
|
475
|
+
const label = (agent) => agent === "claude-code" ? "Claude Code" : agent === "codex" ? "Codex" : agent === "cursor" ? "Cursor" : agent === "gemini" ? "Gemini CLI" : agent;
|
|
476
|
+
const order = ["claude-code", "codex", "cursor", "gemini"];
|
|
459
477
|
const agents = [...new Set(items.map((item) => item.server.agent))].sort((a, b2) => {
|
|
460
478
|
const rank = (agent) => {
|
|
461
479
|
const at2 = order.indexOf(agent);
|
|
@@ -582,7 +600,8 @@ function McpTab(props) {
|
|
|
582
600
|
const { t, injected } = props;
|
|
583
601
|
const [servers, setServers] = (0, import_react2.useState)(null);
|
|
584
602
|
const [editor, setEditor] = (0, import_react2.useState)(null);
|
|
585
|
-
const [
|
|
603
|
+
const [confirmRow, setConfirmRow] = (0, import_react2.useState)(null);
|
|
604
|
+
const [globalError, setGlobalError] = (0, import_react2.useState)(null);
|
|
586
605
|
const [importOpen, setImportOpen] = (0, import_react2.useState)(false);
|
|
587
606
|
const [importItems, setImportItems] = (0, import_react2.useState)(null);
|
|
588
607
|
const [busy, setBusy] = (0, import_react2.useState)(false);
|
|
@@ -594,6 +613,8 @@ function McpTab(props) {
|
|
|
594
613
|
const [reload, setReload] = (0, import_react2.useState)(0);
|
|
595
614
|
const [pasteJson, setPasteJson] = (0, import_react2.useState)("");
|
|
596
615
|
const [pasteError, setPasteError] = (0, import_react2.useState)(null);
|
|
616
|
+
const [checks, setChecks] = (0, import_react2.useState)({});
|
|
617
|
+
const [importScope, setImportScope] = (0, import_react2.useState)("profile");
|
|
597
618
|
const openImport = async () => {
|
|
598
619
|
setImportOpen(true);
|
|
599
620
|
setImportItems(null);
|
|
@@ -615,7 +636,7 @@ function McpTab(props) {
|
|
|
615
636
|
const items = importItems.filter((item) => item.checked && !item.existing).map((item) => ({ agent: item.server.agent, name: item.server.name }));
|
|
616
637
|
setBusy(true);
|
|
617
638
|
try {
|
|
618
|
-
const body = await injected.applyImport(items);
|
|
639
|
+
const body = await injected.applyImport(items, importScope);
|
|
619
640
|
const failed = body.results.filter((item) => !item.ok);
|
|
620
641
|
setOutcome(failed.length === 0 ? { ok: true, text: t("restartNeeded") } : { ok: false, text: `${t("failed")}: ${failed.map((item) => `${item.name} (${item.error})`).join(", ")}` });
|
|
621
642
|
setImportOpen(false);
|
|
@@ -635,7 +656,9 @@ function McpTab(props) {
|
|
|
635
656
|
let current = true;
|
|
636
657
|
void injected.list().then(
|
|
637
658
|
(body) => {
|
|
638
|
-
if (current)
|
|
659
|
+
if (!current) return;
|
|
660
|
+
setServers(body.servers);
|
|
661
|
+
setGlobalError(body.globalError ?? null);
|
|
639
662
|
},
|
|
640
663
|
(error) => {
|
|
641
664
|
if (current) {
|
|
@@ -652,7 +675,7 @@ function McpTab(props) {
|
|
|
652
675
|
setFormError(null);
|
|
653
676
|
setPasteError(null);
|
|
654
677
|
setPasteJson("");
|
|
655
|
-
setEditor({ id: "", serverName: "", transport: "stdio", command: "", args: "", env: "", url: "", headers: "" });
|
|
678
|
+
setEditor({ id: "", scope: "profile", serverName: "", transport: "stdio", command: "", args: "", env: "", url: "", headers: "" });
|
|
656
679
|
};
|
|
657
680
|
const openEdit = (row) => {
|
|
658
681
|
setFormError(null);
|
|
@@ -660,6 +683,7 @@ function McpTab(props) {
|
|
|
660
683
|
setPasteJson("");
|
|
661
684
|
setEditor({
|
|
662
685
|
id: row.id,
|
|
686
|
+
scope: row.scope,
|
|
663
687
|
serverName: row.serverName,
|
|
664
688
|
transport: row.transport,
|
|
665
689
|
command: row.command ?? "",
|
|
@@ -704,6 +728,7 @@ function McpTab(props) {
|
|
|
704
728
|
try {
|
|
705
729
|
await injected.save({
|
|
706
730
|
id: editor.id,
|
|
731
|
+
scope: editor.scope,
|
|
707
732
|
serverName: editor.serverName.trim(),
|
|
708
733
|
transport: editor.transport,
|
|
709
734
|
...editor.transport === "stdio" ? {
|
|
@@ -727,7 +752,7 @@ function McpTab(props) {
|
|
|
727
752
|
const doToggle = async (row) => {
|
|
728
753
|
setBusy(true);
|
|
729
754
|
try {
|
|
730
|
-
await injected.toggle(row.id, !row.disabled);
|
|
755
|
+
await injected.toggle(row.id, !row.disabled, row.scope);
|
|
731
756
|
setOutcome({ ok: true, text: t("restartNeeded") });
|
|
732
757
|
reloadList(true);
|
|
733
758
|
} catch (error) {
|
|
@@ -737,17 +762,40 @@ function McpTab(props) {
|
|
|
737
762
|
}
|
|
738
763
|
};
|
|
739
764
|
const doRemove = async () => {
|
|
740
|
-
if (
|
|
765
|
+
if (confirmRow === null) return;
|
|
766
|
+
setBusy(true);
|
|
767
|
+
try {
|
|
768
|
+
await injected.remove(confirmRow.id, confirmRow.scope);
|
|
769
|
+
setOutcome({ ok: true, text: t("restartNeeded") });
|
|
770
|
+
reloadList(true);
|
|
771
|
+
} catch (error) {
|
|
772
|
+
setOutcome({ ok: false, text: `${t("failed")}: ${String(error instanceof Error ? error.message : error)}` });
|
|
773
|
+
} finally {
|
|
774
|
+
setBusy(false);
|
|
775
|
+
setConfirmRow(null);
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
const doCheck = async (row) => {
|
|
779
|
+
const key = `${row.scope}/${row.id}`;
|
|
780
|
+
setChecks((current) => ({ ...current, [key]: "busy" }));
|
|
781
|
+
try {
|
|
782
|
+
const result = await injected.check(row.id, row.scope);
|
|
783
|
+
setChecks((current) => ({ ...current, [key]: result }));
|
|
784
|
+
} catch (error) {
|
|
785
|
+
setChecks((current) => ({ ...current, [key]: { ok: false, detail: String(error instanceof Error ? error.message : error) } }));
|
|
786
|
+
}
|
|
787
|
+
};
|
|
788
|
+
const doCopy = async (row) => {
|
|
741
789
|
setBusy(true);
|
|
742
790
|
try {
|
|
743
|
-
|
|
791
|
+
const toScope = row.scope === "global" ? "profile" : "global";
|
|
792
|
+
await injected.copy(row.id, row.scope, toScope);
|
|
744
793
|
setOutcome({ ok: true, text: t("restartNeeded") });
|
|
745
794
|
reloadList(true);
|
|
746
795
|
} catch (error) {
|
|
747
796
|
setOutcome({ ok: false, text: `${t("failed")}: ${String(error instanceof Error ? error.message : error)}` });
|
|
748
797
|
} finally {
|
|
749
798
|
setBusy(false);
|
|
750
|
-
setConfirmId(null);
|
|
751
799
|
}
|
|
752
800
|
};
|
|
753
801
|
const doRestart = () => {
|
|
@@ -797,6 +845,13 @@ function McpTab(props) {
|
|
|
797
845
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.StateDot, { state: outcome.ok ? "done" : "error", size: 10 }),
|
|
798
846
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dpc-bannerBody", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: outcome.text }) })
|
|
799
847
|
] }),
|
|
848
|
+
globalError !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dpc-banner", "data-kind": "error", role: "alert", children: [
|
|
849
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.StateDot, { state: "error", size: 10 }),
|
|
850
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dpc-bannerBody", children: [
|
|
851
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("globalLayerError") }),
|
|
852
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dpc-bannerHint", children: globalError })
|
|
853
|
+
] })
|
|
854
|
+
] }),
|
|
800
855
|
(pending || restarting) && restartBanner,
|
|
801
856
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dpc-listHead", children: [
|
|
802
857
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { children: t("mcpTab") }),
|
|
@@ -809,17 +864,30 @@ function McpTab(props) {
|
|
|
809
864
|
servers !== null && servers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { className: "dpc-cards", children: servers.map((row) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { className: "dpc-card", children: [
|
|
810
865
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dpc-cardTop", children: [
|
|
811
866
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { className: "dpc-cardTitle", title: row.id, children: row.serverName }),
|
|
867
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dpc-tag", "data-kind": row.scope === "global" ? "source" : void 0, children: row.scope === "global" ? t("scopeGlobal") : t("scopeProfile") }),
|
|
812
868
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dpc-tag", children: row.transport }),
|
|
813
869
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dpc-tag", "data-kind": row.disabled ? "off" : void 0, children: row.disabled ? t("disabled") : t("enabled") })
|
|
814
870
|
] }),
|
|
815
871
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "dpc-cardDesc", children: row.transport === "stdio" ? `${row.command ?? ""} ${(row.args ?? []).join(" ")}` : row.url ?? "" }),
|
|
872
|
+
row.shadowed === true && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "dpc-formError", children: t("shadowedByGlobal") }),
|
|
873
|
+
(() => {
|
|
874
|
+
const check = checks[`${row.scope}/${row.id}`];
|
|
875
|
+
if (check === void 0) return null;
|
|
876
|
+
if (check === "busy") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "dpc-cardDesc", children: t("checkRunning") });
|
|
877
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: check.ok ? "dpc-cardDesc" : "dpc-formError", children: [
|
|
878
|
+
check.ok ? `\u2713 ${t("checkOk")}` : `\u2717 ${t("checkFail")}`,
|
|
879
|
+
check.detail !== void 0 && ` \xB7 ${check.detail}`
|
|
880
|
+
] });
|
|
881
|
+
})(),
|
|
816
882
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dpc-cardRow", children: [
|
|
817
883
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dpc-spacer" }),
|
|
884
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "ghost", size: "sm", disabled: busy, onClick: () => void doCheck(row), children: t("checkLabel") }),
|
|
885
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "ghost", size: "sm", disabled: busy, onClick: () => void doCopy(row), children: t("copyToOther") }),
|
|
818
886
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "ghost", size: "sm", disabled: busy, onClick: () => void doToggle(row), children: t("toggle") }),
|
|
819
887
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "ghost", size: "sm", disabled: busy, onClick: () => openEdit(row), children: t("edit") }),
|
|
820
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "ghost", size: "sm", disabled: busy, onClick: () =>
|
|
888
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "ghost", size: "sm", disabled: busy, onClick: () => setConfirmRow(row), children: t("delete") })
|
|
821
889
|
] })
|
|
822
|
-
] }, row.id)) }),
|
|
890
|
+
] }, `${row.scope}/${row.id}`)) }),
|
|
823
891
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
824
892
|
import_dsh_client_ui_primitives2.Modal,
|
|
825
893
|
{
|
|
@@ -829,6 +897,23 @@ function McpTab(props) {
|
|
|
829
897
|
className: "dpc-modalForm",
|
|
830
898
|
contentClassName: "dpc-modalScroll",
|
|
831
899
|
children: editor !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dpc-form", children: [
|
|
900
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "dpc-label", children: [
|
|
901
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("scopeLabel") }),
|
|
902
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
903
|
+
"select",
|
|
904
|
+
{
|
|
905
|
+
className: "dpc-select",
|
|
906
|
+
value: editor.scope,
|
|
907
|
+
disabled: editor.id !== "",
|
|
908
|
+
onChange: (event) => setEditor({ ...editor, scope: event.target.value }),
|
|
909
|
+
children: [
|
|
910
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "profile", children: t("scopeProfile") }),
|
|
911
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "global", children: t("scopeGlobal") })
|
|
912
|
+
]
|
|
913
|
+
}
|
|
914
|
+
),
|
|
915
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dpc-formatHint", children: t("scopeHint") })
|
|
916
|
+
] }),
|
|
832
917
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "dpc-label", children: [
|
|
833
918
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("serverName") }),
|
|
834
919
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
@@ -927,12 +1012,12 @@ function McpTab(props) {
|
|
|
927
1012
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
928
1013
|
import_dsh_client_ui_primitives2.Modal,
|
|
929
1014
|
{
|
|
930
|
-
open:
|
|
931
|
-
onClose: () =>
|
|
1015
|
+
open: confirmRow !== null,
|
|
1016
|
+
onClose: () => setConfirmRow(null),
|
|
932
1017
|
title: t("confirmRemove"),
|
|
933
|
-
description:
|
|
1018
|
+
description: confirmRow?.serverName ?? void 0,
|
|
934
1019
|
footer: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
935
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "ghost", onClick: () =>
|
|
1020
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "ghost", onClick: () => setConfirmRow(null), children: t("cancel") }),
|
|
936
1021
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "primary", disabled: busy, onClick: () => void doRemove(), children: t("delete") })
|
|
937
1022
|
] }),
|
|
938
1023
|
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: t("removeWarn") })
|
|
@@ -960,6 +1045,23 @@ function McpTab(props) {
|
|
|
960
1045
|
className: "dpc-modalWide",
|
|
961
1046
|
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dpc-form", children: [
|
|
962
1047
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "dpc-intro", style: { margin: 0 }, children: t("importIntro") }),
|
|
1048
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dpc-cardRow", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { style: { display: "inline-flex", alignItems: "center", gap: 8 }, children: [
|
|
1049
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("scopeLabel") }),
|
|
1050
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1051
|
+
"select",
|
|
1052
|
+
{
|
|
1053
|
+
className: "dpc-select",
|
|
1054
|
+
style: { width: "auto" },
|
|
1055
|
+
value: importScope,
|
|
1056
|
+
disabled: busy,
|
|
1057
|
+
onChange: (event) => setImportScope(event.target.value),
|
|
1058
|
+
children: [
|
|
1059
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "profile", children: t("scopeProfile") }),
|
|
1060
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "global", children: t("scopeGlobal") })
|
|
1061
|
+
]
|
|
1062
|
+
}
|
|
1063
|
+
)
|
|
1064
|
+
] }) }),
|
|
963
1065
|
importItems === null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "dpc-empty", children: t("loading") }),
|
|
964
1066
|
importItems !== null && importItems.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "dpc-empty", children: t("importEmpty") }),
|
|
965
1067
|
importItems !== null && importItems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dpc-importScroll", children: importGroups(importItems).map((group) => {
|
|
@@ -4456,9 +4558,20 @@ var zh = {
|
|
|
4456
4558
|
confirmRemoveRoot: "\u786E\u8BA4\u79FB\u9664\u8BE5\u4ED3\u5E93\uFF1F",
|
|
4457
4559
|
removeRootWarn: "\u5C06\u53D6\u6D88\u626B\u63CF\u8BE5\u4ED3\u5E93\u5E76\u5220\u9664\u4E0B\u8F7D\u5230 DSH_HOME \u7684\u526F\u672C\uFF08\u672C\u5730\u76EE\u5F55\u672C\u8EAB\u4E0D\u53D7\u5F71\u54CD\uFF09\u3002",
|
|
4458
4560
|
mcpTitle: "MCP \u670D\u52A1\u5668",
|
|
4459
|
-
mcpIntro: "\u7BA1\u7406
|
|
4561
|
+
mcpIntro: "\u7BA1\u7406 MCP \u670D\u52A1\u5668\u884C\uFF08@deepseek-ai/dsh-mcp-client\uFF09\u3002\u670D\u52A1\u5668\u53EF\u653E\u5728 profile \u5C42\uFF08\u4EC5\u672C profile\uFF09\u6216\u5168\u5C40\u5C42\uFF08DSH_HOME/cordis.patch.yml\uFF0C\u5BF9\u672C\u673A\u6240\u6709 profile \u751F\u6548\uFF09\uFF1B\u65B0\u589E\u3001\u4FEE\u6539\u6216\u5220\u9664\u540E\u9700\u8981\u91CD\u542F dsh \u624D\u751F\u6548\u3002",
|
|
4460
4562
|
addServer: "\u6DFB\u52A0\u670D\u52A1\u5668",
|
|
4461
4563
|
editServer: "\u7F16\u8F91\u670D\u52A1\u5668",
|
|
4564
|
+
scopeLabel: "\u751F\u6548\u8303\u56F4",
|
|
4565
|
+
scopeGlobal: "\u5168\u5C40",
|
|
4566
|
+
scopeProfile: "\u5F53\u524D profile",
|
|
4567
|
+
scopeHint: "\u5168\u5C40\uFF1A\u5199\u5165 DSH_HOME/cordis.patch.yml\uFF0C\u5BF9\u672C\u673A\u6240\u6709 profile \u751F\u6548\uFF1B\u5F53\u524D profile\uFF1A\u53EA\u5F71\u54CD\u672C profile\u3002",
|
|
4568
|
+
shadowedByGlobal: "\u5168\u5C40\u5C42\u5B58\u5728\u540C\u540D id\uFF0C\u6B64\u884C\u4E0D\u751F\u6548",
|
|
4569
|
+
globalLayerError: "\u5168\u5C40\u914D\u7F6E\uFF08DSH_HOME/cordis.patch.yml\uFF09\u8BFB\u53D6\u5931\u8D25\uFF0C\u5168\u5C40\u670D\u52A1\u5668\u6682\u672A\u663E\u793A\uFF1A",
|
|
4570
|
+
checkLabel: "\u68C0\u67E5",
|
|
4571
|
+
checkRunning: "\u68C0\u67E5\u4E2D\u2026",
|
|
4572
|
+
checkOk: "\u68C0\u67E5\u901A\u8FC7",
|
|
4573
|
+
checkFail: "\u68C0\u67E5\u672A\u901A\u8FC7",
|
|
4574
|
+
copyToOther: "\u590D\u5236\u5230\u53E6\u4E00\u5C42",
|
|
4462
4575
|
serverName: "\u670D\u52A1\u5668\u540D\uFF08\u5DE5\u5177\u540D\u524D\u7F00\uFF09",
|
|
4463
4576
|
transport: "\u4F20\u8F93\u65B9\u5F0F",
|
|
4464
4577
|
transportStdio: "stdio\uFF08\u672C\u5730\u547D\u4EE4\uFF09",
|
|
@@ -4472,10 +4585,10 @@ var zh = {
|
|
|
4472
4585
|
enabled: "\u542F\u7528\u4E2D",
|
|
4473
4586
|
toggle: "\u505C\u7528/\u542F\u7528",
|
|
4474
4587
|
confirmRemove: "\u786E\u8BA4\u79FB\u9664\u8BE5\u670D\u52A1\u5668\uFF1F",
|
|
4475
|
-
removeWarn: "\u5C06\u4ECE
|
|
4588
|
+
removeWarn: "\u5C06\u4ECE\u914D\u7F6E\u4E2D\u79FB\u9664\u8FD9\u4E00\u884C\uFF0C\u91CD\u542F dsh \u540E\u5176\u5DE5\u5177\u4E0D\u518D\u51FA\u73B0\u3002",
|
|
4476
4589
|
emptyMcp: "\u8FD8\u6CA1\u6709\u914D\u7F6E MCP \u670D\u52A1\u5668",
|
|
4477
4590
|
importServers: "\u4ECE\u5176\u4ED6 Agent \u5BFC\u5165",
|
|
4478
|
-
importIntro: "\u626B\u63CF Claude Code\uFF08~/.claude.json\uFF09\
|
|
4591
|
+
importIntro: "\u626B\u63CF Claude Code\uFF08~/.claude.json\uFF09\u3001Codex\uFF08~/.codex/config.toml\uFF09\u3001Cursor\uFF08~/.cursor/mcp.json\uFF09\u4E0E Gemini CLI\uFF08~/.gemini/settings.json\uFF09\u7684 MCP \u670D\u52A1\u5668\u914D\u7F6E\uFF0C\u52FE\u9009\u540E\u5BFC\u5165\u5230\u6240\u9009\u8303\u56F4\u3002",
|
|
4479
4592
|
importEmpty: "\u6CA1\u6709\u53D1\u73B0\u53EF\u5BFC\u5165\u7684 MCP \u670D\u52A1\u5668",
|
|
4480
4593
|
importSelectAll: "\u5168\u9009",
|
|
4481
4594
|
importExisting: "\u5DF2\u5B58\u5728",
|
|
@@ -4501,7 +4614,7 @@ var zh = {
|
|
|
4501
4614
|
marketSkills: "\u6280\u80FD\u5E02\u573A",
|
|
4502
4615
|
marketMcp: "MCP \u5E02\u573A",
|
|
4503
4616
|
marketSkillsIntro: "\u5B89\u88C5\u6280\u80FD\u4ED3\u5E93\uFF08GitHub \u4E0B\u8F7D\u89E3\u5305\uFF0C\u5B9E\u65F6\u8FDB\u5165\u626B\u63CF\u76EE\u5F55\uFF09\uFF1B\u5DF2\u5B89\u88C5\u7684\u4ED3\u5E93\u53EF\u5728\u300C\u6280\u80FD\u300D\u9875\u7BA1\u7406\u3002",
|
|
4504
|
-
marketMcpIntro: "\u6DFB\u52A0 MCP \u670D\u52A1\u5668\u884C\uFF08\
|
|
4617
|
+
marketMcpIntro: "\u6DFB\u52A0 MCP \u670D\u52A1\u5668\u884C\uFF08\u4E0A\u65B9\u53EF\u9009\u5199\u5165\u5F53\u524D profile \u8FD8\u662F\u5168\u5C40\u5C42\uFF0C\u6DFB\u52A0\u540E\u9700\u91CD\u542F\u751F\u6548\uFF09\uFF1B\u9700\u8981\u5BC6\u94A5\u7684\u670D\u52A1\u5728\u5B89\u88C5\u540E\u4E8E\u5217\u8868\u4E2D\u8865\u586B\u73AF\u5883\u53D8\u91CF\u3002",
|
|
4505
4618
|
marketEmpty: "\u5E02\u573A\u5217\u8868\u4E3A\u7A7A\u6216\u4E0D\u53EF\u7528",
|
|
4506
4619
|
marketOffline: "\u5728\u7EBF\u7D22\u5F15\u4E0D\u53EF\u8FBE\uFF0C\u5F53\u524D\u5C55\u793A\u5305\u5185\u5FEB\u7167\uFF08\u53EF\u80FD\u4E0E\u6700\u65B0\u5217\u8868\u6709\u5DEE\u5F02\uFF09\u3002",
|
|
4507
4620
|
marketSkillCount: "{n} \u4E2A\u6280\u80FD",
|
|
@@ -4588,9 +4701,20 @@ var en = {
|
|
|
4588
4701
|
confirmRemoveRoot: "Remove this repository?",
|
|
4589
4702
|
removeRootWarn: "Stops scanning the repository and deletes the copy downloaded into DSH_HOME (a local folder itself is untouched).",
|
|
4590
4703
|
mcpTitle: "MCP servers",
|
|
4591
|
-
mcpIntro: "Manage
|
|
4704
|
+
mcpIntro: "Manage MCP server rows (@deepseek-ai/dsh-mcp-client). A server lives either in this profile or in the global layer (DSH_HOME/cordis.patch.yml, applied to every profile on this machine); additions, edits, and removals take effect after a dsh restart.",
|
|
4592
4705
|
addServer: "Add server",
|
|
4593
4706
|
editServer: "Edit server",
|
|
4707
|
+
scopeLabel: "Scope",
|
|
4708
|
+
scopeGlobal: "Global",
|
|
4709
|
+
scopeProfile: "This profile",
|
|
4710
|
+
scopeHint: "Global writes DSH_HOME/cordis.patch.yml and applies to every profile on this machine; this profile writes the current profile only.",
|
|
4711
|
+
shadowedByGlobal: "a global row with the same id wins \u2014 this row has no effect",
|
|
4712
|
+
globalLayerError: "Failed to read the global layer (DSH_HOME/cordis.patch.yml); global servers are hidden:",
|
|
4713
|
+
checkLabel: "Check",
|
|
4714
|
+
checkRunning: "Checking\u2026",
|
|
4715
|
+
checkOk: "OK",
|
|
4716
|
+
checkFail: "Failed",
|
|
4717
|
+
copyToOther: "Copy to other layer",
|
|
4594
4718
|
serverName: "Server name (tool name prefix)",
|
|
4595
4719
|
transport: "Transport",
|
|
4596
4720
|
transportStdio: "stdio (local command)",
|
|
@@ -4604,10 +4728,10 @@ var en = {
|
|
|
4604
4728
|
enabled: "Enabled",
|
|
4605
4729
|
toggle: "Enable/disable",
|
|
4606
4730
|
confirmRemove: "Remove this server?",
|
|
4607
|
-
removeWarn: "Removes the row from
|
|
4731
|
+
removeWarn: "Removes the row from its configuration; its tools disappear after the next dsh restart.",
|
|
4608
4732
|
emptyMcp: "No MCP servers configured yet",
|
|
4609
4733
|
importServers: "Import from other agents",
|
|
4610
|
-
importIntro: "Scans Claude Code (~/.claude.json)
|
|
4734
|
+
importIntro: "Scans the MCP server configs of Claude Code (~/.claude.json), Codex (~/.codex/config.toml), Cursor (~/.cursor/mcp.json), and Gemini CLI (~/.gemini/settings.json); selected entries land in the scope picked below.",
|
|
4611
4735
|
importEmpty: "No importable MCP servers found",
|
|
4612
4736
|
importSelectAll: "Select all",
|
|
4613
4737
|
importExisting: "already here",
|
|
@@ -4633,7 +4757,7 @@ var en = {
|
|
|
4633
4757
|
marketSkills: "Skills market",
|
|
4634
4758
|
marketMcp: "MCP market",
|
|
4635
4759
|
marketSkillsIntro: "Installs skill repositories (GitHub download, live catalog); manage installed ones on the Skills tab.",
|
|
4636
|
-
marketMcpIntro: "Adds MCP server rows (
|
|
4760
|
+
marketMcpIntro: "Adds MCP server rows (pick the target layer \u2014 this profile or global \u2014 above; restart to apply). Servers needing keys get their environment filled in on the row after install.",
|
|
4637
4761
|
marketEmpty: "Market list is empty or unavailable",
|
|
4638
4762
|
marketOffline: "Online index unreachable \u2014 showing the bundled snapshot, which may lag behind.",
|
|
4639
4763
|
marketSkillCount: "{n} skills",
|
|
@@ -4681,10 +4805,12 @@ function apply2(ctx) {
|
|
|
4681
4805
|
const mcpInjected = {
|
|
4682
4806
|
list: () => fetchJson("/dsh-plugin-capabilities/mcp"),
|
|
4683
4807
|
save: (input) => post("/dsh-plugin-capabilities/mcp/save", input),
|
|
4684
|
-
toggle: (id, disabled) => post("/dsh-plugin-capabilities/mcp/toggle", { id, disabled }),
|
|
4685
|
-
remove: (id) => post("/dsh-plugin-capabilities/mcp/remove", { id }),
|
|
4808
|
+
toggle: (id, disabled, scope) => post("/dsh-plugin-capabilities/mcp/toggle", { id, disabled, scope }),
|
|
4809
|
+
remove: (id, scope) => post("/dsh-plugin-capabilities/mcp/remove", { id, scope }),
|
|
4810
|
+
check: (id, scope) => post("/dsh-plugin-capabilities/mcp/check", { id, scope }),
|
|
4811
|
+
copy: (id, scope, toScope) => post("/dsh-plugin-capabilities/mcp/copy", { id, scope, toScope }),
|
|
4686
4812
|
scanImport: () => fetchJson("/dsh-plugin-capabilities/import/scan"),
|
|
4687
|
-
applyImport: (items) => post("/dsh-plugin-capabilities/import/apply", { items }),
|
|
4813
|
+
applyImport: (items, scope) => post("/dsh-plugin-capabilities/import/apply", { items, scope }),
|
|
4688
4814
|
restart: async () => {
|
|
4689
4815
|
if (window.dshDesktop !== void 0) {
|
|
4690
4816
|
window.dshDesktop.restartSidecar?.();
|
|
@@ -4701,7 +4827,7 @@ function apply2(ctx) {
|
|
|
4701
4827
|
skillsIndex: () => fetchJson("/dsh-plugin-capabilities/market/skills"),
|
|
4702
4828
|
mcpIndex: () => fetchJson("/dsh-plugin-capabilities/market/mcp"),
|
|
4703
4829
|
installSkillRepo: (url) => post("/dsh-plugin-capabilities/market/skills/install", { url }),
|
|
4704
|
-
installMcp: (id) => post("/dsh-plugin-capabilities/market/mcp/install", { id }),
|
|
4830
|
+
installMcp: (id, scope) => post("/dsh-plugin-capabilities/market/mcp/install", { id, scope }),
|
|
4705
4831
|
removeRoot: skillsInjected.removeRoot
|
|
4706
4832
|
};
|
|
4707
4833
|
ctx.slots.inject("settings.section", () => {
|