dsh-plugin-capabilities 0.1.4 → 0.1.6
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 +119 -24
- package/lib/client.js.map +4 -4
- package/lib/index.js +11 -2
- package/lib/index.js.map +4 -4
- package/package.json +2 -1
- package/skills/find-skills/LICENSE +21 -0
- package/skills/find-skills/SKILL.md +141 -0
- package/skills/skill-creator/LICENSE.txt +202 -0
- package/skills/skill-creator/SKILL.md +485 -0
- package/skills/skill-creator/agents/analyzer.md +274 -0
- package/skills/skill-creator/agents/comparator.md +202 -0
- package/skills/skill-creator/agents/grader.md +223 -0
- package/skills/skill-creator/assets/eval_review.html +146 -0
- package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/skills/skill-creator/references/schemas.md +430 -0
- package/skills/skill-creator/scripts/__init__.py +0 -0
- package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/skills/skill-creator/scripts/generate_report.py +326 -0
- package/skills/skill-creator/scripts/improve_description.py +247 -0
- package/skills/skill-creator/scripts/package_skill.py +136 -0
- package/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/skills/skill-creator/scripts/run_eval.py +310 -0
- package/skills/skill-creator/scripts/run_loop.py +328 -0
- package/skills/skill-creator/scripts/utils.py +47 -0
- package/src/client/CapabilitiesSection.tsx +102 -0
- package/src/client/McpTab.tsx +2 -0
- package/src/client/SkillsTab.tsx +2 -0
- package/src/client/css.ts +16 -2
- package/src/client/index.ts +15 -22
- package/src/client/locales.ts +2 -0
- package/src/index.ts +22 -6
- package/src/packaged-skills.test.ts +40 -0
- package/src/smoke.test.ts +8 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/dsh-plugin-capabilities)
|
|
4
4
|
[](./LICENSE)
|
|
5
5
|
|
|
6
|
-
在 dsh 设置页管理技能与 MCP
|
|
6
|
+
在 dsh 设置页管理技能与 MCP 服务器。本插件在设置里新增一级分区「技能与 MCP」(与「通用设置」「模型」并列),内含「技能」「MCP」两个标签页,技能目录和 profile 的 MCP 服务器行都能直接在页面上查看与维护,不必手工编辑文件;来自 Claude Code、Codex 等其他 agent 的技能与 MCP 配置也能一并纳入。`dsh web` 与 [DSH Desktop](https://github.com/qinyre/dsh-Desktop) 均可使用。
|
|
7
7
|
|
|
8
8
|
## 技能
|
|
9
9
|
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
如果机器上存在 Claude Code 或 Codex 的技能目录(`~/.claude/skills`、`~/.codex/skills`),它们会作为额外的扫描根自动进入目录。文件不会被复制,改动留在原地,两边实时同步。
|
|
15
15
|
|
|
16
|
+
本插件还自带两条只读技能:skill-creator(创建与迭代改进技能,来自 [anthropics/skills](https://github.com/anthropics/skills),Apache-2.0)与 find-skills(发现并安装社区技能,来自 [vercel-labs/skills](https://github.com/vercel-labs/skills),MIT)。它们随插件进入扫描目录,设置页里来源显示为「自定义」,会话中可直接调用;升级插件即更新、卸载插件即移除,不向 `DSH_HOME` 写入任何文件。
|
|
17
|
+
|
|
16
18
|
## MCP
|
|
17
19
|
|
|
18
20
|

|
|
@@ -29,7 +31,7 @@ MCP 行的变更需要重启 dsh 才会进入组合。MCP 页头部有常驻的
|
|
|
29
31
|
dsh plugin --profile web add dsh-plugin-capabilities
|
|
30
32
|
```
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
安装后打开设置,即可在一级导航里看到「技能与 MCP」分区(位于「模型」与「插件」之间)。开发时也可以直接安装本地源码检出:`dsh plugin --profile web add file:/path/to/dsh-plugin-capabilities`,包内的 `prepare` 脚本会自动构建出 `lib/`。
|
|
33
35
|
|
|
34
36
|
## 工作原理
|
|
35
37
|
|
package/lib/client.js
CHANGED
|
@@ -28,15 +28,23 @@ __export(index_exports, {
|
|
|
28
28
|
name: () => name
|
|
29
29
|
});
|
|
30
30
|
module.exports = __toCommonJS(index_exports);
|
|
31
|
-
var
|
|
31
|
+
var import_react4 = require("react");
|
|
32
32
|
|
|
33
|
-
// src/client/
|
|
34
|
-
var
|
|
35
|
-
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
33
|
+
// src/client/CapabilitiesSection.tsx
|
|
34
|
+
var import_react3 = require("react");
|
|
36
35
|
|
|
37
36
|
// src/client/css.ts
|
|
38
37
|
var CSS = `
|
|
39
38
|
.dpc-section{display:flex;flex-direction:column;gap:14px;width:100%;max-width:760px;color:var(--dsw-alias-label-primary)}
|
|
39
|
+
.dpc-heading{margin:0;font-size:18px;line-height:26px;font-weight:600}
|
|
40
|
+
/* Top-level section's internal tabs \u2014 same underline-tab look as the host's
|
|
41
|
+
Plugins section so the promoted placement still reads as one family. */
|
|
42
|
+
.dpc-tabs{display:flex;align-items:flex-end;gap:22px;border-bottom:1px solid var(--dsw-alias-border-l2);margin-top:2px}
|
|
43
|
+
.dpc-tab{position:relative;border:0;padding:7px 1px 9px;background:transparent;color:var(--dsw-alias-label-tertiary);font:inherit;font-size:13px;line-height:20px;cursor:pointer}
|
|
44
|
+
.dpc-tab:hover,.dpc-tab[data-active='true']{color:var(--dsw-alias-label-primary)}
|
|
45
|
+
.dpc-tab[data-active='true']::after,.dpc-tab:focus-visible::after{position:absolute;right:0;bottom:-1px;left:0;height:2px;border-radius:2px 2px 0 0;background:var(--dsw-alias-label-primary);content:''}
|
|
46
|
+
.dpc-tab:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px;border-radius:2px;color:var(--dsw-alias-label-primary)}
|
|
47
|
+
.dpc-tabPanel{min-width:0;padding-top:2px}
|
|
40
48
|
.dpc-head{display:flex;align-items:center;gap:8px}
|
|
41
49
|
.dpc-head h3{margin:0;font-size:13px;line-height:20px;font-weight:600}
|
|
42
50
|
.dpc-head>svg{flex:none;color:var(--dsw-alias-label-tertiary)}
|
|
@@ -70,8 +78,8 @@ var CSS = `
|
|
|
70
78
|
.dpc-label{display:flex;flex-direction:column;gap:4px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}
|
|
71
79
|
.dpc-label>span:first-child{color:var(--dsw-alias-label-tertiary)}
|
|
72
80
|
.dpc-input,.dpc-textarea,.dpc-select{width:100%;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:7px 10px;outline:none;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px}
|
|
73
|
-
.dpc-textarea{min-height:
|
|
74
|
-
.dpc-textarea[data-short='true']{min-height:
|
|
81
|
+
.dpc-textarea{min-height:240px;resize:vertical;font-family:var(--ds-font-family-code);line-height:1.5}
|
|
82
|
+
.dpc-textarea[data-short='true']{min-height:96px}
|
|
75
83
|
.dpc-input:focus-visible,.dpc-textarea:focus-visible,.dpc-select:focus-visible{border-color:var(--dsw-alias-state-business-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--dsw-alias-state-business-primary) 18%,transparent)}
|
|
76
84
|
.dpc-checks{display:flex;gap:16px;font-size:13px;line-height:20px}
|
|
77
85
|
.dpc-checks label{display:inline-flex;align-items:center;gap:6px;cursor:pointer}
|
|
@@ -80,6 +88,11 @@ var CSS = `
|
|
|
80
88
|
its own scroll so title, intro, and footer stay pinned. The doubled class
|
|
81
89
|
beats the host dialog's module CSS regardless of injection order. */
|
|
82
90
|
.dpc-modalWide.dpc-modalWide{width:min(680px,100%)}
|
|
91
|
+
/* Editor dialogs (new skill / server): 640px wide so markdown bodies and
|
|
92
|
+
command/arg/env lines stop wrapping mid-token; the content column scrolls
|
|
93
|
+
on short viewports instead of clipping past the dialog edge. */
|
|
94
|
+
.dpc-modalForm.dpc-modalForm{width:min(640px,100%)}
|
|
95
|
+
.dpc-modalScroll.dpc-modalScroll{max-height:calc(100vh - 160px);overflow-y:auto}
|
|
83
96
|
.dpc-importScroll{display:flex;flex-direction:column;gap:14px;max-height:min(400px,52vh);overflow-y:auto;padding:2px 4px 2px 2px}
|
|
84
97
|
.dpc-importGroup{display:flex;flex-direction:column;gap:8px}
|
|
85
98
|
.dpc-importHead{display:flex;align-items:center;gap:8px;padding:0 2px}
|
|
@@ -89,6 +102,8 @@ var CSS = `
|
|
|
89
102
|
`;
|
|
90
103
|
|
|
91
104
|
// src/client/McpTab.tsx
|
|
105
|
+
var import_react = require("react");
|
|
106
|
+
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
92
107
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
93
108
|
function importGroups(items) {
|
|
94
109
|
const label = (agent) => agent === "claude-code" ? "Claude Code" : agent === "codex" ? "Codex" : agent;
|
|
@@ -335,6 +350,8 @@ function McpTab(props) {
|
|
|
335
350
|
open: editor !== null,
|
|
336
351
|
onClose: () => setEditor(null),
|
|
337
352
|
title: editor !== null && editor.id !== "" ? t("editServer") : t("addServer"),
|
|
353
|
+
className: "dpc-modalForm",
|
|
354
|
+
contentClassName: "dpc-modalScroll",
|
|
338
355
|
children: editor !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dpc-form", children: [
|
|
339
356
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "dpc-label", children: [
|
|
340
357
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: t("serverName") }),
|
|
@@ -664,6 +681,8 @@ function SkillsTab(props) {
|
|
|
664
681
|
open: editor !== null,
|
|
665
682
|
onClose: () => setEditor(null),
|
|
666
683
|
title: editor === null ? "" : editor.mode === "create" ? t("newSkill") : editor.mode === "edit" ? t("editSkill") : t("viewSkill"),
|
|
684
|
+
className: "dpc-modalForm",
|
|
685
|
+
contentClassName: "dpc-modalScroll",
|
|
667
686
|
children: editor !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dpc-form", children: [
|
|
668
687
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "dpc-label", children: [
|
|
669
688
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("skillName") }),
|
|
@@ -765,8 +784,94 @@ function SkillsTab(props) {
|
|
|
765
784
|
] });
|
|
766
785
|
}
|
|
767
786
|
|
|
787
|
+
// src/client/CapabilitiesSection.tsx
|
|
788
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
789
|
+
function CapabilitiesSection(props) {
|
|
790
|
+
const { t, skills, mcp } = props;
|
|
791
|
+
const tabsId = (0, import_react3.useId)();
|
|
792
|
+
const tabRefs = (0, import_react3.useRef)([]);
|
|
793
|
+
const rows = [
|
|
794
|
+
{ id: "skills", label: t("skillsTab") },
|
|
795
|
+
{ id: "mcp", label: t("mcpTab") }
|
|
796
|
+
];
|
|
797
|
+
const [activeId, setActiveId] = (0, import_react3.useState)("skills");
|
|
798
|
+
const [visitedIds, setVisitedIds] = (0, import_react3.useState)(() => /* @__PURE__ */ new Set(["skills"]));
|
|
799
|
+
(0, import_react3.useEffect)(() => {
|
|
800
|
+
setVisitedIds((previous) => {
|
|
801
|
+
if (previous.has(activeId)) return previous;
|
|
802
|
+
return /* @__PURE__ */ new Set([...previous, activeId]);
|
|
803
|
+
});
|
|
804
|
+
}, [activeId]);
|
|
805
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dpc-section", children: [
|
|
806
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: CSS }),
|
|
807
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { className: "dpc-heading", children: t("sectionNav") }),
|
|
808
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dpc-tabs", role: "tablist", "aria-label": t("sectionNav"), children: rows.map((row, index) => {
|
|
809
|
+
const selected = row.id === activeId;
|
|
810
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
811
|
+
"button",
|
|
812
|
+
{
|
|
813
|
+
ref: (element) => {
|
|
814
|
+
tabRefs.current[index] = element;
|
|
815
|
+
},
|
|
816
|
+
id: `${tabsId}-tab-${row.id}`,
|
|
817
|
+
type: "button",
|
|
818
|
+
role: "tab",
|
|
819
|
+
className: "dpc-tab",
|
|
820
|
+
"aria-selected": selected,
|
|
821
|
+
"aria-controls": `${tabsId}-panel-${row.id}`,
|
|
822
|
+
"data-active": selected ? "true" : void 0,
|
|
823
|
+
tabIndex: selected ? 0 : -1,
|
|
824
|
+
onClick: () => {
|
|
825
|
+
setActiveId(row.id);
|
|
826
|
+
},
|
|
827
|
+
onKeyDown: (event) => {
|
|
828
|
+
let nextIndex;
|
|
829
|
+
switch (event.key) {
|
|
830
|
+
case "ArrowRight":
|
|
831
|
+
nextIndex = (index + 1) % rows.length;
|
|
832
|
+
break;
|
|
833
|
+
case "ArrowLeft":
|
|
834
|
+
nextIndex = (index - 1 + rows.length) % rows.length;
|
|
835
|
+
break;
|
|
836
|
+
case "Home":
|
|
837
|
+
nextIndex = 0;
|
|
838
|
+
break;
|
|
839
|
+
case "End":
|
|
840
|
+
nextIndex = rows.length - 1;
|
|
841
|
+
break;
|
|
842
|
+
default:
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
event.preventDefault();
|
|
846
|
+
setActiveId(rows[nextIndex]?.id ?? "skills");
|
|
847
|
+
tabRefs.current[nextIndex]?.focus();
|
|
848
|
+
},
|
|
849
|
+
children: row.label
|
|
850
|
+
},
|
|
851
|
+
row.id
|
|
852
|
+
);
|
|
853
|
+
}) }),
|
|
854
|
+
rows.filter((row) => row.id === activeId || visitedIds.has(row.id)).map((row) => {
|
|
855
|
+
const selected = row.id === activeId;
|
|
856
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
857
|
+
"div",
|
|
858
|
+
{
|
|
859
|
+
id: `${tabsId}-panel-${row.id}`,
|
|
860
|
+
className: "dpc-tabPanel",
|
|
861
|
+
role: "tabpanel",
|
|
862
|
+
"aria-labelledby": `${tabsId}-tab-${row.id}`,
|
|
863
|
+
hidden: !selected,
|
|
864
|
+
children: row.id === "skills" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SkillsTab, { t, injected: skills }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(McpTab, { t, injected: mcp })
|
|
865
|
+
},
|
|
866
|
+
row.id
|
|
867
|
+
);
|
|
868
|
+
})
|
|
869
|
+
] });
|
|
870
|
+
}
|
|
871
|
+
|
|
768
872
|
// src/client/locales.ts
|
|
769
873
|
var zh = {
|
|
874
|
+
sectionNav: "\u6280\u80FD\u4E0E MCP",
|
|
770
875
|
skillsTab: "\u6280\u80FD",
|
|
771
876
|
mcpTab: "MCP",
|
|
772
877
|
skillsTitle: "\u6280\u80FD\u7BA1\u7406",
|
|
@@ -837,6 +942,7 @@ var zh = {
|
|
|
837
942
|
failed: "\u64CD\u4F5C\u5931\u8D25"
|
|
838
943
|
};
|
|
839
944
|
var en = {
|
|
945
|
+
sectionNav: "Skills & MCP",
|
|
840
946
|
skillsTab: "Skills",
|
|
841
947
|
mcpTab: "MCP",
|
|
842
948
|
skillsTitle: "Skills",
|
|
@@ -946,25 +1052,14 @@ function apply(ctx) {
|
|
|
946
1052
|
},
|
|
947
1053
|
desktop: window.dshDesktop !== void 0
|
|
948
1054
|
};
|
|
949
|
-
ctx.slots.inject("settings.
|
|
950
|
-
return ctx.slots.register({
|
|
951
|
-
name: "settings.plugins.tab",
|
|
952
|
-
id: "capabilities-skills",
|
|
953
|
-
order: 30,
|
|
954
|
-
label: () => t("skillsTab"),
|
|
955
|
-
locale: NS,
|
|
956
|
-
inject: () => skillsInjected
|
|
957
|
-
}, () => (0, import_react3.createElement)(SkillsTab, { t, injected: skillsInjected }));
|
|
958
|
-
});
|
|
959
|
-
ctx.slots.inject("settings.plugins.tab", () => {
|
|
1055
|
+
ctx.slots.inject("settings.section", () => {
|
|
960
1056
|
return ctx.slots.register({
|
|
961
|
-
name: "settings.
|
|
962
|
-
id: "capabilities
|
|
963
|
-
order:
|
|
964
|
-
label: () => t("
|
|
965
|
-
locale: NS
|
|
966
|
-
|
|
967
|
-
}, () => (0, import_react3.createElement)(McpTab, { t, injected: mcpInjected }));
|
|
1057
|
+
name: "settings.section",
|
|
1058
|
+
id: "capabilities",
|
|
1059
|
+
order: 12,
|
|
1060
|
+
label: () => t("sectionNav"),
|
|
1061
|
+
locale: NS
|
|
1062
|
+
}, () => (0, import_react4.createElement)(CapabilitiesSection, { t, skills: skillsInjected, mcp: mcpInjected }));
|
|
968
1063
|
});
|
|
969
1064
|
}
|
|
970
1065
|
|