dsh-plugin-capabilities 0.3.6 → 0.3.8
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 +3 -1
- package/lib/client.js +63 -20
- package/lib/client.js.map +2 -2
- package/lib/index.js +79 -30
- package/lib/index.js.map +2 -2
- package/package.json +1 -1
- package/src/client/MarketTab.tsx +1 -1
- package/src/client/McpTab.tsx +59 -19
- package/src/client/index.ts +5 -4
- package/src/client/locales.ts +16 -4
- package/src/index.ts +2 -1
- package/src/mcp.test.ts +83 -2
- package/src/mcp.ts +96 -18
- package/src/profile.ts +6 -2
- package/src/routes.ts +36 -21
package/README.md
CHANGED
|
@@ -25,7 +25,9 @@
|
|
|
25
25
|
|
|
26
26
|

|
|
27
27
|
|
|
28
|
-
「MCP」页管理 profile patch 中的 MCP 服务器行,每行对应一个 `@deepseek-ai/dsh-mcp-client` 实例。stdio 服务器填写命令与参数,streamable-http 服务器填写 URL,编辑、停用、移除都在页面上完成。YAML 读写采用文档级 API,文件中的其他行与注释不受影响。新行写在一个 `- insert:` 块里——加载器只会挂载 insert 形式的行,裸的 `- id:` 条目是对已有行的覆盖,目标不存在时会被跳过;0.1.3 之前写入的裸行会在下一次保存时自动迁入 insert 块。
|
|
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
|
+
|
|
30
|
+
服务器行不只存在于 profile 里。dsh 还有一层全局补丁(`DSH_HOME/cordis.patch.yml`),对这台机器上的所有 profile 生效,组合时排在 profile 层之后、同名 id 以全局为准。0.3.8 起,「MCP」页把两层合在一起展示:每行带「全局」或「当前 profile」标记,两层出现同名 id 时 profile 行会注明自己不生效。添加服务器时可以选择写入哪一层,编辑、停用、移除也都落在该行所在的层。全局文件损坏不会连累整个页面:profile 行照常列出,顶部横幅单独报出全局文件的路径与出错行列。
|
|
29
31
|
|
|
30
32
|
添加或编辑服务器时,表单下方有「完整格式与快速填充」区:一边是随表单实时更新的完整 YAML 行(和保存后落进 `cordis.patch.yml` 的一模一样),另一边是等价的 `mcpServers` JSON 写法,可以直接抄去别的工具。反过来也行——把 Claude Code 配置、官方文档或任意 JSON 粘进输入框,点「解析并填充」,服务器名、命令、参数、环境变量、URL、请求头都会自动填好,`{"mcpServers": {...}}` 包装、裸条目、dsh 行三种形状都认。
|
|
31
33
|
|
package/lib/client.js
CHANGED
|
@@ -259,7 +259,7 @@ function MarketTab(props) {
|
|
|
259
259
|
setOutcome({ ok: true, text: t("rootRemoved") });
|
|
260
260
|
refreshSkills();
|
|
261
261
|
} else {
|
|
262
|
-
await mcp.remove(target.id);
|
|
262
|
+
await mcp.remove(target.id, "profile");
|
|
263
263
|
setOutcome({ ok: true, text: t("restartNeeded") });
|
|
264
264
|
refreshMcp();
|
|
265
265
|
}
|
|
@@ -582,7 +582,8 @@ function McpTab(props) {
|
|
|
582
582
|
const { t, injected } = props;
|
|
583
583
|
const [servers, setServers] = (0, import_react2.useState)(null);
|
|
584
584
|
const [editor, setEditor] = (0, import_react2.useState)(null);
|
|
585
|
-
const [
|
|
585
|
+
const [confirmRow, setConfirmRow] = (0, import_react2.useState)(null);
|
|
586
|
+
const [globalError, setGlobalError] = (0, import_react2.useState)(null);
|
|
586
587
|
const [importOpen, setImportOpen] = (0, import_react2.useState)(false);
|
|
587
588
|
const [importItems, setImportItems] = (0, import_react2.useState)(null);
|
|
588
589
|
const [busy, setBusy] = (0, import_react2.useState)(false);
|
|
@@ -635,7 +636,9 @@ function McpTab(props) {
|
|
|
635
636
|
let current = true;
|
|
636
637
|
void injected.list().then(
|
|
637
638
|
(body) => {
|
|
638
|
-
if (current)
|
|
639
|
+
if (!current) return;
|
|
640
|
+
setServers(body.servers);
|
|
641
|
+
setGlobalError(body.globalError ?? null);
|
|
639
642
|
},
|
|
640
643
|
(error) => {
|
|
641
644
|
if (current) {
|
|
@@ -652,7 +655,7 @@ function McpTab(props) {
|
|
|
652
655
|
setFormError(null);
|
|
653
656
|
setPasteError(null);
|
|
654
657
|
setPasteJson("");
|
|
655
|
-
setEditor({ id: "", serverName: "", transport: "stdio", command: "", args: "", env: "", url: "", headers: "" });
|
|
658
|
+
setEditor({ id: "", scope: "profile", serverName: "", transport: "stdio", command: "", args: "", env: "", url: "", headers: "" });
|
|
656
659
|
};
|
|
657
660
|
const openEdit = (row) => {
|
|
658
661
|
setFormError(null);
|
|
@@ -660,6 +663,7 @@ function McpTab(props) {
|
|
|
660
663
|
setPasteJson("");
|
|
661
664
|
setEditor({
|
|
662
665
|
id: row.id,
|
|
666
|
+
scope: row.scope,
|
|
663
667
|
serverName: row.serverName,
|
|
664
668
|
transport: row.transport,
|
|
665
669
|
command: row.command ?? "",
|
|
@@ -704,6 +708,7 @@ function McpTab(props) {
|
|
|
704
708
|
try {
|
|
705
709
|
await injected.save({
|
|
706
710
|
id: editor.id,
|
|
711
|
+
scope: editor.scope,
|
|
707
712
|
serverName: editor.serverName.trim(),
|
|
708
713
|
transport: editor.transport,
|
|
709
714
|
...editor.transport === "stdio" ? {
|
|
@@ -727,7 +732,7 @@ function McpTab(props) {
|
|
|
727
732
|
const doToggle = async (row) => {
|
|
728
733
|
setBusy(true);
|
|
729
734
|
try {
|
|
730
|
-
await injected.toggle(row.id, !row.disabled);
|
|
735
|
+
await injected.toggle(row.id, !row.disabled, row.scope);
|
|
731
736
|
setOutcome({ ok: true, text: t("restartNeeded") });
|
|
732
737
|
reloadList(true);
|
|
733
738
|
} catch (error) {
|
|
@@ -737,17 +742,17 @@ function McpTab(props) {
|
|
|
737
742
|
}
|
|
738
743
|
};
|
|
739
744
|
const doRemove = async () => {
|
|
740
|
-
if (
|
|
745
|
+
if (confirmRow === null) return;
|
|
741
746
|
setBusy(true);
|
|
742
747
|
try {
|
|
743
|
-
await injected.remove(
|
|
748
|
+
await injected.remove(confirmRow.id, confirmRow.scope);
|
|
744
749
|
setOutcome({ ok: true, text: t("restartNeeded") });
|
|
745
750
|
reloadList(true);
|
|
746
751
|
} catch (error) {
|
|
747
752
|
setOutcome({ ok: false, text: `${t("failed")}: ${String(error instanceof Error ? error.message : error)}` });
|
|
748
753
|
} finally {
|
|
749
754
|
setBusy(false);
|
|
750
|
-
|
|
755
|
+
setConfirmRow(null);
|
|
751
756
|
}
|
|
752
757
|
};
|
|
753
758
|
const doRestart = () => {
|
|
@@ -797,6 +802,13 @@ function McpTab(props) {
|
|
|
797
802
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.StateDot, { state: outcome.ok ? "done" : "error", size: 10 }),
|
|
798
803
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dpc-bannerBody", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: outcome.text }) })
|
|
799
804
|
] }),
|
|
805
|
+
globalError !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dpc-banner", "data-kind": "error", role: "alert", children: [
|
|
806
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.StateDot, { state: "error", size: 10 }),
|
|
807
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dpc-bannerBody", children: [
|
|
808
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("globalLayerError") }),
|
|
809
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dpc-bannerHint", children: globalError })
|
|
810
|
+
] })
|
|
811
|
+
] }),
|
|
800
812
|
(pending || restarting) && restartBanner,
|
|
801
813
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dpc-listHead", children: [
|
|
802
814
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { children: t("mcpTab") }),
|
|
@@ -809,17 +821,19 @@ function McpTab(props) {
|
|
|
809
821
|
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
822
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dpc-cardTop", children: [
|
|
811
823
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { className: "dpc-cardTitle", title: row.id, children: row.serverName }),
|
|
824
|
+
/* @__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
825
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dpc-tag", children: row.transport }),
|
|
813
826
|
/* @__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
827
|
] }),
|
|
815
828
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "dpc-cardDesc", children: row.transport === "stdio" ? `${row.command ?? ""} ${(row.args ?? []).join(" ")}` : row.url ?? "" }),
|
|
829
|
+
row.shadowed === true && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "dpc-formError", children: t("shadowedByGlobal") }),
|
|
816
830
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dpc-cardRow", children: [
|
|
817
831
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dpc-spacer" }),
|
|
818
832
|
/* @__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
833
|
/* @__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: () =>
|
|
834
|
+
/* @__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
835
|
] })
|
|
822
|
-
] }, row.id)) }),
|
|
836
|
+
] }, `${row.scope}/${row.id}`)) }),
|
|
823
837
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
824
838
|
import_dsh_client_ui_primitives2.Modal,
|
|
825
839
|
{
|
|
@@ -829,6 +843,23 @@ function McpTab(props) {
|
|
|
829
843
|
className: "dpc-modalForm",
|
|
830
844
|
contentClassName: "dpc-modalScroll",
|
|
831
845
|
children: editor !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dpc-form", children: [
|
|
846
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "dpc-label", children: [
|
|
847
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("scopeLabel") }),
|
|
848
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
849
|
+
"select",
|
|
850
|
+
{
|
|
851
|
+
className: "dpc-select",
|
|
852
|
+
value: editor.scope,
|
|
853
|
+
disabled: editor.id !== "",
|
|
854
|
+
onChange: (event) => setEditor({ ...editor, scope: event.target.value }),
|
|
855
|
+
children: [
|
|
856
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "profile", children: t("scopeProfile") }),
|
|
857
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "global", children: t("scopeGlobal") })
|
|
858
|
+
]
|
|
859
|
+
}
|
|
860
|
+
),
|
|
861
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dpc-formatHint", children: t("scopeHint") })
|
|
862
|
+
] }),
|
|
832
863
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "dpc-label", children: [
|
|
833
864
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("serverName") }),
|
|
834
865
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
@@ -927,12 +958,12 @@ function McpTab(props) {
|
|
|
927
958
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
928
959
|
import_dsh_client_ui_primitives2.Modal,
|
|
929
960
|
{
|
|
930
|
-
open:
|
|
931
|
-
onClose: () =>
|
|
961
|
+
open: confirmRow !== null,
|
|
962
|
+
onClose: () => setConfirmRow(null),
|
|
932
963
|
title: t("confirmRemove"),
|
|
933
|
-
description:
|
|
964
|
+
description: confirmRow?.serverName ?? void 0,
|
|
934
965
|
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: () =>
|
|
966
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "ghost", onClick: () => setConfirmRow(null), children: t("cancel") }),
|
|
936
967
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "primary", disabled: busy, onClick: () => void doRemove(), children: t("delete") })
|
|
937
968
|
] }),
|
|
938
969
|
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: t("removeWarn") })
|
|
@@ -4456,9 +4487,15 @@ var zh = {
|
|
|
4456
4487
|
confirmRemoveRoot: "\u786E\u8BA4\u79FB\u9664\u8BE5\u4ED3\u5E93\uFF1F",
|
|
4457
4488
|
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
4489
|
mcpTitle: "MCP \u670D\u52A1\u5668",
|
|
4459
|
-
mcpIntro: "\u7BA1\u7406
|
|
4490
|
+
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
4491
|
addServer: "\u6DFB\u52A0\u670D\u52A1\u5668",
|
|
4461
4492
|
editServer: "\u7F16\u8F91\u670D\u52A1\u5668",
|
|
4493
|
+
scopeLabel: "\u751F\u6548\u8303\u56F4",
|
|
4494
|
+
scopeGlobal: "\u5168\u5C40",
|
|
4495
|
+
scopeProfile: "\u5F53\u524D profile",
|
|
4496
|
+
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",
|
|
4497
|
+
shadowedByGlobal: "\u5168\u5C40\u5C42\u5B58\u5728\u540C\u540D id\uFF0C\u6B64\u884C\u4E0D\u751F\u6548",
|
|
4498
|
+
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",
|
|
4462
4499
|
serverName: "\u670D\u52A1\u5668\u540D\uFF08\u5DE5\u5177\u540D\u524D\u7F00\uFF09",
|
|
4463
4500
|
transport: "\u4F20\u8F93\u65B9\u5F0F",
|
|
4464
4501
|
transportStdio: "stdio\uFF08\u672C\u5730\u547D\u4EE4\uFF09",
|
|
@@ -4472,7 +4509,7 @@ var zh = {
|
|
|
4472
4509
|
enabled: "\u542F\u7528\u4E2D",
|
|
4473
4510
|
toggle: "\u505C\u7528/\u542F\u7528",
|
|
4474
4511
|
confirmRemove: "\u786E\u8BA4\u79FB\u9664\u8BE5\u670D\u52A1\u5668\uFF1F",
|
|
4475
|
-
removeWarn: "\u5C06\u4ECE
|
|
4512
|
+
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
4513
|
emptyMcp: "\u8FD8\u6CA1\u6709\u914D\u7F6E MCP \u670D\u52A1\u5668",
|
|
4477
4514
|
importServers: "\u4ECE\u5176\u4ED6 Agent \u5BFC\u5165",
|
|
4478
4515
|
importIntro: "\u626B\u63CF Claude Code\uFF08~/.claude.json\uFF09\u4E0E Codex\uFF08~/.codex/config.toml\uFF09\u7684 MCP \u670D\u52A1\u5668\u914D\u7F6E\uFF0C\u52FE\u9009\u540E\u5BFC\u5165\u4E3A\u672C profile \u7684\u670D\u52A1\u5668\u884C\u3002",
|
|
@@ -4588,9 +4625,15 @@ var en = {
|
|
|
4588
4625
|
confirmRemoveRoot: "Remove this repository?",
|
|
4589
4626
|
removeRootWarn: "Stops scanning the repository and deletes the copy downloaded into DSH_HOME (a local folder itself is untouched).",
|
|
4590
4627
|
mcpTitle: "MCP servers",
|
|
4591
|
-
mcpIntro: "Manage
|
|
4628
|
+
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
4629
|
addServer: "Add server",
|
|
4593
4630
|
editServer: "Edit server",
|
|
4631
|
+
scopeLabel: "Scope",
|
|
4632
|
+
scopeGlobal: "Global",
|
|
4633
|
+
scopeProfile: "This profile",
|
|
4634
|
+
scopeHint: "Global writes DSH_HOME/cordis.patch.yml and applies to every profile on this machine; this profile writes the current profile only.",
|
|
4635
|
+
shadowedByGlobal: "a global row with the same id wins \u2014 this row has no effect",
|
|
4636
|
+
globalLayerError: "Failed to read the global layer (DSH_HOME/cordis.patch.yml); global servers are hidden:",
|
|
4594
4637
|
serverName: "Server name (tool name prefix)",
|
|
4595
4638
|
transport: "Transport",
|
|
4596
4639
|
transportStdio: "stdio (local command)",
|
|
@@ -4604,7 +4647,7 @@ var en = {
|
|
|
4604
4647
|
enabled: "Enabled",
|
|
4605
4648
|
toggle: "Enable/disable",
|
|
4606
4649
|
confirmRemove: "Remove this server?",
|
|
4607
|
-
removeWarn: "Removes the row from
|
|
4650
|
+
removeWarn: "Removes the row from its configuration; its tools disappear after the next dsh restart.",
|
|
4608
4651
|
emptyMcp: "No MCP servers configured yet",
|
|
4609
4652
|
importServers: "Import from other agents",
|
|
4610
4653
|
importIntro: "Scans Claude Code (~/.claude.json) and Codex (~/.codex/config.toml) MCP server configs; selected entries become server rows in this profile.",
|
|
@@ -4681,8 +4724,8 @@ function apply2(ctx) {
|
|
|
4681
4724
|
const mcpInjected = {
|
|
4682
4725
|
list: () => fetchJson("/dsh-plugin-capabilities/mcp"),
|
|
4683
4726
|
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 }),
|
|
4727
|
+
toggle: (id, disabled, scope) => post("/dsh-plugin-capabilities/mcp/toggle", { id, disabled, scope }),
|
|
4728
|
+
remove: (id, scope) => post("/dsh-plugin-capabilities/mcp/remove", { id, scope }),
|
|
4686
4729
|
scanImport: () => fetchJson("/dsh-plugin-capabilities/import/scan"),
|
|
4687
4730
|
applyImport: (items) => post("/dsh-plugin-capabilities/import/apply", { items }),
|
|
4688
4731
|
restart: async () => {
|