reskill 0.14.0 → 0.16.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/dist/index.js CHANGED
@@ -190,12 +190,13 @@ function remove(targetPath) {
190
190
  }
191
191
  function copyDir(src, dest, options) {
192
192
  const exclude = options?.exclude || [];
193
+ const excludePrefix = options?.excludePrefix || '_';
193
194
  ensureDir(dest);
194
195
  const entries = external_node_fs_.readdirSync(src, {
195
196
  withFileTypes: true
196
197
  });
197
198
  for (const entry of entries){
198
- if (exclude.includes(entry.name)) continue;
199
+ if (exclude.includes(entry.name) || entry.name.startsWith(excludePrefix)) continue;
199
200
  const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
200
201
  const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
201
202
  if (entry.isDirectory()) copyDir(srcPath, destPath, options);
@@ -272,7 +273,7 @@ function sanitizeName(name) {
272
273
  if (sanitized.length > 255) sanitized = sanitized.substring(0, 255);
273
274
  return sanitized;
274
275
  }
275
- const execAsync = (0, __WEBPACK_EXTERNAL_MODULE_node_util__.promisify)(__WEBPACK_EXTERNAL_MODULE_node_child_process__.exec);
276
+ const git_execAsync = (0, __WEBPACK_EXTERNAL_MODULE_node_util__.promisify)(__WEBPACK_EXTERNAL_MODULE_node_child_process__.exec);
276
277
  class GitCloneError extends Error {
277
278
  repoUrl;
278
279
  originalError;
@@ -320,7 +321,7 @@ class GitCloneError extends Error {
320
321
  }
321
322
  }
322
323
  async function git(args, cwd) {
323
- const { stdout } = await execAsync(`git ${args.join(' ')}`, {
324
+ const { stdout } = await git_execAsync(`git ${args.join(' ')}`, {
324
325
  cwd,
325
326
  encoding: 'utf-8'
326
327
  });
@@ -454,6 +455,202 @@ function parseGitUrl(url) {
454
455
  }
455
456
  return null;
456
457
  }
458
+ const installer_AGENTS_DIR = '.agents';
459
+ const installer_SKILLS_SUBDIR = 'skills';
460
+ const DEFAULT_EXCLUDE_FILES = [
461
+ 'README.md',
462
+ 'metadata.json',
463
+ '.reskill-commit'
464
+ ];
465
+ const EXCLUDE_PREFIX = '_';
466
+ function installer_sanitizeName(name) {
467
+ let sanitized = name.replace(/[/\\:\0]/g, '');
468
+ sanitized = sanitized.replace(/^[.\s]+|[.\s]+$/g, '');
469
+ sanitized = sanitized.replace(/^\.+/, '');
470
+ if (!sanitized || 0 === sanitized.length) sanitized = 'unnamed-skill';
471
+ if (sanitized.length > 255) sanitized = sanitized.substring(0, 255);
472
+ return sanitized;
473
+ }
474
+ function installer_isPathSafe(basePath, targetPath) {
475
+ const normalizedBase = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(basePath));
476
+ const normalizedTarget = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(targetPath));
477
+ return normalizedTarget.startsWith(normalizedBase + __WEBPACK_EXTERNAL_MODULE_node_path__.sep) || normalizedTarget === normalizedBase;
478
+ }
479
+ function installer_getCanonicalSkillsDir(isGlobal, cwd) {
480
+ const baseDir = isGlobal ? (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)() : cwd || process.cwd();
481
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, installer_AGENTS_DIR, installer_SKILLS_SUBDIR);
482
+ }
483
+ function installer_ensureDir(dirPath) {
484
+ if (!external_node_fs_.existsSync(dirPath)) external_node_fs_.mkdirSync(dirPath, {
485
+ recursive: true
486
+ });
487
+ }
488
+ function installer_remove(targetPath) {
489
+ if (external_node_fs_.existsSync(targetPath)) external_node_fs_.rmSync(targetPath, {
490
+ recursive: true,
491
+ force: true
492
+ });
493
+ }
494
+ function copyDirectory(src, dest, options) {
495
+ const exclude = new Set(options?.exclude || DEFAULT_EXCLUDE_FILES);
496
+ installer_ensureDir(dest);
497
+ const entries = external_node_fs_.readdirSync(src, {
498
+ withFileTypes: true
499
+ });
500
+ for (const entry of entries){
501
+ if (exclude.has(entry.name) || entry.name.startsWith(EXCLUDE_PREFIX)) continue;
502
+ const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
503
+ const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
504
+ if (entry.isDirectory()) copyDirectory(srcPath, destPath, options);
505
+ else external_node_fs_.copyFileSync(srcPath, destPath);
506
+ }
507
+ }
508
+ async function installer_createSymlink(target, linkPath) {
509
+ try {
510
+ try {
511
+ const stats = external_node_fs_.lstatSync(linkPath);
512
+ if (stats.isSymbolicLink()) {
513
+ const existingTarget = external_node_fs_.readlinkSync(linkPath);
514
+ if (__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(existingTarget) === __WEBPACK_EXTERNAL_MODULE_node_path__.resolve(target)) return true;
515
+ external_node_fs_.rmSync(linkPath);
516
+ } else external_node_fs_.rmSync(linkPath, {
517
+ recursive: true
518
+ });
519
+ } catch (err) {
520
+ if (err && 'object' == typeof err && 'code' in err) {
521
+ if ('ELOOP' === err.code) try {
522
+ external_node_fs_.rmSync(linkPath, {
523
+ force: true
524
+ });
525
+ } catch {}
526
+ }
527
+ }
528
+ const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
529
+ installer_ensureDir(linkDir);
530
+ const relativePath = __WEBPACK_EXTERNAL_MODULE_node_path__.relative(linkDir, target);
531
+ const symlinkType = 'win32' === (0, __WEBPACK_EXTERNAL_MODULE_node_os__.platform)() ? 'junction' : void 0;
532
+ external_node_fs_.symlinkSync(relativePath, linkPath, symlinkType);
533
+ return true;
534
+ } catch {
535
+ return false;
536
+ }
537
+ }
538
+ class Installer {
539
+ cwd;
540
+ isGlobal;
541
+ constructor(options = {}){
542
+ this.cwd = options.cwd || process.cwd();
543
+ this.isGlobal = options.global || false;
544
+ }
545
+ getCanonicalPath(skillName) {
546
+ const sanitized = installer_sanitizeName(skillName);
547
+ const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
548
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
549
+ }
550
+ getAgentSkillPath(skillName, agentType) {
551
+ const agent = getAgentConfig(agentType);
552
+ const sanitized = installer_sanitizeName(skillName);
553
+ const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
554
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
555
+ }
556
+ async installForAgent(sourcePath, skillName, agentType, options = {}) {
557
+ const agent = getAgentConfig(agentType);
558
+ const installMode = options.mode || 'symlink';
559
+ const sanitized = installer_sanitizeName(skillName);
560
+ const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
561
+ const canonicalDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
562
+ const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
563
+ const agentDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
564
+ if (!installer_isPathSafe(canonicalBase, canonicalDir)) return {
565
+ success: false,
566
+ path: agentDir,
567
+ mode: installMode,
568
+ error: 'Invalid skill name: potential path traversal detected'
569
+ };
570
+ if (!installer_isPathSafe(agentBase, agentDir)) return {
571
+ success: false,
572
+ path: agentDir,
573
+ mode: installMode,
574
+ error: 'Invalid skill name: potential path traversal detected'
575
+ };
576
+ try {
577
+ if ('copy' === installMode) {
578
+ installer_ensureDir(agentDir);
579
+ installer_remove(agentDir);
580
+ copyDirectory(sourcePath, agentDir);
581
+ return {
582
+ success: true,
583
+ path: agentDir,
584
+ mode: 'copy'
585
+ };
586
+ }
587
+ installer_ensureDir(canonicalDir);
588
+ installer_remove(canonicalDir);
589
+ copyDirectory(sourcePath, canonicalDir);
590
+ const symlinkCreated = await installer_createSymlink(canonicalDir, agentDir);
591
+ if (!symlinkCreated) {
592
+ try {
593
+ installer_remove(agentDir);
594
+ } catch {}
595
+ installer_ensureDir(agentDir);
596
+ copyDirectory(sourcePath, agentDir);
597
+ return {
598
+ success: true,
599
+ path: agentDir,
600
+ canonicalPath: canonicalDir,
601
+ mode: 'symlink',
602
+ symlinkFailed: true
603
+ };
604
+ }
605
+ return {
606
+ success: true,
607
+ path: agentDir,
608
+ canonicalPath: canonicalDir,
609
+ mode: 'symlink'
610
+ };
611
+ } catch (error) {
612
+ return {
613
+ success: false,
614
+ path: agentDir,
615
+ mode: installMode,
616
+ error: error instanceof Error ? error.message : 'Unknown error'
617
+ };
618
+ }
619
+ }
620
+ async installToAgents(sourcePath, skillName, targetAgents, options = {}) {
621
+ const results = new Map();
622
+ for (const agent of targetAgents){
623
+ const result = await this.installForAgent(sourcePath, skillName, agent, options);
624
+ results.set(agent, result);
625
+ }
626
+ return results;
627
+ }
628
+ isInstalled(skillName, agentType) {
629
+ const skillPath = this.getAgentSkillPath(skillName, agentType);
630
+ return external_node_fs_.existsSync(skillPath);
631
+ }
632
+ uninstallFromAgent(skillName, agentType) {
633
+ const skillPath = this.getAgentSkillPath(skillName, agentType);
634
+ if (!external_node_fs_.existsSync(skillPath)) return false;
635
+ installer_remove(skillPath);
636
+ return true;
637
+ }
638
+ uninstallFromAgents(skillName, targetAgents) {
639
+ const results = new Map();
640
+ for (const agent of targetAgents)results.set(agent, this.uninstallFromAgent(skillName, agent));
641
+ const canonicalPath = this.getCanonicalPath(skillName);
642
+ if (external_node_fs_.existsSync(canonicalPath)) installer_remove(canonicalPath);
643
+ return results;
644
+ }
645
+ listInstalledSkills(agentType) {
646
+ const agent = getAgentConfig(agentType);
647
+ const skillsDir = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
648
+ if (!external_node_fs_.existsSync(skillsDir)) return [];
649
+ return external_node_fs_.readdirSync(skillsDir, {
650
+ withFileTypes: true
651
+ }).filter((entry)=>entry.isDirectory() || entry.isSymbolicLink()).map((entry)=>entry.name);
652
+ }
653
+ }
457
654
  class CacheManager {
458
655
  cacheDir;
459
656
  constructor(cacheDir){
@@ -526,9 +723,7 @@ class CacheManager {
526
723
  if (!cached) throw new Error(`Skill ${parsed.raw} version ${version} not found in cache`);
527
724
  if (exists(destPath)) remove(destPath);
528
725
  copyDir(cached.path, destPath, {
529
- exclude: [
530
- '.reskill-commit'
531
- ]
726
+ exclude: DEFAULT_EXCLUDE_FILES
532
727
  });
533
728
  }
534
729
  clearSkill(parsed, version) {
@@ -564,6 +759,31 @@ class CacheManager {
564
759
  registries
565
760
  };
566
761
  }
762
+ async getRemoteCommit(repoUrl, ref) {
763
+ const { exec } = await import("node:child_process");
764
+ const { promisify } = await import("node:util");
765
+ const execAsync = promisify(exec);
766
+ try {
767
+ const { stdout } = await execAsync(`git ls-remote ${repoUrl} ${ref}`, {
768
+ encoding: 'utf-8'
769
+ });
770
+ if (stdout.trim()) {
771
+ const [commit] = stdout.trim().split('\t');
772
+ return commit;
773
+ }
774
+ const { stdout: allRefs } = await execAsync(`git ls-remote ${repoUrl}`, {
775
+ encoding: 'utf-8'
776
+ });
777
+ const lines = allRefs.trim().split('\n');
778
+ for (const line of lines){
779
+ const [commit, refPath] = line.split('\t');
780
+ if (refPath === `refs/heads/${ref}` || refPath === `refs/tags/${ref}` || refPath === ref) return commit;
781
+ }
782
+ return '';
783
+ } catch {
784
+ return '';
785
+ }
786
+ }
567
787
  }
568
788
  const DEFAULT_SKILLS_JSON = {
569
789
  skills: {},
@@ -870,200 +1090,6 @@ class GitResolver {
870
1090
  };
871
1091
  }
872
1092
  }
873
- const installer_AGENTS_DIR = '.agents';
874
- const installer_SKILLS_SUBDIR = 'skills';
875
- function installer_sanitizeName(name) {
876
- let sanitized = name.replace(/[/\\:\0]/g, '');
877
- sanitized = sanitized.replace(/^[.\s]+|[.\s]+$/g, '');
878
- sanitized = sanitized.replace(/^\.+/, '');
879
- if (!sanitized || 0 === sanitized.length) sanitized = 'unnamed-skill';
880
- if (sanitized.length > 255) sanitized = sanitized.substring(0, 255);
881
- return sanitized;
882
- }
883
- function installer_isPathSafe(basePath, targetPath) {
884
- const normalizedBase = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(basePath));
885
- const normalizedTarget = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(targetPath));
886
- return normalizedTarget.startsWith(normalizedBase + __WEBPACK_EXTERNAL_MODULE_node_path__.sep) || normalizedTarget === normalizedBase;
887
- }
888
- function installer_getCanonicalSkillsDir(isGlobal, cwd) {
889
- const baseDir = isGlobal ? (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)() : cwd || process.cwd();
890
- return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, installer_AGENTS_DIR, installer_SKILLS_SUBDIR);
891
- }
892
- function installer_ensureDir(dirPath) {
893
- if (!external_node_fs_.existsSync(dirPath)) external_node_fs_.mkdirSync(dirPath, {
894
- recursive: true
895
- });
896
- }
897
- function installer_remove(targetPath) {
898
- if (external_node_fs_.existsSync(targetPath)) external_node_fs_.rmSync(targetPath, {
899
- recursive: true,
900
- force: true
901
- });
902
- }
903
- function copyDirectory(src, dest, options) {
904
- const exclude = new Set(options?.exclude || [
905
- 'README.md',
906
- 'metadata.json',
907
- '.reskill-commit'
908
- ]);
909
- installer_ensureDir(dest);
910
- const entries = external_node_fs_.readdirSync(src, {
911
- withFileTypes: true
912
- });
913
- for (const entry of entries){
914
- if (exclude.has(entry.name) || entry.name.startsWith('_')) continue;
915
- const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
916
- const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
917
- if (entry.isDirectory()) copyDirectory(srcPath, destPath, options);
918
- else external_node_fs_.copyFileSync(srcPath, destPath);
919
- }
920
- }
921
- async function installer_createSymlink(target, linkPath) {
922
- try {
923
- try {
924
- const stats = external_node_fs_.lstatSync(linkPath);
925
- if (stats.isSymbolicLink()) {
926
- const existingTarget = external_node_fs_.readlinkSync(linkPath);
927
- if (__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(existingTarget) === __WEBPACK_EXTERNAL_MODULE_node_path__.resolve(target)) return true;
928
- external_node_fs_.rmSync(linkPath);
929
- } else external_node_fs_.rmSync(linkPath, {
930
- recursive: true
931
- });
932
- } catch (err) {
933
- if (err && 'object' == typeof err && 'code' in err) {
934
- if ('ELOOP' === err.code) try {
935
- external_node_fs_.rmSync(linkPath, {
936
- force: true
937
- });
938
- } catch {}
939
- }
940
- }
941
- const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
942
- installer_ensureDir(linkDir);
943
- const relativePath = __WEBPACK_EXTERNAL_MODULE_node_path__.relative(linkDir, target);
944
- const symlinkType = 'win32' === (0, __WEBPACK_EXTERNAL_MODULE_node_os__.platform)() ? 'junction' : void 0;
945
- external_node_fs_.symlinkSync(relativePath, linkPath, symlinkType);
946
- return true;
947
- } catch {
948
- return false;
949
- }
950
- }
951
- class Installer {
952
- cwd;
953
- isGlobal;
954
- constructor(options = {}){
955
- this.cwd = options.cwd || process.cwd();
956
- this.isGlobal = options.global || false;
957
- }
958
- getCanonicalPath(skillName) {
959
- const sanitized = installer_sanitizeName(skillName);
960
- const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
961
- return __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
962
- }
963
- getAgentSkillPath(skillName, agentType) {
964
- const agent = getAgentConfig(agentType);
965
- const sanitized = installer_sanitizeName(skillName);
966
- const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
967
- return __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
968
- }
969
- async installForAgent(sourcePath, skillName, agentType, options = {}) {
970
- const agent = getAgentConfig(agentType);
971
- const installMode = options.mode || 'symlink';
972
- const sanitized = installer_sanitizeName(skillName);
973
- const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
974
- const canonicalDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
975
- const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
976
- const agentDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
977
- if (!installer_isPathSafe(canonicalBase, canonicalDir)) return {
978
- success: false,
979
- path: agentDir,
980
- mode: installMode,
981
- error: 'Invalid skill name: potential path traversal detected'
982
- };
983
- if (!installer_isPathSafe(agentBase, agentDir)) return {
984
- success: false,
985
- path: agentDir,
986
- mode: installMode,
987
- error: 'Invalid skill name: potential path traversal detected'
988
- };
989
- try {
990
- if ('copy' === installMode) {
991
- installer_ensureDir(agentDir);
992
- installer_remove(agentDir);
993
- copyDirectory(sourcePath, agentDir);
994
- return {
995
- success: true,
996
- path: agentDir,
997
- mode: 'copy'
998
- };
999
- }
1000
- installer_ensureDir(canonicalDir);
1001
- installer_remove(canonicalDir);
1002
- copyDirectory(sourcePath, canonicalDir);
1003
- const symlinkCreated = await installer_createSymlink(canonicalDir, agentDir);
1004
- if (!symlinkCreated) {
1005
- try {
1006
- installer_remove(agentDir);
1007
- } catch {}
1008
- installer_ensureDir(agentDir);
1009
- copyDirectory(sourcePath, agentDir);
1010
- return {
1011
- success: true,
1012
- path: agentDir,
1013
- canonicalPath: canonicalDir,
1014
- mode: 'symlink',
1015
- symlinkFailed: true
1016
- };
1017
- }
1018
- return {
1019
- success: true,
1020
- path: agentDir,
1021
- canonicalPath: canonicalDir,
1022
- mode: 'symlink'
1023
- };
1024
- } catch (error) {
1025
- return {
1026
- success: false,
1027
- path: agentDir,
1028
- mode: installMode,
1029
- error: error instanceof Error ? error.message : 'Unknown error'
1030
- };
1031
- }
1032
- }
1033
- async installToAgents(sourcePath, skillName, targetAgents, options = {}) {
1034
- const results = new Map();
1035
- for (const agent of targetAgents){
1036
- const result = await this.installForAgent(sourcePath, skillName, agent, options);
1037
- results.set(agent, result);
1038
- }
1039
- return results;
1040
- }
1041
- isInstalled(skillName, agentType) {
1042
- const skillPath = this.getAgentSkillPath(skillName, agentType);
1043
- return external_node_fs_.existsSync(skillPath);
1044
- }
1045
- uninstallFromAgent(skillName, agentType) {
1046
- const skillPath = this.getAgentSkillPath(skillName, agentType);
1047
- if (!external_node_fs_.existsSync(skillPath)) return false;
1048
- installer_remove(skillPath);
1049
- return true;
1050
- }
1051
- uninstallFromAgents(skillName, targetAgents) {
1052
- const results = new Map();
1053
- for (const agent of targetAgents)results.set(agent, this.uninstallFromAgent(skillName, agent));
1054
- const canonicalPath = this.getCanonicalPath(skillName);
1055
- if (external_node_fs_.existsSync(canonicalPath)) installer_remove(canonicalPath);
1056
- return results;
1057
- }
1058
- listInstalledSkills(agentType) {
1059
- const agent = getAgentConfig(agentType);
1060
- const skillsDir = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
1061
- if (!external_node_fs_.existsSync(skillsDir)) return [];
1062
- return external_node_fs_.readdirSync(skillsDir, {
1063
- withFileTypes: true
1064
- }).filter((entry)=>entry.isDirectory() || entry.isSymbolicLink()).map((entry)=>entry.name);
1065
- }
1066
- }
1067
1093
  const LOCKFILE_VERSION = 1;
