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.
Files changed (35) hide show
  1. package/README.md +4 -2
  2. package/lib/client.js +119 -24
  3. package/lib/client.js.map +4 -4
  4. package/lib/index.js +11 -2
  5. package/lib/index.js.map +4 -4
  6. package/package.json +2 -1
  7. package/skills/find-skills/LICENSE +21 -0
  8. package/skills/find-skills/SKILL.md +141 -0
  9. package/skills/skill-creator/LICENSE.txt +202 -0
  10. package/skills/skill-creator/SKILL.md +485 -0
  11. package/skills/skill-creator/agents/analyzer.md +274 -0
  12. package/skills/skill-creator/agents/comparator.md +202 -0
  13. package/skills/skill-creator/agents/grader.md +223 -0
  14. package/skills/skill-creator/assets/eval_review.html +146 -0
  15. package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  16. package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  17. package/skills/skill-creator/references/schemas.md +430 -0
  18. package/skills/skill-creator/scripts/__init__.py +0 -0
  19. package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  20. package/skills/skill-creator/scripts/generate_report.py +326 -0
  21. package/skills/skill-creator/scripts/improve_description.py +247 -0
  22. package/skills/skill-creator/scripts/package_skill.py +136 -0
  23. package/skills/skill-creator/scripts/quick_validate.py +103 -0
  24. package/skills/skill-creator/scripts/run_eval.py +310 -0
  25. package/skills/skill-creator/scripts/run_loop.py +328 -0
  26. package/skills/skill-creator/scripts/utils.py +47 -0
  27. package/src/client/CapabilitiesSection.tsx +102 -0
  28. package/src/client/McpTab.tsx +2 -0
  29. package/src/client/SkillsTab.tsx +2 -0
  30. package/src/client/css.ts +16 -2
  31. package/src/client/index.ts +15 -22
  32. package/src/client/locales.ts +2 -0
  33. package/src/index.ts +22 -6
  34. package/src/packaged-skills.test.ts +40 -0
  35. package/src/smoke.test.ts +8 -1
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![npm version](https://img.shields.io/npm/v/dsh-plugin-capabilities)](https://www.npmjs.com/package/dsh-plugin-capabilities)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
5
5
 
6
- 在 dsh 设置页管理技能与 MCP 服务器。本插件在插件区新增「技能」「MCP」两个标签页,技能目录和 profile 的 MCP 服务器行都能直接在页面上查看与维护,不必手工编辑文件;来自 Claude Code、Codex 等其他 agent 的技能与 MCP 配置也能一并纳入。`dsh web` 与 [DSH Desktop](https://github.com/qinyre/dsh-Desktop) 均可使用。
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
  ![「MCP」标签页](docs/images/screenshot-mcp.png)
@@ -29,7 +31,7 @@ MCP 行的变更需要重启 dsh 才会进入组合。MCP 页头部有常驻的
29
31
  dsh plugin --profile web add dsh-plugin-capabilities
30
32
  ```
31
33
 
32
- 安装后打开 设置 → 插件,即可看到新增的「技能」与「MCP」标签页。开发时也可以直接安装本地源码检出:`dsh plugin --profile web add file:/path/to/dsh-plugin-capabilities`,包内的 `prepare` 脚本会自动构建出 `lib/`。
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 import_react3 = require("react");
31
+ var import_react4 = require("react");
32
32
 
33
- // src/client/McpTab.tsx
34
- var import_react = require("react");
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:120px;resize:vertical;font-family:var(--ds-font-family-code);line-height:1.5}
74
- .dpc-textarea[data-short='true']{min-height:64px}
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.plugins.tab", () => {
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.plugins.tab",
962
- id: "capabilities-mcp",
963
- order: 40,
964
- label: () => t("mcpTab"),
965
- locale: NS,
966
- inject: () => mcpInjected
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