@skills-hub-ai/mcp 0.1.6 → 0.1.7

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 CHANGED
@@ -38,10 +38,10 @@ Add to your Cursor MCP settings (`~/.cursor/mcp.json`):
38
38
 
39
39
  The server scans these directories for installed skills:
40
40
 
41
- | Tool | Directory |
42
- |------|-----------|
41
+ | Tool | Directory |
42
+ | ----------- | ------------------- |
43
43
  | Claude Code | `~/.claude/skills/` |
44
- | Cursor | `~/.cursor/skills/` |
44
+ | Cursor | `~/.cursor/skills/` |
45
45
 
46
46
  Each skill directory should contain a `SKILL.md` file (installed via `skills-hub install <slug>`).
47
47
 
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,aAAa,EAAE,OAAO,CAAC;IACvB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE;QACX,QAAQ,EAAE,KAAK,CAAC;YACd,KAAK,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAC;gBAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;aAAE,CAAC;YACnE,SAAS,EAAE,MAAM,CAAC;YAClB,UAAU,EAAE,OAAO,CAAC;SACrB,CAAC,CAAC;KACJ,GAAG,IAAI,CAAC;CACV;AAED,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,MAAM,EACjB,KAAK,SAAK,EACV,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAY9B;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAO7E"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,aAAa,EAAE,OAAO,CAAC;IACvB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE;QACX,QAAQ,EAAE,KAAK,CAAC;YACd,KAAK,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAC;gBAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;aAAE,CAAC;YACnE,SAAS,EAAE,MAAM,CAAC;YAClB,UAAU,EAAE,OAAO,CAAC;SACrB,CAAC,CAAC;KACJ,GAAG,IAAI,CAAC;CACV;AAED,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,MAAM,EACjB,KAAK,SAAK,EACV,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAgB9B;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAS7E"}
package/dist/api.js CHANGED
@@ -11,7 +11,11 @@ function fetchWithTimeout(url) {
11
11
  return fetch(url, { signal: controller.signal, headers }).finally(() => clearTimeout(timer));
12
12
  }
13
13
  export async function searchSkills(query, category, limit = 10, org) {
14
- const params = new URLSearchParams({ q: query, limit: String(limit), sort: "relevance" });
14
+ const params = new URLSearchParams({
15
+ q: query,
16
+ limit: String(limit),
17
+ sort: "relevance",
18
+ });
15
19
  if (category)
16
20
  params.set("category", category);
17
21
  if (org)
package/dist/api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,2BAA2B,CAAC;AAC9E,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE,CAAC;AACzD,MAAM,UAAU,GAAG,MAAM,CAAC;AAE1B,SAAS,gBAAgB,CAAC,GAAW;IACnC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,UAAU,CAAC,CAAC;IAC/D,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,SAAS,EAAE,CAAC;IACnD,CAAC;IACD,OAAO,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/F,CAAC;AAqCD,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAa,EACb,QAAiB,EACjB,KAAK,GAAG,EAAE,EACV,GAAY;IAEZ,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IAC1F,IAAI,QAAQ;QAAE,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC/C,IAAI,GAAG;QAAE,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAEhC,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,GAAG,OAAO,kBAAkB,MAAM,EAAE,CAAC,CAAC;IACzE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,kBAAkB,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAmC,CAAC;IAClE,OAAO,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAY;IAC/C,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,GAAG,OAAO,kBAAkB,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3F,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAsB,CAAC;AACjD,CAAC"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,2BAA2B,CAAC;AAC9E,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE,CAAC;AACzD,MAAM,UAAU,GAAG,MAAM,CAAC;AAE1B,SAAS,gBAAgB,CAAC,GAAW;IACnC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,UAAU,CAAC,CAAC;IAC/D,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,SAAS,EAAE,CAAC;IACnD,CAAC;IACD,OAAO,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CACrE,YAAY,CAAC,KAAK,CAAC,CACpB,CAAC;AACJ,CAAC;AAqCD,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAa,EACb,QAAiB,EACjB,KAAK,GAAG,EAAE,EACV,GAAY;IAEZ,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,CAAC,EAAE,KAAK;QACR,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;QACpB,IAAI,EAAE,WAAW;KAClB,CAAC,CAAC;IACH,IAAI,QAAQ;QAAE,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC/C,IAAI,GAAG;QAAE,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAEhC,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,GAAG,OAAO,kBAAkB,MAAM,EAAE,CAAC,CAAC;IACzE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,kBAAkB,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAmC,CAAC;IAClE,OAAO,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAY;IAC/C,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAChC,GAAG,OAAO,kBAAkB,kBAAkB,CAAC,IAAI,CAAC,EAAE,CACvD,CAAC;IACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAsB,CAAC;AACjD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,WAAW,EAAE,MAAM,6BAA6B,CAAC;AA0C7E,oDAAoD;AACpD,wBAAgB,cAAc,IAAI,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAczD;AAED,8CAA8C;AAC9C,wBAAgB,UAAU,IAAI,IAAI,CAGjC"}
1
+ {"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAuC7E,oDAAoD;AACpD,wBAAgB,cAAc,IAAI,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAczD;AAED,8CAA8C;AAC9C,wBAAgB,UAAU,IAAI,IAAI,CAGjC"}
package/dist/discover.js CHANGED
@@ -8,10 +8,7 @@ let cacheTime = 0;
8
8
  /** Directories where skills may be installed */
9
9
  function getSkillPaths() {
10
10
  const home = homedir();
11
- return [
12
- join(home, ".claude", "skills"),
13
- join(home, ".cursor", "skills"),
14
- ];
11
+ return [join(home, ".claude", "skills"), join(home, ".cursor", "skills")];
15
12
  }
16
13
  /** Scan a single skills directory and collect parsed skills */