1068
1094
  class LockManager {
1069
1095
  projectRoot;
@@ -1127,6 +1153,7 @@ class LockManager {
1127
1153
  const lockedSkill = {
1128
1154
  source: options.source,
1129
1155
  version: options.version,
1156
+ ref: options.ref,
1130
1157
  resolved: options.resolved,
1131
1158
  commit: options.commit,
1132
1159
  installedAt: new Date().toISOString()
@@ -1164,7 +1191,7 @@ class LockManager {
1164
1191
  this.lockData = null;
1165
1192
  }
1166
1193
  }
1167
- const logger = {
1194
+ const logger_logger = {
1168
1195
  info (message) {
1169
1196
  console.log(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].blue('ℹ'), message);
1170
1197
  },
@@ -1247,35 +1274,43 @@ class SkillManager {
1247
1274
  const { force = false, save = true } = options;
1248
1275
  const resolved = await this.resolver.resolve(ref);
1249
1276
  const { parsed, repoUrl } = resolved;
1250
- const version = resolved.ref;
1277
+ const gitRef = resolved.ref;
1251
1278
  const skillName = parsed.subPath ? __WEBPACK_EXTERNAL_MODULE_node_path__.basename(parsed.subPath) : parsed.repo;
1252
1279
  const skillPath = this.getSkillPath(skillName);
1253
1280
  if (exists(skillPath) && !force) {
1254
1281
  const locked = this.lockManager.get(skillName);
1255
- if (locked && locked.version === version) {
1256
- logger.info(`${skillName}@${version} is already installed`);
1282
+ const lockedRef = locked?.ref || locked?.version;
1283
+ if (locked && lockedRef === gitRef) {
1284
+ logger_logger.info(`${skillName}@${gitRef} is already installed`);
1257
1285
  const installed = this.getInstalledSkill(skillName);
1258
1286
  if (installed) return installed;
1259
1287
  }
1260
1288
  if (!force) {
1261
- logger.warn(`${skillName} is already installed. Use --force to reinstall.`);
1289
+ logger_logger.warn(`${skillName} is already installed. Use --force to reinstall.`);
1262
1290
  const installed = this.getInstalledSkill(skillName);
1263
1291
  if (installed) return installed;
1264
1292
  }
1265
1293
  }
1266
- logger["package"](`Installing ${skillName}@${version}...`);
1267
- let cacheResult = await this.cache.get(parsed, version);
1268
- if (cacheResult) logger.debug(`Using cached ${skillName}@${version}`);
1294
+ logger_logger["package"](`Installing ${skillName}@${gitRef}...`);
1295
+ let cacheResult = await this.cache.get(parsed, gitRef);
1296
+ if (cacheResult) logger_logger.debug(`Using cached ${skillName}@${gitRef}`);
1269
1297
  else {
1270
- logger.debug(`Caching ${skillName}@${version} from ${repoUrl}`);
1271
- cacheResult = await this.cache.cache(repoUrl, parsed, version, version);
1298
+ logger_logger.debug(`Caching ${skillName}@${gitRef} from ${repoUrl}`);
1299
+ cacheResult = await this.cache.cache(repoUrl, parsed, gitRef, gitRef);
1272
1300
  }
1273
1301
  ensureDir(this.getInstallDir());
1274
1302
  if (exists(skillPath)) remove(skillPath);
1275
- await this.cache.copyTo(parsed, version, skillPath);
1303
+ await this.cache.copyTo(parsed, gitRef, skillPath);
1304
+ let semanticVersion = gitRef;
1305
+ const skillJsonPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(skillPath, 'skill.json');
1306
+ if (exists(skillJsonPath)) try {
1307
+ const skillJson = readJson(skillJsonPath);
1308
+ if (skillJson.version) semanticVersion = skillJson.version;
1309
+ } catch {}
1276
1310
  if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
1277
1311
  source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
1278
- version,
1312
+ version: semanticVersion,
1313
+ ref: gitRef,
1279
1314
  resolved: repoUrl,
1280
1315
  commit: cacheResult.commit
1281
1316
  });
@@ -1283,8 +1318,9 @@ class SkillManager {
1283
1318
  this.config.ensureExists();
1284
1319
  this.config.addSkill(skillName, ref);
1285
1320
  }
1321
+ const displayVersion = semanticVersion !== gitRef ? `${semanticVersion} (${gitRef})` : gitRef;
1286
1322
  const locationHint = this.isGlobal ? '(global)' : '';
1287
- logger.success(`Installed ${skillName}@${version} to ${skillPath} ${locationHint}`.trim());
1323
+ logger_logger.success(`Installed ${skillName}@${displayVersion} to ${skillPath} ${locationHint}`.trim());
1288
1324
  const installed = this.getInstalledSkill(skillName);
1289
1325
  if (!installed) throw new Error(`Failed to get installed skill info for ${skillName}`);
1290
1326
  return installed;
@@ -1299,7 +1335,7 @@ class SkillManager {
1299
1335
  });
1300
1336
  installed.push(skill);
1301
1337
  } catch (error) {
1302
- logger.error(`Failed to install ${name}: ${error.message}`);
1338
+ logger_logger.error(`Failed to install ${name}: ${error.message}`);
1303
1339
  }
1304
1340
  return installed;
1305
1341
  }
