@max-null/dsh-skill-mcp-center 0.6.0 → 0.6.1
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/client.js +86 -50
- package/dist/service.d.ts +10 -0
- package/dist/service.js +40 -0
- package/package.json +1 -1
package/client.js
CHANGED
|
@@ -81,6 +81,10 @@ var CSS = `
|
|
|
81
81
|
.smc-toggle::after { content: ''; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: #fff; transition: left .15s; }
|
|
82
82
|
.smc-toggle.on::after { left: 21px; }
|
|
83
83
|
.smc-toggle:disabled { opacity: 0.4; cursor: default; }
|
|
84
|
+
.smc-skill-group { margin-bottom: 10px; }
|
|
85
|
+
.smc-skill-group-head { display: flex; align-items: baseline; gap: 6px; padding: 6px 2px 4px; font-size: 11px; font-weight: 600; letter-spacing: .04em; color: var(--dsw-alias-label-caption); }
|
|
86
|
+
.smc-skill-group-count { font-weight: 400; opacity: .7; }
|
|
87
|
+
.smc-skill-group-note { padding: 0 2px 6px; font-size: 11px; line-height: 1.5; color: var(--dsw-alias-label-caption); }
|
|
84
88
|
|
|
85
89
|
.smc-input { height: 34px; padding: 0 12px; border-radius: 8px; border: 1px solid var(--dsw-alias-border-l2); background: var(--dsw-alias-bg-layer-3); color: var(--dsw-alias-label-primary); font-size: 13px; line-height: 1.5; outline: none; font-family: inherit; }
|
|
86
90
|
.smc-input:focus { border-color: var(--dsw-alias-brand-primary); }
|
|
@@ -236,6 +240,11 @@ var zhDict = {
|
|
|
236
240
|
groupGlobal: "\u5168\u5C40",
|
|
237
241
|
groupWorkspace: "\u5DE5\u4F5C\u533A",
|
|
238
242
|
groupBundled: "\u5185\u7F6E\uFF08DSH \u5B98\u65B9\uFF09",
|
|
243
|
+
groupProject: "\u9879\u76EE\u7EA7",
|
|
244
|
+
groupUser: "\u7528\u6237\u7EA7",
|
|
245
|
+
groupPlugin: "\u63D2\u4EF6\u81EA\u5E26",
|
|
246
|
+
groupRuntime: "\u4EE3\u7801\u6CE8\u518C",
|
|
247
|
+
groupRuntimeNote: "\u7531\u63D2\u4EF6\u5728\u8FD0\u884C\u65F6\u6CE8\u518C\uFF0C\u4E0D\u53EF\u5728\u6B64\u7981\u7528",
|
|
239
248
|
readOnlyBadge: "\u5185\u7F6E\u53EA\u8BFB",
|
|
240
249
|
noMatch: "\u6CA1\u6709\u5339\u914D\u7684 skill",
|
|
241
250
|
detailPath: "\u8DEF\u5F84",
|
|
@@ -295,6 +304,11 @@ var enDict = {
|
|
|
295
304
|
groupGlobal: "Global",
|
|
296
305
|
groupWorkspace: "Workspace",
|
|
297
306
|
groupBundled: "Built-in (DSH official)",
|
|
307
|
+
groupProject: "Project",
|
|
308
|
+
groupUser: "User",
|
|
309
|
+
groupPlugin: "Plugin-bundled",
|
|
310
|
+
groupRuntime: "Code-registered",
|
|
311
|
+
groupRuntimeNote: "Registered by a plugin at runtime; cannot be disabled here",
|
|
298
312
|
readOnlyBadge: "built-in read-only",
|
|
299
313
|
noMatch: "No matching skills",
|
|
300
314
|
detailPath: "path",
|
|
@@ -835,6 +849,21 @@ function sourceLabel(source, short = false) {
|
|
|
835
849
|
const name = pkg.split("/").pop() ?? pkg;
|
|
836
850
|
return short ? name : `plugin \xB7 ${name}`;
|
|
837
851
|
}
|
|
852
|
+
var SKILL_GROUP_ORDER = ["project", "user", "plugin", "bundled", "runtime"];
|
|
853
|
+
var SKILL_GROUP_LABEL = {
|
|
854
|
+
project: "groupProject",
|
|
855
|
+
user: "groupUser",
|
|
856
|
+
plugin: "groupPlugin",
|
|
857
|
+
bundled: "groupBundled",
|
|
858
|
+
runtime: "groupRuntime"
|
|
859
|
+
};
|
|
860
|
+
function skillGroupOf(source) {
|
|
861
|
+
if (source === "project-dsh" || source === "project-agents") return "project";
|
|
862
|
+
if (source === "user-dsh" || source === "user-agents") return "user";
|
|
863
|
+
if (source.startsWith("plugin:")) return "plugin";
|
|
864
|
+
if (source === "bundled") return "bundled";
|
|
865
|
+
return "runtime";
|
|
866
|
+
}
|
|
838
867
|
function skillInNamespace(s, ns) {
|
|
839
868
|
if (ns === "all") return true;
|
|
840
869
|
if (ns === "global") {
|
|
@@ -927,57 +956,64 @@ function SidebarSkillTab({ visible, cwd }) {
|
|
|
927
956
|
k
|
|
928
957
|
)) })
|
|
929
958
|
] }),
|
|
930
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-sidebar-list", children: noWorkspace ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-empty", children: t("noWorkspace") }) : visibleItems.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-empty", children: q !== "" ? t("noMatch") : t("noSkills") }) :
|
|
931
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "smc-
|
|
932
|
-
|
|
933
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className:
|
|
934
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "smc-srv-name", children: s.name }),
|
|
935
|
-
!s.modelInvocable && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "smc-badge", children: t("modelDisabled") }),
|
|
936
|
-
!s.writable && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "smc-badge", children: sourceLabel(s.source, true) }),
|
|
937
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
938
|
-
"button",
|
|
939
|
-
{
|
|
940
|
-
type: "button",
|
|
941
|
-
className: "smc-btn",
|
|
942
|
-
style: { height: 20, padding: "0 6px", fontSize: 11 },
|
|
943
|
-
onClick: () => {
|
|
944
|
-
openMd(s.path);
|
|
945
|
-
},
|
|
946
|
-
"aria-label": mdPath === s.path ? t("hideMd") : t("viewMd"),
|
|
947
|
-
children: mdPath === s.path ? t("hideMd") : "MD"
|
|
948
|
-
}
|
|
949
|
-
),
|
|
950
|
-
s.writable && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
951
|
-
"button",
|
|
952
|
-
{
|
|
953
|
-
type: "button",
|
|
954
|
-
className: "smc-btn danger",
|
|
955
|
-
style: { height: 20, padding: "0 6px", fontSize: 11 },
|
|
956
|
-
onClick: () => {
|
|
957
|
-
removeSkill(s);
|
|
958
|
-
},
|
|
959
|
-
"aria-label": t("deleteSkill"),
|
|
960
|
-
children: t("remove")
|
|
961
|
-
}
|
|
962
|
-
),
|
|
963
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
964
|
-
"button",
|
|
965
|
-
{
|
|
966
|
-
type: "button",
|
|
967
|
-
className: `smc-toggle${s.modelInvocable ? " on" : ""}`,
|
|
968
|
-
title: t("toggleModelVisible"),
|
|
969
|
-
onClick: () => {
|
|
970
|
-
void rpc("toggleSkill", { path: s.path }).then(() => {
|
|
971
|
-
load();
|
|
972
|
-
});
|
|
973
|
-
},
|
|
974
|
-
"aria-label": s.modelInvocable ? t("disable") : t("enable")
|
|
975
|
-
}
|
|
976
|
-
)
|
|
959
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-sidebar-list", children: noWorkspace ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-empty", children: t("noWorkspace") }) : visibleItems.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-empty", children: q !== "" ? t("noMatch") : t("noSkills") }) : SKILL_GROUP_ORDER.map((kind) => ({ kind, items: visibleItems.filter((s) => skillGroupOf(s.source) === kind) })).filter((group) => group.items.length > 0).map((group) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "smc-skill-group", children: [
|
|
960
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "smc-skill-group-head", children: [
|
|
961
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: t(SKILL_GROUP_LABEL[group.kind]) }),
|
|
962
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "smc-skill-group-count", children: group.items.length })
|
|
977
963
|
] }),
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
964
|
+
group.kind === "runtime" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-skill-group-note", children: t("groupRuntimeNote") }),
|
|
965
|
+
group.items.map((s) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
966
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "smc-srv", title: `${s.description}
|
|
967
|
+
${s.path}`, children: [
|
|
968
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `smc-dot${s.modelInvocable ? "" : " idle"}` }),
|
|
969
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "smc-srv-name", children: s.name }),
|
|
970
|
+
!s.modelInvocable && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "smc-badge", children: t("modelDisabled") }),
|
|
971
|
+
!s.writable && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "smc-badge", children: sourceLabel(s.source, true) }),
|
|
972
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
973
|
+
"button",
|
|
974
|
+
{
|
|
975
|
+
type: "button",
|
|
976
|
+
className: "smc-btn",
|
|
977
|
+
style: { height: 20, padding: "0 6px", fontSize: 11 },
|
|
978
|
+
onClick: () => {
|
|
979
|
+
openMd(s.path);
|
|
980
|
+
},
|
|
981
|
+
"aria-label": mdPath === s.path ? t("hideMd") : t("viewMd"),
|
|
982
|
+
children: mdPath === s.path ? t("hideMd") : "MD"
|
|
983
|
+
}
|
|
984
|
+
),
|
|
985
|
+
s.writable && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
986
|
+
"button",
|
|
987
|
+
{
|
|
988
|
+
type: "button",
|
|
989
|
+
className: "smc-btn danger",
|
|
990
|
+
style: { height: 20, padding: "0 6px", fontSize: 11 },
|
|
991
|
+
onClick: () => {
|
|
992
|
+
removeSkill(s);
|
|
993
|
+
},
|
|
994
|
+
"aria-label": t("deleteSkill"),
|
|
995
|
+
children: t("remove")
|
|
996
|
+
}
|
|
997
|
+
),
|
|
998
|
+
s.writable && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
999
|
+
"button",
|
|
1000
|
+
{
|
|
1001
|
+
type: "button",
|
|
1002
|
+
className: `smc-toggle${s.modelInvocable ? " on" : ""}`,
|
|
1003
|
+
title: t("toggleModelVisible"),
|
|
1004
|
+
onClick: () => {
|
|
1005
|
+
void rpc("toggleSkill", { path: s.path }).then(() => {
|
|
1006
|
+
load();
|
|
1007
|
+
});
|
|
1008
|
+
},
|
|
1009
|
+
"aria-label": s.modelInvocable ? t("disable") : t("enable")
|
|
1010
|
+
}
|
|
1011
|
+
)
|
|
1012
|
+
] }),
|
|
1013
|
+
s.description !== "" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-srv-desc", children: s.description }),
|
|
1014
|
+
mdPath === s.path && (mdError !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-md-err", children: t("mdLoadFailed", { e: mdError }) }) : mdText === null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-md", children: t("loading") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-md", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MdWithRefs, { text: mdText }) }))
|
|
1015
|
+
] }, s.path === "" ? `runtime:${s.name}` : s.path))
|
|
1016
|
+
] }, group.kind)) })
|
|
981
1017
|
] });
|
|
982
1018
|
}
|
|
983
1019
|
var inject = ["slots", "connection", "locale"];
|
package/dist/service.d.ts
CHANGED
|
@@ -163,6 +163,16 @@ export declare class SkillMcpService extends Service {
|
|
|
163
163
|
* bundled inside loaded plugin packages, and any configured official roots.
|
|
164
164
|
*/
|
|
165
165
|
listSkills(cwd?: string): Promise<SkillView[]>;
|
|
166
|
+
/**
|
|
167
|
+
* 补上「运行时注册」的 skill:`ctx.skills.register()` 注册的条目没有 SKILL.md,
|
|
168
|
+
* 磁盘扫描(本项目的主要取数方式)看不到它们——dsh-jubensha 的 DM 手册、office、
|
|
169
|
+
* genui 都属于这一类。用户因此报了「面板少了很多 skill」。
|
|
170
|
+
*
|
|
171
|
+
* skills 服务是**可选**的:web-app 宿主把它关掉(presets 拥有发现,没有全局层可列),
|
|
172
|
+
* 所以这里 feature-detect,拿不到就原样返回空,不改变既有行为。
|
|
173
|
+
* 这些条目没有可写的 SKILL.md,标成 `writable: false`——开关对它们没有意义。
|
|
174
|
+
*/
|
|
175
|
+
private runtimeOnlySkills;
|
|
166
176
|
/** Flip one disk-backed skill's model invocation by rewriting its SKILL.md frontmatter. */
|
|
167
177
|
toggleSkill(path: string): Promise<SkillView>;
|
|
168
178
|
/**
|
package/dist/service.js
CHANGED
|
@@ -268,8 +268,48 @@ export class SkillMcpService extends Service {
|
|
|
268
268
|
for (const dir of this.officialSkillDirs) {
|
|
269
269
|
skills.push(...await scanSkillRoot(dir, 'bundled', false, 'dsh-official'));
|
|
270
270
|
}
|
|
271
|
+
skills.push(...await this.runtimeOnlySkills(skills));
|
|
271
272
|
return skills;
|
|
272
273
|
}
|
|
274
|
+
/**
|
|
275
|
+
* 补上「运行时注册」的 skill:`ctx.skills.register()` 注册的条目没有 SKILL.md,
|
|
276
|
+
* 磁盘扫描(本项目的主要取数方式)看不到它们——dsh-jubensha 的 DM 手册、office、
|
|
277
|
+
* genui 都属于这一类。用户因此报了「面板少了很多 skill」。
|
|
278
|
+
*
|
|
279
|
+
* skills 服务是**可选**的:web-app 宿主把它关掉(presets 拥有发现,没有全局层可列),
|
|
280
|
+
* 所以这里 feature-detect,拿不到就原样返回空,不改变既有行为。
|
|
281
|
+
* 这些条目没有可写的 SKILL.md,标成 `writable: false`——开关对它们没有意义。
|
|
282
|
+
*/
|
|
283
|
+
async runtimeOnlySkills(diskBacked) {
|
|
284
|
+
const skills = this.ctx.get('skills');
|
|
285
|
+
if (skills === undefined)
|
|
286
|
+
return [];
|
|
287
|
+
let catalog;
|
|
288
|
+
try {
|
|
289
|
+
catalog = await skills.list();
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
// 目录服务不可用不该让整个面板失败——磁盘那部分仍然有价值。
|
|
293
|
+
return [];
|
|
294
|
+
}
|
|
295
|
+
const known = new Set(diskBacked.map(skill => skill.name));
|
|
296
|
+
const extra = [];
|
|
297
|
+
for (const entry of catalog) {
|
|
298
|
+
if (known.has(entry.name))
|
|
299
|
+
continue;
|
|
300
|
+
extra.push({
|
|
301
|
+
name: entry.name,
|
|
302
|
+
description: entry.description,
|
|
303
|
+
source: 'runtime',
|
|
304
|
+
provider: entry.provider,
|
|
305
|
+
modelInvocable: entry.invocation.modelInvocable,
|
|
306
|
+
userInvocable: entry.invocation.userInvocable,
|
|
307
|
+
writable: false,
|
|
308
|
+
path: '',
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
return extra;
|
|
312
|
+
}
|
|
273
313
|
/** Flip one disk-backed skill's model invocation by rewriting its SKILL.md frontmatter. */
|
|
274
314
|
async toggleSkill(path) {
|
|
275
315
|
let text;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@max-null/dsh-skill-mcp-center",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Skill & MCP management center for DeepSeek Harness — manage skills and MCP servers in Settings, live MCP status in the sidebar",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|