17
14
  function scanDir(dir, out) {
@@ -1 +1 @@
1
- {"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,YAAY,EAAoB,MAAM,6BAA6B,CAAC;AAE7E,MAAM,YAAY,GAAG,MAAM,CAAC;AAE5B,IAAI,KAAK,GAAoC,IAAI,CAAC;AAClD,IAAI,SAAS,GAAG,CAAC,CAAC;AAElB,gDAAgD;AAChD,SAAS,aAAa;IACpB,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,OAAO;QACL,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC;QAC/B,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC;KAChC,CAAC;AACJ,CAAC;AAED,+DAA+D;AAC/D,SAAS,OAAO,CAAC,GAAW,EAAE,GAA6B;IACzD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO;IAE7B,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;YAAE,SAAS;QAEnC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACxB,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS,CAAC,qCAAqC;QAElE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;QAC9C,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,SAAS;QAErC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;YACrC,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACnC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,uBAAuB;QACzB,CAAC;IACH,CAAC;AACH,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,cAAc;IAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,IAAI,KAAK,IAAI,GAAG,GAAG,SAAS,GAAG,YAAY,EAAE,CAAC;QAC5C,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC9C,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,EAAE,CAAC;QAClC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACvB,CAAC;IAED,KAAK,GAAG,MAAM,CAAC;IACf,SAAS,GAAG,GAAG,CAAC;IAChB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,UAAU;IACxB,KAAK,GAAG,IAAI,CAAC;IACb,SAAS,GAAG,CAAC,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,YAAY,EAAoB,MAAM,6BAA6B,CAAC;AAE7E,MAAM,YAAY,GAAG,MAAM,CAAC;AAE5B,IAAI,KAAK,GAAoC,IAAI,CAAC;AAClD,IAAI,SAAS,GAAG,CAAC,CAAC;AAElB,gDAAgD;AAChD,SAAS,aAAa;IACpB,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC5E,CAAC;AAED,+DAA+D;AAC/D,SAAS,OAAO,CAAC,GAAW,EAAE,GAA6B;IACzD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO;IAE7B,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;YAAE,SAAS;QAEnC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACxB,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS,CAAC,qCAAqC;QAElE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;QAC9C,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,SAAS;QAErC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;YACrC,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACnC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,uBAAuB;QACzB,CAAC;IACH,CAAC;AACH,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,cAAc;IAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,IAAI,KAAK,IAAI,GAAG,GAAG,SAAS,GAAG,YAAY,EAAE,CAAC;QAC5C,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC9C,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,EAAE,CAAC;QAClC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACvB,CAAC;IAED,KAAK,GAAG,MAAM,CAAC;IACf,SAAS,GAAG,GAAG,CAAC;IAChB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,UAAU;IACxB,KAAK,GAAG,IAAI,CAAC;IACb,SAAS,GAAG,CAAC,CAAC;AAChB,CAAC"}
package/dist/index.js CHANGED
@@ -54,10 +54,19 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
54
54
  inputSchema: {
55
55
  type: "object",
56
56
  properties: {
57
- query: { type: "string", description: "Search query (e.g. 'code review', 'testing React')" },
58
- category: { type: "string", description: "Filter by category slug (e.g. 'review', 'test', 'build')" },
57
+ query: {
58
+ type: "string",
59
+ description: "Search query (e.g. 'code review', 'testing React')",
60
+ },
61
+ category: {
62
+ type: "string",
63
+ description: "Filter by category slug (e.g. 'review', 'test', 'build')",
64
+ },
59
65
  limit: { type: "number", description: "Max results (default 10)" },
60
- organization: { type: "string", description: "Organization slug to include org-private skills in results (requires authentication)" },
66
+ organization: {
67
+ type: "string",
68
+ description: "Organization slug to include org-private skills in results (requires authentication)",
69
+ },
61
70
  },
62
71
  required: ["query"],
63
72
  },
@@ -68,7 +77,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
68
77
  inputSchema: {
69
78
  type: "object",
70
79
  properties: {
71
- slug: { type: "string", description: "Skill slug (e.g. 'review-code')" },
80
+ slug: {
81
+ type: "string",
82
+ description: "Skill slug (e.g. 'review-code')",
83
+ },
72
84
  },
73
85
  required: ["slug"],
74
86
  },
@@ -80,7 +92,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
80
92
  type: "object",
81
93
  properties: {
82
94
  slug: { type: "string", description: "Skill slug to install" },
83
- target: { type: "string", enum: ["claude-code", "cursor"], description: "Install target (default: claude-code)" },
95
+ target: {
96
+ type: "string",
97
+ enum: ["claude-code", "cursor"],
98
+ description: "Install target (default: claude-code)",
99
+ },
84
100
  },
85
101
  required: ["slug"],
86
102
  },
@@ -106,7 +122,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
106
122
  const limit = Math.min(Math.max(args?.limit || 10, 1), 100);
107
123
  const results = await searchSkills(query, args?.category, limit, args?.organization);
108
124
  return {
109
- content: [{
125
+ content: [
126
+ {
110
127
  type: "text",
111
128
  text: JSON.stringify(results.map((s) => ({
112
129
  slug: s.slug,
@@ -119,7 +136,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
119
136
  isComposition: s.isComposition,
120
137
  tags: s.tags,
121
138
  })), null, 2),
122
- }],
139
+ },
140
+ ],
123
141
  };
124
142
  }
125
143
  case "get_skill_detail": {
@@ -128,7 +146,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
128
146
  throw new McpError(ErrorCode.InvalidParams, "slug is required");
129
147
  const detail = await getSkillDetail(slug);
130
148
  return {
131
- content: [{
149
+ content: [
150
+ {
132
151
  type: "text",
133
152
  text: JSON.stringify({
134
153
  slug: detail.slug,
@@ -143,9 +162,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
143
162
  tags: detail.tags,
144
163
  isComposition: detail.isComposition,
145
164
  composition: detail.composition,
146
- instructionsPreview: detail.instructions?.slice(0, 500) + (detail.instructions?.length > 500 ? "..." : ""),
165
+ instructionsPreview: detail.instructions?.slice(0, 500) +
166
+ (detail.instructions?.length > 500 ? "..." : ""),
147
167
  }, null, 2),
148
- }],
168
+ },
169
+ ],
149
170
  };
150
171
  }
151
172
  case "install_skill": {
@@ -155,10 +176,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
155
176
  const target = args?.target || "claude-code";
156
177
  const result = await installSkill(slug, target);
157
178
  return {
158
- content: [{
179
+ content: [
180
+ {
159
181
  type: "text",
160
182
  text: JSON.stringify(result, null, 2),
161
- }],
183
+ },
184
+ ],
162
185
  };
163
186
  }
164
187
  case "list_installed_skills": {
@@ -171,10 +194,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
171
194
  category: skill.category || null,
172
195
  }));
173
196
  return {
174
- content: [{
197
+ content: [
198
+ {
175
199
  type: "text",
176
200
  text: JSON.stringify(list, null, 2),
177
- }],
201
+ },
202
+ ],
178
203
  };
179
204
  }
180
205
  default:
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AA0BA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,wEAAwE;AACxE,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,aAAa,GAAG,QAAwB,GAC/C,OAAO,CAAC,aAAa,CAAC,CA+BxB"}
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AAiCA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,wEAAwE;AACxE,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,aAAa,GAAG,QAAwB,GAC/C,OAAO,CAAC,aAAa,CAAC,CA6CxB"}
package/dist/installer.js CHANGED
@@ -21,6 +21,12 @@ function getSkillsDir(target) {
21
21
  ? join(home, ".cursor", "skills")
22
22
  : join(home, ".claude", "skills");
23
23
  }
24
+ function getCommandsDir(target) {
25
+ const home = homedir();
26
+ return target === "cursor"
27
+ ? join(home, ".cursor", "skills")
28
+ : join(home, ".claude", "commands");
29
+ }
24
30
  /** Install a single skill from the API to the local skills directory */
