joyskills-cli 0.2.1 → 0.2.3
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/package.json +1 -1
- package/src/commands/install.js +69 -17
package/package.json
CHANGED
package/src/commands/install.js
CHANGED
|
@@ -67,42 +67,94 @@ function detectSkillType(skillName) {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
|
-
* 安装公开 skill
|
|
70
|
+
* 安装公开 skill(自己实现,不依赖 openskills)
|
|
71
71
|
*/
|
|
72
72
|
async function installPublicSkill(skillName, options, localManager, lockfileManager) {
|
|
73
73
|
console.log(`📦 Installing public skill: ${skillName}`);
|
|
74
|
-
console.log(`💡 Using openskills install...\n`);
|
|
75
74
|
|
|
75
|
+
const registryManager = require('../registry');
|
|
76
|
+
const tmpDir = `/tmp/joyskills-${Date.now()}`;
|
|
77
|
+
|
|
76
78
|
try {
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
// 1. 解析 skill 名称
|
|
80
|
+
// anthropics/skills/pdf -> owner=anthropics, repo=skills, 相对路径=skills/pdf
|
|
81
|
+
// skillforge/code-review -> owner=skillforge, repo=code-review, 相对路径=code-review
|
|
82
|
+
const parts = skillName.split('/');
|
|
83
|
+
if (parts.length < 2) {
|
|
84
|
+
throw new Error(`Invalid skill name: ${skillName}. Expected format: owner/repo or owner/repo/path`);
|
|
82
85
|
}
|
|
83
86
|
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
const owner = parts[0];
|
|
88
|
+
const repo = parts[1];
|
|
89
|
+
|
|
90
|
+
// 相对路径:如果有子路径,用 repo/subpath;否则用 repo
|
|
91
|
+
const relativePath = parts.length > 2
|
|
92
|
+
? `${repo}/${parts.slice(2).join('/')}` // anthropics/skills/pdf -> skills/pdf
|
|
93
|
+
: repo; // skillforge/code-review -> code-review
|
|
94
|
+
|
|
95
|
+
// 2. clone 仓库
|
|
96
|
+
const repoUrl = `https://github.com/${owner}/${repo}`;
|
|
97
|
+
console.log(`🔄 Cloning from: ${repoUrl}`);
|
|
98
|
+
|
|
99
|
+
execSync(`git clone --depth 1 ${repoUrl} ${tmpDir}`, {
|
|
100
|
+
stdio: 'pipe',
|
|
101
|
+
encoding: 'utf-8'
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// 3. 寻找 SKILL.md
|
|
105
|
+
const skillSourceDir = path.join(tmpDir, relativePath);
|
|
106
|
+
const skillMdPath = path.join(skillSourceDir, 'SKILL.md');
|
|
107
|
+
|
|
108
|
+
if (!fs.existsSync(skillMdPath)) {
|
|
109
|
+
throw new Error(`SKILL.md not found at ${relativePath}. Please check the skill path.`);
|
|
90
110
|
}
|
|
91
111
|
|
|
92
|
-
//
|
|
112
|
+
// 4. 确定安装目标目录(只用最后一级目录名)
|
|
113
|
+
const skillDirName = parts[parts.length - 1]; // anthropics/skills/pdf -> pdf
|
|
114
|
+
const targetDir = options.global
|
|
115
|
+
? localManager.getGlobalSkillPath(skillDirName)
|
|
116
|
+
: localManager.getProjectSkillPath(skillDirName);
|
|
117
|
+
|
|
118
|
+
const location = options.global ? 'global (~/.claude/skills)' : 'project (./.claude/skills)';
|
|
119
|
+
console.log(`📍 Location: ${location}`);
|
|
120
|
+
|
|
121
|
+
// 5. 复制文件
|
|
122
|
+
if (fs.existsSync(targetDir)) {
|
|
123
|
+
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
124
|
+
}
|
|
125
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
126
|
+
|
|
127
|
+
// 复制所有文件
|
|
128
|
+
const files = fs.readdirSync(skillSourceDir);
|
|
129
|
+
for (const file of files) {
|
|
130
|
+
const srcPath = path.join(skillSourceDir, file);
|
|
131
|
+
const destPath = path.join(targetDir, file);
|
|
132
|
+
|
|
133
|
+
if (fs.statSync(srcPath).isDirectory()) {
|
|
134
|
+
fs.cpSync(srcPath, destPath, { recursive: true });
|
|
135
|
+
} else {
|
|
136
|
+
fs.copyFileSync(srcPath, destPath);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 6. 更新 lockfile
|
|
93
141
|
lockfileManager.updateSkill(skillName, {
|
|
94
142
|
version: options.version || 'latest',
|
|
95
143
|
source: 'public',
|
|
96
144
|
installedAt: new Date().toISOString()
|
|
97
145
|
});
|
|
98
|
-
|
|
99
146
|
await lockfileManager.save();
|
|
100
147
|
|
|
101
|
-
console.log(
|
|
148
|
+
console.log(`✅ Successfully installed ${skillName}`);
|
|
102
149
|
console.log(`💡 Run 'joySkills sync' to update AGENTS.md`);
|
|
103
150
|
|
|
104
151
|
} catch (error) {
|
|
105
|
-
throw new Error(`
|
|
152
|
+
throw new Error(`Failed to install ${skillName}: ${error.message}`);
|
|
153
|
+
} finally {
|
|
154
|
+
// 清理临时目录
|
|
155
|
+
if (fs.existsSync(tmpDir)) {
|
|
156
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
157
|
+
}
|
|
106
158
|
}
|
|
107
159
|
}
|
|
108
160
|
|