dsh-plugin-settings-custom 1.0.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/README.md +3 -0
- package/cordis.patch.yml +4 -0
- package/lib/client.js +404 -0
- package/lib/index.js +30 -0
- package/package.json +45 -0
package/README.md
ADDED
package/cordis.patch.yml
ADDED
package/lib/client.js
ADDED
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "dsh-plugin-settings-custom",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
|
+
let react = require("react");
|
|
9
|
+
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
10
|
+
let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
|
|
11
|
+
//#region locales
|
|
12
|
+
/** Simplified Chinese dictionary (key-set source of truth). */
|
|
13
|
+
const zh = {
|
|
14
|
+
"nav": "自定义",
|
|
15
|
+
"global.title": "全局指令(AGENTS.md)",
|
|
16
|
+
"global.description": "写入此文件的内容会自动注入到所有会话的系统提示中,新消息立即生效,支持 Markdown。",
|
|
17
|
+
"global.placeholder": "# 全局指令\n\n在这里写入对所有对话都生效的规则、偏好或背景信息…",
|
|
18
|
+
"global.save": "保存",
|
|
19
|
+
"global.saving": "保存中…",
|
|
20
|
+
"global.saved": "已保存 ✓",
|
|
21
|
+
"global.loadFailed": "读取失败:{msg}",
|
|
22
|
+
"global.saveFailed": "保存失败:{msg}",
|
|
23
|
+
"skills.title": "技能(Skills)",
|
|
24
|
+
"skills.description": "管理已安装的技能:启用、停用或删除。停用后模型将无法调用该技能。",
|
|
25
|
+
"skills.empty": "暂无已安装的技能",
|
|
26
|
+
"skills.enable": "启用",
|
|
27
|
+
"skills.disable": "停用",
|
|
28
|
+
"skills.delete": "删除",
|
|
29
|
+
"skills.deleting": "删除中…",
|
|
30
|
+
"skills.failed": "操作失败:{msg}",
|
|
31
|
+
"mcp.title": "MCP 服务器",
|
|
32
|
+
"mcp.description": "管理 MCP 服务器配置:启用、停用或删除。修改后需要重启生效。",
|
|
33
|
+
"mcp.empty": "暂未配置 MCP 服务器",
|
|
34
|
+
"mcp.enable": "启用",
|
|
35
|
+
"mcp.disable": "停用",
|
|
36
|
+
"mcp.delete": "删除",
|
|
37
|
+
"mcp.failed": "操作失败:{msg}"
|
|
38
|
+
};
|
|
39
|
+
/** English dictionary, checked complete against the zh key set. */
|
|
40
|
+
const en = {
|
|
41
|
+
"nav": "Custom",
|
|
42
|
+
"global.title": "Global instructions (AGENTS.md)",
|
|
43
|
+
"global.description": "Content written here is injected into every session's system prompt. New messages pick it up immediately. Markdown supported.",
|
|
44
|
+
"global.placeholder": "# Global instructions\n\nWrite rules, preferences, or background that apply to all conversations…",
|
|
45
|
+
"global.save": "Save",
|
|
46
|
+
"global.saving": "Saving…",
|
|
47
|
+
"global.saved": "Saved ✓",
|
|
48
|
+
"global.loadFailed": "Failed to load: {msg}",
|
|
49
|
+
"global.saveFailed": "Failed to save: {msg}",
|
|
50
|
+
"skills.title": "Skills",
|
|
51
|
+
"skills.description": "Manage installed skills: enable, disable, or delete. Disabled skills are unavailable to the model.",
|
|
52
|
+
"skills.empty": "No skills installed",
|
|
53
|
+
"skills.enable": "Enable",
|
|
54
|
+
"skills.disable": "Disable",
|
|
55
|
+
"skills.delete": "Delete",
|
|
56
|
+
"skills.deleting": "Deleting…",
|
|
57
|
+
"skills.failed": "Operation failed: {msg}",
|
|
58
|
+
"mcp.title": "MCP servers",
|
|
59
|
+
"mcp.description": "Manage MCP server configuration: enable, disable, or delete. Changes apply after a restart.",
|
|
60
|
+
"mcp.empty": "No MCP servers configured",
|
|
61
|
+
"mcp.enable": "Enable",
|
|
62
|
+
"mcp.disable": "Disable",
|
|
63
|
+
"mcp.delete": "Delete",
|
|
64
|
+
"mcp.failed": "Operation failed: {msg}"
|
|
65
|
+
};
|
|
66
|
+
const NS = "dsh-plugin-settings-custom";
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region styles
|
|
69
|
+
const css = `
|
|
70
|
+
.scc_card{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-specific-card-bg,var(--dsw-alias-surface-1));border-radius:12px;padding:16px;margin:0 0 16px}
|
|
71
|
+
.scc_heading{font-size:14px;font-weight:600;line-height:20px;color:var(--dsw-alias-label-primary);margin:0 0 4px}
|
|
72
|
+
.scc_desc{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary);margin:0 0 12px}
|
|
73
|
+
.scc_textarea{box-sizing:border-box;width:100%;min-height:240px;resize:vertical;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-input-bg,var(--dsw-alias-surface-2));color:var(--dsw-alias-label-primary);border-radius:8px;padding:10px 12px;font-size:13px;line-height:20px;font-family:var(--dsw-font-family-mono,Consolas,monospace);outline:none}
|
|
74
|
+
.scc_textarea:focus{border-color:var(--dsw-alias-interactive-border-hover,var(--dsw-alias-label-tertiary))}
|
|
75
|
+
.scc_footer{align-items:center;gap:10px;margin-top:10px;display:flex}
|
|
76
|
+
.scc_status{font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary)}
|
|
77
|
+
.scc_status.scc_err{color:var(--dsw-alias-state-error-primary)}
|
|
78
|
+
.scc_row{align-items:center;gap:10px;min-width:0;padding:8px 0;display:flex;flex-wrap:nowrap}
|
|
79
|
+
.scc_row+.scc_row{box-shadow:inset 0 1px 0 var(--dsw-alias-border-l1)}
|
|
80
|
+
.scc_rowName{min-width:0;flex:1 1 auto;font-size:13px;line-height:18px;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}
|
|
81
|
+
.scc_rowMeta{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary);flex:none;margin-left:6px}
|
|
82
|
+
.scc_rowActions{flex:none;align-items:center;gap:6px;display:flex;flex-wrap:nowrap}
|
|
83
|
+
`;
|
|
84
|
+
const tagId = "@deepseek-ai/dsh-client-ui-settings-custom/styles";
|
|
85
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
86
|
+
const tag = document.createElement("style");
|
|
87
|
+
tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-settings-custom";
|
|
88
|
+
tag.dataset.pluginCss = tagId;
|
|
89
|
+
tag.textContent = css;
|
|
90
|
+
document.head.appendChild(tag);
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region GlobalInstructionsSection
|
|
94
|
+
/**
|
|
95
|
+
* Edit `$DSH_HOME/AGENTS.md` in place. Saving writes through the host
|
|
96
|
+
* `settings.custom.globalInstructionsWrite` RPC; the agent-instructions
|
|
97
|
+
* plugin picks the file up on the next message (no restart needed).
|
|
98
|
+
*/
|
|
99
|
+
function GlobalInstructionsCard({ api, t }) {
|
|
100
|
+
const [content, setContent] = (0, react.useState)("");
|
|
101
|
+
const [loaded, setLoaded] = (0, react.useState)(false);
|
|
102
|
+
const [saving, setSaving] = (0, react.useState)(false);
|
|
103
|
+
const [status, setStatus] = (0, react.useState)(null);
|
|
104
|
+
const [error, setError] = (0, react.useState)(null);
|
|
105
|
+
(0, react.useEffect)(() => {
|
|
106
|
+
let stale = false;
|
|
107
|
+
api.settings.custom.globalInstructionsRead({}).then((resp) => {
|
|
108
|
+
if (stale) return;
|
|
109
|
+
if (resp.result.ok) {
|
|
110
|
+
setContent(resp.result.value.content);
|
|
111
|
+
setLoaded(true);
|
|
112
|
+
} else {
|
|
113
|
+
setError(t("global.loadFailed", { msg: resp.result.error.message }));
|
|
114
|
+
}
|
|
115
|
+
}).catch((e) => {
|
|
116
|
+
if (!stale) setError(t("global.loadFailed", { msg: e && e.message ? e.message : String(e) }));
|
|
117
|
+
});
|
|
118
|
+
return () => { stale = true; };
|
|
119
|
+
}, [api, t]);
|
|
120
|
+
const save = () => {
|
|
121
|
+
if (saving) return;
|
|
122
|
+
setSaving(true);
|
|
123
|
+
setError(null);
|
|
124
|
+
setStatus(null);
|
|
125
|
+
api.settings.custom.globalInstructionsWrite({ content }).then((resp) => {
|
|
126
|
+
setSaving(false);
|
|
127
|
+
if (resp.result.ok) setStatus(t("global.saved"));
|
|
128
|
+
else setError(t("global.saveFailed", { msg: resp.result.error.message }));
|
|
129
|
+
}).catch((e) => {
|
|
130
|
+
setSaving(false);
|
|
131
|
+
setError(t("global.saveFailed", { msg: e && e.message ? e.message : String(e) }));
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
return react_jsx_runtime.jsx("div", {
|
|
135
|
+
className: "scc_card",
|
|
136
|
+
children: [
|
|
137
|
+
react_jsx_runtime.jsx("h3", { className: "scc_heading", children: t("global.title") }),
|
|
138
|
+
react_jsx_runtime.jsx("p", { className: "scc_desc", children: t("global.description") }),
|
|
139
|
+
react_jsx_runtime.jsx("textarea", {
|
|
140
|
+
className: "scc_textarea",
|
|
141
|
+
value: content,
|
|
142
|
+
placeholder: t("global.placeholder"),
|
|
143
|
+
disabled: !loaded || saving,
|
|
144
|
+
spellCheck: false,
|
|
145
|
+
onChange: (e) => {
|
|
146
|
+
setContent(e.target.value);
|
|
147
|
+
setStatus(null);
|
|
148
|
+
}
|
|
149
|
+
}),
|
|
150
|
+
react_jsx_runtime.jsx("div", {
|
|
151
|
+
className: "scc_footer",
|
|
152
|
+
children: [
|
|
153
|
+
react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
154
|
+
variant: "primary",
|
|
155
|
+
disabled: !loaded || saving,
|
|
156
|
+
onClick: save,
|
|
157
|
+
children: saving ? t("global.saving") : t("global.save")
|
|
158
|
+
}),
|
|
159
|
+
status !== null && react_jsx_runtime.jsx("span", { className: "scc_status", children: status }),
|
|
160
|
+
error !== null && react_jsx_runtime.jsx("span", { className: "scc_status scc_err", role: "alert", children: error })
|
|
161
|
+
]
|
|
162
|
+
})
|
|
163
|
+
]
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region SkillsCard
|
|
168
|
+
/** List installed skills with enable/disable/delete controls. */
|
|
169
|
+
function SkillsCard({ api, t }) {
|
|
170
|
+
const [skills, setSkills] = (0, react.useState)(null);
|
|
171
|
+
const [error, setError] = (0, react.useState)(null);
|
|
172
|
+
const [busyName, setBusyName] = (0, react.useState)(null);
|
|
173
|
+
const load = (0, react.useCallback)(() => {
|
|
174
|
+
api.settings.custom.skillsList({}).then((resp) => {
|
|
175
|
+
if (resp.result.ok) {
|
|
176
|
+
setSkills(resp.result.value.skills);
|
|
177
|
+
setError(null);
|
|
178
|
+
} else {
|
|
179
|
+
setError(t("skills.failed", { msg: resp.result.error.message }));
|
|
180
|
+
}
|
|
181
|
+
}).catch((e) => {
|
|
182
|
+
setError(t("skills.failed", { msg: e && e.message ? e.message : String(e) }));
|
|
183
|
+
});
|
|
184
|
+
}, [api, t]);
|
|
185
|
+
(0, react.useEffect)(() => {
|
|
186
|
+
load();
|
|
187
|
+
}, [load]);
|
|
188
|
+
const toggle = (skill) => {
|
|
189
|
+
setBusyName(skill.name);
|
|
190
|
+
setError(null);
|
|
191
|
+
api.settings.custom.skillsSetEnabled({ name: skill.name, enabled: !skill.enabled }).then((resp) => {
|
|
192
|
+
setBusyName(null);
|
|
193
|
+
if (resp.result.ok) load();
|
|
194
|
+
else setError(t("skills.failed", { msg: resp.result.error.message }));
|
|
195
|
+
}).catch((e) => {
|
|
196
|
+
setBusyName(null);
|
|
197
|
+
setError(t("skills.failed", { msg: e && e.message ? e.message : String(e) }));
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
const remove = (skill) => {
|
|
201
|
+
if (busyName !== null) return;
|
|
202
|
+
if (typeof window !== "undefined" && !window.confirm(`${t("skills.delete")}: ${skill.name}?`)) return;
|
|
203
|
+
setBusyName(skill.name);
|
|
204
|
+
setError(null);
|
|
205
|
+
api.settings.custom.skillsRemove({ name: skill.name }).then((resp) => {
|
|
206
|
+
setBusyName(null);
|
|
207
|
+
if (resp.result.ok) load();
|
|
208
|
+
else setError(t("skills.failed", { msg: resp.result.error.message }));
|
|
209
|
+
}).catch((e) => {
|
|
210
|
+
setBusyName(null);
|
|
211
|
+
setError(t("skills.failed", { msg: e && e.message ? e.message : String(e) }));
|
|
212
|
+
});
|
|
213
|
+
};
|
|
214
|
+
return react_jsx_runtime.jsx("div", {
|
|
215
|
+
className: "scc_card",
|
|
216
|
+
children: [
|
|
217
|
+
react_jsx_runtime.jsx("h3", { className: "scc_heading", children: t("skills.title") }),
|
|
218
|
+
react_jsx_runtime.jsx("p", { className: "scc_desc", children: t("skills.description") }),
|
|
219
|
+
error !== null && react_jsx_runtime.jsx("div", { className: "scc_status scc_err", role: "alert", children: error }),
|
|
220
|
+
skills === null ? null : skills.length === 0 ? react_jsx_runtime.jsx("p", { className: "scc_status", children: t("skills.empty") }) : skills.map((skill) => react_jsx_runtime.jsxs("div", {
|
|
221
|
+
className: "scc_row",
|
|
222
|
+
title: skill.description.length > 0 ? skill.description : void 0,
|
|
223
|
+
children: [
|
|
224
|
+
react_jsx_runtime.jsxs("div", {
|
|
225
|
+
className: "scc_rowName",
|
|
226
|
+
children: [skill.name, skill.enabled ? null : react_jsx_runtime.jsx("span", { className: "scc_rowMeta", children: " (已停用)" })]
|
|
227
|
+
}),
|
|
228
|
+
react_jsx_runtime.jsxs("div", {
|
|
229
|
+
className: "scc_rowActions",
|
|
230
|
+
children: [
|
|
231
|
+
react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
232
|
+
variant: "outline",
|
|
233
|
+
disabled: busyName !== null,
|
|
234
|
+
onClick: () => toggle(skill),
|
|
235
|
+
children: skill.enabled ? t("skills.disable") : t("skills.enable")
|
|
236
|
+
}),
|
|
237
|
+
react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
238
|
+
variant: "outline",
|
|
239
|
+
disabled: busyName !== null,
|
|
240
|
+
onClick: () => remove(skill),
|
|
241
|
+
children: busyName === skill.name ? t("skills.deleting") : t("skills.delete")
|
|
242
|
+
})
|
|
243
|
+
]
|
|
244
|
+
})
|
|
245
|
+
]
|
|
246
|
+
}, skill.name))
|
|
247
|
+
]
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region McpCard
|
|
252
|
+
/** List configured MCP servers with enable/disable/delete controls. */
|
|
253
|
+
function McpCard({ api, t }) {
|
|
254
|
+
const [servers, setServers] = (0, react.useState)(null);
|
|
255
|
+
const [error, setError] = (0, react.useState)(null);
|
|
256
|
+
const [busyId, setBusyId] = (0, react.useState)(null);
|
|
257
|
+
const load = (0, react.useCallback)(() => {
|
|
258
|
+
api.settings.custom.mcpList({}).then((resp) => {
|
|
259
|
+
if (resp.result.ok) {
|
|
260
|
+
setServers(resp.result.value.servers);
|
|
261
|
+
setError(null);
|
|
262
|
+
} else {
|
|
263
|
+
setError(t("mcp.failed", { msg: resp.result.error.message }));
|
|
264
|
+
}
|
|
265
|
+
}).catch((e) => {
|
|
266
|
+
setError(t("mcp.failed", { msg: e && e.message ? e.message : String(e) }));
|
|
267
|
+
});
|
|
268
|
+
}, [api, t]);
|
|
269
|
+
(0, react.useEffect)(() => {
|
|
270
|
+
load();
|
|
271
|
+
}, [load]);
|
|
272
|
+
const toggle = (server) => {
|
|
273
|
+
setBusyId(server.id);
|
|
274
|
+
setError(null);
|
|
275
|
+
api.settings.custom.mcpSetEnabled({ id: server.id, enabled: !server.enabled }).then((resp) => {
|
|
276
|
+
setBusyId(null);
|
|
277
|
+
if (resp.result.ok) load();
|
|
278
|
+
else setError(t("mcp.failed", { msg: resp.result.error.message }));
|
|
279
|
+
}).catch((e) => {
|
|
280
|
+
setBusyId(null);
|
|
281
|
+
setError(t("mcp.failed", { msg: e && e.message ? e.message : String(e) }));
|
|
282
|
+
});
|
|
283
|
+
};
|
|
284
|
+
const remove = (server) => {
|
|
285
|
+
if (busyId !== null) return;
|
|
286
|
+
if (typeof window !== "undefined" && !window.confirm(`${t("mcp.delete")}: ${server.serverName}?`)) return;
|
|
287
|
+
setBusyId(server.id);
|
|
288
|
+
setError(null);
|
|
289
|
+
api.settings.custom.mcpRemove({ id: server.id }).then((resp) => {
|
|
290
|
+
setBusyId(null);
|
|
291
|
+
if (resp.result.ok) load();
|
|
292
|
+
else setError(t("mcp.failed", { msg: resp.result.error.message }));
|
|
293
|
+
}).catch((e) => {
|
|
294
|
+
setBusyId(null);
|
|
295
|
+
setError(t("mcp.failed", { msg: e && e.message ? e.message : String(e) }));
|
|
296
|
+
});
|
|
297
|
+
};
|
|
298
|
+
return react_jsx_runtime.jsx("div", {
|
|
299
|
+
className: "scc_card",
|
|
300
|
+
children: [
|
|
301
|
+
react_jsx_runtime.jsx("h3", { className: "scc_heading", children: t("mcp.title") }),
|
|
302
|
+
react_jsx_runtime.jsx("p", { className: "scc_desc", children: t("mcp.description") }),
|
|
303
|
+
error !== null && react_jsx_runtime.jsx("div", { className: "scc_status scc_err", role: "alert", children: error }),
|
|
304
|
+
servers === null ? null : servers.length === 0 ? react_jsx_runtime.jsx("p", { className: "scc_status", children: t("mcp.empty") }) : servers.map((server) => react_jsx_runtime.jsxs("div", {
|
|
305
|
+
className: "scc_row",
|
|
306
|
+
children: [
|
|
307
|
+
react_jsx_runtime.jsxs("div", {
|
|
308
|
+
className: "scc_rowName",
|
|
309
|
+
children: [server.serverName, server.enabled ? null : react_jsx_runtime.jsx("span", { className: "scc_rowMeta", children: " (已停用)" })]
|
|
310
|
+
}),
|
|
311
|
+
react_jsx_runtime.jsxs("div", {
|
|
312
|
+
className: "scc_rowActions",
|
|
313
|
+
children: [
|
|
314
|
+
react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
315
|
+
variant: "outline",
|
|
316
|
+
disabled: busyId !== null,
|
|
317
|
+
onClick: () => toggle(server),
|
|
318
|
+
children: server.enabled ? t("mcp.disable") : t("mcp.enable")
|
|
319
|
+
}),
|
|
320
|
+
react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
321
|
+
variant: "outline",
|
|
322
|
+
disabled: busyId !== null,
|
|
323
|
+
onClick: () => remove(server),
|
|
324
|
+
children: t("mcp.delete")
|
|
325
|
+
})
|
|
326
|
+
]
|
|
327
|
+
})
|
|
328
|
+
]
|
|
329
|
+
}, server.id))
|
|
330
|
+
]
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
//#endregion
|
|
334
|
+
//#region CustomSection
|
|
335
|
+
/** Settings section shell: global instructions, skill management, and MCP management. */
|
|
336
|
+
function CustomSection({ api, t }) {
|
|
337
|
+
if (api === void 0 || t === void 0) return null;
|
|
338
|
+
return react_jsx_runtime.jsx("div", {
|
|
339
|
+
children: [
|
|
340
|
+
react_jsx_runtime.jsx(GlobalInstructionsCard, { api, t }),
|
|
341
|
+
react_jsx_runtime.jsx(SkillsCard, { api, t }),
|
|
342
|
+
react_jsx_runtime.jsx(McpCard, { api, t })
|
|
343
|
+
]
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
//#endregion
|
|
347
|
+
//#region plugin
|
|
348
|
+
//#region fetch adapter (replaces patched RPCs with the plugin's HTTP routes)
|
|
349
|
+
function makeApi() {
|
|
350
|
+
function get(path) {
|
|
351
|
+
return fetch(path).then(function(r){return r.json()}).then(function(d){
|
|
352
|
+
if (d && d.ok === false) return { result: { ok: false, error: { message: d.error || "failed" } } };
|
|
353
|
+
return { result: { ok: true, value: d } };
|
|
354
|
+
}).catch(function(e){ return { result: { ok: false, error: { message: String(e && e.message || e) } } }; });
|
|
355
|
+
}
|
|
356
|
+
function post(path, body) {
|
|
357
|
+
return fetch(path, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body || {}) }).then(function(r){return r.json()}).then(function(d){
|
|
358
|
+
if (d && d.ok === false) return { result: { ok: false, error: { message: d.error || "failed" } } };
|
|
359
|
+
return { result: { ok: true, value: d } };
|
|
360
|
+
}).catch(function(e){ return { result: { ok: false, error: { message: String(e && e.message || e) } } }; });
|
|
361
|
+
}
|
|
362
|
+
return { settings: { custom: {
|
|
363
|
+
globalInstructionsRead: function(){ return get("/dsh-plugin-global-instructions/global.json"); },
|
|
364
|
+
globalInstructionsWrite: function(p){ return post("/dsh-plugin-global-instructions/global.json", { content: p && p.content }); },
|
|
365
|
+
skillsList: function(){ return get("/dsh-plugin-skill-manager/skills.json"); },
|
|
366
|
+
skillsSetEnabled: function(p){ return post("/dsh-plugin-skill-manager/skills.json", { action: "setEnabled", name: p && p.name, enabled: p && p.enabled }); },
|
|
367
|
+
skillsRemove: function(p){ return post("/dsh-plugin-skill-manager/skills.json", { action: "remove", name: p && p.name }); },
|
|
368
|
+
mcpList: function(){ return get("/dsh-plugin-mcp-manager/mcp.json"); },
|
|
369
|
+
mcpSetEnabled: function(p){ return post("/dsh-plugin-mcp-manager/mcp.json", { action: "setEnabled", id: p && p.id, enabled: p && p.enabled }); },
|
|
370
|
+
mcpRemove: function(p){ return post("/dsh-plugin-mcp-manager/mcp.json", { action: "remove", id: p && p.id }); }
|
|
371
|
+
} } };
|
|
372
|
+
}
|
|
373
|
+
//#endregion
|
|
374
|
+
|
|
375
|
+
const inject = [
|
|
376
|
+
"slots",
|
|
377
|
+
"locale"
|
|
378
|
+
];
|
|
379
|
+
function apply(ctx) {
|
|
380
|
+
ctx.effect(() => ctx.locale.register(NS, {
|
|
381
|
+
zh,
|
|
382
|
+
en
|
|
383
|
+
}), "ui-settings-custom: copy dictionaries");
|
|
384
|
+
|
|
385
|
+
const t = ctx.locale.bind(NS);
|
|
386
|
+
const injected = () => ({
|
|
387
|
+
api: makeApi(),
|
|
388
|
+
t
|
|
389
|
+
});
|
|
390
|
+
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
391
|
+
name: "settings.section",
|
|
392
|
+
id: "custom",
|
|
393
|
+
order: 30,
|
|
394
|
+
label: () => t("nav"),
|
|
395
|
+
locale: NS,
|
|
396
|
+
inject: injected
|
|
397
|
+
}, CustomSection));
|
|
398
|
+
}
|
|
399
|
+
//#endregion
|
|
400
|
+
exports.apply = apply;
|
|
401
|
+
exports.inject = inject;
|
|
402
|
+
return module.exports;
|
|
403
|
+
}
|
|
404
|
+
});
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
const CLIENT_JS = `(function(){
|
|
4
|
+
if (window.__dshSettingsCustom) return
|
|
5
|
+
window.__dshSettingsCustom = true
|
|
6
|
+
// 在设置页导航里加“自定义”入口,并提供一个容器 .dsh-custom-host 供 1/3/4 插件面板挂载
|
|
7
|
+
function boot(){
|
|
8
|
+
var nav = document.querySelector('[class*="settings"] nav, [role="tablist"], [class*="setting-nav"], nav')
|
|
9
|
+
var host = document.querySelector('[class*="settings"], [data-role="settings"], main, body')
|
|
10
|
+
if (!host) return setTimeout(boot, 300)
|
|
11
|
+
if (!host.querySelector('.dsh-custom-host')) {
|
|
12
|
+
var c = document.createElement('div'); c.className='dsh-custom-host'
|
|
13
|
+
c.innerHTML='<div class="dsh-custom-title">自定义</div>'
|
|
14
|
+
host.appendChild(c)
|
|
15
|
+
}
|
|
16
|
+
// 有导航则追加一个“自定义” tab(尽力)
|
|
17
|
+
if (nav && !nav.querySelector('[data-dsh-custom-tab]')) {
|
|
18
|
+
var t=document.createElement('button'); t.setAttribute('data-dsh-custom-tab','1'); t.textContent='自定义'
|
|
19
|
+
t.className='dsh-custom-tab'; nav.appendChild(t)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (document.readyState==='loading') document.addEventListener('DOMContentLoaded', boot)
|
|
23
|
+
else boot()
|
|
24
|
+
})()`
|
|
25
|
+
const name = 'dsh-plugin-settings-custom'
|
|
26
|
+
const inject = ['webServer']
|
|
27
|
+
function apply(ctx){
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
export { name, inject, apply }
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-plugin-settings-custom",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "DSH 设置页\"自定义\"页签(容纳全局指令/Skill/MCP 面板)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dsh",
|
|
7
|
+
"dsh-plugin",
|
|
8
|
+
"deepseek-harness",
|
|
9
|
+
"settings",
|
|
10
|
+
"custom"
|
|
11
|
+
],
|
|
12
|
+
"type": "module",
|
|
13
|
+
"main": "lib/index.js",
|
|
14
|
+
"files": [
|
|
15
|
+
"lib",
|
|
16
|
+
"cordis.patch.yml",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"dsh": {
|
|
20
|
+
"bundle": {
|
|
21
|
+
"patch": "./cordis.patch.yml"
|
|
22
|
+
},
|
|
23
|
+
"client": {
|
|
24
|
+
"inject": [
|
|
25
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
26
|
+
"@deepseek-ai/dsh-client-locale",
|
|
27
|
+
"@deepseek-ai/dsh-client-ui-settings"
|
|
28
|
+
],
|
|
29
|
+
"platform": "web"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"exports": {
|
|
34
|
+
".": "./lib/index.js",
|
|
35
|
+
"./client": "./lib/client.js",
|
|
36
|
+
"./package.json": "./package.json"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/mengyu-arch/dsh-plugins.git"
|
|
44
|
+
}
|
|
45
|
+
}
|