25
31
  export async function installSkill(slug, target = "claude-code") {
26
32
  validateSlug(slug);
@@ -37,6 +43,19 @@ category: ${yamlEscape(skill.category.slug)}
37
43
  ${skill.instructions}
38
44
  `;
39
45
  writeFileSync(join(skillDir, "SKILL.md"), content);
46
+ // Register as slash command (Claude Code reads from ~/.claude/commands/)
47
+ if (target === "claude-code") {
48
+ const commandsDir = getCommandsDir(target);
49
+ mkdirSync(commandsDir, { recursive: true });
50
+ const commandContent = `name: ${yamlEscape(skill.name)}
51
+ description: ${yamlEscape(skill.description)}
52
+ version: ${yamlEscape(skill.latestVersion)}
53
+ category: ${yamlEscape(skill.category.slug)}
54
+
55
+ ${skill.instructions}
56
+ `;
57
+ writeFileSync(join(commandsDir, `${slug}.md`), commandContent);
58
+ }
40
59
  // Install composition dependencies
41
60
  const deps = [];
42
61
  if (skill.composition?.children.length) {
@@ -82,6 +101,18 @@ category: ${yamlEscape(childDetail.category.slug)}
82
101
  ${childDetail.instructions}
83
102
  `;
84
103
  writeFileSync(join(childDir, "SKILL.md"), content);
104
+ // Register child as slash command too
105
+ if (target === "claude-code") {
106
+ const commandsDir = getCommandsDir(target);
107
+ const commandContent = `name: ${yamlEscape(childDetail.name)}
108
+ description: ${yamlEscape(childDetail.description)}
109
+ version: ${yamlEscape(childDetail.latestVersion)}
110
+ category: ${yamlEscape(childDetail.category.slug)}
111
+
112
+ ${childDetail.instructions}
113
+ `;
114
+ writeFileSync(join(commandsDir, `${childSlug}.md`), commandContent);
115
+ }
85
116
  installed.push(childSlug);
86
117
  // Recurse if this child is also a composition
87
118
  await installDependencies(childDetail, target, installed, visited, depth + 1);
@@ -1 +1 @@
1
- {"version":3,"file":"installer.js","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"installer.js","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skills-hub-ai/mcp",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "MCP server for skills-hub.ai — serve installed skills as prompts in any MCP-compatible AI tool",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -28,10 +28,10 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@modelcontextprotocol/sdk": "^1.27.1",
31
- "@skills-hub-ai/skill-parser": "0.2.0"
31
+ "@skills-hub-ai/skill-parser": "0.2.1"
32
32
  },
33
33
  "devDependencies": {
34
- "@types/node": "^22.0.0",
34
+ "@types/node": "^25.5.0",
35
35
  "tsx": "^4.0.0",
36
36
  "typescript": "^5.7.0",
37
37
  "vitest": "^2.0.0"
package/src/api.test.ts CHANGED
@@ -18,7 +18,9 @@ describe("auth header", () => {
18
18
  await searchSkills("test");
19
19
 
20
20
  const opts = mockFetch.mock.calls[0][1] as RequestInit;
21
- expect((opts.headers as Record<string, string>)["Authorization"]).toBeUndefined();
21
+ expect(
22
+ (opts.headers as Record<string, string>)["Authorization"],
23
+ ).toBeUndefined();
22
24
  });
23
25
 
24
26
  it("omits Authorization header on getSkillDetail when token not set", async () => {
@@ -30,7 +32,9 @@ describe("auth header", () => {
30
32
  await getSkillDetail("test-skill");
31
33
 
32
34
  const opts = mockFetch.mock.calls[0][1] as RequestInit;
33
- expect((opts.headers as Record<string, string>)["Authorization"]).toBeUndefined();
35
+ expect(
36
+ (opts.headers as Record<string, string>)["Authorization"],
37
+ ).toBeUndefined();
34
38
  });
35
39
  });
36
40
 
@@ -38,17 +42,35 @@ describe("searchSkills", () => {
38
42
  it("calls search API with query", async () => {
39
43
  mockFetch.mockResolvedValue({
40
44
  ok: true,
41
- json: () => Promise.resolve({
42
- data: [
43
- { slug: "review-code", name: "Review Code", description: "AI code review", qualityScore: 92, installCount: 150, avgRating: 4.8, latestVersion: "1.0.0", category: { name: "Review", slug: "review" }, isComposition: false, tags: ["review"] },
44
- ],
45
- }),
45
+ json: () =>
46
+ Promise.resolve({
47
+ data: [
48
+ {
49
+ slug: "review-code",
50
+ name: "Review Code",
51
+ description: "AI code review",
52
+ qualityScore: 92,
53
+ installCount: 150,
54
+ avgRating: 4.8,
55
+ latestVersion: "1.0.0",
56
+ category: { name: "Review", slug: "review" },
57
+ isComposition: false,
58
+ tags: ["review"],
59
+ },
60
+ ],
61
+ }),
46
62
  });
47
63
 
48
64
  const results = await searchSkills("code review");
49
65
 
50
- expect(mockFetch).toHaveBeenCalledWith(expect.stringContaining("/api/v1/search?"), expect.objectContaining({ signal: expect.any(AbortSignal) }));
51
- expect(mockFetch).toHaveBeenCalledWith(expect.stringContaining("q=code+review"), expect.anything());
66
+ expect(mockFetch).toHaveBeenCalledWith(
67
+ expect.stringContaining("/api/v1/search?"),
68
+ expect.objectContaining({ signal: expect.any(AbortSignal) }),
69
+ );
70
+ expect(mockFetch).toHaveBeenCalledWith(
71
+ expect.stringContaining("q=code+review"),
72
+ expect.anything(),
73
+ );
52
74
  expect(results).toHaveLength(1);
53
75
  expect(results[0].slug).toBe("review-code");
54
76
  });
@@ -61,7 +83,10 @@ describe("searchSkills", () => {
61
83
 
62
84
  await searchSkills("test", "build");
63
85
 
64
- expect(mockFetch).toHaveBeenCalledWith(expect.stringContaining("category=build"), expect.anything());
86
+ expect(mockFetch).toHaveBeenCalledWith(
87
+ expect.stringContaining("category=build"),
88
+ expect.anything(),
89
+ );
65
90
  });
66
91
 
67
92
  it("passes limit", async () => {
@@ -72,11 +97,18 @@ describe("searchSkills", () => {
72
97
 
73
98
  await searchSkills("test", undefined, 5);
74
99
 
75
- expect(mockFetch).toHaveBeenCalledWith(expect.stringContaining("limit=5"), expect.anything());
100
+ expect(mockFetch).toHaveBeenCalledWith(
101
+ expect.stringContaining("limit=5"),
102
+ expect.anything(),
103
+ );
76
104
  });
77
105
 
78
106
  it("throws on API error", async () => {
79
- mockFetch.mockResolvedValue({ ok: false, status: 500, statusText: "Internal Server Error" });
107
+ mockFetch.mockResolvedValue({
108
+ ok: false,
109
+ status: 500,
110
+ statusText: "Internal Server Error",
111
+ });
80
112
 
81
113
  await expect(searchSkills("fail")).rejects.toThrow("Search failed: 500");
82
114
  });
@@ -99,7 +131,10 @@ describe("searchSkills", () => {
99
131
 
100
132
  await searchSkills("testing", undefined, 10, "my-org");
101
133
 
102
- expect(mockFetch).toHaveBeenCalledWith(expect.stringContaining("org=my-org"), expect.anything());
134
+ expect(mockFetch).toHaveBeenCalledWith(
135
+ expect.stringContaining("org=my-org"),
136
+ expect.anything(),
137
+ );
103
138
  });
104
139
 
105
140
  it("omits org query parameter when not provided", async () => {
@@ -140,15 +175,24 @@ describe("getSkillDetail", () => {
140
175
 
141
176
  const result = await getSkillDetail("review-code");
142
177
 
143
- expect(mockFetch).toHaveBeenCalledWith(expect.stringContaining("/api/v1/skills/review-code"), expect.anything());
178
+ expect(mockFetch).toHaveBeenCalledWith(
179
+ expect.stringContaining("/api/v1/skills/review-code"),
180
+ expect.anything(),
181
+ );
144
182
  expect(result.slug).toBe("review-code");
145
183
  expect(result.instructions).toBe("Review the code");
146
184
  });
147
185
 
148
186
  it("throws on not found", async () => {
149
- mockFetch.mockResolvedValue({ ok: false, status: 404, statusText: "Not Found" });
187
+ mockFetch.mockResolvedValue({
188
+ ok: false,
189
+ status: 404,
190
+ statusText: "Not Found",
191
+ });
150
192
 
151
- await expect(getSkillDetail("nonexistent")).rejects.toThrow("Skill not found: nonexistent");
193
+ await expect(getSkillDetail("nonexistent")).rejects.toThrow(
194
+ "Skill not found: nonexistent",
195
+ );
152
196
  });
153
197
 
154
198
  it("URL-encodes the slug", async () => {
@@ -159,6 +203,9 @@ describe("getSkillDetail", () => {
159
203
 
160
204
  await getSkillDetail("my-skill");
161
205
 
162
- expect(mockFetch).toHaveBeenCalledWith(expect.stringContaining("/api/v1/skills/my-skill"), expect.anything());
206
+ expect(mockFetch).toHaveBeenCalledWith(
207
+ expect.stringContaining("/api/v1/skills/my-skill"),
208
+ expect.anything(),
209
+ );
163
210
  });
164
211
  });
package/src/api.ts CHANGED
@@ -9,7 +9,9 @@ function fetchWithTimeout(url: string): Promise<Response> {
9
9
  if (API_TOKEN) {
10
10
  headers["Authorization"] = `ApiKey ${API_TOKEN}`;
11
11
  }
12
- return fetch(url, { signal: controller.signal, headers }).finally(() => clearTimeout(timer));
12
+ return fetch(url, { signal: controller.signal, headers }).finally(() =>
13
+ clearTimeout(timer),
14
+ );
13
15
  }
14
16
 
15
17
  export interface SkillSearchResult {
@@ -53,7 +55,11 @@ export async function searchSkills(
53
55
  limit = 10,
54
56
  org?: string,
55
57
  ): Promise<SkillSearchResult[]> {
56
- const params = new URLSearchParams({ q: query, limit: String(limit), sort: "relevance" });
58
+ const params = new URLSearchParams({
59
+ q: query,
60
+ limit: String(limit),
61
+ sort: "relevance",
62
+ });
57
63
  if (category) params.set("category", category);
58
64
  if (org) params.set("org", org);
59
65
 
@@ -67,7 +73,9 @@ export async function searchSkills(
67
73
  }
68
74
 
69
75
  export async function getSkillDetail(slug: string): Promise<SkillDetailResult> {
70
- const res = await fetchWithTimeout(`${API_URL}/api/v1/skills/${encodeURIComponent(slug)}`);
76
+ const res = await fetchWithTimeout(
77
+ `${API_URL}/api/v1/skills/${encodeURIComponent(slug)}`,
78
+ );
71
79
  if (!res.ok) {
72
80
  throw new Error(`Skill not found: ${slug} (${res.status})`);
73
81
  }
@@ -36,7 +36,11 @@ Check for OWASP top 10 vulnerabilities.
36
36
  `;
37
37
 
38
38
  function makeDirent(name: string): ReturnType<typeof readdirSync>[0] {
39
- return { name, isDirectory: () => true, isFile: () => false } as unknown as ReturnType<typeof readdirSync>[0];
39
+ return {
40
+ name,
41
+ isDirectory: () => true,
42
+ isFile: () => false,
43
+ } as unknown as ReturnType<typeof readdirSync>[0];
40
44
  }
41
45
 
42
46
  beforeEach(() => {
@@ -58,7 +62,9 @@ describe("discoverSkills", () => {
58
62
  expect(skills.size).toBe(1);
59
63
  expect(skills.has("code-review")).toBe(true);
60
64
  expect(skills.get("code-review")!.name).toBe("Code Review");
61
- expect(skills.get("code-review")!.instructions).toContain("Review the code carefully");
65
+ expect(skills.get("code-review")!.instructions).toContain(
66
+ "Review the code carefully",
67
+ );
62
68
  });
63
69
 
64
70
  it("discovers skills from cursor skills directory", () => {
@@ -80,7 +86,8 @@ describe("discoverSkills", () => {
80
86
  mockReaddirSync.mockImplementation((dir) => {
81
87
  const s = String(dir);
82
88
  if (s.includes(".claude")) return [makeDirent("code-review")];
83
- if (s.includes(".cursor")) return [makeDirent("code-review"), makeDirent("security-scan")];
89
+ if (s.includes(".cursor"))
90
+ return [makeDirent("code-review"), makeDirent("security-scan")];
84
91
  return [];
85
92
  });
86
93
  mockReadFileSync.mockImplementation((p) => {
package/src/discover.ts CHANGED
@@ -11,10 +11,7 @@ let cacheTime = 0;
11
11
  /** Directories where skills may be installed */
12
12
  function getSkillPaths(): string[] {
13
13
  const home = homedir();
14
- return [
15
- join(home, ".claude", "skills"),
16
- join(home, ".cursor", "skills"),
17
- ];
14
+ return [join(home, ".claude", "skills"), join(home, ".cursor", "skills")];
18
15
  }
19
16
 
20
17
  /** Scan a single skills directory and collect parsed skills */
package/src/index.test.ts CHANGED
@@ -19,9 +19,14 @@ vi.mock("@modelcontextprotocol/sdk/server/index.js", () => {
19
19
  const handlers = new Map<string, (req: unknown) => Promise<unknown>>();
20
20
  return {
21
21
  Server: vi.fn().mockImplementation(() => ({
22
- setRequestHandler: vi.fn((schema: { method: string }, handler: (req: unknown) => Promise<unknown>) => {
23
- handlers.set(schema.method, handler);
24
- }),
22
+ setRequestHandler: vi.fn(
23
+ (
24
+ schema: { method: string },
25
+ handler: (req: unknown) => Promise<unknown>,
26
+ ) => {
27
+ handlers.set(schema.method, handler);
28
+ },
29
+ ),
25
30
  connect: vi.fn(),
26
31
  _handlers: handlers,
27
32
  })),
@@ -37,7 +42,12 @@ vi.mock("@modelcontextprotocol/sdk/types.js", () => ({
37
42
  GetPromptRequestSchema: { method: "prompts/get" },
38
43
  ListToolsRequestSchema: { method: "tools/list" },
39
44
  CallToolRequestSchema: { method: "tools/call" },
40
- ErrorCode: { InvalidRequest: -32600, InvalidParams: -32602, MethodNotFound: -32601, InternalError: -32603 },
45
+ ErrorCode: {
46
+ InvalidRequest: -32600,
47
+ InvalidParams: -32602,
48
+ MethodNotFound: -32601,
49
+ InternalError: -32603,
50
+ },
41
51
  McpError: class McpError extends Error {
42
52
  code: number;
43
53
  constructor(code: number, message: string) {
@@ -57,7 +67,11 @@ const mockSearchSkills = vi.mocked(searchSkills);
57
67
  const mockGetSkillDetail = vi.mocked(getSkillDetail);
58
68
  const mockInstallSkill = vi.mocked(installSkill);
59
69
 
60
- function makeSkill(name: string, description: string, instructions: string): ParsedSkill {
70
+ function makeSkill(
71
+ name: string,
72
+ description: string,
73
+ instructions: string,
74
+ ): ParsedSkill {
61
75
  return {
62
76
  name,
63
77
  description,
@@ -97,9 +111,14 @@ beforeEach(async () => {
97
111
  handlers = h;
98
112
  return {
99
113
  Server: vi.fn().mockImplementation(() => ({
100
- setRequestHandler: vi.fn((schema: { method: string }, handler: (req: unknown) => Promise<unknown>) => {
101
- h.set(schema.method, handler);
102
- }),
114
+ setRequestHandler: vi.fn(
115
+ (
116
+ schema: { method: string },
117
+ handler: (req: unknown) => Promise<unknown>,
118
+ ) => {
119
+ h.set(schema.method, handler);
120
+ },
121
+ ),
103
122
  connect: vi.fn(),
104
123
  })),
105
124
  };
@@ -114,7 +133,12 @@ beforeEach(async () => {
114
133
  GetPromptRequestSchema: { method: "prompts/get" },
115
134
  ListToolsRequestSchema: { method: "tools/list" },
116
135
  CallToolRequestSchema: { method: "tools/call" },
117
- ErrorCode: { InvalidRequest: -32600, InvalidParams: -32602, MethodNotFound: -32601, InternalError: -32603 },
136
+ ErrorCode: {
137
+ InvalidRequest: -32600,
138
+ InvalidParams: -32602,
139
+ MethodNotFound: -32601,
140
+ InternalError: -32603,
141
+ },
118
142
  McpError: class McpError extends Error {
119
143
  code: number;
120
144
  constructor(code: number, message: string) {
@@ -138,12 +162,20 @@ describe("MCP server", () => {
138
162
 
139
163
  it("listPrompts returns discovered skills", async () => {
140
164
  const skills = new Map<string, ParsedSkill>();
141
- skills.set("code-review", makeSkill("Code Review", "Review code quality", "Review carefully"));
142
- skills.set("security-scan", makeSkill("Security Scan", "Find vulnerabilities", "Check OWASP"));
165
+ skills.set(
166
+ "code-review",
167
+ makeSkill("Code Review", "Review code quality", "Review carefully"),
168
+ );
169
+ skills.set(
170
+ "security-scan",
171
+ makeSkill("Security Scan", "Find vulnerabilities", "Check OWASP"),
172
+ );
143
173
  mockDiscoverSkills.mockReturnValue(skills);
144
174
 
145
175
  const handler = handlers.get("prompts/list")!;
146
- const result = (await handler({})) as { prompts: Array<{ name: string; description: string }> };
176
+ const result = (await handler({})) as {
177
+ prompts: Array<{ name: string; description: string }>;
178
+ };
147
179
 
148
180
  expect(result.prompts).toHaveLength(2);
149
181
  expect(result.prompts[0].name).toBe("code-review");
@@ -162,13 +194,22 @@ describe("MCP server", () => {
162
194
 
163
195
  it("getPrompt returns skill instructions", async () => {
164
196
  const skills = new Map<string, ParsedSkill>();
165
- skills.set("code-review", makeSkill("Code Review", "Review code quality", "Review carefully"));
197
+ skills.set(
198
+ "code-review",
199
+ makeSkill("Code Review", "Review code quality", "Review carefully"),
200
+ );
166
201
  mockDiscoverSkills.mockReturnValue(skills);
167
202
 
168
203
  const handler = handlers.get("prompts/get")!;
169
204
  const result = (await handler({
170
205
  params: { name: "code-review", arguments: {} },
171
- })) as { description: string; messages: Array<{ role: string; content: { type: string; text: string } }> };
206
+ })) as {
207
+ description: string;
208
+ messages: Array<{
209
+ role: string;
210
+ content: { type: string; text: string };
211
+ }>;
212
+ };
172
213
 
173
214
  expect(result.description).toBe("Review code quality");
174
215
  expect(result.messages).toHaveLength(1);
@@ -178,15 +219,23 @@ describe("MCP server", () => {
178
219
 
179
220
  it("getPrompt appends input argument to instructions", async () => {
180
221
  const skills = new Map<string, ParsedSkill>();
181
- skills.set("code-review", makeSkill("Code Review", "Review code quality", "Review carefully"));
222
+ skills.set(
223
+ "code-review",
224
+ makeSkill("Code Review", "Review code quality", "Review carefully"),
225
+ );
182
226
  mockDiscoverSkills.mockReturnValue(skills);
183
227
 
184
228
  const handler = handlers.get("prompts/get")!;
185
229
  const result = (await handler({
186
- params: { name: "code-review", arguments: { input: "Focus on error handling" } },
230
+ params: {
231
+ name: "code-review",
232
+ arguments: { input: "Focus on error handling" },
233
+ },
187
234
  })) as { messages: Array<{ content: { text: string } }> };
188
235
 
189
- expect(result.messages[0].content.text).toBe("Review carefully\n\nFocus on error handling");
236
+ expect(result.messages[0].content.text).toBe(
237
+ "Review carefully\n\nFocus on error handling",
238
+ );
190
239
  });
191
240
 
192
241
  it("getPrompt throws McpError for unknown skill", async () => {
@@ -196,7 +245,7 @@ describe("MCP server", () => {
196
245
 
197
246
  await expect(
198
247
  handler({ params: { name: "nonexistent", arguments: {} } }),
199
- ).rejects.toThrow('Unknown skill: nonexistent');
248
+ ).rejects.toThrow("Unknown skill: nonexistent");
200
249
  });
201
250
 
202
251
  it("registers tools/list and tools/call handlers", () => {
@@ -237,7 +286,12 @@ describe("MCP server", () => {
237
286
  params: { name: "search_skills", arguments: { query: "code review" } },
238
287
  })) as { content: Array<{ text: string }> };
239
288
 
240
- expect(mockSearchSkills).toHaveBeenCalledWith("code review", undefined, 10, undefined);
289
+ expect(mockSearchSkills).toHaveBeenCalledWith(
290
+ "code review",
291
+ undefined,
292
+ 10,
293
+ undefined,
294
+ );
241
295
  const parsed = JSON.parse(result.content[0].text);
242
296
  expect(parsed).toHaveLength(1);
243
297
  expect(parsed[0].slug).toBe("review-code");
@@ -248,10 +302,18 @@ describe("MCP server", () => {
248
302
 
249
303
  const handler = handlers.get("tools/call")!;
250
304
  await handler({
251
- params: { name: "search_skills", arguments: { query: "deploy", organization: "my-org" } },
305
+ params: {
306
+ name: "search_skills",
307
+ arguments: { query: "deploy", organization: "my-org" },
308
+ },
252
309
  });
253
310
 
254
- expect(mockSearchSkills).toHaveBeenCalledWith("deploy", undefined, 10, "my-org");
311
+ expect(mockSearchSkills).toHaveBeenCalledWith(
312
+ "deploy",
313
+ undefined,
314
+ 10,
315
+ "my-org",
316
+ );
255
317
  });
256
318
 
257
319
  it("search_skills throws when query is missing", async () => {
@@ -311,7 +373,10 @@ describe("MCP server", () => {
311
373
 
312
374
  it("list_installed_skills returns discovered skills", async () => {
313
375
  const skills = new Map<string, ParsedSkill>();
314
- skills.set("code-review", makeSkill("Code Review", "Review code quality", "Review carefully"));
376
+ skills.set(
377
+ "code-review",
378
+ makeSkill("Code Review", "Review code quality", "Review carefully"),
379
+ );
315
380
  mockDiscoverSkills.mockReturnValue(skills);
316
381
 
317
382
  const handler = handlers.get("tools/call")!;
package/src/index.ts CHANGED
@@ -73,37 +73,58 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
73
73
  tools: [
74
74
  {
75
75
  name: "search_skills",
76
- description: "Search the skills-hub.ai catalog for skills matching a query. Supports org-scoped search to include organization-private skills (requires SKILLS_HUB_API_TOKEN).",
76
+ description:
77
+ "Search the skills-hub.ai catalog for skills matching a query. Supports org-scoped search to include organization-private skills (requires SKILLS_HUB_API_TOKEN).",
77
78
  inputSchema: {
78
79
  type: "object" as const,
79
80
  properties: {
80
- query: { type: "string", description: "Search query (e.g. 'code review', 'testing React')" },
81
- category: { type: "string", description: "Filter by category slug (e.g. 'review', 'test', 'build')" },
81
+ query: {
82
+ type: "string",
83
+ description: "Search query (e.g. 'code review', 'testing React')",
84
+ },
85
+ category: {
86
+ type: "string",
87
+ description:
88
+ "Filter by category slug (e.g. 'review', 'test', 'build')",
89
+ },
82
90
  limit: { type: "number", description: "Max results (default 10)" },
83
- organization: { type: "string", description: "Organization slug to include org-private skills in results (requires authentication)" },
91
+ organization: {
92
+ type: "string",
93
+ description:
94
+ "Organization slug to include org-private skills in results (requires authentication)",
95
+ },
84
96
  },
85
97
  required: ["query"],
86
98
  },
87
99
  },
88
100
  {
89
101
  name: "get_skill_detail",
90
- description: "Get full details about a skill including instructions, composition children, and metadata",
102
+ description:
103
+ "Get full details about a skill including instructions, composition children, and metadata",
91
104
  inputSchema: {
92
105
  type: "object" as const,
93
106
  properties: {
94
- slug: { type: "string", description: "Skill slug (e.g. 'review-code')" },
107
+ slug: {
108
+ type: "string",
109
+ description: "Skill slug (e.g. 'review-code')",
110
+ },
95
111
  },
96
112
  required: ["slug"],
97
113
  },
98
114
  },
99
115
  {
100
116
  name: "install_skill",
101
- description: "Install a skill from skills-hub.ai to the local skills directory",
117
+ description:
118
+ "Install a skill from skills-hub.ai to the local skills directory",
102
119
  inputSchema: {
103
120
  type: "object" as const,
104
121
  properties: {
105
122
  slug: { type: "string", description: "Skill slug to install" },
106
- target: { type: "string", enum: ["claude-code", "cursor"], description: "Install target (default: claude-code)" },
123
+ target: {
124
+ type: "string",
125
+ enum: ["claude-code", "cursor"],
126
+ description: "Install target (default: claude-code)",
127
+ },
107
128
  },
108
129
  required: ["slug"],
109
130
  },
@@ -126,63 +147,88 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
126
147
  switch (name) {
127
148
  case "search_skills": {
128
149
  const query = args?.query as string;
129
- if (!query) throw new McpError(ErrorCode.InvalidParams, "query is required");
150
+ if (!query)
151
+ throw new McpError(ErrorCode.InvalidParams, "query is required");
130
152
  const limit = Math.min(Math.max((args?.limit as number) || 10, 1), 100);
131
- const results = await searchSkills(query, args?.category as string | undefined, limit, args?.organization as string | undefined);
153
+ const results = await searchSkills(
154
+ query,
155
+ args?.category as string | undefined,
156
+ limit,
157
+ args?.organization as string | undefined,
158
+ );
132
159
  return {
133
- content: [{
134
- type: "text" as const,
135
- text: JSON.stringify(results.map((s) => ({
136
- slug: s.slug,
137
- name: s.name,
138
- description: s.description,
139
- qualityScore: s.qualityScore,
140
- installCount: s.installCount,
141
- avgRating: s.avgRating,
142
- category: s.category.name,
143
- isComposition: s.isComposition,
144
- tags: s.tags,
145
- })), null, 2),
146
- }],
160
+ content: [
161
+ {
162
+ type: "text" as const,
163
+ text: JSON.stringify(
164
+ results.map((s) => ({
165
+ slug: s.slug,
166
+ name: s.name,
167
+ description: s.description,
168
+ qualityScore: s.qualityScore,
169
+ installCount: s.installCount,
170
+ avgRating: s.avgRating,
171
+ category: s.category.name,
172
+ isComposition: s.isComposition,
173
+ tags: s.tags,
174
+ })),
175
+ null,
176
+ 2,
177
+ ),
178
+ },
179
+ ],
147
180
  };
148
181
  }
149
182
 
150
183
  case "get_skill_detail": {
151
184
  const slug = args?.slug as string;
152
- if (!slug) throw new McpError(ErrorCode.InvalidParams, "slug is required");
185
+ if (!slug)
186
+ throw new McpError(ErrorCode.InvalidParams, "slug is required");
153
187
  const detail = await getSkillDetail(slug);
154
188
  return {
155
- content: [{
156
- type: "text" as const,
157
- text: JSON.stringify({
158
- slug: detail.slug,
159
- name: detail.name,
160
- description: detail.description,
161
- qualityScore: detail.qualityScore,
162
- installCount: detail.installCount,
163
- avgRating: detail.avgRating,
164
- latestVersion: detail.latestVersion,
165
- category: detail.category,
166
- platforms: detail.platforms,
167
- tags: detail.tags,
168
- isComposition: detail.isComposition,
169
- composition: detail.composition,
170
- instructionsPreview: detail.instructions?.slice(0, 500) + (detail.instructions?.length > 500 ? "..." : ""),
171
- }, null, 2),
172
- }],
189
+ content: [
190
+ {
191
+ type: "text" as const,
192
+ text: JSON.stringify(
193
+ {
194
+ slug: detail.slug,
195
+ name: detail.name,
196
+ description: detail.description,
197
+ qualityScore: detail.qualityScore,
198
+ installCount: detail.installCount,
199
+ avgRating: detail.avgRating,
200
+ latestVersion: detail.latestVersion,
201
+ category: detail.category,
202
+ platforms: detail.platforms,
203
+ tags: detail.tags,
204
+ isComposition: detail.isComposition,
205
+ composition: detail.composition,
206
+ instructionsPreview:
207
+ detail.instructions?.slice(0, 500) +
208
+ (detail.instructions?.length > 500 ? "..." : ""),
209
+ },
210
+ null,
211
+ 2,
212
+ ),
213
+ },
214
+ ],
173
215
  };
174
216
  }
175
217
 
176
218
  case "install_skill": {
177
219
  const slug = args?.slug as string;
178
- if (!slug) throw new McpError(ErrorCode.InvalidParams, "slug is required");
179
- const target = (args?.target as "claude-code" | "cursor") || "claude-code";
220
+ if (!slug)
221
+ throw new McpError(ErrorCode.InvalidParams, "slug is required");
222
+ const target =
223
+ (args?.target as "claude-code" | "cursor") || "claude-code";
180
224
  const result = await installSkill(slug, target);
181
225
  return {
182
- content: [{
183
- type: "text" as const,
184
- text: JSON.stringify(result, null, 2),
185
- }],
226
+ content: [
227
+ {
228
+ type: "text" as const,
229
+ text: JSON.stringify(result, null, 2),
230
+ },
231
+ ],
186
232
  };
187
233
  }
188
234
 
@@ -196,10 +242,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
196
242
  category: skill.category || null,
197
243
  }));
198
244
  return {
199
- content: [{
200
- type: "text" as const,
201
- text: JSON.stringify(list, null, 2),
202
- }],
245
+ content: [
246
+ {
247
+ type: "text" as const,
248
+ text: JSON.stringify(list, null, 2),
249
+ },
250
+ ],
203
251
  };
204
252
  }
205
253
 
@@ -46,7 +46,10 @@ describe("installSkill", () => {
46
46
 
47
47
  const result = await installSkill("review-code");
48
48
 
49
- expect(mockMkdirSync).toHaveBeenCalledWith(expect.stringContaining("review-code"), { recursive: true });
49
+ expect(mockMkdirSync).toHaveBeenCalledWith(
50
+ expect.stringContaining("review-code"),
51
+ { recursive: true },
52
+ );
50
53
  expect(mockWriteFileSync).toHaveBeenCalledWith(
51
54
  expect.stringContaining("SKILL.md"),
52
55
  expect.stringContaining("name: Review Code"),
@@ -56,26 +59,36 @@ describe("installSkill", () => {
56
59
  expect(result.dependencies).toEqual([]);
57
60
  });
58
61
 
59
- it("writes correct YAML frontmatter", async () => {
62
+ it("writes SKILL.md and command file", async () => {
60
63
  mockGetSkillDetail.mockResolvedValue(baseSkill);
61
64
 
62
65
  await installSkill("review-code");
63
66
 
64
- const written = mockWriteFileSync.mock.calls[0][1] as string;
65
- expect(written).toContain("name: Review Code");
66
- expect(written).toContain("description: AI code review");
67
- expect(written).toContain("version: 1.2.0");
68
- expect(written).toContain("category: review");
69
- expect(written).toContain("Review all code changes carefully.");
67
+ // SKILL.md (with frontmatter fences) + command .md (without fences)
68
+ expect(mockWriteFileSync).toHaveBeenCalledTimes(2);
69
+
70
+ const skillContent = mockWriteFileSync.mock.calls[0][1] as string;
71
+ expect(skillContent).toContain("---");
72
+ expect(skillContent).toContain("name: Review Code");
73
+ expect(skillContent).toContain("Review all code changes carefully.");
74
+
75
+ const commandPath = mockWriteFileSync.mock.calls[1][0] as string;
76
+ const commandContent = mockWriteFileSync.mock.calls[1][1] as string;
77
+ expect(commandPath).toContain("commands/review-code.md");
78
+ expect(commandContent).not.toContain("---");
79
+ expect(commandContent).toContain("name: Review Code");
80
+ expect(commandContent).toContain("Review all code changes carefully.");
70
81
  });
71
82
 
72
- it("installs to cursor directory when target is cursor", async () => {
83
+ it("installs to cursor directory without command file", async () => {
73
84
  mockGetSkillDetail.mockResolvedValue(baseSkill);
74
85
 
75
86
  const result = await installSkill("review-code", "cursor");
76
87
 
77
88
  expect(result.path).toContain(".cursor");
78
89
  expect(result.path).toContain("skills");
90
+ // Cursor only writes SKILL.md, no command file
91
+ expect(mockWriteFileSync).toHaveBeenCalledTimes(1);
79
92
  });
80
93
 
81
94
  it("installs composition dependencies", async () => {
@@ -86,14 +99,36 @@ describe("installSkill", () => {
86
99
  isComposition: true,
87
100
  composition: {
88
101
  children: [
89
- { skill: { slug: "lint-check", name: "Lint Check", qualityScore: 85 }, sortOrder: 0, isParallel: false },
90
- { skill: { slug: "test-coverage", name: "Test Coverage", qualityScore: 80 }, sortOrder: 1, isParallel: false },
102
+ {
103
+ skill: { slug: "lint-check", name: "Lint Check", qualityScore: 85 },
104
+ sortOrder: 0,
105
+ isParallel: false,
106
+ },
107
+ {
108
+ skill: {
109
+ slug: "test-coverage",
110
+ name: "Test Coverage",
111
+ qualityScore: 80,
112
+ },
113
+ sortOrder: 1,
114
+ isParallel: false,
115
+ },
91
116
  ],
92
117
  },
93
118
  };
94
119
 
95
- const childSkill1 = { ...baseSkill, slug: "lint-check", name: "Lint Check", instructions: "Run lint" };
96
- const childSkill2 = { ...baseSkill, slug: "test-coverage", name: "Test Coverage", instructions: "Check coverage" };
120
+ const childSkill1 = {
121
+ ...baseSkill,
122
+ slug: "lint-check",
123
+ name: "Lint Check",
124
+ instructions: "Run lint",
125
+ };
126
+ const childSkill2 = {
127
+ ...baseSkill,
128
+ slug: "test-coverage",
129
+ name: "Test Coverage",
130
+ instructions: "Check coverage",
131
+ };
97
132
 
98
133
  mockGetSkillDetail
99
134
  .mockResolvedValueOnce(parentSkill)
@@ -103,8 +138,8 @@ describe("installSkill", () => {
103
138
  const result = await installSkill("full-review");
104
139
 
105
140
  expect(result.dependencies).toEqual(["lint-check", "test-coverage"]);
106
- // Parent + 2 children = 3 writes
107
- expect(mockWriteFileSync).toHaveBeenCalledTimes(3);
141
+ // Parent + 2 children = 3 SKILL.md + 3 command files = 6 writes
142
+ expect(mockWriteFileSync).toHaveBeenCalledTimes(6);
108
143
  });
109
144
 
110
145
  it("skips already-installed children", async () => {
@@ -114,7 +149,11 @@ describe("installSkill", () => {
114
149
  isComposition: true,
115
150
  composition: {
116
151
  children: [
117
- { skill: { slug: "lint-check", name: "Lint Check", qualityScore: 85 }, sortOrder: 0, isParallel: false },
152
+ {
153
+ skill: { slug: "lint-check", name: "Lint Check", qualityScore: 85 },
154
+ sortOrder: 0,
155
+ isParallel: false,
156
+ },
118
157
  ],
119
158
  },
120
159
  };
@@ -126,9 +165,9 @@ describe("installSkill", () => {
126
165
 
127
166
  const result = await installSkill("full-review");
128
167
 
129
- // Only parent installed, child skipped
168
+ // Only parent installed (SKILL.md + command), child skipped
130
169
  expect(result.dependencies).toEqual([]);
131
- expect(mockWriteFileSync).toHaveBeenCalledTimes(1);
170
+ expect(mockWriteFileSync).toHaveBeenCalledTimes(2);
132
171
  });
133
172
 
134
173
  it("continues if a child fails", async () => {
@@ -138,13 +177,26 @@ describe("installSkill", () => {
138
177
  isComposition: true,
139
178
  composition: {
140
179
  children: [
141
- { skill: { slug: "broken-skill", name: "Broken", qualityScore: null }, sortOrder: 0, isParallel: false },
142
- { skill: { slug: "good-skill", name: "Good", qualityScore: 90 }, sortOrder: 1, isParallel: false },
180
+ {
181
+ skill: { slug: "broken-skill", name: "Broken", qualityScore: null },
182
+ sortOrder: 0,
183
+ isParallel: false,
184
+ },
185
+ {
186
+ skill: { slug: "good-skill", name: "Good", qualityScore: 90 },
187
+ sortOrder: 1,
188
+ isParallel: false,
189
+ },
143
190
  ],
144
191
  },
145
192
  };
146
193
 
147
- const goodSkill = { ...baseSkill, slug: "good-skill", name: "Good", instructions: "Do good" };
194
+ const goodSkill = {
195
+ ...baseSkill,
196
+ slug: "good-skill",
197
+ name: "Good",
198
+ instructions: "Do good",
199
+ };
148
200
 
149
201
  mockGetSkillDetail
150
202
  .mockResolvedValueOnce(parentSkill)
package/src/installer.ts CHANGED
@@ -24,6 +24,13 @@ function getSkillsDir(target: "claude-code" | "cursor"): string {
24
24
  : join(home, ".claude", "skills");
25
25
  }
26
26
 
27
+ function getCommandsDir(target: "claude-code" | "cursor"): string {
28
+ const home = homedir();
29
+ return target === "cursor"
30
+ ? join(home, ".cursor", "skills")
31
+ : join(home, ".claude", "commands");
32
+ }
33
+
27
34
  export interface InstallResult {
28
35
  slug: string;
29
36
  version: string;
@@ -54,6 +61,20 @@ ${skill.instructions}
54
61
 
55
62
  writeFileSync(join(skillDir, "SKILL.md"), content);
56
63
 
64
+ // Register as slash command (Claude Code reads from ~/.claude/commands/)
65
+ if (target === "claude-code") {
66
+ const commandsDir = getCommandsDir(target);
67
+ mkdirSync(commandsDir, { recursive: true });
68
+ const commandContent = `name: ${yamlEscape(skill.name)}
69
+ description: ${yamlEscape(skill.description)}
70
+ version: ${yamlEscape(skill.latestVersion)}
71
+ category: ${yamlEscape(skill.category.slug)}
72
+
73
+ ${skill.instructions}
74
+ `;
75
+ writeFileSync(join(commandsDir, `${slug}.md`), commandContent);
76
+ }
77
+
57
78
  // Install composition dependencies
58
79
  const deps: string[] = [];
59
80
  if (skill.composition?.children.length) {
@@ -85,7 +106,11 @@ async function installDependencies(
85
106
  if (visited.has(childSlug)) continue;
86
107
  visited.add(childSlug);
87
108
 
88
- try { validateSlug(childSlug); } catch { continue; }
109
+ try {
110
+ validateSlug(childSlug);
111
+ } catch {
112
+ continue;
113
+ }
89
114
 
90
115
  // Skip if already installed locally
91
116
  if (existsSync(join(skillsDir, childSlug, "SKILL.md"))) continue;
@@ -105,10 +130,30 @@ category: ${yamlEscape(childDetail.category.slug)}
105
130
  ${childDetail.instructions}
106
131
  `;
107
132
  writeFileSync(join(childDir, "SKILL.md"), content);
133
+
134
+ // Register child as slash command too
135
+ if (target === "claude-code") {
136
+ const commandsDir = getCommandsDir(target);
137
+ const commandContent = `name: ${yamlEscape(childDetail.name)}
138
+ description: ${yamlEscape(childDetail.description)}
139
+ version: ${yamlEscape(childDetail.latestVersion)}
140
+ category: ${yamlEscape(childDetail.category.slug)}
141
+
142
+ ${childDetail.instructions}
143
+ `;
144
+ writeFileSync(join(commandsDir, `${childSlug}.md`), commandContent);
145
+ }
146
+
108
147
  installed.push(childSlug);
109
148
 
110
149
  // Recurse if this child is also a composition
111
- await installDependencies(childDetail, target, installed, visited, depth + 1);
150
+ await installDependencies(
151
+ childDetail,
152
+ target,
153
+ installed,
154
+ visited,
155
+ depth + 1,
156
+ );
112
157
  } catch {
113
158
  // Skip failed children, don't block the parent install
114
159
  }