joyskills-cli 0.2.0 → 0.2.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "joyskills-cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Team-level skill governance compatible with open skill / Claude Skills",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -67,38 +67,87 @@ function detectSkillType(skillName) {
67
67
  }
68
68
 
69
69
  /**
70
- * 安装公开 skill(使用 openskills)
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
- // 检查 openskills 是否可用
78
- try {
79
- execSync('npx openskills --version', { stdio: 'pipe' });
80
- } catch (error) {
81
- throw new Error('openskills not found. Please install: npm install -g openskills');
79
+ // 1. 解析 skill 名称:anthropics/skills/pdf -> owner=anthropics, repo=skills, path=pdf
80
+ const parts = skillName.split('/');
81
+ if (parts.length < 2) {
82
+ throw new Error(`Invalid skill name: ${skillName}. Expected format: owner/repo or owner/repo/path`);
82
83
  }
83
84
 
84
- // 调用 openskills install
85
- const cmd = `npx openskills install ${skillName}`;
86
- execSync(cmd, { stdio: 'inherit' });
85
+ const owner = parts[0];
86
+ const repo = parts[1];
87
+ const skillPath = parts.slice(2).join('/') || repo; // 如果没有 path,默认用 repo 名
87
88
 
88
- // 更新 lockfile
89
+ // 2. clone 仓库
90
+ const repoUrl = `https://github.com/${owner}/${repo}`;
91
+ console.log(`🔄 Cloning from: ${repoUrl}`);
92
+
93
+ execSync(`git clone --depth 1 ${repoUrl} ${tmpDir}`, {
94
+ stdio: 'pipe',
95
+ encoding: 'utf-8'
96
+ });
97
+
98
+ // 3. 寻找 SKILL.md
99
+ const skillSourceDir = path.join(tmpDir, skillPath);
100
+ const skillMdPath = path.join(skillSourceDir, 'SKILL.md');
101
+
102
+ if (!fs.existsSync(skillMdPath)) {
103
+ throw new Error(`SKILL.md not found at ${skillPath}. Please check the skill path.`);
104
+ }
105
+
106
+ // 4. 确定安装目标目录
107
+ const targetDir = options.global
108
+ ? localManager.getGlobalSkillPath(skillPath)
109
+ : localManager.getProjectSkillPath(skillPath);
110
+
111
+ const location = options.global ? 'global (~/.claude/skills)' : 'project (./.claude/skills)';
112
+ console.log(`📍 Location: ${location}`);
113
+
114
+ // 5. 复制文件
115
+ if (fs.existsSync(targetDir)) {
116
+ fs.rmSync(targetDir, { recursive: true, force: true });
117
+ }
118
+ fs.mkdirSync(targetDir, { recursive: true });
119
+
120
+ // 复制所有文件
121
+ const files = fs.readdirSync(skillSourceDir);
122
+ for (const file of files) {
123
+ const srcPath = path.join(skillSourceDir, file);
124
+ const destPath = path.join(targetDir, file);
125
+
126
+ if (fs.statSync(srcPath).isDirectory()) {
127
+ fs.cpSync(srcPath, destPath, { recursive: true });
128
+ } else {
129
+ fs.copyFileSync(srcPath, destPath);
130
+ }
131
+ }
132
+
133
+ // 6. 更新 lockfile
89
134
  lockfileManager.updateSkill(skillName, {
90
135
  version: options.version || 'latest',
91
136
  source: 'public',
92
137
  installedAt: new Date().toISOString()
93
138
  });
94
-
95
139
  await lockfileManager.save();
96
140
 
97
- console.log(`\n✅ Successfully installed public skill: ${skillName}`);
141
+ console.log(`✅ Successfully installed ${skillName}`);
98
142
  console.log(`💡 Run 'joySkills sync' to update AGENTS.md`);
99
143
 
100
144
  } catch (error) {
101
- throw new Error(`openskills install failed: ${error.message}`);
145
+ throw new Error(`Failed to install ${skillName}: ${error.message}`);
146
+ } finally {
147
+ // 清理临时目录
148
+ if (fs.existsSync(tmpDir)) {
149
+ fs.rmSync(tmpDir, { recursive: true, force: true });
150
+ }
102
151
  }
103
152
  }
104
153