eskill 1.0.13 → 1.0.15
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 +4 -3
- package/lib/installer.js +46 -5
- package/lib/search.js +7 -6
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -51,11 +51,12 @@ program
|
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
console.log(`\
|
|
54
|
+
console.log(`\n已安装的技能:\n`);
|
|
55
55
|
skills.forEach(skill => {
|
|
56
|
-
|
|
56
|
+
const displayName = skill.author ? `${skill.name}@${skill.author}` : skill.name;
|
|
57
|
+
console.log(` • ${displayName}`);
|
|
57
58
|
});
|
|
58
|
-
console.log(
|
|
59
|
+
console.log(`\n总计: ${skills.length} 个技能\n`);
|
|
59
60
|
} catch (error) {
|
|
60
61
|
console.error(`错误: ${error.message}`);
|
|
61
62
|
process.exit(1);
|
package/lib/installer.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execSync } from 'child_process';
|
|
2
|
-
import { existsSync, mkdirSync, symlinkSync, rmSync, readdirSync } from 'fs';
|
|
2
|
+
import { existsSync, mkdirSync, symlinkSync, rmSync, readdirSync, writeFileSync, readFileSync } from 'fs';
|
|
3
3
|
import { join, basename, dirname } from 'path';
|
|
4
4
|
import { tmpdir } from 'os';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
@@ -24,6 +24,30 @@ function getSkillsStorageDir() {
|
|
|
24
24
|
return join(pkgDir, 'skills-storage');
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* 保存技能元数据
|
|
29
|
+
*/
|
|
30
|
+
function saveSkillMeta(skillPath, meta) {
|
|
31
|
+
const metaPath = join(skillPath, '.eskill-meta.json');
|
|
32
|
+
writeFileSync(metaPath, JSON.stringify(meta, null, 2));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 读取技能元数据
|
|
37
|
+
*/
|
|
38
|
+
function getSkillMeta(skillPath) {
|
|
39
|
+
const metaPath = join(skillPath, '.eskill-meta.json');
|
|
40
|
+
if (!existsSync(metaPath)) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const content = readFileSync(metaPath, 'utf-8');
|
|
45
|
+
return JSON.parse(content);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
27
51
|
/**
|
|
28
52
|
* 从 Git URL 安装技能
|
|
29
53
|
*/
|
|
@@ -105,6 +129,17 @@ export async function installFromGitUrl(gitUrl, options = {}) {
|
|
|
105
129
|
console.log(` 存储位置: eskill 包目录`);
|
|
106
130
|
console.log(` 说明: 卸载 eskill 时会自动删除所有技能`);
|
|
107
131
|
|
|
132
|
+
// 保存技能元数据(作者、Git URL 等)
|
|
133
|
+
saveSkillMeta(targetPath, {
|
|
134
|
+
name: skillName,
|
|
135
|
+
author: parsed.owner,
|
|
136
|
+
gitUrl: gitUrl,
|
|
137
|
+
platform: parsed.platform,
|
|
138
|
+
repo: parsed.repo,
|
|
139
|
+
branch: parsed.branch,
|
|
140
|
+
installedAt: new Date().toISOString()
|
|
141
|
+
});
|
|
142
|
+
|
|
108
143
|
return { success: true, path: targetPath };
|
|
109
144
|
} finally {
|
|
110
145
|
// 无论成功或失败,都清理临时目录
|
|
@@ -128,10 +163,16 @@ export function listSkills(agent = 'claude') {
|
|
|
128
163
|
// 读取目录中的技能
|
|
129
164
|
return readdirSync(skillDir, { withFileTypes: true })
|
|
130
165
|
.filter(dirent => dirent.isDirectory())
|
|
131
|
-
.map(dirent =>
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
166
|
+
.map(dirent => {
|
|
167
|
+
const skillPath = join(skillDir, dirent.name);
|
|
168
|
+
const meta = getSkillMeta(skillPath);
|
|
169
|
+
return {
|
|
170
|
+
name: dirent.name,
|
|
171
|
+
path: skillPath,
|
|
172
|
+
author: meta?.author || null,
|
|
173
|
+
installedAt: meta?.installedAt || null
|
|
174
|
+
};
|
|
175
|
+
});
|
|
135
176
|
}
|
|
136
177
|
|
|
137
178
|
/**
|
package/lib/search.js
CHANGED
|
@@ -77,20 +77,21 @@ export function formatSkillList(skills, showIndex = true) {
|
|
|
77
77
|
|
|
78
78
|
let output = '\n';
|
|
79
79
|
skills.forEach((skill, index) => {
|
|
80
|
+
// 格式: name@author
|
|
81
|
+
const skillName = skill.name || skill.title || 'unknown';
|
|
82
|
+
const author = skill.author || skill.owner || '';
|
|
83
|
+
const displayName = author ? `${skillName}@${author}` : skillName;
|
|
84
|
+
|
|
80
85
|
if (showIndex) {
|
|
81
|
-
output += ` ${index + 1}. ${
|
|
86
|
+
output += ` ${index + 1}. ${displayName}\n`;
|
|
82
87
|
} else {
|
|
83
|
-
output += ` • ${
|
|
88
|
+
output += ` • ${displayName}\n`;
|
|
84
89
|
}
|
|
85
90
|
|
|
86
91
|
if (skill.description) {
|
|
87
92
|
output += ` ${skill.description.substring(0, 80)}${skill.description.length > 80 ? '...' : ''}\n`;
|
|
88
93
|
}
|
|
89
94
|
|
|
90
|
-
if (skill.author || skill.owner) {
|
|
91
|
-
output += ` 作者: ${skill.author || skill.owner}\n`;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
95
|
if (skill.stars !== undefined) {
|
|
95
96
|
output += ` Stars: ⭐ ${skill.stars}\n`;
|
|
96
97
|
}
|