@workskills/getskill 1.0.0 → 1.1.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/EXAMPLES.md +29 -2
- package/README.md +43 -18
- package/index.js +108 -20
- package/package.json +2 -2
package/EXAMPLES.md
CHANGED
|
@@ -147,6 +147,12 @@ const getskill = require('@workskills/getskill');
|
|
|
147
147
|
|
|
148
148
|
(async () => {
|
|
149
149
|
try {
|
|
150
|
+
// 设置自定义 API 地址(可选)
|
|
151
|
+
getskill.setBaseUrl('https://getskill.work');
|
|
152
|
+
|
|
153
|
+
// 查看当前 API 地址
|
|
154
|
+
console.log('当前 API:', getskill.getBaseUrl());
|
|
155
|
+
|
|
150
156
|
// 检查 Git 是否已安装
|
|
151
157
|
const isGitInstalled = await getskill.checkGitInstalled();
|
|
152
158
|
console.log('Git 已安装:', isGitInstalled);
|
|
@@ -161,7 +167,7 @@ const getskill = require('@workskills/getskill');
|
|
|
161
167
|
console.log('搜索结果:', results);
|
|
162
168
|
|
|
163
169
|
// 安装技能
|
|
164
|
-
const result = await getskill.downloadSkill('commit-helper');
|
|
170
|
+
const result = await getskill.downloadSkill('skills/commit-helper');
|
|
165
171
|
console.log('安装成功:', result.files);
|
|
166
172
|
|
|
167
173
|
// 更新技能
|
|
@@ -224,7 +230,28 @@ $ getskill search commit
|
|
|
224
230
|
执行命令时出错: connect ETIMEDOUT
|
|
225
231
|
```
|
|
226
232
|
|
|
227
|
-
## 场景 6:
|
|
233
|
+
## 场景 6: 配置自定义 API 地址
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# 查看当前 API 地址
|
|
237
|
+
$ getskill config get
|
|
238
|
+
当前 BASE_URL: https://getskill.work
|
|
239
|
+
|
|
240
|
+
# 设置自定义 API 地址
|
|
241
|
+
$ getskill config set https://custom-api.example.com
|
|
242
|
+
BASE_URL 已设置为: https://custom-api.example.com
|
|
243
|
+
|
|
244
|
+
# 通过环境变量设置
|
|
245
|
+
$ GETSKILL_BASE_URL=https://another-api.com getskill search commit
|
|
246
|
+
找到 2 个技能:
|
|
247
|
+
...
|
|
248
|
+
|
|
249
|
+
# 验证配置
|
|
250
|
+
$ getskill config get
|
|
251
|
+
当前 BASE_URL: https://custom-api.example.com
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## 场景 7: 目录结构查看
|
|
228
255
|
|
|
229
256
|
```bash
|
|
230
257
|
# 安装几个技能后查看目录结构
|
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ OpenClaw 技能管理工具 - 从 getskill.work 搜索、下载和更新技能
|
|
|
10
10
|
- 🛠️ 自动检测并引导安装 Git(如未安装)
|
|
11
11
|
- 📂 跨平台支持(Windows/macOS/Linux)
|
|
12
12
|
- 💾 自动管理技能文件到 OpenClaw skills 目录
|
|
13
|
+
- ⚙️ 支持自定义 API 地址
|
|
13
14
|
|
|
14
15
|
## 工作原理
|
|
15
16
|
|
|
@@ -142,25 +143,44 @@ getskill clean
|
|
|
142
143
|
|
|
143
144
|
清理所有 Git 仓库缓存(不影响 skills 目录中的文件)
|
|
144
145
|
|
|
146
|
+
### 配置 API 地址
|
|
147
|
+
|
|
148
|
+
查看当前 API 地址:
|
|
149
|
+
```bash
|
|
150
|
+
getskill config get
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
设置自定义 API 地址:
|
|
154
|
+
```bash
|
|
155
|
+
getskill config set https://your-custom-api.com
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
通过环境变量设置:
|
|
159
|
+
```bash
|
|
160
|
+
GETSKILL_BASE_URL=https://your-custom-api.com getskill search keyword
|
|
161
|
+
```
|
|
162
|
+
|
|
145
163
|
## API 接口规范
|
|
146
164
|
|
|
147
165
|
### 搜索 API
|
|
148
166
|
|
|
149
167
|
```
|
|
150
|
-
GET https://getskill.work/
|
|
168
|
+
GET https://getskill.work/repo/search?sort=updated&order=desc&q=<关键词>&page=1&limit=20
|
|
151
169
|
```
|
|
152
170
|
|
|
153
171
|
响应格式:
|
|
154
172
|
```json
|
|
155
173
|
{
|
|
156
|
-
"
|
|
174
|
+
"ok": true,
|
|
175
|
+
"data": [
|
|
157
176
|
{
|
|
158
|
-
"
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
177
|
+
"repository": {
|
|
178
|
+
"id": 1,
|
|
179
|
+
"full_name": "skills/commit-helper",
|
|
180
|
+
"description": "帮助生成规范的 git commit 信息",
|
|
181
|
+
"html_url": "https://getskill.work/skills/commit-helper",
|
|
182
|
+
"clone_url": "https://getskill.work/skills/commit-helper.git"
|
|
183
|
+
}
|
|
164
184
|
}
|
|
165
185
|
]
|
|
166
186
|
}
|
|
@@ -169,20 +189,19 @@ GET https://getskill.work/api/skills/search?q=<关键词>
|
|
|
169
189
|
### 详情 API
|
|
170
190
|
|
|
171
191
|
```
|
|
172
|
-
GET https://getskill.work/
|
|
192
|
+
GET https://getskill.work/repo/<技能名称>
|
|
173
193
|
```
|
|
174
194
|
|
|
175
195
|
响应格式:
|
|
176
196
|
```json
|
|
177
197
|
{
|
|
178
|
-
"
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
"readme": "..."
|
|
198
|
+
"repository": {
|
|
199
|
+
"id": 1,
|
|
200
|
+
"full_name": "skills/commit-helper",
|
|
201
|
+
"description": "帮助生成规范的 git commit 信息",
|
|
202
|
+
"html_url": "https://getskill.work/skills/commit-helper",
|
|
203
|
+
"clone_url": "https://getskill.work/skills/commit-helper.git"
|
|
204
|
+
}
|
|
186
205
|
}
|
|
187
206
|
```
|
|
188
207
|
|
|
@@ -191,11 +210,14 @@ GET https://getskill.work/api/skills/<技能ID>
|
|
|
191
210
|
```javascript
|
|
192
211
|
const getskill = require('@workskills/getskill');
|
|
193
212
|
|
|
213
|
+
// 设置自定义 API 地址(可选)
|
|
214
|
+
getskill.setBaseUrl('https://your-custom-api.com');
|
|
215
|
+
|
|
194
216
|
// 搜索技能
|
|
195
217
|
const results = await getskill.searchSkills('commit');
|
|
196
218
|
|
|
197
219
|
// 安装技能
|
|
198
|
-
const result = await getskill.downloadSkill('commit-helper');
|
|
220
|
+
const result = await getskill.downloadSkill('skills/commit-helper');
|
|
199
221
|
console.log(result.files); // 已复制的文件列表
|
|
200
222
|
|
|
201
223
|
// 更新技能
|
|
@@ -207,6 +229,9 @@ const skills = getskill.listLocalSkills();
|
|
|
207
229
|
// 获取目录
|
|
208
230
|
const skillsDir = getskill.getSkillsDirectory();
|
|
209
231
|
const cacheDir = getskill.getSkillsCacheDirectory();
|
|
232
|
+
|
|
233
|
+
// 获取当前 API 地址
|
|
234
|
+
const baseUrl = getskill.getBaseUrl();
|
|
210
235
|
```
|
|
211
236
|
|
|
212
237
|
## 技能仓库规范
|
package/index.js
CHANGED
|
@@ -7,6 +7,29 @@ const path = require('path');
|
|
|
7
7
|
const os = require('os');
|
|
8
8
|
const { exec } = require('child_process');
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* 基础 URL 配置
|
|
12
|
+
* 可以通过环境变量 GETSKILL_BASE_URL 自定义
|
|
13
|
+
*/
|
|
14
|
+
let BASE_URL = process.env.GETSKILL_BASE_URL || 'https://getskill.work';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 设置自定义 BASE_URL
|
|
18
|
+
* @param {string} url - 自定义的基础 URL
|
|
19
|
+
*/
|
|
20
|
+
function setBaseUrl(url) {
|
|
21
|
+
BASE_URL = url.replace(/\/$/, ''); // 移除末尾的斜杠
|
|
22
|
+
console.log(`BASE_URL 已设置为: ${BASE_URL}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 获取当前 BASE_URL
|
|
27
|
+
* @returns {string} 当前的基础 URL
|
|
28
|
+
*/
|
|
29
|
+
function getBaseUrl() {
|
|
30
|
+
return BASE_URL;
|
|
31
|
+
}
|
|
32
|
+
|
|
10
33
|
/**
|
|
11
34
|
* 检查 Git 是否已安装
|
|
12
35
|
*/
|
|
@@ -259,18 +282,46 @@ function executeCommand(command, cwd) {
|
|
|
259
282
|
}
|
|
260
283
|
|
|
261
284
|
/**
|
|
262
|
-
*
|
|
285
|
+
* 搜索技能(从配置的 BASE_URL API)
|
|
263
286
|
* @param {string} keyword - 搜索关键词
|
|
287
|
+
* @param {Object} options - 搜索选项
|
|
288
|
+
* @param {string} options.sort - 排序字段,默认 'updated'
|
|
289
|
+
* @param {string} options.order - 排序顺序,默认 'desc'
|
|
290
|
+
* @param {number} options.page - 页码,默认 1
|
|
291
|
+
* @param {number} options.limit - 每页数量,默认 20
|
|
264
292
|
* @returns {Promise<Array>} 技能列表(包含 git 地址)
|
|
265
293
|
*/
|
|
266
|
-
async function searchSkills(keyword) {
|
|
267
|
-
const
|
|
294
|
+
async function searchSkills(keyword, options = {}) {
|
|
295
|
+
const {
|
|
296
|
+
sort = 'updated',
|
|
297
|
+
order = 'desc',
|
|
298
|
+
page = 1,
|
|
299
|
+
limit = 20
|
|
300
|
+
} = options;
|
|
301
|
+
|
|
302
|
+
const url = `${BASE_URL}/repo/search?sort=${sort}&order=${order}&q=${encodeURIComponent(keyword)}&page=${page}&limit=${limit}`;
|
|
268
303
|
|
|
269
304
|
try {
|
|
270
305
|
const response = await request(url);
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
306
|
+
const result = JSON.parse(response.body);
|
|
307
|
+
|
|
308
|
+
// 解析返回格式: { ok: true, data: [{ repository: {...} }] }
|
|
309
|
+
if (!result.ok || !result.data) {
|
|
310
|
+
return [];
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// 提取需要的字段
|
|
314
|
+
return result.data.map(item => {
|
|
315
|
+
const repo = item.repository || {};
|
|
316
|
+
return {
|
|
317
|
+
name: repo.full_name || '',
|
|
318
|
+
full_name: repo.full_name || '',
|
|
319
|
+
description: repo.description || '',
|
|
320
|
+
html_url: repo.html_url || '',
|
|
321
|
+
git_url: repo.html_url ? `${repo.html_url}.git` : '',
|
|
322
|
+
clone_url: repo.clone_url || ''
|
|
323
|
+
};
|
|
324
|
+
});
|
|
274
325
|
} catch (error) {
|
|
275
326
|
console.error('搜索技能失败:', error.message);
|
|
276
327
|
throw error;
|
|
@@ -279,17 +330,38 @@ async function searchSkills(keyword) {
|
|
|
279
330
|
|
|
280
331
|
/**
|
|
281
332
|
* 获取技能详情(包含 git 地址)
|
|
282
|
-
* @param {string} skillId - 技能ID
|
|
333
|
+
* @param {string} skillId - 技能ID或名称
|
|
283
334
|
* @returns {Promise<Object>} 技能详情
|
|
284
335
|
*/
|
|
285
336
|
async function getSkillDetail(skillId) {
|
|
286
|
-
const url =
|
|
337
|
+
const url = `${BASE_URL}/repo/${encodeURIComponent(skillId)}`;
|
|
287
338
|
|
|
288
339
|
try {
|
|
289
340
|
const response = await request(url);
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
341
|
+
const result = JSON.parse(response.body);
|
|
342
|
+
|
|
343
|
+
// 如果返回的数据格式类似搜索接口,需要解析 repository
|
|
344
|
+
if (result.repository) {
|
|
345
|
+
const repo = result.repository;
|
|
346
|
+
return {
|
|
347
|
+
name: repo.full_name || repo.name || skillId,
|
|
348
|
+
full_name: repo.full_name || '',
|
|
349
|
+
description: repo.description || '',
|
|
350
|
+
html_url: repo.html_url || '',
|
|
351
|
+
git_url: repo.html_url ? `${repo.html_url}.git` : '',
|
|
352
|
+
clone_url: repo.clone_url || ''
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// 如果是直接返回数据(向后兼容)
|
|
357
|
+
return {
|
|
358
|
+
name: result.full_name || result.name || skillId,
|
|
359
|
+
full_name: result.full_name || '',
|
|
360
|
+
description: result.description || '',
|
|
361
|
+
html_url: result.html_url || '',
|
|
362
|
+
git_url: result.html_url ? `${result.html_url}.git` : (result.git_url || ''),
|
|
363
|
+
clone_url: result.clone_url || ''
|
|
364
|
+
};
|
|
293
365
|
} catch (error) {
|
|
294
366
|
console.error('获取技能详情失败:', error.message);
|
|
295
367
|
throw error;
|
|
@@ -386,12 +458,14 @@ async function downloadSkill(skillIdOrName) {
|
|
|
386
458
|
console.log(`获取技能信息: ${skillIdOrName}...`);
|
|
387
459
|
const skillDetail = await getSkillDetail(skillIdOrName);
|
|
388
460
|
|
|
389
|
-
|
|
390
|
-
|
|
461
|
+
// 支持 clone_url 或 git_url
|
|
462
|
+
const gitUrl = skillDetail.clone_url || skillDetail.git_url;
|
|
463
|
+
if (!gitUrl) {
|
|
464
|
+
throw new Error('技能信息中未包含 git_url 或 clone_url');
|
|
391
465
|
}
|
|
392
466
|
|
|
393
467
|
const skillName = skillDetail.name || skillIdOrName;
|
|
394
|
-
const repoPath = await cloneOrUpdateRepo(
|
|
468
|
+
const repoPath = await cloneOrUpdateRepo(gitUrl, skillName);
|
|
395
469
|
const copiedFiles = copySkillFiles(repoPath);
|
|
396
470
|
|
|
397
471
|
return {
|
|
@@ -475,16 +549,13 @@ async function cli() {
|
|
|
475
549
|
const results = await searchSkills(args[1]);
|
|
476
550
|
console.log(`找到 ${results.length} 个技能:\n`);
|
|
477
551
|
results.forEach((skill, index) => {
|
|
478
|
-
console.log(`${index + 1}. ${skill.
|
|
552
|
+
console.log(`${index + 1}. ${skill.full_name}`);
|
|
479
553
|
if (skill.description) {
|
|
480
554
|
console.log(` 描述: ${skill.description}`);
|
|
481
555
|
}
|
|
482
556
|
if (skill.git_url) {
|
|
483
557
|
console.log(` Git: ${skill.git_url}`);
|
|
484
558
|
}
|
|
485
|
-
if (skill.author) {
|
|
486
|
-
console.log(` 作者: ${skill.author}`);
|
|
487
|
-
}
|
|
488
559
|
console.log('');
|
|
489
560
|
});
|
|
490
561
|
break;
|
|
@@ -527,6 +598,18 @@ async function cli() {
|
|
|
527
598
|
console.log(`缓存目录: ${getSkillsCacheDirectory()}`);
|
|
528
599
|
break;
|
|
529
600
|
|
|
601
|
+
case 'config':
|
|
602
|
+
if (args[1] === 'set' && args[2]) {
|
|
603
|
+
setBaseUrl(args[2]);
|
|
604
|
+
} else if (args[1] === 'get') {
|
|
605
|
+
console.log(`当前 BASE_URL: ${getBaseUrl()}`);
|
|
606
|
+
} else {
|
|
607
|
+
console.log('用法:');
|
|
608
|
+
console.log(' getskill config set <URL> - 设置自定义 API 地址');
|
|
609
|
+
console.log(' getskill config get - 查看当前 API 地址');
|
|
610
|
+
}
|
|
611
|
+
break;
|
|
612
|
+
|
|
530
613
|
case 'clean':
|
|
531
614
|
const cacheDir = getSkillsCacheDirectory();
|
|
532
615
|
if (fs.existsSync(cacheDir)) {
|
|
@@ -541,13 +624,16 @@ async function cli() {
|
|
|
541
624
|
console.log('GetSkill - OpenClaw 技能管理工具');
|
|
542
625
|
console.log('');
|
|
543
626
|
console.log('用法:');
|
|
544
|
-
console.log(' getskill search <关键词> - 从
|
|
627
|
+
console.log(' getskill search <关键词> - 从 API 搜索技能');
|
|
545
628
|
console.log(' getskill install <技能名称> - 通过 git clone 安装技能');
|
|
546
629
|
console.log(' getskill update <技能名称> - 通过 git pull 更新技能');
|
|
547
630
|
console.log(' getskill list - 列出本地技能');
|
|
548
631
|
console.log(' getskill path - 显示目录路径');
|
|
632
|
+
console.log(' getskill config set <URL> - 设置自定义 API 地址');
|
|
633
|
+
console.log(' getskill config get - 查看当前 API 地址');
|
|
549
634
|
console.log(' getskill clean - 清理 git 缓存');
|
|
550
635
|
console.log('');
|
|
636
|
+
console.log(`当前 API: ${getBaseUrl()}`);
|
|
551
637
|
console.log(`技能目录: ${getSkillsDirectory()}`);
|
|
552
638
|
console.log(`缓存目录: ${getSkillsCacheDirectory()}`);
|
|
553
639
|
}
|
|
@@ -569,7 +655,9 @@ module.exports = {
|
|
|
569
655
|
cloneOrUpdateRepo,
|
|
570
656
|
copySkillFiles,
|
|
571
657
|
checkGitInstalled,
|
|
572
|
-
ensureGitInstalled
|
|
658
|
+
ensureGitInstalled,
|
|
659
|
+
setBaseUrl,
|
|
660
|
+
getBaseUrl
|
|
573
661
|
};
|
|
574
662
|
|
|
575
663
|
// 如果直接运行此文件,执行 CLI
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workskills/getskill",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Search, install, and update OpenClaw skills
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "Search, install, and update OpenClaw skills with automatic Git integration and configurable API endpoint",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"getskill": "./index.js"
|