skillsmgr 0.3.1 → 0.4.0
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/README.md +12 -0
- package/README.zh-CN.md +12 -0
- package/dist/index.js +255 -50
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -124,6 +124,18 @@ Sync and verify deployed skills.
|
|
|
124
124
|
npx skillsmgr sync
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
+
### `npx skillsmgr update`
|
|
128
|
+
|
|
129
|
+
Update installed skills to latest version from remote.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Update all installed sources
|
|
133
|
+
npx skillsmgr update
|
|
134
|
+
|
|
135
|
+
# Update specific source
|
|
136
|
+
npx skillsmgr update anthropic
|
|
137
|
+
```
|
|
138
|
+
|
|
127
139
|
## Directory Structure
|
|
128
140
|
|
|
129
141
|
```
|
package/README.zh-CN.md
CHANGED
|
@@ -124,6 +124,18 @@ npx skillsmgr remove code-review --tool claude-code
|
|
|
124
124
|
npx skillsmgr sync
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
+
### `npx skillsmgr update`
|
|
128
|
+
|
|
129
|
+
从远程更新已安装的 skills 到最新版本。
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# 更新所有已安装的源
|
|
133
|
+
npx skillsmgr update
|
|
134
|
+
|
|
135
|
+
# 更新特定源
|
|
136
|
+
npx skillsmgr update anthropic
|
|
137
|
+
```
|
|
138
|
+
|
|
127
139
|
## 目录结构
|
|
128
140
|
|
|
129
141
|
```
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command9 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/setup.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -68,6 +68,10 @@ function readSymlinkTarget(path) {
|
|
|
68
68
|
function readFileContent(path) {
|
|
69
69
|
return readFileSync(path, "utf-8");
|
|
70
70
|
}
|
|
71
|
+
function writeFile(path, content) {
|
|
72
|
+
ensureDir(dirname(path));
|
|
73
|
+
writeFileSync(path, content, "utf-8");
|
|
74
|
+
}
|
|
71
75
|
function fileExists(path) {
|
|
72
76
|
return existsSync(path);
|
|
73
77
|
}
|
|
@@ -137,7 +141,7 @@ var setupCommand = new Command("setup").description("Initialize ~/.skills-manage
|
|
|
137
141
|
|
|
138
142
|
// src/commands/install.ts
|
|
139
143
|
import { Command as Command2 } from "commander";
|
|
140
|
-
import { join as
|
|
144
|
+
import { join as join7 } from "path";
|
|
141
145
|
|
|
142
146
|
// src/services/git.ts
|
|
143
147
|
import { execSync } from "child_process";
|
|
@@ -365,6 +369,52 @@ var GitHubService = class {
|
|
|
365
369
|
}
|
|
366
370
|
};
|
|
367
371
|
|
|
372
|
+
// src/services/sources.ts
|
|
373
|
+
import { join as join6 } from "path";
|
|
374
|
+
var SOURCES_FILE = join6(SKILLS_MANAGER_DIR, "sources.json");
|
|
375
|
+
var SourcesService = class {
|
|
376
|
+
load() {
|
|
377
|
+
if (!fileExists(SOURCES_FILE)) {
|
|
378
|
+
return { version: "1.0", sources: {} };
|
|
379
|
+
}
|
|
380
|
+
const content = readFileContent(SOURCES_FILE);
|
|
381
|
+
return JSON.parse(content);
|
|
382
|
+
}
|
|
383
|
+
save(data) {
|
|
384
|
+
writeFile(SOURCES_FILE, JSON.stringify(data, null, 2));
|
|
385
|
+
}
|
|
386
|
+
addSource(key, info) {
|
|
387
|
+
const data = this.load();
|
|
388
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
389
|
+
data.sources[key] = {
|
|
390
|
+
...info,
|
|
391
|
+
installedAt: data.sources[key]?.installedAt || now,
|
|
392
|
+
updatedAt: now
|
|
393
|
+
};
|
|
394
|
+
this.save(data);
|
|
395
|
+
}
|
|
396
|
+
getSource(key) {
|
|
397
|
+
const data = this.load();
|
|
398
|
+
return data.sources[key];
|
|
399
|
+
}
|
|
400
|
+
getAllSources() {
|
|
401
|
+
const data = this.load();
|
|
402
|
+
return data.sources;
|
|
403
|
+
}
|
|
404
|
+
removeSource(key) {
|
|
405
|
+
const data = this.load();
|
|
406
|
+
delete data.sources[key];
|
|
407
|
+
this.save(data);
|
|
408
|
+
}
|
|
409
|
+
updateTimestamp(key) {
|
|
410
|
+
const data = this.load();
|
|
411
|
+
if (data.sources[key]) {
|
|
412
|
+
data.sources[key].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
413
|
+
this.save(data);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
|
|
368
418
|
// src/utils/prompts.ts
|
|
369
419
|
import inquirer from "inquirer";
|
|
370
420
|
|
|
@@ -875,6 +925,7 @@ var ProgressBar = class {
|
|
|
875
925
|
};
|
|
876
926
|
|
|
877
927
|
// src/commands/install.ts
|
|
928
|
+
var sourcesService = new SourcesService();
|
|
878
929
|
function parseSkillDescription(content) {
|
|
879
930
|
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
880
931
|
if (!frontmatterMatch) {
|
|
@@ -884,16 +935,16 @@ function parseSkillDescription(content) {
|
|
|
884
935
|
return descMatch ? descMatch[1].trim() : "";
|
|
885
936
|
}
|
|
886
937
|
async function installFromAnthropic(options) {
|
|
887
|
-
const
|
|
938
|
+
const githubService2 = new GitHubService();
|
|
888
939
|
const owner = "anthropics";
|
|
889
940
|
const repo = "skills";
|
|
890
941
|
console.log("Fetching available skills from anthropic/skills...");
|
|
891
|
-
const skillsList = await
|
|
942
|
+
const skillsList = await githubService2.listSkills(owner, repo, "skills");
|
|
892
943
|
if (skillsList.length === 0) {
|
|
893
944
|
console.log("No skills found in repository");
|
|
894
945
|
return;
|
|
895
946
|
}
|
|
896
|
-
const defaultBranch = await
|
|
947
|
+
const defaultBranch = await githubService2.getDefaultBranch(owner, repo);
|
|
897
948
|
const skills = [];
|
|
898
949
|
const progress = new ProgressBar(skillsList.length, "Fetching skill info");
|
|
899
950
|
progress.start();
|
|
@@ -932,19 +983,24 @@ async function installFromAnthropic(options) {
|
|
|
932
983
|
}
|
|
933
984
|
console.log(`
|
|
934
985
|
Downloading ${selectedSkills.length} skills...`);
|
|
935
|
-
const targetBase =
|
|
986
|
+
const targetBase = join7(SKILLS_MANAGER_DIR, "official", "anthropic");
|
|
936
987
|
for (const skill of selectedSkills) {
|
|
937
|
-
const targetDir =
|
|
988
|
+
const targetDir = join7(targetBase, skill.name);
|
|
938
989
|
process.stdout.write(` ${skill.name}...`);
|
|
939
|
-
await
|
|
990
|
+
await githubService2.downloadSkill(owner, repo, skill.path, targetDir);
|
|
940
991
|
console.log(" \u2713");
|
|
941
992
|
}
|
|
942
993
|
console.log(`
|
|
943
994
|
\u2713 Installed ${selectedSkills.length} skills to ${targetBase}`);
|
|
995
|
+
sourcesService.addSource("official/anthropic", {
|
|
996
|
+
url: "https://github.com/anthropics/skills",
|
|
997
|
+
type: "official",
|
|
998
|
+
repoName: "anthropic"
|
|
999
|
+
});
|
|
944
1000
|
}
|
|
945
1001
|
async function installFromGitHubUrl(url, options) {
|
|
946
|
-
const
|
|
947
|
-
const parsed =
|
|
1002
|
+
const githubService2 = new GitHubService();
|
|
1003
|
+
const parsed = githubService2.parseGitHubUrl(url);
|
|
948
1004
|
if (!parsed) {
|
|
949
1005
|
return false;
|
|
950
1006
|
}
|
|
@@ -952,9 +1008,9 @@ async function installFromGitHubUrl(url, options) {
|
|
|
952
1008
|
const isAnthropic = owner === "anthropics" && repo === "skills";
|
|
953
1009
|
if (path) {
|
|
954
1010
|
const skillName = path.split("/").pop() || path;
|
|
955
|
-
const targetDir =
|
|
1011
|
+
const targetDir = githubService2.getTargetDir(owner, repo, skillName, options.custom);
|
|
956
1012
|
console.log(`Downloading ${skillName}...`);
|
|
957
|
-
await
|
|
1013
|
+
await githubService2.downloadSkill(owner, repo, path, targetDir);
|
|
958
1014
|
console.log(`\u2713 Installed ${skillName} to ${targetDir}`);
|
|
959
1015
|
return true;
|
|
960
1016
|
}
|
|
@@ -963,7 +1019,7 @@ async function installFromGitHubUrl(url, options) {
|
|
|
963
1019
|
const skillsPaths = ["skills", ".", "src/skills"];
|
|
964
1020
|
for (const skillsPath of skillsPaths) {
|
|
965
1021
|
try {
|
|
966
|
-
skillsList = await
|
|
1022
|
+
skillsList = await githubService2.listSkills(owner, repo, skillsPath);
|
|
967
1023
|
if (skillsList.length > 0) break;
|
|
968
1024
|
} catch {
|
|
969
1025
|
continue;
|
|
@@ -972,7 +1028,7 @@ async function installFromGitHubUrl(url, options) {
|
|
|
972
1028
|
if (skillsList.length === 0) {
|
|
973
1029
|
return false;
|
|
974
1030
|
}
|
|
975
|
-
const defaultBranch = await
|
|
1031
|
+
const defaultBranch = await githubService2.getDefaultBranch(owner, repo);
|
|
976
1032
|
const skills = [];
|
|
977
1033
|
const progress = new ProgressBar(skillsList.length, "Fetching skill info");
|
|
978
1034
|
progress.start();
|
|
@@ -1009,20 +1065,26 @@ async function installFromGitHubUrl(url, options) {
|
|
|
1009
1065
|
Downloading ${selectedSkills.length} skills...`);
|
|
1010
1066
|
let targetBase;
|
|
1011
1067
|
if (isAnthropic) {
|
|
1012
|
-
targetBase =
|
|
1068
|
+
targetBase = join7(SKILLS_MANAGER_DIR, "official", "anthropic");
|
|
1013
1069
|
} else if (options.custom) {
|
|
1014
|
-
targetBase =
|
|
1070
|
+
targetBase = join7(SKILLS_MANAGER_DIR, "custom", repo);
|
|
1015
1071
|
} else {
|
|
1016
|
-
targetBase =
|
|
1072
|
+
targetBase = join7(SKILLS_MANAGER_DIR, "community", repo);
|
|
1017
1073
|
}
|
|
1018
1074
|
for (const skill of selectedSkills) {
|
|
1019
|
-
const targetDir =
|
|
1075
|
+
const targetDir = join7(targetBase, skill.name);
|
|
1020
1076
|
process.stdout.write(` ${skill.name}...`);
|
|
1021
|
-
await
|
|
1077
|
+
await githubService2.downloadSkill(owner, repo, skill.path, targetDir);
|
|
1022
1078
|
console.log(" \u2713");
|
|
1023
1079
|
}
|
|
1024
1080
|
console.log(`
|
|
1025
1081
|
\u2713 Installed ${selectedSkills.length} skills to ${targetBase}`);
|
|
1082
|
+
const sourceKey = isAnthropic ? "official/anthropic" : options.custom ? `custom/${repo}` : `community/${repo}`;
|
|
1083
|
+
sourcesService.addSource(sourceKey, {
|
|
1084
|
+
url: `https://github.com/${owner}/${repo}`,
|
|
1085
|
+
type: isAnthropic ? "official" : options.custom ? "custom" : "community",
|
|
1086
|
+
repoName: repo
|
|
1087
|
+
});
|
|
1026
1088
|
return true;
|
|
1027
1089
|
}
|
|
1028
1090
|
async function installViaGitClone(source, options) {
|
|
@@ -1040,7 +1102,7 @@ async function installViaGitClone(source, options) {
|
|
|
1040
1102
|
const repoPath = gitService.clone(source, options.custom || false);
|
|
1041
1103
|
let skillsRoot = repoPath;
|
|
1042
1104
|
if (source === "anthropic") {
|
|
1043
|
-
const skillsSubdir =
|
|
1105
|
+
const skillsSubdir = join7(repoPath, "skills");
|
|
1044
1106
|
if (fileExists(skillsSubdir)) {
|
|
1045
1107
|
skillsRoot = skillsSubdir;
|
|
1046
1108
|
}
|
|
@@ -1048,7 +1110,7 @@ async function installViaGitClone(source, options) {
|
|
|
1048
1110
|
const skillDirs = getDirectoriesInDir(skillsRoot);
|
|
1049
1111
|
const skills = [];
|
|
1050
1112
|
for (const dir of skillDirs) {
|
|
1051
|
-
const skillMdPath =
|
|
1113
|
+
const skillMdPath = join7(dir.path, "SKILL.md");
|
|
1052
1114
|
if (fileExists(skillMdPath)) {
|
|
1053
1115
|
const content = readFileContent(skillMdPath);
|
|
1054
1116
|
const description = parseSkillDescription(content);
|
|
@@ -1067,6 +1129,7 @@ async function installViaGitClone(source, options) {
|
|
|
1067
1129
|
`);
|
|
1068
1130
|
if (options.all) {
|
|
1069
1131
|
console.log(`\u2713 Installed ${skills.length} skills to ${repoPath}`);
|
|
1132
|
+
saveGitCloneSource(source, repoPath, options);
|
|
1070
1133
|
return;
|
|
1071
1134
|
}
|
|
1072
1135
|
const selectedNames = await promptSkillsToInstall(skills);
|
|
@@ -1081,6 +1144,33 @@ async function installViaGitClone(source, options) {
|
|
|
1081
1144
|
}
|
|
1082
1145
|
console.log(`
|
|
1083
1146
|
\u2713 Installed ${selectedNames.length} skills to ${repoPath}`);
|
|
1147
|
+
saveGitCloneSource(source, repoPath, options);
|
|
1148
|
+
}
|
|
1149
|
+
function saveGitCloneSource(source, repoPath, options) {
|
|
1150
|
+
const repoName = repoPath.split("/").pop() || source;
|
|
1151
|
+
let type;
|
|
1152
|
+
let sourceKey;
|
|
1153
|
+
if (source === "anthropic" || repoPath.includes("/official/")) {
|
|
1154
|
+
type = "official";
|
|
1155
|
+
sourceKey = "official/anthropic";
|
|
1156
|
+
} else if (options.custom || repoPath.includes("/custom/")) {
|
|
1157
|
+
type = "custom";
|
|
1158
|
+
sourceKey = `custom/${repoName}`;
|
|
1159
|
+
} else {
|
|
1160
|
+
type = "community";
|
|
1161
|
+
sourceKey = `community/${repoName}`;
|
|
1162
|
+
}
|
|
1163
|
+
let url = source;
|
|
1164
|
+
if (source === "anthropic") {
|
|
1165
|
+
url = "https://github.com/anthropics/skills";
|
|
1166
|
+
} else if (!source.startsWith("http")) {
|
|
1167
|
+
url = `https://github.com/${source}`;
|
|
1168
|
+
}
|
|
1169
|
+
sourcesService.addSource(sourceKey, {
|
|
1170
|
+
url,
|
|
1171
|
+
type,
|
|
1172
|
+
repoName
|
|
1173
|
+
});
|
|
1084
1174
|
}
|
|
1085
1175
|
async function executeInstall(source, options) {
|
|
1086
1176
|
if (!fileExists(SKILLS_MANAGER_DIR)) {
|
|
@@ -1109,11 +1199,125 @@ var installCommand = new Command2("install").description("Download skills from a
|
|
|
1109
1199
|
await executeInstall(source, options);
|
|
1110
1200
|
});
|
|
1111
1201
|
|
|
1112
|
-
// src/commands/
|
|
1202
|
+
// src/commands/update.ts
|
|
1113
1203
|
import { Command as Command3 } from "commander";
|
|
1204
|
+
import { join as join8 } from "path";
|
|
1205
|
+
var sourcesService2 = new SourcesService();
|
|
1206
|
+
var githubService = new GitHubService();
|
|
1207
|
+
async function updateSource(key, info) {
|
|
1208
|
+
const parsed = githubService.parseGitHubUrl(info.url);
|
|
1209
|
+
if (!parsed) {
|
|
1210
|
+
console.log(` \u26A0 Cannot parse URL: ${info.url}`);
|
|
1211
|
+
return 0;
|
|
1212
|
+
}
|
|
1213
|
+
const { owner, repo } = parsed;
|
|
1214
|
+
let skillsList = [];
|
|
1215
|
+
const skillsPaths = ["skills", ".", "src/skills"];
|
|
1216
|
+
for (const skillsPath of skillsPaths) {
|
|
1217
|
+
try {
|
|
1218
|
+
skillsList = await githubService.listSkills(owner, repo, skillsPath);
|
|
1219
|
+
if (skillsList.length > 0) break;
|
|
1220
|
+
} catch {
|
|
1221
|
+
continue;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
if (skillsList.length === 0) {
|
|
1225
|
+
console.log(` \u26A0 No skills found in ${owner}/${repo}`);
|
|
1226
|
+
return 0;
|
|
1227
|
+
}
|
|
1228
|
+
const defaultBranch = await githubService.getDefaultBranch(owner, repo);
|
|
1229
|
+
const skills = [];
|
|
1230
|
+
const progress = new ProgressBar(skillsList.length, "Checking skills");
|
|
1231
|
+
progress.start();
|
|
1232
|
+
for (const skill of skillsList) {
|
|
1233
|
+
try {
|
|
1234
|
+
const response = await fetch(
|
|
1235
|
+
`https://raw.githubusercontent.com/${owner}/${repo}/${defaultBranch}/${skill.path}/SKILL.md`
|
|
1236
|
+
);
|
|
1237
|
+
if (response.ok) {
|
|
1238
|
+
skills.push(skill);
|
|
1239
|
+
}
|
|
1240
|
+
} catch {
|
|
1241
|
+
}
|
|
1242
|
+
progress.tick();
|
|
1243
|
+
}
|
|
1244
|
+
progress.complete();
|
|
1245
|
+
if (skills.length === 0) {
|
|
1246
|
+
return 0;
|
|
1247
|
+
}
|
|
1248
|
+
let targetBase;
|
|
1249
|
+
if (info.type === "official") {
|
|
1250
|
+
targetBase = join8(SKILLS_MANAGER_DIR, "official", info.repoName);
|
|
1251
|
+
} else if (info.type === "custom") {
|
|
1252
|
+
targetBase = join8(SKILLS_MANAGER_DIR, "custom", info.repoName);
|
|
1253
|
+
} else {
|
|
1254
|
+
targetBase = join8(SKILLS_MANAGER_DIR, "community", info.repoName);
|
|
1255
|
+
}
|
|
1256
|
+
let updatedCount = 0;
|
|
1257
|
+
for (const skill of skills) {
|
|
1258
|
+
const targetDir = join8(targetBase, skill.name);
|
|
1259
|
+
try {
|
|
1260
|
+
if (fileExists(targetDir)) {
|
|
1261
|
+
removeDir(targetDir);
|
|
1262
|
+
}
|
|
1263
|
+
await githubService.downloadSkill(owner, repo, skill.path, targetDir);
|
|
1264
|
+
updatedCount++;
|
|
1265
|
+
} catch {
|
|
1266
|
+
console.log(` \u26A0 Failed to update ${skill.name}`);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
sourcesService2.updateTimestamp(key);
|
|
1270
|
+
return updatedCount;
|
|
1271
|
+
}
|
|
1272
|
+
async function executeUpdate(source) {
|
|
1273
|
+
if (!fileExists(SKILLS_MANAGER_DIR)) {
|
|
1274
|
+
console.log("Skills manager not set up. Run: skillsmgr setup");
|
|
1275
|
+
process.exit(1);
|
|
1276
|
+
}
|
|
1277
|
+
const allSources = sourcesService2.getAllSources();
|
|
1278
|
+
if (Object.keys(allSources).length === 0) {
|
|
1279
|
+
console.log("No installed sources found.");
|
|
1280
|
+
console.log("\nRun: skillsmgr install anthropic");
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1283
|
+
if (source) {
|
|
1284
|
+
const matchingKey = Object.keys(allSources).find(
|
|
1285
|
+
(k) => k === source || k.endsWith(`/${source}`) || allSources[k].repoName === source
|
|
1286
|
+
);
|
|
1287
|
+
if (!matchingKey) {
|
|
1288
|
+
console.log(`Source '${source}' not found.`);
|
|
1289
|
+
console.log("\nInstalled sources:");
|
|
1290
|
+
for (const key of Object.keys(allSources)) {
|
|
1291
|
+
console.log(` ${key}`);
|
|
1292
|
+
}
|
|
1293
|
+
return;
|
|
1294
|
+
}
|
|
1295
|
+
console.log(`Updating ${matchingKey}...`);
|
|
1296
|
+
const count = await updateSource(matchingKey, allSources[matchingKey]);
|
|
1297
|
+
console.log(`
|
|
1298
|
+
\u2713 Updated ${count} skills from ${matchingKey}`);
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
console.log("Updating all installed sources...\n");
|
|
1302
|
+
let totalUpdated = 0;
|
|
1303
|
+
for (const [key, info] of Object.entries(allSources)) {
|
|
1304
|
+
console.log(`${key}:`);
|
|
1305
|
+
const count = await updateSource(key, info);
|
|
1306
|
+
console.log(` \u2713 ${count} skills updated
|
|
1307
|
+
`);
|
|
1308
|
+
totalUpdated += count;
|
|
1309
|
+
}
|
|
1310
|
+
console.log(`Done! Updated ${totalUpdated} skills from ${Object.keys(allSources).length} sources.`);
|
|
1311
|
+
}
|
|
1312
|
+
var updateCommand = new Command3("update").description("Update installed skills to latest version").argument("[source]", 'Specific source to update (e.g., "anthropic")').action(async (source) => {
|
|
1313
|
+
await executeUpdate(source);
|
|
1314
|
+
});
|
|
1315
|
+
|
|
1316
|
+
// src/commands/list.ts
|
|
1317
|
+
import { Command as Command4 } from "commander";
|
|
1114
1318
|
|
|
1115
1319
|
// src/services/skills.ts
|
|
1116
|
-
import { join as
|
|
1320
|
+
import { join as join9 } from "path";
|
|
1117
1321
|
var SkillsService = class {
|
|
1118
1322
|
constructor(skillsDir) {
|
|
1119
1323
|
this.skillsDir = skillsDir;
|
|
@@ -1121,14 +1325,14 @@ var SkillsService = class {
|
|
|
1121
1325
|
getAllSkills() {
|
|
1122
1326
|
const skills = [];
|
|
1123
1327
|
for (const source of SKILL_SOURCES) {
|
|
1124
|
-
const sourceDir =
|
|
1328
|
+
const sourceDir = join9(this.skillsDir, source);
|
|
1125
1329
|
const sourceSkills = this.getSkillsFromSource(sourceDir, source);
|
|
1126
1330
|
skills.push(...sourceSkills);
|
|
1127
1331
|
}
|
|
1128
1332
|
return skills;
|
|
1129
1333
|
}
|
|
1130
1334
|
getSkillsBySource(source) {
|
|
1131
|
-
const sourceDir =
|
|
1335
|
+
const sourceDir = join9(this.skillsDir, source);
|
|
1132
1336
|
return this.getSkillsFromSource(sourceDir, source);
|
|
1133
1337
|
}
|
|
1134
1338
|
getSkillByName(name) {
|
|
@@ -1159,7 +1363,7 @@ var SkillsService = class {
|
|
|
1159
1363
|
} else {
|
|
1160
1364
|
const repoDirs = getDirectoriesInDir(sourceDir);
|
|
1161
1365
|
for (const repoDir of repoDirs) {
|
|
1162
|
-
const skillsSubdir =
|
|
1366
|
+
const skillsSubdir = join9(repoDir.path, "skills");
|
|
1163
1367
|
const searchDir = fileExists(skillsSubdir) ? skillsSubdir : repoDir.path;
|
|
1164
1368
|
const skillDirs = getDirectoriesInDir(searchDir);
|
|
1165
1369
|
for (const skillDir of skillDirs) {
|
|
@@ -1174,7 +1378,7 @@ var SkillsService = class {
|
|
|
1174
1378
|
return skills;
|
|
1175
1379
|
}
|
|
1176
1380
|
loadSkill(skillPath, source) {
|
|
1177
|
-
const skillMdPath =
|
|
1381
|
+
const skillMdPath = join9(skillPath, "SKILL.md");
|
|
1178
1382
|
if (!fileExists(skillMdPath)) {
|
|
1179
1383
|
return void 0;
|
|
1180
1384
|
}
|
|
@@ -1203,7 +1407,7 @@ var SkillsService = class {
|
|
|
1203
1407
|
};
|
|
1204
1408
|
|
|
1205
1409
|
// src/services/scanner.ts
|
|
1206
|
-
import { join as
|
|
1410
|
+
import { join as join10 } from "path";
|
|
1207
1411
|
import { readdirSync as readdirSync2 } from "fs";
|
|
1208
1412
|
var DeploymentScanner = class {
|
|
1209
1413
|
constructor(projectDir, skillsManagerDir = SKILLS_MANAGER_DIR) {
|
|
@@ -1223,7 +1427,7 @@ var DeploymentScanner = class {
|
|
|
1223
1427
|
}
|
|
1224
1428
|
scanToolDeployment(toolName, config) {
|
|
1225
1429
|
const deployments = [];
|
|
1226
|
-
const baseDir =
|
|
1430
|
+
const baseDir = join10(this.projectDir, config.skillsDir);
|
|
1227
1431
|
const baseDeployment = this.scanDirectory(toolName, baseDir, config.skillsDir);
|
|
1228
1432
|
if (baseDeployment.skills.length > 0) {
|
|
1229
1433
|
deployments.push(baseDeployment);
|
|
@@ -1231,7 +1435,7 @@ var DeploymentScanner = class {
|
|
|
1231
1435
|
if (config.supportsModeSpecific && config.availableModes) {
|
|
1232
1436
|
for (const mode of config.availableModes) {
|
|
1233
1437
|
const modeDir = getTargetDir(config, mode);
|
|
1234
|
-
const fullModeDir =
|
|
1438
|
+
const fullModeDir = join10(this.projectDir, modeDir);
|
|
1235
1439
|
const modeDeployment = this.scanDirectory(toolName, fullModeDir, modeDir, mode);
|
|
1236
1440
|
if (modeDeployment.skills.length > 0) {
|
|
1237
1441
|
deployments.push(modeDeployment);
|
|
@@ -1276,7 +1480,7 @@ var DeploymentScanner = class {
|
|
|
1276
1480
|
try {
|
|
1277
1481
|
const entries = readdirSync2(fullPath, { withFileTypes: true });
|
|
1278
1482
|
for (const entry of entries) {
|
|
1279
|
-
const skillPath =
|
|
1483
|
+
const skillPath = join10(fullPath, entry.name);
|
|
1280
1484
|
const scanned = this.scanSkill(skillPath, entry.name);
|
|
1281
1485
|
if (scanned) {
|
|
1282
1486
|
deployment.skills.push(scanned);
|
|
@@ -1287,7 +1491,7 @@ var DeploymentScanner = class {
|
|
|
1287
1491
|
return deployment;
|
|
1288
1492
|
}
|
|
1289
1493
|
scanSkill(skillPath, name) {
|
|
1290
|
-
const skillMdPath =
|
|
1494
|
+
const skillMdPath = join10(skillPath, "SKILL.md");
|
|
1291
1495
|
if (!fileExists(skillMdPath)) {
|
|
1292
1496
|
return null;
|
|
1293
1497
|
}
|
|
@@ -1408,15 +1612,15 @@ async function listDeployed() {
|
|
|
1408
1612
|
console.log();
|
|
1409
1613
|
}
|
|
1410
1614
|
}
|
|
1411
|
-
var listCommand = new
|
|
1615
|
+
var listCommand = new Command4("list").description("List available or deployed skills").option("--deployed", "List deployed skills in current project").action(async (options) => {
|
|
1412
1616
|
await executeList(options);
|
|
1413
1617
|
});
|
|
1414
1618
|
|
|
1415
1619
|
// src/commands/init.ts
|
|
1416
|
-
import { Command as
|
|
1620
|
+
import { Command as Command5 } from "commander";
|
|
1417
1621
|
|
|
1418
1622
|
// src/services/deployer.ts
|
|
1419
|
-
import { join as
|
|
1623
|
+
import { join as join11 } from "path";
|
|
1420
1624
|
import { existsSync as existsSync3, rmSync as rmSync2 } from "fs";
|
|
1421
1625
|
var Deployer = class {
|
|
1422
1626
|
constructor(projectDir) {
|
|
@@ -1424,9 +1628,9 @@ var Deployer = class {
|
|
|
1424
1628
|
}
|
|
1425
1629
|
deploySkill(skill, toolConfig, mode, targetMode) {
|
|
1426
1630
|
const targetDir = getTargetDir(toolConfig, targetMode);
|
|
1427
|
-
const fullTargetDir =
|
|
1631
|
+
const fullTargetDir = join11(this.projectDir, targetDir);
|
|
1428
1632
|
ensureDir(fullTargetDir);
|
|
1429
|
-
const skillTargetPath =
|
|
1633
|
+
const skillTargetPath = join11(fullTargetDir, skill.name);
|
|
1430
1634
|
if (mode === "link") {
|
|
1431
1635
|
linkDir(skill.path, skillTargetPath);
|
|
1432
1636
|
} else {
|
|
@@ -1440,14 +1644,14 @@ var Deployer = class {
|
|
|
1440
1644
|
}
|
|
1441
1645
|
removeSkill(skillName, toolConfig, targetMode) {
|
|
1442
1646
|
const targetDir = getTargetDir(toolConfig, targetMode);
|
|
1443
|
-
const skillPath =
|
|
1647
|
+
const skillPath = join11(this.projectDir, targetDir, skillName);
|
|
1444
1648
|
if (existsSync3(skillPath)) {
|
|
1445
1649
|
rmSync2(skillPath, { recursive: true, force: true });
|
|
1446
1650
|
}
|
|
1447
1651
|
}
|
|
1448
1652
|
getDeployedSkillPath(skillName, toolConfig, targetMode) {
|
|
1449
1653
|
const targetDir = getTargetDir(toolConfig, targetMode);
|
|
1450
|
-
return
|
|
1654
|
+
return join11(this.projectDir, targetDir, skillName);
|
|
1451
1655
|
}
|
|
1452
1656
|
isSkillDeployed(skillName, toolConfig, targetMode) {
|
|
1453
1657
|
const skillPath = this.getDeployedSkillPath(skillName, toolConfig, targetMode);
|
|
@@ -1526,12 +1730,12 @@ async function executeInit(options) {
|
|
|
1526
1730
|
`Done! Deployed ${selectedSkillNames.length} skills to ${selectedTools.length} tool${selectedTools.length > 1 ? "s" : ""}.`
|
|
1527
1731
|
);
|
|
1528
1732
|
}
|
|
1529
|
-
var initCommand = new
|
|
1733
|
+
var initCommand = new Command5("init").description("Deploy skills to current project").option("--copy", "Copy files instead of creating symlinks").action(async (options) => {
|
|
1530
1734
|
await executeInit(options);
|
|
1531
1735
|
});
|
|
1532
1736
|
|
|
1533
1737
|
// src/commands/add.ts
|
|
1534
|
-
import { Command as
|
|
1738
|
+
import { Command as Command6 } from "commander";
|
|
1535
1739
|
async function executeAdd(skillName, options) {
|
|
1536
1740
|
if (!fileExists(SKILLS_MANAGER_DIR)) {
|
|
1537
1741
|
console.log("Skills manager not set up. Run: skillsmgr setup");
|
|
@@ -1587,12 +1791,12 @@ async function executeAdd(skillName, options) {
|
|
|
1587
1791
|
);
|
|
1588
1792
|
}
|
|
1589
1793
|
}
|
|
1590
|
-
var addCommand = new
|
|
1794
|
+
var addCommand = new Command6("add").description("Add a skill to the project").argument("<skill>", "Skill name to add").option("--tool <tool>", "Add to specific tool only").option("--copy", "Copy files instead of creating symlinks").action(async (skill, options) => {
|
|
1591
1795
|
await executeAdd(skill, options);
|
|
1592
1796
|
});
|
|
1593
1797
|
|
|
1594
1798
|
// src/commands/remove.ts
|
|
1595
|
-
import { Command as
|
|
1799
|
+
import { Command as Command7 } from "commander";
|
|
1596
1800
|
async function executeRemove(skillName, options) {
|
|
1597
1801
|
const scanner = new DeploymentScanner(process.cwd(), SKILLS_MANAGER_DIR);
|
|
1598
1802
|
const deployer = new Deployer(process.cwd());
|
|
@@ -1629,13 +1833,13 @@ async function executeRemove(skillName, options) {
|
|
|
1629
1833
|
console.log(`Skill '${skillName}' not found in any configured tool`);
|
|
1630
1834
|
}
|
|
1631
1835
|
}
|
|
1632
|
-
var removeCommand = new
|
|
1836
|
+
var removeCommand = new Command7("remove").description("Remove a skill from the project").argument("<skill>", "Skill name to remove").option("--tool <tool>", "Remove from specific tool only").action(async (skill, options) => {
|
|
1633
1837
|
await executeRemove(skill, options);
|
|
1634
1838
|
});
|
|
1635
1839
|
|
|
1636
1840
|
// src/commands/sync.ts
|
|
1637
|
-
import { Command as
|
|
1638
|
-
import { join as
|
|
1841
|
+
import { Command as Command8 } from "commander";
|
|
1842
|
+
import { join as join12 } from "path";
|
|
1639
1843
|
async function executeSync() {
|
|
1640
1844
|
const scanner = new DeploymentScanner(process.cwd(), SKILLS_MANAGER_DIR);
|
|
1641
1845
|
const deployer = new Deployer(process.cwd());
|
|
@@ -1680,8 +1884,8 @@ async function executeSync() {
|
|
|
1680
1884
|
continue;
|
|
1681
1885
|
}
|
|
1682
1886
|
if (skill.deployMode === "copy") {
|
|
1683
|
-
const sourceSkillMd =
|
|
1684
|
-
const deployedSkillMd =
|
|
1887
|
+
const sourceSkillMd = join12(sourcePath, "SKILL.md");
|
|
1888
|
+
const deployedSkillMd = join12(deployedPath, "SKILL.md");
|
|
1685
1889
|
if (fileExists(sourceSkillMd) && fileExists(deployedSkillMd)) {
|
|
1686
1890
|
const sourceContent = readFileContent(sourceSkillMd);
|
|
1687
1891
|
const deployedContent = readFileContent(deployedSkillMd);
|
|
@@ -1727,15 +1931,16 @@ async function executeSync() {
|
|
|
1727
1931
|
`Sync complete: ${updatedCount} updated, ${removedCount} removed`
|
|
1728
1932
|
);
|
|
1729
1933
|
}
|
|
1730
|
-
var syncCommand = new
|
|
1934
|
+
var syncCommand = new Command8("sync").description("Sync and verify deployed skills").action(async () => {
|
|
1731
1935
|
await executeSync();
|
|
1732
1936
|
});
|
|
1733
1937
|
|
|
1734
1938
|
// src/index.ts
|
|
1735
|
-
var program = new
|
|
1939
|
+
var program = new Command9();
|
|
1736
1940
|
program.name("skillsmgr").description("Unified skills manager for AI coding tools").version("0.1.0");
|
|
1737
1941
|
program.addCommand(setupCommand);
|
|
1738
1942
|
program.addCommand(installCommand);
|
|
1943
|
+
program.addCommand(updateCommand);
|
|
1739
1944
|
program.addCommand(listCommand);
|
|
1740
1945
|
program.addCommand(initCommand);
|
|
1741
1946
|
program.addCommand(addCommand);
|