@@ -1307,22 +1343,33 @@ class SkillManager {
1307
1343
  const skillPath = this.getSkillPath(name);
1308
1344
  if (!exists(skillPath)) {
1309
1345
  const location = this.isGlobal ? '(global)' : '';
1310
- logger.warn(`Skill ${name} is not installed ${location}`.trim());
1346
+ logger_logger.warn(`Skill ${name} is not installed ${location}`.trim());
1311
1347
  return false;
1312
1348
  }
1313
1349
  remove(skillPath);
1314
1350
  if (!this.isGlobal) this.lockManager.remove(name);
1315
1351
  if (!this.isGlobal && this.config.exists()) this.config.removeSkill(name);
1316
1352
  const locationHint = this.isGlobal ? '(global)' : '';
1317
- logger.success(`Uninstalled ${name} ${locationHint}`.trim());
1353
+ logger_logger.success(`Uninstalled ${name} ${locationHint}`.trim());
1318
1354
  return true;
1319
1355
  }
1356
+ checkNeedsUpdate(name, remoteCommit) {
1357
+ const locked = this.lockManager.get(name);
1358
+ if (!locked?.commit) return true;
1359
+ return locked.commit !== remoteCommit;
1360
+ }
1320
1361
  async update(name) {
1321
1362
  const updated = [];
1322
1363
  if (name) {
1323
1364
  const ref = this.config.getSkillRef(name);
1324
1365
  if (!ref) {
1325
- logger.error(`Skill ${name} not found in skills.json`);
1366
+ logger_logger.error(`Skill ${name} not found in skills.json`);
1367
+ return [];
1368
+ }
1369
+ const resolved = await this.resolver.resolve(ref);
1370
+ const remoteCommit = await this.cache.getRemoteCommit(resolved.repoUrl, resolved.ref);
1371
+ if (!this.checkNeedsUpdate(name, remoteCommit)) {
1372
+ logger_logger.info(`${name} is already up to date`);
1326
1373
  return [];
1327
1374
  }
1328
1375
  const skill = await this.install(ref, {
@@ -1333,13 +1380,19 @@ class SkillManager {
1333
1380
  } else {
1334
1381
  const skills = this.config.getSkills();
1335
1382
  for (const [skillName, ref] of Object.entries(skills))try {
1383
+ const resolved = await this.resolver.resolve(ref);
1384
+ const remoteCommit = await this.cache.getRemoteCommit(resolved.repoUrl, resolved.ref);
1385
+ if (!this.checkNeedsUpdate(skillName, remoteCommit)) {
1386
+ logger_logger.info(`${skillName} is already up to date`);
1387
+ continue;
1388
+ }
1336
1389
  const skill = await this.install(ref, {
1337
1390
  force: true,
1338
1391
  save: false
1339
1392
  });
1340
1393
  updated.push(skill);
1341
1394
  } catch (error) {
1342
- logger.error(`Failed to update ${skillName}: ${error.message}`);
1395
+ logger_logger.error(`Failed to update ${skillName}: ${error.message}`);
1343
1396
  }
1344
1397
  }
1345
1398
  return updated;
@@ -1356,7 +1409,7 @@ class SkillManager {
1356
1409
  const linkPath = this.getSkillPath(skillName);
1357
1410
  ensureDir(__WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath));
1358
1411
  createSymlink(absolutePath, linkPath);
1359
- logger.success(`Linked ${skillName} → ${absolutePath}`);
1412
+ logger_logger.success(`Linked ${skillName} → ${absolutePath}`);
1360
1413
  return {
1361
1414
  name: skillName,
1362
1415
  path: linkPath,
@@ -1368,15 +1421,15 @@ class SkillManager {
1368
1421
  unlink(name) {
1369
1422
  const skillPath = this.getSkillPath(name);
1370
1423
  if (!exists(skillPath)) {
1371
- logger.warn(`Skill ${name} is not installed`);
1424
+ logger_logger.warn(`Skill ${name} is not installed`);
1372
1425
  return false;
1373
1426
  }
1374
1427
  if (!isSymlink(skillPath)) {
1375
- logger.warn(`Skill ${name} is not a linked skill`);
1428
+ logger_logger.warn(`Skill ${name} is not a linked skill`);
1376
1429
  return false;
1377
1430
  }
1378
1431
  remove(skillPath);
1379
- logger.success(`Unlinked ${name}`);
1432
+ logger_logger.success(`Unlinked ${name}`);
1380
1433
  return true;
1381
1434
  }
1382
1435
  list() {
@@ -1446,7 +1499,8 @@ class SkillManager {
1446
1499
  const skills = this.config.getSkills();
1447
1500
  for (const [name, ref] of Object.entries(skills))try {
1448
1501
  const locked = this.lockManager.get(name);
1449
- const current = locked?.version || 'unknown';
1502
+ const currentRef = locked?.ref || locked?.version || 'unknown';
1503
+ const currentVersion = locked?.version || 'unknown';
1450
1504
  const parsed = this.resolver.parseRef(ref);
1451
1505
  const repoUrl = this.resolver.buildRepoUrl(parsed);
1452
1506
  const latestResolved = await this.resolver.resolveVersion(repoUrl, {
@@ -1455,15 +1509,15 @@ class SkillManager {
1455
1509
  raw: 'latest'
1456
1510
  });
1457
1511
  const latest = latestResolved.ref;
1458
- const updateAvailable = current !== latest && 'unknown' !== current;
1512
+ const updateAvailable = currentRef !== latest && 'unknown' !== currentRef;
1459
1513
  results.push({
1460
1514
  name,
1461
- current,
1515
+ current: currentVersion !== currentRef ? `${currentVersion} (${currentRef})` : currentRef,
1462
1516
  latest,
1463
1517
  updateAvailable
1464
1518
  });
1465
1519
  } catch (error) {
1466
- logger.debug(`Failed to check ${name}: ${error.message}`);
1520
+ logger_logger.debug(`Failed to check ${name}: ${error.message}`);
1467
1521
  results.push({
1468
1522
  name,
1469
1523
  current: 'unknown',
@@ -1477,16 +1531,22 @@ class SkillManager {
1477
1531
  const { save = true, mode = 'symlink' } = options;
1478
1532
  const resolved = await this.resolver.resolve(ref);
1479
1533
  const { parsed, repoUrl } = resolved;
1480
- const version = resolved.ref;
1534
+ const gitRef = resolved.ref;
1481
1535
  const skillName = parsed.subPath ? __WEBPACK_EXTERNAL_MODULE_node_path__.basename(parsed.subPath) : parsed.repo;
1482
- logger["package"](`Installing ${skillName}@${version} to ${targetAgents.length} agent(s)...`);
1483
- let cacheResult = await this.cache.get(parsed, version);
1484
- if (cacheResult) logger.debug(`Using cached ${skillName}@${version}`);
1536
+ logger_logger["package"](`Installing ${skillName}@${gitRef} to ${targetAgents.length} agent(s)...`);
1537
+ let cacheResult = await this.cache.get(parsed, gitRef);
1538
+ if (cacheResult) logger_logger.debug(`Using cached ${skillName}@${gitRef}`);
1485
1539
  else {
1486
- logger.debug(`Caching ${skillName}@${version} from ${repoUrl}`);
1487
- cacheResult = await this.cache.cache(repoUrl, parsed, version, version);
1540
+ logger_logger.debug(`Caching ${skillName}@${gitRef} from ${repoUrl}`);
1541
+ cacheResult = await this.cache.cache(repoUrl, parsed, gitRef, gitRef);
1488
1542
  }
1489
- const sourcePath = this.cache.getCachePath(parsed, version);
1543
+ const sourcePath = this.cache.getCachePath(parsed, gitRef);
1544
+ let semanticVersion = gitRef;
1545
+ const skillJsonPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(sourcePath, 'skill.json');
1546
+ if (exists(skillJsonPath)) try {
1547
+ const skillJson = readJson(skillJsonPath);
1548
+ if (skillJson.version) semanticVersion = skillJson.version;
1549
+ } catch {}
1490
1550
  const installer = new Installer({
1491
1551
  cwd: this.projectRoot,
1492
1552
  global: this.isGlobal
@@ -1496,7 +1556,8 @@ class SkillManager {
1496
1556
  });
1497
1557
  if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
1498
1558
  source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
1499
- version,
1559
+ version: semanticVersion,
1560
+ ref: gitRef,
1500
1561
  resolved: repoUrl,
1501
1562
  commit: cacheResult.commit
1502
1563
  });
@@ -1506,12 +1567,13 @@ class SkillManager {
1506
1567
  }
1507
1568
  const successCount = Array.from(results.values()).filter((r)=>r.success).length;
1508
1569
  const failCount = results.size - successCount;
1509
- if (0 === failCount) logger.success(`Installed ${skillName}@${version} to ${successCount} agent(s)`);
1510
- else logger.warn(`Installed ${skillName}@${version} to ${successCount} agent(s), ${failCount} failed`);
1570
+ const displayVersion = semanticVersion !== gitRef ? `${semanticVersion} (${gitRef})` : gitRef;
1571
+ if (0 === failCount) logger_logger.success(`Installed ${skillName}@${displayVersion} to ${successCount} agent(s)`);
1572
+ else logger_logger.warn(`Installed ${skillName}@${displayVersion} to ${successCount} agent(s), ${failCount} failed`);
1511
1573
  const skill = {
1512
1574
  name: skillName,
1513
1575
  path: sourcePath,
1514
- version,
1576
+ version: semanticVersion,
1515
1577
  source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`
1516
1578
  };
1517
1579
  return {
@@ -1551,7 +1613,7 @@ class SkillManager {
1551
1613
  if (!this.isGlobal) this.lockManager.remove(name);
1552
1614
  if (!this.isGlobal && this.config.exists()) this.config.removeSkill(name);
1553
1615
  const successCount = Array.from(results.values()).filter((r)=>r).length;
1554
- logger.success(`Uninstalled ${name} from ${successCount} agent(s)`);
1616
+ logger_logger.success(`Uninstalled ${name} from ${successCount} agent(s)`);
1555
1617
  return results;
1556
1618
  }
1557
1619
  }
@@ -1698,4 +1760,4 @@ function generateSkillMd(skill) {
1698
1760
  frontmatter.push('');
1699
1761
  return frontmatter.join('\n') + skill.content;
1700
1762
  }
1701
- export { CacheManager, ConfigLoader, DEFAULT_REGISTRIES, GitResolver, Installer, LockManager, SkillManager, SkillValidationError, agents, detectInstalledAgents, generateSkillMd, getAgentConfig, getAgentSkillsDir, getAllAgentTypes, getCanonicalSkillPath, getCanonicalSkillsDir, hasValidSkillMd, isPathSafe, isValidAgentType, logger, parseSkillFromDir, parseSkillMd, parseSkillMdFile, sanitizeName, shortenPath, validateSkillDescription, validateSkillName };
1763
+ export { CacheManager, ConfigLoader, DEFAULT_REGISTRIES, GitResolver, Installer, LockManager, SkillManager, SkillValidationError, agents, detectInstalledAgents, generateSkillMd, getAgentConfig, getAgentSkillsDir, getAllAgentTypes, getCanonicalSkillPath, getCanonicalSkillsDir, hasValidSkillMd, isPathSafe, isValidAgentType, logger_logger as logger, parseSkillFromDir, parseSkillMd, parseSkillMdFile, sanitizeName, shortenPath, validateSkillDescription, validateSkillName };