joyskills-cli 0.3.2 → 0.3.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/update.js +39 -2
- package/src/version-checker.js +114 -2
package/package.json
CHANGED
package/src/commands/update.js
CHANGED
|
@@ -187,18 +187,26 @@ async function getSpecifiedSkills(projectRoot, skillNames) {
|
|
|
187
187
|
continue;
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
let teamSource = null;
|
|
190
191
|
const lockData = lockfile.getSkill(name);
|
|
191
192
|
|
|
192
193
|
if (lockData?.source?.startsWith('team:')) {
|
|
194
|
+
teamSource = lockData.source;
|
|
195
|
+
} else {
|
|
196
|
+
// 尝试从所有 registry 查找
|
|
197
|
+
teamSource = await findSkillInRegistries(name);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (teamSource) {
|
|
193
201
|
// team:// 类型
|
|
194
|
-
const updateInfo = await checkTeamSkillUpdate(skill,
|
|
202
|
+
const updateInfo = await checkTeamSkillUpdate(skill, teamSource);
|
|
195
203
|
if (updateInfo.hasUpdate) {
|
|
196
204
|
skills.push({
|
|
197
205
|
name: skill.name,
|
|
198
206
|
path: skill.path,
|
|
199
207
|
currentVersion: skill.version,
|
|
200
208
|
latestVersion: updateInfo.latestVersion,
|
|
201
|
-
source:
|
|
209
|
+
source: teamSource,
|
|
202
210
|
type: 'team',
|
|
203
211
|
});
|
|
204
212
|
}
|
|
@@ -265,6 +273,35 @@ async function checkTeamSkillUpdate(skill, source) {
|
|
|
265
273
|
};
|
|
266
274
|
}
|
|
267
275
|
|
|
276
|
+
/**
|
|
277
|
+
* 从所有 registry 中查找 skill
|
|
278
|
+
*/
|
|
279
|
+
async function findSkillInRegistries(skillName) {
|
|
280
|
+
const JOYSKILL_CONFIG_DIR = process.env.JOYSKILL_CONFIG_DIR || path.join(os.homedir(), '.joyskill');
|
|
281
|
+
const configPath = path.join(JOYSKILL_CONFIG_DIR, 'config.json');
|
|
282
|
+
|
|
283
|
+
if (!fs.existsSync(configPath)) {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
288
|
+
const registries = config.registries || {};
|
|
289
|
+
|
|
290
|
+
for (const [name, reg] of Object.entries(registries)) {
|
|
291
|
+
if (!reg.path || !fs.existsSync(reg.path)) continue;
|
|
292
|
+
|
|
293
|
+
const { findSkills } = await import('./install.js');
|
|
294
|
+
const skills = await findSkills(reg.path);
|
|
295
|
+
const found = skills.find(s => s.name === skillName);
|
|
296
|
+
|
|
297
|
+
if (found) {
|
|
298
|
+
return `team:${name}`;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
|
|
268
305
|
/**
|
|
269
306
|
* 检查 Git 类型的 Skill 是否有更新
|
|
270
307
|
*/
|
package/src/version-checker.js
CHANGED
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
import * as fs from 'fs';
|
|
7
7
|
import * as path from 'path';
|
|
8
|
+
import * as os from 'os';
|
|
8
9
|
import simpleGit from 'simple-git';
|
|
9
10
|
import { SkillLoader } from './skill-loader.js';
|
|
11
|
+
import { LockfileManager } from './lockfile.js';
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* 获取 Skill 的 Git 信息
|
|
@@ -77,7 +79,30 @@ export async function checkRemoteUpdate(skillPath, currentCommit) {
|
|
|
77
79
|
/**
|
|
78
80
|
* 检查单个 Skill
|
|
79
81
|
*/
|
|
80
|
-
export async function checkSkill(skill) {
|
|
82
|
+
export async function checkSkill(skill, projectRoot) {
|
|
83
|
+
// 首先尝试从 lockfile 获取 source
|
|
84
|
+
let teamSource = null;
|
|
85
|
+
|
|
86
|
+
if (projectRoot) {
|
|
87
|
+
const lockfile = new LockfileManager(projectRoot);
|
|
88
|
+
await lockfile.load();
|
|
89
|
+
const lockData = lockfile.getSkill(skill.name);
|
|
90
|
+
if (lockData?.source?.startsWith('team:')) {
|
|
91
|
+
teamSource = lockData.source;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 如果没有 lockfile 记录,尝试从所有 registry 查找
|
|
96
|
+
if (!teamSource) {
|
|
97
|
+
teamSource = await findSkillInRegistries(skill.name);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 如果是 team:// skill,对比 registry 版本
|
|
101
|
+
if (teamSource) {
|
|
102
|
+
return await checkTeamSkill(skill, teamSource);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Git skill: 对比 commit
|
|
81
106
|
const gitInfo = await getSkillGitInfo(skill.path);
|
|
82
107
|
|
|
83
108
|
if (!gitInfo) {
|
|
@@ -103,6 +128,93 @@ export async function checkSkill(skill) {
|
|
|
103
128
|
};
|
|
104
129
|
}
|
|
105
130
|
|
|
131
|
+
/**
|
|
132
|
+
* 从所有 registry 中查找 skill
|
|
133
|
+
*/
|
|
134
|
+
async function findSkillInRegistries(skillName) {
|
|
135
|
+
const JOYSKILL_CONFIG_DIR = process.env.JOYSKILL_CONFIG_DIR || path.join(os.homedir(), '.joyskill');
|
|
136
|
+
const configPath = path.join(JOYSKILL_CONFIG_DIR, 'config.json');
|
|
137
|
+
|
|
138
|
+
if (!fs.existsSync(configPath)) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
143
|
+
const registries = config.registries || {};
|
|
144
|
+
|
|
145
|
+
for (const [name, reg] of Object.entries(registries)) {
|
|
146
|
+
if (!reg.path || !fs.existsSync(reg.path)) continue;
|
|
147
|
+
|
|
148
|
+
const { findSkills } = await import('./commands/install.js');
|
|
149
|
+
const skills = await findSkills(reg.path);
|
|
150
|
+
const found = skills.find(s => s.name === skillName);
|
|
151
|
+
|
|
152
|
+
if (found) {
|
|
153
|
+
return `team:${name}`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* 检查 team:// skill 更新
|
|
162
|
+
*/
|
|
163
|
+
async function checkTeamSkill(skill, source) {
|
|
164
|
+
const registryName = source.replace('team:', '');
|
|
165
|
+
const JOYSKILL_CONFIG_DIR = process.env.JOYSKILL_CONFIG_DIR || path.join(os.homedir(), '.joyskill');
|
|
166
|
+
const configPath = path.join(JOYSKILL_CONFIG_DIR, 'config.json');
|
|
167
|
+
|
|
168
|
+
if (!fs.existsSync(configPath)) {
|
|
169
|
+
return {
|
|
170
|
+
name: skill.name,
|
|
171
|
+
hasUpdate: false,
|
|
172
|
+
currentVersion: skill.version,
|
|
173
|
+
source: 'team',
|
|
174
|
+
error: 'No registry config',
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
179
|
+
const reg = config.registries?.[registryName];
|
|
180
|
+
|
|
181
|
+
if (!reg?.path || !fs.existsSync(reg.path)) {
|
|
182
|
+
return {
|
|
183
|
+
name: skill.name,
|
|
184
|
+
hasUpdate: false,
|
|
185
|
+
currentVersion: skill.version,
|
|
186
|
+
source: 'team',
|
|
187
|
+
error: `Registry ${registryName} not found`,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// 从 registry 查找最新版本
|
|
192
|
+
const { findSkills } = await import('./commands/install.js');
|
|
193
|
+
const registrySkills = await findSkills(reg.path);
|
|
194
|
+
const registrySkill = registrySkills.find(s => s.name === skill.name);
|
|
195
|
+
|
|
196
|
+
if (!registrySkill) {
|
|
197
|
+
return {
|
|
198
|
+
name: skill.name,
|
|
199
|
+
hasUpdate: false,
|
|
200
|
+
currentVersion: skill.version,
|
|
201
|
+
source: 'team',
|
|
202
|
+
error: 'Skill not found in registry',
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const hasUpdate = registrySkill.version && registrySkill.version !== skill.version;
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
name: skill.name,
|
|
210
|
+
hasUpdate,
|
|
211
|
+
currentVersion: skill.version,
|
|
212
|
+
latestVersion: registrySkill.version,
|
|
213
|
+
commitsBehind: hasUpdate ? 1 : 0, // 版本不同即视为有更新
|
|
214
|
+
source: `team:${registryName}`,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
106
218
|
/**
|
|
107
219
|
* 检查所有 Skills
|
|
108
220
|
*/
|
|
@@ -113,7 +225,7 @@ export async function checkAllSkills(projectRoot) {
|
|
|
113
225
|
const results = [];
|
|
114
226
|
|
|
115
227
|
for (const skill of skills) {
|
|
116
|
-
const result = await checkSkill(skill);
|
|
228
|
+
const result = await checkSkill(skill, projectRoot);
|
|
117
229
|
results.push(result);
|
|
118
230
|
}
|
|
119
231
|
|