eskill 1.0.18 → 1.0.21
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/cli.js +34 -1
- package/lib/installer.js +102 -7
- package/package.json +2 -1
- package/scripts/uninstall.js +21 -0
package/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import ora from 'ora';
|
|
4
|
-
import { installFromGitUrl, listSkills, removeSkill } from './lib/installer.js';
|
|
4
|
+
import { installFromGitUrl, listSkills, removeSkill, cleanupAllSkills, cleanupAll } from './lib/installer.js';
|
|
5
5
|
import { AGENTS, getDefaultAgent } from './lib/agent-config.js';
|
|
6
6
|
import { bashCompletionScript, zshCompletionScript, listSkillsForCompletion } from './lib/completion.js';
|
|
7
7
|
import { searchSkills, formatSkillList } from './lib/search.js';
|
|
@@ -203,6 +203,39 @@ program
|
|
|
203
203
|
}
|
|
204
204
|
});
|
|
205
205
|
|
|
206
|
+
// 清理命令
|
|
207
|
+
program
|
|
208
|
+
.command('cleanup')
|
|
209
|
+
.description('清理 eskill 数据')
|
|
210
|
+
.option('-a, --all', '清理所有数据(包括配置和技能)', false)
|
|
211
|
+
.action(async (options) => {
|
|
212
|
+
try {
|
|
213
|
+
if (options.all) {
|
|
214
|
+
console.log('\n⚠️ 警告:这将删除所有 eskill 数据(包括 API Key 配置和已安装的技能)');
|
|
215
|
+
|
|
216
|
+
const rl = readline.createInterface({
|
|
217
|
+
input: process.stdin,
|
|
218
|
+
output: process.stdout
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
rl.question('确认完全清理?: ', (answer) => {
|
|
222
|
+
rl.close();
|
|
223
|
+
if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
|
|
224
|
+
cleanupAll();
|
|
225
|
+
} else {
|
|
226
|
+
console.log('\n已取消清理\n');
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
} else {
|
|
230
|
+
console.log('\n清理所有已安装的技能(保留配置)...\n');
|
|
231
|
+
cleanupAllSkills();
|
|
232
|
+
}
|
|
233
|
+
} catch (error) {
|
|
234
|
+
console.error(`\n❌ 清理失败: ${error.message}\n`);
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
|
|
206
239
|
// 列出支持的 agents
|
|
207
240
|
program
|
|
208
241
|
.command('agents')
|
package/lib/installer.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { execSync } from 'child_process';
|
|
2
|
-
import { existsSync, mkdirSync, symlinkSync, rmSync, readdirSync, writeFileSync, readFileSync } from 'fs';
|
|
2
|
+
import { existsSync, mkdirSync, symlinkSync, rmSync, readdirSync, writeFileSync, readFileSync, copyFileSync } from 'fs';
|
|
3
3
|
import { join, basename, dirname } from 'path';
|
|
4
|
-
import { tmpdir } from 'os';
|
|
4
|
+
import { tmpdir, homedir } from 'os';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import { parseGitUrl } from './git-url-parser.js';
|
|
7
7
|
import { AGENTS, expandHomePath } from './agent-config.js';
|
|
@@ -19,11 +19,63 @@ function getEskillPackageDir() {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
22
|
+
* 获取技能存储目录(用户主目录下,不受 npm 更新影响)
|
|
23
23
|
*/
|
|
24
24
|
function getSkillsStorageDir() {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
return join(homedir(), '.eskill', 'skills');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 迁移旧位置的技能到新位置
|
|
30
|
+
*/
|
|
31
|
+
function migrateOldSkills() {
|
|
32
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
33
|
+
const __dirname = dirname(__filename);
|
|
34
|
+
const pkgDir = dirname(__dirname);
|
|
35
|
+
const oldDir = join(pkgDir, 'skills-storage');
|
|
36
|
+
const newDir = getSkillsStorageDir();
|
|
37
|
+
|
|
38
|
+
// 如果旧位置不存在,无需迁移
|
|
39
|
+
if (!existsSync(oldDir)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 如果新位置已存在,不重复迁移
|
|
44
|
+
if (existsSync(newDir)) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
// 创建新目录
|
|
50
|
+
mkdirSync(newDir, { recursive: true });
|
|
51
|
+
|
|
52
|
+
// 读取旧目录中的技能
|
|
53
|
+
const skills = readdirSync(oldDir, { withFileTypes: true })
|
|
54
|
+
.filter(dirent => dirent.isDirectory());
|
|
55
|
+
|
|
56
|
+
if (skills.length === 0) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log(`\n检测到旧位置的技能,正在迁移...`);
|
|
61
|
+
|
|
62
|
+
// 迁移每个技能
|
|
63
|
+
for (const skill of skills) {
|
|
64
|
+
const oldPath = join(oldDir, skill.name);
|
|
65
|
+
const newPath = join(newDir, skill.name);
|
|
66
|
+
|
|
67
|
+
// 递归复制目录
|
|
68
|
+
execSync(`cp -r "${oldPath}" "${newPath}"`, { stdio: 'inherit' });
|
|
69
|
+
console.log(` ✓ 迁移: ${skill.name}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.log(`\n技能迁移完成!\n`);
|
|
73
|
+
console.log(`旧位置: ${oldDir}`);
|
|
74
|
+
console.log(`新位置: ${newDir}`);
|
|
75
|
+
console.log(`\n提示: 可以删除旧位置以节省空间\n`);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.log(`\n迁移失败: ${error.message}`);
|
|
78
|
+
}
|
|
27
79
|
}
|
|
28
80
|
|
|
29
81
|
/**
|
|
@@ -220,8 +272,8 @@ export async function installFromGitUrl(gitUrl, options = {}) {
|
|
|
220
272
|
}
|
|
221
273
|
|
|
222
274
|
console.log(`\n✓ 技能已安装到: ${targetPath}`);
|
|
223
|
-
console.log(` 存储位置: eskill
|
|
224
|
-
console.log(` 说明:
|
|
275
|
+
console.log(` 存储位置: ~/.eskill/skills/`);
|
|
276
|
+
console.log(` 说明: 技能永久保存,更新 eskill 不会丢失`);
|
|
225
277
|
|
|
226
278
|
// 保存技能元数据(作者、Git URL 等)
|
|
227
279
|
saveSkillMeta(targetPath, {
|
|
@@ -248,6 +300,9 @@ export async function installFromGitUrl(gitUrl, options = {}) {
|
|
|
248
300
|
* 列出已安装的技能
|
|
249
301
|
*/
|
|
250
302
|
export function listSkills(agent = 'claude') {
|
|
303
|
+
// 自动迁移旧位置的技能
|
|
304
|
+
migrateOldSkills();
|
|
305
|
+
|
|
251
306
|
const skillDir = getSkillsStorageDir();
|
|
252
307
|
|
|
253
308
|
if (!existsSync(skillDir)) {
|
|
@@ -284,6 +339,46 @@ export function removeSkill(skillName, agent = 'claude') {
|
|
|
284
339
|
console.log(`✓ 已删除技能: ${skillName}`);
|
|
285
340
|
}
|
|
286
341
|
|
|
342
|
+
/**
|
|
343
|
+
* 清理所有技能(用于卸载)
|
|
344
|
+
*/
|
|
345
|
+
export function cleanupAllSkills() {
|
|
346
|
+
const skillDir = getSkillsStorageDir();
|
|
347
|
+
|
|
348
|
+
if (!existsSync(skillDir)) {
|
|
349
|
+
console.log('没有需要清理的技能');
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
try {
|
|
354
|
+
rmSync(skillDir, { recursive: true, force: true });
|
|
355
|
+
console.log(`✓ 已清理所有技能: ${skillDir}`);
|
|
356
|
+
} catch (error) {
|
|
357
|
+
console.error(`清理失败: ${error.message}`);
|
|
358
|
+
throw error;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* 完全清理 eskill(包括配置和技能)
|
|
364
|
+
*/
|
|
365
|
+
export function cleanupAll() {
|
|
366
|
+
const eskillDir = join(homedir(), '.eskill');
|
|
367
|
+
|
|
368
|
+
if (!existsSync(eskillDir)) {
|
|
369
|
+
console.log('没有需要清理的数据');
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
try {
|
|
374
|
+
rmSync(eskillDir, { recursive: true, force: true });
|
|
375
|
+
console.log(`✓ 已完全清理 eskill 数据: ${eskillDir}`);
|
|
376
|
+
} catch (error) {
|
|
377
|
+
console.error(`清理失败: ${error.message}`);
|
|
378
|
+
throw error;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
287
382
|
/**
|
|
288
383
|
* 获取技能存储目录路径
|
|
289
384
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eskill",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.21",
|
|
4
4
|
"description": "Unified AI Agent Skills Management - Install skills from Git URLs",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"prepublishOnly": "node scripts/pre-publish-check.js",
|
|
12
|
+
"preuninstall": "node scripts/uninstall.js",
|
|
12
13
|
"test": "node scripts/pre-publish-check.js",
|
|
13
14
|
"security-check": "node scripts/pre-publish-check.js"
|
|
14
15
|
},
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* eskill 卸载脚本
|
|
4
|
+
* 在 npm uninstall 时自动清理技能和配置
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync } from 'fs';
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
import { homedir } from 'os';
|
|
9
|
+
import { rmSync } from 'fs';
|
|
10
|
+
|
|
11
|
+
const ESKILL_DIR = join(homedir(), '.eskill');
|
|
12
|
+
|
|
13
|
+
if (existsSync(ESKILL_DIR)) {
|
|
14
|
+
try {
|
|
15
|
+
// 删除整个 .eskill 目录
|
|
16
|
+
rmSync(ESKILL_DIR, { recursive: true, force: true });
|
|
17
|
+
console.log('✓ eskill 数据已清理');
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.error(`清理失败: ${error.message}`);
|
|
20
|
+
}
|
|
21
|
+
}
|