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 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 Command8 } from "commander";
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 join6 } from "path";
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 githubService = new GitHubService();
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 githubService.listSkills(owner, repo, "skills");
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 githubService.getDefaultBranch(owner, repo);
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 = join6(SKILLS_MANAGER_DIR, "official", "anthropic");
986
+ const targetBase = join7(SKILLS_MANAGER_DIR, "official", "anthropic");
936
987
  for (const skill of selectedSkills) {
937
- const targetDir = join6(targetBase, skill.name);
988
+ const targetDir = join7(targetBase, skill.name);
938
989
  process.stdout.write(` ${skill.name}...`);
939
- await githubService.downloadSkill(owner, repo, skill.path, targetDir);
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 githubService = new GitHubService();
947
- const parsed = githubService.parseGitHubUrl(url);
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 = githubService.getTargetDir(owner, repo, skillName, options.custom);
1011
+ const targetDir = githubService2.getTargetDir(owner, repo, skillName, options.custom);
956
1012
  console.log(`Downloading ${skillName}...`);
957
- await githubService.downloadSkill(owner, repo, path, targetDir);
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 githubService.listSkills(owner, repo, skillsPath);
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 githubService.getDefaultBranch(owner, repo);
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 = join6(SKILLS_MANAGER_DIR, "official", "anthropic");
1068
+ targetBase = join7(SKILLS_MANAGER_DIR, "official", "anthropic");
1013
1069
  } else if (options.custom) {
1014
- targetBase = join6(SKILLS_MANAGER_DIR, "custom", repo);
1070
+ targetBase = join7(SKILLS_MANAGER_DIR, "custom", repo);
1015
1071
  } else {
1016
- targetBase = join6(SKILLS_MANAGER_DIR, "community", repo);
1072
+ targetBase = join7(SKILLS_MANAGER_DIR, "community", repo);
1017
1073
  }
1018
1074
  for (const skill of selectedSkills) {
1019
- const targetDir = join6(targetBase, skill.name);
1075
+ const targetDir = join7(targetBase, skill.name);
1020
1076
  process.stdout.write(` ${skill.name}...`);
1021
- await githubService.downloadSkill(owner, repo, skill.path, targetDir);
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 = join6(repoPath, "skills");
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 = join6(dir.path, "SKILL.md");
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/list.ts
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 join7 } from "path";
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 = join7(this.skillsDir, source);
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 = join7(this.skillsDir, source);
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 = join7(repoDir.path, "skills");
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 = join7(skillPath, "SKILL.md");
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 join8 } from "path";
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 = join8(this.projectDir, config.skillsDir);
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 = join8(this.projectDir, modeDir);
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 = join8(fullPath, entry.name);
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 = join8(skillPath, "SKILL.md");
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 Command3("list").description("List available or deployed skills").option("--deployed", "List deployed skills in current project").action(async (options) => {
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 Command4 } from "commander";
1620
+ import { Command as Command5 } from "commander";
1417
1621
 
1418
1622
  // src/services/deployer.ts
1419
- import { join as join9 } from "path";
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 = join9(this.projectDir, targetDir);
1631
+ const fullTargetDir = join11(this.projectDir, targetDir);
1428
1632
  ensureDir(fullTargetDir);
1429
- const skillTargetPath = join9(fullTargetDir, skill.name);
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 = join9(this.projectDir, targetDir, skillName);
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 join9(this.projectDir, targetDir, skillName);
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 Command4("init").description("Deploy skills to current project").option("--copy", "Copy files instead of creating symlinks").action(async (options) => {
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 Command5 } from "commander";
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 Command5("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) => {
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 Command6 } from "commander";
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 Command6("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) => {
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 Command7 } from "commander";
1638
- import { join as join10 } from "path";
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 = join10(sourcePath, "SKILL.md");
1684
- const deployedSkillMd = join10(deployedPath, "SKILL.md");
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 Command7("sync").description("Sync and verify deployed skills").action(async () => {
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 Command8();
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillsmgr",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Unified skills manager for AI coding tools",
5
5
  "type": "module",
6
6
  "bin": {