eskill 1.0.17 → 1.0.20

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 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';
@@ -135,15 +135,36 @@ program
135
135
 
136
136
  console.log(formatSkillList(skills));
137
137
 
138
- // 显示分页信息
139
- if (total > 0) {
140
- console.log(`总计: ${total} 个技能\n`);
141
- }
138
+ // 显示分页信息和提示
139
+ if (total > 0 && skills.length > 0) {
140
+ const currentPage = pagination.page || parseInt(options.page);
141
+ const totalPages = pagination.totalPages || Math.ceil(total / skills.length);
142
+ const limit = pagination.limit || parseInt(options.limit);
143
+
144
+ // 分页信息
145
+ console.log(`┌─ 搜索结果 ──────────────────────────────────────────`);
146
+ console.log(`│ 总计: ${total} 个技能 | 当前: 第 ${currentPage}/${totalPages} 页 | 每页: ${limit} 个`);
147
+ console.log(`└────────────────────────────────────────────────────\n`);
142
148
 
143
- // 显示安装提示
144
- if (skills.length > 0) {
145
- console.log('💡 使用以下命令安装技能:');
146
- console.log(` eskill install <GitHub URL>\n`);
149
+ // 安装提示(使用第一个结果作为示例)
150
+ const firstSkill = skills[0];
151
+ const skillName = firstSkill.name || firstSkill.title || 'skill-name';
152
+ const author = firstSkill.author || firstSkill.owner || 'author';
153
+ console.log(`💡 安装技能:`);
154
+ console.log(` eskill install ${skillName}@${author}\n`);
155
+
156
+ // 翻页提示
157
+ if (totalPages > 1) {
158
+ console.log(`📖 翻页:`);
159
+ if (currentPage < totalPages) {
160
+ console.log(` eskill search ${query} --page ${currentPage + 1}`);
161
+ console.log(` eskill search ${query} -p ${currentPage + 1} # 简写`);
162
+ }
163
+ if (currentPage > 1) {
164
+ console.log(` eskill search ${query} --page ${currentPage - 1} # 上一页`);
165
+ }
166
+ console.log(``);
167
+ }
147
168
  }
148
169
  } catch (error) {
149
170
  spinner.fail(`搜索失败: ${error.message}`);
@@ -182,6 +203,39 @@ program
182
203
  }
183
204
  });
184
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
+
185
239
  // 列出支持的 agents
186
240
  program
187
241
  .command('agents')
package/lib/installer.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { execSync } from 'child_process';
2
- import { existsSync, mkdirSync, symlinkSync, rmSync, readdirSync, writeFileSync, readFileSync } from 'fs';
3
- import { join, basename, dirname } from 'path';
2
+ import { existsSync, mkdirSync, symlinkSync, rmSync, readdirSync, writeFileSync, readFileSync, copyFileSync } from 'fs';
3
+ import { join, basename, dirname, homedir } from 'path';
4
4
  import { tmpdir } from 'os';
5
5
  import { fileURLToPath } from 'url';
6
6
  import { parseGitUrl } from './git-url-parser.js';
@@ -19,11 +19,63 @@ function getEskillPackageDir() {
19
19
  }
20
20
 
21
21
  /**
22
- * 获取技能存储目录
22
+ * 获取技能存储目录(用户主目录下,不受 npm 更新影响)
23
23
  */
24
24
  function getSkillsStorageDir() {
25
- const pkgDir = getEskillPackageDir();
26
- return join(pkgDir, 'skills-storage');
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(` 说明: 卸载 eskill 时会自动删除所有技能`);
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.17",
3
+ "version": "1.0.20",
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
+ }