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/cli/index.js CHANGED
@@ -4,10 +4,11 @@ import * as __WEBPACK_EXTERNAL_MODULE_node_path__ from "node:path";
4
4
  import * as __WEBPACK_EXTERNAL_MODULE_node_url__ from "node:url";
5
5
  import * as __WEBPACK_EXTERNAL_MODULE_commander__ from "commander";
6
6
  import * as __WEBPACK_EXTERNAL_MODULE_chalk__ from "chalk";
7
+ import * as __WEBPACK_EXTERNAL_MODULE_semver__ from "semver";
8
+ import * as __WEBPACK_EXTERNAL_MODULE_tabtab__ from "tabtab";
7
9
  import * as __WEBPACK_EXTERNAL_MODULE_node_os__ from "node:os";
8
10
  import * as __WEBPACK_EXTERNAL_MODULE_node_child_process__ from "node:child_process";
9
11
  import * as __WEBPACK_EXTERNAL_MODULE_node_util__ from "node:util";
10
- import * as __WEBPACK_EXTERNAL_MODULE_semver__ from "semver";
11
12
  import * as __WEBPACK_EXTERNAL_MODULE__clack_prompts__ from "@clack/prompts";
12
13
  import * as __WEBPACK_EXTERNAL_MODULE_ora__ from "ora";
13
14
  var __webpack_modules__ = {
@@ -26,93 +27,7 @@ function __webpack_require__(moduleId) {
26
27
  return module.exports;
27
28
  }
28
29
  var external_node_fs_ = __webpack_require__("node:fs");
29
- function exists(filePath) {
30
- return external_node_fs_.existsSync(filePath);
31
- }
32
- function readJson(filePath) {
33
- const content = external_node_fs_.readFileSync(filePath, 'utf-8');
34
- return JSON.parse(content);
35
- }
36
- function writeJson(filePath, data, indent = 2) {
37
- const dir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(filePath);
38
- if (!exists(dir)) external_node_fs_.mkdirSync(dir, {
39
- recursive: true
40
- });
41
- external_node_fs_.writeFileSync(filePath, `${JSON.stringify(data, null, indent)}\n`, 'utf-8');
42
- }
43
- function ensureDir(dirPath) {
44
- if (!exists(dirPath)) external_node_fs_.mkdirSync(dirPath, {
45
- recursive: true
46
- });
47
- }
48
- function remove(targetPath) {
49
- if (exists(targetPath)) external_node_fs_.rmSync(targetPath, {
50
- recursive: true,
51
- force: true
52
- });
53
- }
54
- function copyDir(src, dest, options) {
55
- const exclude = options?.exclude || [];
56
- ensureDir(dest);
57
- const entries = external_node_fs_.readdirSync(src, {
58
- withFileTypes: true
59
- });
60
- for (const entry of entries){
61
- if (exclude.includes(entry.name)) continue;
62
- const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
63
- const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
64
- if (entry.isDirectory()) copyDir(srcPath, destPath, options);
65
- else external_node_fs_.copyFileSync(srcPath, destPath);
66
- }
67
- }
68
- function listDir(dirPath) {
69
- if (!exists(dirPath)) return [];
70
- return external_node_fs_.readdirSync(dirPath);
71
- }
72
- function isDirectory(targetPath) {
73
- if (!exists(targetPath)) return false;
74
- return external_node_fs_.statSync(targetPath).isDirectory();
75
- }
76
- function isSymlink(targetPath) {
77
- if (!exists(targetPath)) return false;
78
- return external_node_fs_.lstatSync(targetPath).isSymbolicLink();
79
- }
80
- function createSymlink(target, linkPath) {
81
- const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
82
- ensureDir(linkDir);
83
- if (exists(linkPath)) remove(linkPath);
84
- external_node_fs_.symlinkSync(target, linkPath, 'dir');
85
- }
86
- function getRealPath(linkPath) {
87
- return external_node_fs_.realpathSync(linkPath);
88
- }
89
- function getSkillsJsonPath(projectRoot) {
90
- const root = projectRoot || process.cwd();
91
- return __WEBPACK_EXTERNAL_MODULE_node_path__.join(root, 'skills.json');
92
- }
93
- function getSkillsLockPath(projectRoot) {
94
- const root = projectRoot || process.cwd();
95
- return __WEBPACK_EXTERNAL_MODULE_node_path__.join(root, 'skills.lock');
96
- }
97
- function getCacheDir() {
98
- const home = process.env.HOME || process.env.USERPROFILE || '';
99
- return process.env.RESKILL_CACHE_DIR || __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.reskill-cache');
100
- }
101
- function getHomeDir() {
102
- return process.env.HOME || process.env.USERPROFILE || '';
103
- }
104
- function getGlobalSkillsDir() {
105
- const home = getHomeDir();
106
- return __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.claude', 'skills');
107
- }
108
- function shortenPath(fullPath, cwd) {
109
- const home = getHomeDir();
110
- const currentDir = cwd || process.cwd();
111
- if (fullPath.startsWith(home)) return fullPath.replace(home, '~');
112
- if (fullPath.startsWith(currentDir)) return `.${fullPath.slice(currentDir.length)}`;
113
- return fullPath;
114
- }
115
- const logger = {
30
+ const logger_logger = {
116
31
  info (message) {
117
32
  console.log(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].blue('ℹ'), message);
118
33
  },
@@ -153,6 +68,40 @@ const logger = {
153
68
  }
154
69
  }
155
70
  };
71
+ async function checkForUpdate(packageName, currentVersion, options = {}) {
72
+ const timeout = options.timeout ?? 3000;
73
+ try {
74
+ const controller = new AbortController();
75
+ const timeoutId = setTimeout(()=>controller.abort(), timeout);
76
+ const response = await fetch(`https://registry.npmjs.org/${packageName}`, {
77
+ signal: controller.signal
78
+ });
79
+ clearTimeout(timeoutId);
80
+ if (!response.ok) return null;
81
+ const data = await response.json();
82
+ const latest = data['dist-tags']?.latest;
83
+ if (!latest) return null;
84
+ const hasUpdate = __WEBPACK_EXTERNAL_MODULE_semver__["default"].gt(latest, currentVersion);
85
+ return {
86
+ current: currentVersion,
87
+ latest,
88
+ hasUpdate
89
+ };
90
+ } catch {
91
+ return null;
92
+ }
93
+ }
94
+ function formatUpdateMessage(result) {
95
+ if (!result.hasUpdate) return '';
96
+ return `
97
+ ┌────────────────────────────────────────────────────┐
98
+ │ │
99
+ │ Update available: ${result.current} → ${result.latest.padEnd(10)} │
100
+ │ Run: npm install -g reskill@latest │
101
+ │ │
102
+ └────────────────────────────────────────────────────┘
103
+ `;
104
+ }
156
105
  const agent_registry_home = (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)();
157
106
  const agents = {
158
107
  amp: {
@@ -286,7 +235,94 @@ function getAgentConfig(type) {
286
235
  function isValidAgentType(type) {
287
236
  return type in agents;
288
237
  }
289
- const execAsync = (0, __WEBPACK_EXTERNAL_MODULE_node_util__.promisify)(__WEBPACK_EXTERNAL_MODULE_node_child_process__.exec);
238
+ function exists(filePath) {
239
+ return external_node_fs_.existsSync(filePath);
240
+ }
241
+ function readJson(filePath) {
242
+ const content = external_node_fs_.readFileSync(filePath, 'utf-8');
243
+ return JSON.parse(content);
244
+ }
245
+ function writeJson(filePath, data, indent = 2) {
246
+ const dir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(filePath);
247
+ if (!exists(dir)) external_node_fs_.mkdirSync(dir, {
248
+ recursive: true
249
+ });
250
+ external_node_fs_.writeFileSync(filePath, `${JSON.stringify(data, null, indent)}\n`, 'utf-8');
251
+ }
252
+ function ensureDir(dirPath) {
253
+ if (!exists(dirPath)) external_node_fs_.mkdirSync(dirPath, {
254
+ recursive: true
255
+ });
256
+ }
257
+ function remove(targetPath) {
258
+ if (exists(targetPath)) external_node_fs_.rmSync(targetPath, {
259
+ recursive: true,
260
+ force: true
261
+ });
262
+ }
263
+ function copyDir(src, dest, options) {
264
+ const exclude = options?.exclude || [];
265
+ const excludePrefix = options?.excludePrefix || '_';
266
+ ensureDir(dest);
267
+ const entries = external_node_fs_.readdirSync(src, {
268
+ withFileTypes: true
269
+ });
270
+ for (const entry of entries){
271
+ if (exclude.includes(entry.name) || entry.name.startsWith(excludePrefix)) continue;
272
+ const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
273
+ const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
274
+ if (entry.isDirectory()) copyDir(srcPath, destPath, options);
275
+ else external_node_fs_.copyFileSync(srcPath, destPath);
276
+ }
277
+ }
278
+ function listDir(dirPath) {
279
+ if (!exists(dirPath)) return [];
280
+ return external_node_fs_.readdirSync(dirPath);
281
+ }
282
+ function isDirectory(targetPath) {
283
+ if (!exists(targetPath)) return false;
284
+ return external_node_fs_.statSync(targetPath).isDirectory();
285
+ }
286
+ function isSymlink(targetPath) {
287
+ if (!exists(targetPath)) return false;
288
+ return external_node_fs_.lstatSync(targetPath).isSymbolicLink();
289
+ }
290
+ function createSymlink(target, linkPath) {
291
+ const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
292
+ ensureDir(linkDir);
293
+ if (exists(linkPath)) remove(linkPath);
294
+ external_node_fs_.symlinkSync(target, linkPath, 'dir');
295
+ }
296
+ function getRealPath(linkPath) {
297
+ return external_node_fs_.realpathSync(linkPath);
298
+ }
299
+ function getSkillsJsonPath(projectRoot) {
300
+ const root = projectRoot || process.cwd();
301
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(root, 'skills.json');
302
+ }
303
+ function getSkillsLockPath(projectRoot) {
304
+ const root = projectRoot || process.cwd();
305
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(root, 'skills.lock');
306
+ }
307
+ function getCacheDir() {
308
+ const home = process.env.HOME || process.env.USERPROFILE || '';
309
+ return process.env.RESKILL_CACHE_DIR || __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.reskill-cache');
310
+ }
311
+ function getHomeDir() {
312
+ return process.env.HOME || process.env.USERPROFILE || '';
313
+ }
314
+ function getGlobalSkillsDir() {
315
+ const home = getHomeDir();
316
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.claude', 'skills');
317
+ }
318
+ function shortenPath(fullPath, cwd) {
319
+ const home = getHomeDir();
320
+ const currentDir = cwd || process.cwd();
321
+ if (fullPath.startsWith(home)) return fullPath.replace(home, '~');
322
+ if (fullPath.startsWith(currentDir)) return `.${fullPath.slice(currentDir.length)}`;
323
+ return fullPath;
324
+ }
325
+ const git_execAsync = (0, __WEBPACK_EXTERNAL_MODULE_node_util__.promisify)(__WEBPACK_EXTERNAL_MODULE_node_child_process__.exec);
290
326
  class GitCloneError extends Error {
291
327
  repoUrl;
292
328
  originalError;
@@ -334,7 +370,7 @@ class GitCloneError extends Error {
334
370
  }
335
371
  }
336
372
  async function git(args, cwd) {
337
- const { stdout } = await execAsync(`git ${args.join(' ')}`, {
373
+ const { stdout } = await git_execAsync(`git ${args.join(' ')}`, {
338
374
  cwd,
339
375
  encoding: 'utf-8'
340
376
  });
@@ -468,40 +504,236 @@ function parseGitUrl(url) {
468
504
  }
469
505
  return null;
470
506
  }
471
- class CacheManager {
472
- cacheDir;
473
- constructor(cacheDir){
474
- this.cacheDir = cacheDir || getCacheDir();
475
- }
476
- getCacheDir() {
477
- return this.cacheDir;
478
- }
479
- getSkillCachePath(parsed, version) {
480
- return __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, parsed.registry, parsed.owner, parsed.repo, version);
481
- }
482
- getCachePath(parsed, version) {
483
- return this.getSkillCachePath(parsed, version);
484
- }
485
- isCached(parsed, version) {
486
- const cachePath = this.getSkillCachePath(parsed, version);
487
- return exists(cachePath) && isDirectory(cachePath);
507
+ const installer_AGENTS_DIR = '.agents';
508
+ const installer_SKILLS_SUBDIR = 'skills';
509
+ const DEFAULT_EXCLUDE_FILES = [
510
+ 'README.md',
511
+ 'metadata.json',
512
+ '.reskill-commit'
513
+ ];
514
+ const EXCLUDE_PREFIX = '_';
515
+ function installer_sanitizeName(name) {
516
+ let sanitized = name.replace(/[/\\:\0]/g, '');
517
+ sanitized = sanitized.replace(/^[.\s]+|[.\s]+$/g, '');
518
+ sanitized = sanitized.replace(/^\.+/, '');
519
+ if (!sanitized || 0 === sanitized.length) sanitized = 'unnamed-skill';
520
+ if (sanitized.length > 255) sanitized = sanitized.substring(0, 255);
521
+ return sanitized;
522
+ }
523
+ function installer_isPathSafe(basePath, targetPath) {
524
+ const normalizedBase = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(basePath));
525
+ const normalizedTarget = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(targetPath));
526
+ return normalizedTarget.startsWith(normalizedBase + __WEBPACK_EXTERNAL_MODULE_node_path__.sep) || normalizedTarget === normalizedBase;
527
+ }
528
+ function installer_getCanonicalSkillsDir(isGlobal, cwd) {
529
+ const baseDir = isGlobal ? (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)() : cwd || process.cwd();
530
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, installer_AGENTS_DIR, installer_SKILLS_SUBDIR);
531
+ }
532
+ function installer_ensureDir(dirPath) {
533
+ if (!external_node_fs_.existsSync(dirPath)) external_node_fs_.mkdirSync(dirPath, {
534
+ recursive: true
535
+ });
536
+ }
537
+ function installer_remove(targetPath) {
538
+ if (external_node_fs_.existsSync(targetPath)) external_node_fs_.rmSync(targetPath, {
539
+ recursive: true,
540
+ force: true
541
+ });
542
+ }
543
+ function copyDirectory(src, dest, options) {
544
+ const exclude = new Set(options?.exclude || DEFAULT_EXCLUDE_FILES);
545
+ installer_ensureDir(dest);
546
+ const entries = external_node_fs_.readdirSync(src, {
547
+ withFileTypes: true
548
+ });
549
+ for (const entry of entries){
550
+ if (exclude.has(entry.name) || entry.name.startsWith(EXCLUDE_PREFIX)) continue;
551
+ const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
552
+ const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
553
+ if (entry.isDirectory()) copyDirectory(srcPath, destPath, options);
554
+ else external_node_fs_.copyFileSync(srcPath, destPath);
488
555
  }
489
- async get(parsed, version) {
490
- const cachePath = this.getSkillCachePath(parsed, version);
491
- if (!this.isCached(parsed, version)) return null;
492
- const commitFile = __WEBPACK_EXTERNAL_MODULE_node_path__.join(cachePath, '.reskill-commit');
493
- let commit = '';
556
+ }
557
+ async function installer_createSymlink(target, linkPath) {
558
+ try {
494
559
  try {
495
- const fs = await import("node:fs");
496
- if (exists(commitFile)) commit = fs.readFileSync(commitFile, 'utf-8').trim();
497
- } catch {}
498
- return {
499
- path: cachePath,
500
- commit
501
- };
502
- }
503
- async cache(repoUrl, parsed, ref, version) {
504
- const cachePath = this.getSkillCachePath(parsed, version);
560
+ const stats = external_node_fs_.lstatSync(linkPath);
561
+ if (stats.isSymbolicLink()) {
562
+ const existingTarget = external_node_fs_.readlinkSync(linkPath);
563
+ if (__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(existingTarget) === __WEBPACK_EXTERNAL_MODULE_node_path__.resolve(target)) return true;
564
+ external_node_fs_.rmSync(linkPath);
565
+ } else external_node_fs_.rmSync(linkPath, {
566
+ recursive: true
567
+ });
568
+ } catch (err) {
569
+ if (err && 'object' == typeof err && 'code' in err) {
570
+ if ('ELOOP' === err.code) try {
571
+ external_node_fs_.rmSync(linkPath, {
572
+ force: true
573
+ });
574
+ } catch {}
575
+ }
576
+ }
577
+ const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
578
+ installer_ensureDir(linkDir);
579
+ const relativePath = __WEBPACK_EXTERNAL_MODULE_node_path__.relative(linkDir, target);
580
+ const symlinkType = 'win32' === (0, __WEBPACK_EXTERNAL_MODULE_node_os__.platform)() ? 'junction' : void 0;
581
+ external_node_fs_.symlinkSync(relativePath, linkPath, symlinkType);
582
+ return true;
583
+ } catch {
584
+ return false;
585
+ }
586
+ }
587
+ class Installer {
588
+ cwd;
589
+ isGlobal;
590
+ constructor(options = {}){
591
+ this.cwd = options.cwd || process.cwd();
592
+ this.isGlobal = options.global || false;
593
+ }
594
+ getCanonicalPath(skillName) {
595
+ const sanitized = installer_sanitizeName(skillName);
596
+ const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
597
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
598
+ }
599
+ getAgentSkillPath(skillName, agentType) {
600
+ const agent = getAgentConfig(agentType);
601
+ const sanitized = installer_sanitizeName(skillName);
602
+ const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
603
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
604
+ }
605
+ async installForAgent(sourcePath, skillName, agentType, options = {}) {
606
+ const agent = getAgentConfig(agentType);
607
+ const installMode = options.mode || 'symlink';
608
+ const sanitized = installer_sanitizeName(skillName);
609
+ const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
610
+ const canonicalDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
611
+ const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
612
+ const agentDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
613
+ if (!installer_isPathSafe(canonicalBase, canonicalDir)) return {
614
+ success: false,
615
+ path: agentDir,
616
+ mode: installMode,
617
+ error: 'Invalid skill name: potential path traversal detected'
618
+ };
619
+ if (!installer_isPathSafe(agentBase, agentDir)) return {
620
+ success: false,
621
+ path: agentDir,
622
+ mode: installMode,
623
+ error: 'Invalid skill name: potential path traversal detected'
624
+ };
625
+ try {
626
+ if ('copy' === installMode) {
627
+ installer_ensureDir(agentDir);
628
+ installer_remove(agentDir);
629
+ copyDirectory(sourcePath, agentDir);
630
+ return {
631
+ success: true,
632
+ path: agentDir,
633
+ mode: 'copy'
634
+ };
635
+ }
636
+ installer_ensureDir(canonicalDir);
637
+ installer_remove(canonicalDir);
638
+ copyDirectory(sourcePath, canonicalDir);
639
+ const symlinkCreated = await installer_createSymlink(canonicalDir, agentDir);
640
+ if (!symlinkCreated) {
641
+ try {
642
+ installer_remove(agentDir);
643
+ } catch {}
644
+ installer_ensureDir(agentDir);
645
+ copyDirectory(sourcePath, agentDir);
646
+ return {
647
+ success: true,
648
+ path: agentDir,
649
+ canonicalPath: canonicalDir,
650
+ mode: 'symlink',
651
+ symlinkFailed: true
652
+ };
653
+ }
654
+ return {
655
+ success: true,
656
+ path: agentDir,
657
+ canonicalPath: canonicalDir,
658
+ mode: 'symlink'
659
+ };
660
+ } catch (error) {
661
+ return {
662
+ success: false,
663
+ path: agentDir,
664
+ mode: installMode,
665
+ error: error instanceof Error ? error.message : 'Unknown error'
666
+ };
667
+ }
668
+ }
669
+ async installToAgents(sourcePath, skillName, targetAgents, options = {}) {
670
+ const results = new Map();
671
+ for (const agent of targetAgents){
672
+ const result = await this.installForAgent(sourcePath, skillName, agent, options);
673
+ results.set(agent, result);
674
+ }
675
+ return results;
676
+ }
677
+ isInstalled(skillName, agentType) {
678
+ const skillPath = this.getAgentSkillPath(skillName, agentType);
679
+ return external_node_fs_.existsSync(skillPath);
680
+ }
681
+ uninstallFromAgent(skillName, agentType) {
682
+ const skillPath = this.getAgentSkillPath(skillName, agentType);
683
+ if (!external_node_fs_.existsSync(skillPath)) return false;
684
+ installer_remove(skillPath);
685
+ return true;
686
+ }
687
+ uninstallFromAgents(skillName, targetAgents) {
688
+ const results = new Map();
689
+ for (const agent of targetAgents)results.set(agent, this.uninstallFromAgent(skillName, agent));
690
+ const canonicalPath = this.getCanonicalPath(skillName);
691
+ if (external_node_fs_.existsSync(canonicalPath)) installer_remove(canonicalPath);
692
+ return results;
693
+ }
694
+ listInstalledSkills(agentType) {
695
+ const agent = getAgentConfig(agentType);
696
+ const skillsDir = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
697
+ if (!external_node_fs_.existsSync(skillsDir)) return [];
698
+ return external_node_fs_.readdirSync(skillsDir, {
699
+ withFileTypes: true
700
+ }).filter((entry)=>entry.isDirectory() || entry.isSymbolicLink()).map((entry)=>entry.name);
701
+ }
702
+ }
703
+ class CacheManager {
704
+ cacheDir;
705
+ constructor(cacheDir){
706
+ this.cacheDir = cacheDir || getCacheDir();
707
+ }
708
+ getCacheDir() {
709
+ return this.cacheDir;
710
+ }
711
+ getSkillCachePath(parsed, version) {
712
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, parsed.registry, parsed.owner, parsed.repo, version);
713
+ }
714
+ getCachePath(parsed, version) {
715
+ return this.getSkillCachePath(parsed, version);
716
+ }
717
+ isCached(parsed, version) {
718
+ const cachePath = this.getSkillCachePath(parsed, version);
719
+ return exists(cachePath) && isDirectory(cachePath);
720
+ }
721
+ async get(parsed, version) {
722
+ const cachePath = this.getSkillCachePath(parsed, version);
723
+ if (!this.isCached(parsed, version)) return null;
724
+ const commitFile = __WEBPACK_EXTERNAL_MODULE_node_path__.join(cachePath, '.reskill-commit');
725
+ let commit = '';
726
+ try {
727
+ const fs = await import("node:fs");
728
+ if (exists(commitFile)) commit = fs.readFileSync(commitFile, 'utf-8').trim();
729
+ } catch {}
730
+ return {
731
+ path: cachePath,
732
+ commit
733
+ };
734
+ }
735
+ async cache(repoUrl, parsed, ref, version) {
736
+ const cachePath = this.getSkillCachePath(parsed, version);
505
737
  if (exists(cachePath)) remove(cachePath);
506
738
  ensureDir(__WEBPACK_EXTERNAL_MODULE_node_path__.dirname(cachePath));
507
739
  const tempPath = `${cachePath}.tmp`;
@@ -540,9 +772,7 @@ class CacheManager {
540
772
  if (!cached) throw new Error(`Skill ${parsed.raw} version ${version} not found in cache`);
541
773
  if (exists(destPath)) remove(destPath);
542
774
  copyDir(cached.path, destPath, {
543
- exclude: [
544
- '.reskill-commit'
545
- ]
775
+ exclude: DEFAULT_EXCLUDE_FILES
546
776
  });
547
777
  }
548
778
  clearSkill(parsed, version) {
@@ -578,6 +808,31 @@ class CacheManager {
578
808
  registries
579
809
  };
580
810
  }
811
+ async getRemoteCommit(repoUrl, ref) {
812
+ const { exec } = await import("node:child_process");
813
+ const { promisify } = await import("node:util");
814
+ const execAsync = promisify(exec);
815
+ try {
816
+ const { stdout } = await execAsync(`git ls-remote ${repoUrl} ${ref}`, {
817
+ encoding: 'utf-8'
818
+ });
819
+ if (stdout.trim()) {
820
+ const [commit] = stdout.trim().split('\t');
821
+ return commit;
822
+ }
823
+ const { stdout: allRefs } = await execAsync(`git ls-remote ${repoUrl}`, {
824
+ encoding: 'utf-8'
825
+ });
826
+ const lines = allRefs.trim().split('\n');
827
+ for (const line of lines){
828
+ const [commit, refPath] = line.split('\t');
829
+ if (refPath === `refs/heads/${ref}` || refPath === `refs/tags/${ref}` || refPath === ref) return commit;
830
+ }
831
+ return '';
832
+ } catch {
833
+ return '';
834
+ }
835
+ }
581
836
  }
582
837
  const DEFAULT_SKILLS_JSON = {
583
838
  skills: {},
@@ -795,287 +1050,93 @@ class GitResolver {
795
1050
  value: 'latest',
796
1051
  raw
797
1052
  };
798
- if (versionSpec.startsWith('branch:')) return {
799
- type: 'branch',
800
- value: versionSpec.slice(7),
801
- raw
802
- };
803
- if (versionSpec.startsWith('commit:')) return {
804
- type: 'commit',
805
- value: versionSpec.slice(7),
806
- raw
807
- };
808
- if (/^[\^~><]/.test(versionSpec)) return {
809
- type: 'range',
810
- value: versionSpec,
811
- raw
812
- };
813
- return {
814
- type: 'exact',
815
- value: versionSpec,
816
- raw
817
- };
818
- }
819
- buildRepoUrl(parsed) {
820
- if (parsed.gitUrl) return parsed.gitUrl;
821
- return buildRepoUrl(parsed.registry, `${parsed.owner}/${parsed.repo}`);
822
- }
823
- async resolveVersion(repoUrl, versionSpec) {
824
- switch(versionSpec.type){
825
- case 'exact':
826
- return {
827
- ref: versionSpec.value
828
- };
829
- case 'latest':
830
- {
831
- const latestTag = await getLatestTag(repoUrl);
832
- if (!latestTag) {
833
- const defaultBranch = await getDefaultBranch(repoUrl);
834
- return {
835
- ref: defaultBranch
836
- };
837
- }
838
- return {
839
- ref: latestTag.name,
840
- commit: latestTag.commit
841
- };
842
- }
843
- case 'range':
844
- {
845
- const tags = await getRemoteTags(repoUrl);
846
- const matchingTags = tags.filter((tag)=>{
847
- const version = tag.name.replace(/^v/, '');
848
- return __WEBPACK_EXTERNAL_MODULE_semver__.satisfies(version, versionSpec.value);
849
- });
850
- if (0 === matchingTags.length) throw new Error(`No version found matching ${versionSpec.raw} for ${repoUrl}`);
851
- matchingTags.sort((a, b)=>{
852
- const aVer = a.name.replace(/^v/, '');
853
- const bVer = b.name.replace(/^v/, '');
854
- return __WEBPACK_EXTERNAL_MODULE_semver__.compare(bVer, aVer);
855
- });
856
- return {
857
- ref: matchingTags[0].name,
858
- commit: matchingTags[0].commit
859
- };
860
- }
861
- case 'branch':
862
- return {
863
- ref: versionSpec.value
864
- };
865
- case 'commit':
866
- return {
867
- ref: versionSpec.value,
868
- commit: versionSpec.value
869
- };
870
- default:
871
- throw new Error(`Unknown version type: ${versionSpec.type}`);
872
- }
873
- }
874
- async resolve(ref) {
875
- const parsed = this.parseRef(ref);
876
- const repoUrl = this.buildRepoUrl(parsed);
877
- const versionSpec = this.parseVersion(parsed.version);
878
- const resolved = await this.resolveVersion(repoUrl, versionSpec);
879
- return {
880
- parsed,
881
- repoUrl,
882
- ref: resolved.ref,
883
- commit: resolved.commit
884
- };
885
- }
886
- }
887
- const installer_AGENTS_DIR = '.agents';
888
- const installer_SKILLS_SUBDIR = 'skills';
889
- function installer_sanitizeName(name) {
890
- let sanitized = name.replace(/[/\\:\0]/g, '');
891
- sanitized = sanitized.replace(/^[.\s]+|[.\s]+$/g, '');
892
- sanitized = sanitized.replace(/^\.+/, '');
893
- if (!sanitized || 0 === sanitized.length) sanitized = 'unnamed-skill';
894
- if (sanitized.length > 255) sanitized = sanitized.substring(0, 255);
895
- return sanitized;
896
- }
897
- function installer_isPathSafe(basePath, targetPath) {
898
- const normalizedBase = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(basePath));
899
- const normalizedTarget = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(targetPath));
900
- return normalizedTarget.startsWith(normalizedBase + __WEBPACK_EXTERNAL_MODULE_node_path__.sep) || normalizedTarget === normalizedBase;
901
- }
902
- function installer_getCanonicalSkillsDir(isGlobal, cwd) {
903
- const baseDir = isGlobal ? (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)() : cwd || process.cwd();
904
- return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, installer_AGENTS_DIR, installer_SKILLS_SUBDIR);
905
- }
906
- function installer_ensureDir(dirPath) {
907
- if (!external_node_fs_.existsSync(dirPath)) external_node_fs_.mkdirSync(dirPath, {
908
- recursive: true
909
- });
910
- }
911
- function installer_remove(targetPath) {
912
- if (external_node_fs_.existsSync(targetPath)) external_node_fs_.rmSync(targetPath, {
913
- recursive: true,
914
- force: true
915
- });
916
- }
917
- function copyDirectory(src, dest, options) {
918
- const exclude = new Set(options?.exclude || [
919
- 'README.md',
920
- 'metadata.json',
921
- '.reskill-commit'
922
- ]);
923
- installer_ensureDir(dest);
924
- const entries = external_node_fs_.readdirSync(src, {
925
- withFileTypes: true
926
- });
927
- for (const entry of entries){
928
- if (exclude.has(entry.name) || entry.name.startsWith('_')) continue;
929
- const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
930
- const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
931
- if (entry.isDirectory()) copyDirectory(srcPath, destPath, options);
932
- else external_node_fs_.copyFileSync(srcPath, destPath);
933
- }
934
- }
935
- async function installer_createSymlink(target, linkPath) {
936
- try {
937
- try {
938
- const stats = external_node_fs_.lstatSync(linkPath);
939
- if (stats.isSymbolicLink()) {
940
- const existingTarget = external_node_fs_.readlinkSync(linkPath);
941
- if (__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(existingTarget) === __WEBPACK_EXTERNAL_MODULE_node_path__.resolve(target)) return true;
942
- external_node_fs_.rmSync(linkPath);
943
- } else external_node_fs_.rmSync(linkPath, {
944
- recursive: true
945
- });
946
- } catch (err) {
947
- if (err && 'object' == typeof err && 'code' in err) {
948
- if ('ELOOP' === err.code) try {
949
- external_node_fs_.rmSync(linkPath, {
950
- force: true
951
- });
952
- } catch {}
953
- }
954
- }
955
- const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
956
- installer_ensureDir(linkDir);
957
- const relativePath = __WEBPACK_EXTERNAL_MODULE_node_path__.relative(linkDir, target);
958
- const symlinkType = 'win32' === (0, __WEBPACK_EXTERNAL_MODULE_node_os__.platform)() ? 'junction' : void 0;
959
- external_node_fs_.symlinkSync(relativePath, linkPath, symlinkType);
960
- return true;
961
- } catch {
962
- return false;
963
- }
964
- }
965
- class Installer {
966
- cwd;
967
- isGlobal;
968
- constructor(options = {}){
969
- this.cwd = options.cwd || process.cwd();
970
- this.isGlobal = options.global || false;
971
- }
972
- getCanonicalPath(skillName) {
973
- const sanitized = installer_sanitizeName(skillName);
974
- const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
975
- return __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
976
- }
977
- getAgentSkillPath(skillName, agentType) {
978
- const agent = getAgentConfig(agentType);
979
- const sanitized = installer_sanitizeName(skillName);
980
- const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
981
- return __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
982
- }
983
- async installForAgent(sourcePath, skillName, agentType, options = {}) {
984
- const agent = getAgentConfig(agentType);
985
- const installMode = options.mode || 'symlink';
986
- const sanitized = installer_sanitizeName(skillName);
987
- const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
988
- const canonicalDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
989
- const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
990
- const agentDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
991
- if (!installer_isPathSafe(canonicalBase, canonicalDir)) return {
992
- success: false,
993
- path: agentDir,
994
- mode: installMode,
995
- error: 'Invalid skill name: potential path traversal detected'
996
- };
997
- if (!installer_isPathSafe(agentBase, agentDir)) return {
998
- success: false,
999
- path: agentDir,
1000
- mode: installMode,
1001
- error: 'Invalid skill name: potential path traversal detected'
1053
+ if (versionSpec.startsWith('branch:')) return {
1054
+ type: 'branch',
1055
+ value: versionSpec.slice(7),
1056
+ raw
1002
1057
  };
1003
- try {
1004
- if ('copy' === installMode) {
1005
- installer_ensureDir(agentDir);
1006
- installer_remove(agentDir);
1007
- copyDirectory(sourcePath, agentDir);
1058
+ if (versionSpec.startsWith('commit:')) return {
1059
+ type: 'commit',
1060
+ value: versionSpec.slice(7),
1061
+ raw
1062
+ };
1063
+ if (/^[\^~><]/.test(versionSpec)) return {
1064
+ type: 'range',
1065
+ value: versionSpec,
1066
+ raw
1067
+ };
1068
+ return {
1069
+ type: 'exact',
1070
+ value: versionSpec,
1071
+ raw
1072
+ };
1073
+ }
1074
+ buildRepoUrl(parsed) {
1075
+ if (parsed.gitUrl) return parsed.gitUrl;
1076
+ return buildRepoUrl(parsed.registry, `${parsed.owner}/${parsed.repo}`);
1077
+ }
1078
+ async resolveVersion(repoUrl, versionSpec) {
1079
+ switch(versionSpec.type){
1080
+ case 'exact':
1008
1081
  return {
1009
- success: true,
1010
- path: agentDir,
1011
- mode: 'copy'
1082
+ ref: versionSpec.value
1012
1083
  };
1013
- }
1014
- installer_ensureDir(canonicalDir);
1015
- installer_remove(canonicalDir);
1016
- copyDirectory(sourcePath, canonicalDir);
1017
- const symlinkCreated = await installer_createSymlink(canonicalDir, agentDir);
1018
- if (!symlinkCreated) {
1019
- try {
1020
- installer_remove(agentDir);
1021
- } catch {}
1022
- installer_ensureDir(agentDir);
1023
- copyDirectory(sourcePath, agentDir);
1084
+ case 'latest':
1085
+ {
1086
+ const latestTag = await getLatestTag(repoUrl);
1087
+ if (!latestTag) {
1088
+ const defaultBranch = await getDefaultBranch(repoUrl);
1089
+ return {
1090
+ ref: defaultBranch
1091
+ };
1092
+ }
1093
+ return {
1094
+ ref: latestTag.name,
1095
+ commit: latestTag.commit
1096
+ };
1097
+ }
1098
+ case 'range':
1099
+ {
1100
+ const tags = await getRemoteTags(repoUrl);
1101
+ const matchingTags = tags.filter((tag)=>{
1102
+ const version = tag.name.replace(/^v/, '');
1103
+ return __WEBPACK_EXTERNAL_MODULE_semver__.satisfies(version, versionSpec.value);
1104
+ });
1105
+ if (0 === matchingTags.length) throw new Error(`No version found matching ${versionSpec.raw} for ${repoUrl}`);
1106
+ matchingTags.sort((a, b)=>{
1107
+ const aVer = a.name.replace(/^v/, '');
1108
+ const bVer = b.name.replace(/^v/, '');
1109
+ return __WEBPACK_EXTERNAL_MODULE_semver__.compare(bVer, aVer);
1110
+ });
1111
+ return {
1112
+ ref: matchingTags[0].name,
1113
+ commit: matchingTags[0].commit
1114
+ };
1115
+ }
1116
+ case 'branch':
1024
1117
  return {
1025
- success: true,
1026
- path: agentDir,
1027
- canonicalPath: canonicalDir,
1028
- mode: 'symlink',
1029
- symlinkFailed: true
1118
+ ref: versionSpec.value
1030
1119
  };
1031
- }
1032
- return {
1033
- success: true,
1034
- path: agentDir,
1035
- canonicalPath: canonicalDir,
1036
- mode: 'symlink'
1037
- };
1038
- } catch (error) {
1039
- return {
1040
- success: false,
1041
- path: agentDir,
1042
- mode: installMode,
1043
- error: error instanceof Error ? error.message : 'Unknown error'
1044
- };
1045
- }
1046
- }
1047
- async installToAgents(sourcePath, skillName, targetAgents, options = {}) {
1048
- const results = new Map();
1049
- for (const agent of targetAgents){
1050
- const result = await this.installForAgent(sourcePath, skillName, agent, options);
1051
- results.set(agent, result);
1120
+ case 'commit':
1121
+ return {
1122
+ ref: versionSpec.value,
1123
+ commit: versionSpec.value
1124
+ };
1125
+ default:
1126
+ throw new Error(`Unknown version type: ${versionSpec.type}`);
1052
1127
  }
1053
- return results;
1054
- }
1055
- isInstalled(skillName, agentType) {
1056
- const skillPath = this.getAgentSkillPath(skillName, agentType);
1057
- return external_node_fs_.existsSync(skillPath);
1058
- }
1059
- uninstallFromAgent(skillName, agentType) {
1060
- const skillPath = this.getAgentSkillPath(skillName, agentType);
1061
- if (!external_node_fs_.existsSync(skillPath)) return false;
1062
- installer_remove(skillPath);
1063
- return true;
1064
- }
1065
- uninstallFromAgents(skillName, targetAgents) {
1066
- const results = new Map();
1067
- for (const agent of targetAgents)results.set(agent, this.uninstallFromAgent(skillName, agent));
1068
- const canonicalPath = this.getCanonicalPath(skillName);
1069
- if (external_node_fs_.existsSync(canonicalPath)) installer_remove(canonicalPath);
1070
- return results;
1071
1128
  }
1072
- listInstalledSkills(agentType) {
1073
- const agent = getAgentConfig(agentType);
1074
- const skillsDir = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
1075
- if (!external_node_fs_.existsSync(skillsDir)) return [];
1076
- return external_node_fs_.readdirSync(skillsDir, {
1077
- withFileTypes: true
1078
- }).filter((entry)=>entry.isDirectory() || entry.isSymbolicLink()).map((entry)=>entry.name);
1129
+ async resolve(ref) {
1130
+ const parsed = this.parseRef(ref);
1131
+ const repoUrl = this.buildRepoUrl(parsed);
1132
+ const versionSpec = this.parseVersion(parsed.version);
1133
+ const resolved = await this.resolveVersion(repoUrl, versionSpec);
1134
+ return {
1135
+ parsed,
1136
+ repoUrl,
1137
+ ref: resolved.ref,
1138
+ commit: resolved.commit
1139
+ };
1079
1140
  }
1080
1141
  }
1081
1142
  const LOCKFILE_VERSION = 1;
@@ -1141,6 +1202,7 @@ class LockManager {
1141
1202
  const lockedSkill = {
1142
1203
  source: options.source,
1143
1204
  version: options.version,
1205
+ ref: options.ref,
1144
1206
  resolved: options.resolved,
1145
1207
  commit: options.commit,
1146
1208
  installedAt: new Date().toISOString()
@@ -1220,35 +1282,43 @@ class SkillManager {
1220
1282
  const { force = false, save = true } = options;
1221
1283
  const resolved = await this.resolver.resolve(ref);
1222
1284
  const { parsed, repoUrl } = resolved;
1223
- const version = resolved.ref;
1285
+ const gitRef = resolved.ref;
1224
1286
  const skillName = parsed.subPath ? __WEBPACK_EXTERNAL_MODULE_node_path__.basename(parsed.subPath) : parsed.repo;
1225
1287
  const skillPath = this.getSkillPath(skillName);
1226
1288
  if (exists(skillPath) && !force) {
1227
1289
  const locked = this.lockManager.get(skillName);
1228
- if (locked && locked.version === version) {
1229
- logger.info(`${skillName}@${version} is already installed`);
1290
+ const lockedRef = locked?.ref || locked?.version;
1291
+ if (locked && lockedRef === gitRef) {
1292
+ logger_logger.info(`${skillName}@${gitRef} is already installed`);
1230
1293
  const installed = this.getInstalledSkill(skillName);
1231
1294
  if (installed) return installed;
1232
1295
  }
1233
1296
  if (!force) {
1234
- logger.warn(`${skillName} is already installed. Use --force to reinstall.`);
1297
+ logger_logger.warn(`${skillName} is already installed. Use --force to reinstall.`);
1235
1298
  const installed = this.getInstalledSkill(skillName);
1236
1299
  if (installed) return installed;
1237
1300
  }
1238
1301
  }
1239
- logger["package"](`Installing ${skillName}@${version}...`);
1240
- let cacheResult = await this.cache.get(parsed, version);
1241
- if (cacheResult) logger.debug(`Using cached ${skillName}@${version}`);
1302
+ logger_logger["package"](`Installing ${skillName}@${gitRef}...`);
1303
+ let cacheResult = await this.cache.get(parsed, gitRef);
1304
+ if (cacheResult) logger_logger.debug(`Using cached ${skillName}@${gitRef}`);
1242
1305
  else {
1243
- logger.debug(`Caching ${skillName}@${version} from ${repoUrl}`);
1244
- cacheResult = await this.cache.cache(repoUrl, parsed, version, version);
1306
+ logger_logger.debug(`Caching ${skillName}@${gitRef} from ${repoUrl}`);
1307
+ cacheResult = await this.cache.cache(repoUrl, parsed, gitRef, gitRef);
1245
1308
  }
1246
1309
  ensureDir(this.getInstallDir());
1247
1310
  if (exists(skillPath)) remove(skillPath);
1248
- await this.cache.copyTo(parsed, version, skillPath);
1311
+ await this.cache.copyTo(parsed, gitRef, skillPath);
1312
+ let semanticVersion = gitRef;
1313
+ const skillJsonPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(skillPath, 'skill.json');
1314
+ if (exists(skillJsonPath)) try {
1315
+ const skillJson = readJson(skillJsonPath);
1316
+ if (skillJson.version) semanticVersion = skillJson.version;
1317
+ } catch {}
1249
1318
  if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
1250
1319
  source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
1251
- version,
1320
+ version: semanticVersion,
1321
+ ref: gitRef,
1252
1322
  resolved: repoUrl,
1253
1323
  commit: cacheResult.commit
1254
1324
  });
@@ -1256,8 +1326,9 @@ class SkillManager {
1256
1326
  this.config.ensureExists();
1257
1327
  this.config.addSkill(skillName, ref);
1258
1328
  }
1329
+ const displayVersion = semanticVersion !== gitRef ? `${semanticVersion} (${gitRef})` : gitRef;
1259
1330
  const locationHint = this.isGlobal ? '(global)' : '';
1260
- logger.success(`Installed ${skillName}@${version} to ${skillPath} ${locationHint}`.trim());
1331
+ logger_logger.success(`Installed ${skillName}@${displayVersion} to ${skillPath} ${locationHint}`.trim());
1261
1332
  const installed = this.getInstalledSkill(skillName);
1262
1333
  if (!installed) throw new Error(`Failed to get installed skill info for ${skillName}`);
1263
1334
  return installed;
@@ -1272,7 +1343,7 @@ class SkillManager {
1272
1343
  });
1273
1344
  installed.push(skill);
1274
1345
  } catch (error) {
1275
- logger.error(`Failed to install ${name}: ${error.message}`);
1346
+ logger_logger.error(`Failed to install ${name}: ${error.message}`);
1276
1347
  }
1277
1348
  return installed;
1278
1349
  }
@@ -1280,22 +1351,33 @@ class SkillManager {
1280
1351
  const skillPath = this.getSkillPath(name);
1281
1352
  if (!exists(skillPath)) {
1282
1353
  const location = this.isGlobal ? '(global)' : '';
1283
- logger.warn(`Skill ${name} is not installed ${location}`.trim());
1354
+ logger_logger.warn(`Skill ${name} is not installed ${location}`.trim());
1284
1355
  return false;
1285
1356
  }
1286
1357
  remove(skillPath);
1287
1358
  if (!this.isGlobal) this.lockManager.remove(name);
1288
1359
  if (!this.isGlobal && this.config.exists()) this.config.removeSkill(name);
1289
1360
  const locationHint = this.isGlobal ? '(global)' : '';
1290
- logger.success(`Uninstalled ${name} ${locationHint}`.trim());
1361
+ logger_logger.success(`Uninstalled ${name} ${locationHint}`.trim());
1291
1362
  return true;
1292
1363
  }
1364
+ checkNeedsUpdate(name, remoteCommit) {
1365
+ const locked = this.lockManager.get(name);
1366
+ if (!locked?.commit) return true;
1367
+ return locked.commit !== remoteCommit;
1368
+ }
1293
1369
  async update(name) {
1294
1370
  const updated = [];
1295
1371
  if (name) {
1296
1372
  const ref = this.config.getSkillRef(name);
1297
1373
  if (!ref) {
1298
- logger.error(`Skill ${name} not found in skills.json`);
1374
+ logger_logger.error(`Skill ${name} not found in skills.json`);
1375
+ return [];
1376
+ }
1377
+ const resolved = await this.resolver.resolve(ref);
1378
+ const remoteCommit = await this.cache.getRemoteCommit(resolved.repoUrl, resolved.ref);
1379
+ if (!this.checkNeedsUpdate(name, remoteCommit)) {
1380
+ logger_logger.info(`${name} is already up to date`);
1299
1381
  return [];
1300
1382
  }
1301
1383
  const skill = await this.install(ref, {
@@ -1306,13 +1388,19 @@ class SkillManager {
1306
1388
  } else {
1307
1389
  const skills = this.config.getSkills();
1308
1390
  for (const [skillName, ref] of Object.entries(skills))try {
1391
+ const resolved = await this.resolver.resolve(ref);
1392
+ const remoteCommit = await this.cache.getRemoteCommit(resolved.repoUrl, resolved.ref);
1393
+ if (!this.checkNeedsUpdate(skillName, remoteCommit)) {
1394
+ logger_logger.info(`${skillName} is already up to date`);
1395
+ continue;
1396
+ }
1309
1397
  const skill = await this.install(ref, {
1310
1398
  force: true,
1311
1399
  save: false
1312
1400
  });
1313
1401
  updated.push(skill);
1314
1402
  } catch (error) {
1315
- logger.error(`Failed to update ${skillName}: ${error.message}`);
1403
+ logger_logger.error(`Failed to update ${skillName}: ${error.message}`);
1316
1404
  }
1317
1405
  }
1318
1406
  return updated;
@@ -1329,7 +1417,7 @@ class SkillManager {
1329
1417
  const linkPath = this.getSkillPath(skillName);
1330
1418
  ensureDir(__WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath));
1331
1419
  createSymlink(absolutePath, linkPath);
1332
- logger.success(`Linked ${skillName} → ${absolutePath}`);
1420
+ logger_logger.success(`Linked ${skillName} → ${absolutePath}`);
1333
1421
  return {
1334
1422
  name: skillName,
1335
1423
  path: linkPath,
@@ -1341,15 +1429,15 @@ class SkillManager {
1341
1429
  unlink(name) {
1342
1430
  const skillPath = this.getSkillPath(name);
1343
1431
  if (!exists(skillPath)) {
1344
- logger.warn(`Skill ${name} is not installed`);
1432
+ logger_logger.warn(`Skill ${name} is not installed`);
1345
1433
  return false;
1346
1434
  }
1347
1435
  if (!isSymlink(skillPath)) {
1348
- logger.warn(`Skill ${name} is not a linked skill`);
1436
+ logger_logger.warn(`Skill ${name} is not a linked skill`);
1349
1437
  return false;
1350
1438
  }
1351
1439
  remove(skillPath);
1352
- logger.success(`Unlinked ${name}`);
1440
+ logger_logger.success(`Unlinked ${name}`);
1353
1441
  return true;
1354
1442
  }
1355
1443
  list() {
@@ -1419,7 +1507,8 @@ class SkillManager {
1419
1507
  const skills = this.config.getSkills();
1420
1508
  for (const [name, ref] of Object.entries(skills))try {
1421
1509
  const locked = this.lockManager.get(name);
1422
- const current = locked?.version || 'unknown';
1510
+ const currentRef = locked?.ref || locked?.version || 'unknown';
1511
+ const currentVersion = locked?.version || 'unknown';
1423
1512
  const parsed = this.resolver.parseRef(ref);
1424
1513
  const repoUrl = this.resolver.buildRepoUrl(parsed);
1425
1514
  const latestResolved = await this.resolver.resolveVersion(repoUrl, {
@@ -1428,15 +1517,15 @@ class SkillManager {
1428
1517
  raw: 'latest'
1429
1518
  });
1430
1519
  const latest = latestResolved.ref;
1431
- const updateAvailable = current !== latest && 'unknown' !== current;
1520
+ const updateAvailable = currentRef !== latest && 'unknown' !== currentRef;
1432
1521
  results.push({
1433
1522
  name,
1434
- current,
1523
+ current: currentVersion !== currentRef ? `${currentVersion} (${currentRef})` : currentRef,
1435
1524
  latest,
1436
1525
  updateAvailable
1437
1526
  });
1438
1527
  } catch (error) {
1439
- logger.debug(`Failed to check ${name}: ${error.message}`);
1528
+ logger_logger.debug(`Failed to check ${name}: ${error.message}`);
1440
1529
  results.push({
1441
1530
  name,
1442
1531
  current: 'unknown',
@@ -1450,16 +1539,22 @@ class SkillManager {
1450
1539
  const { save = true, mode = 'symlink' } = options;
1451
1540
  const resolved = await this.resolver.resolve(ref);
1452
1541
  const { parsed, repoUrl } = resolved;
1453
- const version = resolved.ref;
1542
+ const gitRef = resolved.ref;
1454
1543
  const skillName = parsed.subPath ? __WEBPACK_EXTERNAL_MODULE_node_path__.basename(parsed.subPath) : parsed.repo;
1455
- logger["package"](`Installing ${skillName}@${version} to ${targetAgents.length} agent(s)...`);
1456
- let cacheResult = await this.cache.get(parsed, version);
1457
- if (cacheResult) logger.debug(`Using cached ${skillName}@${version}`);
1544
+ logger_logger["package"](`Installing ${skillName}@${gitRef} to ${targetAgents.length} agent(s)...`);
1545
+ let cacheResult = await this.cache.get(parsed, gitRef);
1546
+ if (cacheResult) logger_logger.debug(`Using cached ${skillName}@${gitRef}`);
1458
1547
  else {
1459
- logger.debug(`Caching ${skillName}@${version} from ${repoUrl}`);
1460
- cacheResult = await this.cache.cache(repoUrl, parsed, version, version);
1548
+ logger_logger.debug(`Caching ${skillName}@${gitRef} from ${repoUrl}`);
1549
+ cacheResult = await this.cache.cache(repoUrl, parsed, gitRef, gitRef);
1461
1550
  }
1462
- const sourcePath = this.cache.getCachePath(parsed, version);
1551
+ const sourcePath = this.cache.getCachePath(parsed, gitRef);
1552
+ let semanticVersion = gitRef;
1553
+ const skillJsonPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(sourcePath, 'skill.json');
1554
+ if (exists(skillJsonPath)) try {
1555
+ const skillJson = readJson(skillJsonPath);
1556
+ if (skillJson.version) semanticVersion = skillJson.version;
1557
+ } catch {}
1463
1558
  const installer = new Installer({
1464
1559
  cwd: this.projectRoot,
1465
1560
  global: this.isGlobal
@@ -1469,7 +1564,8 @@ class SkillManager {
1469
1564
  });
1470
1565
  if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
1471
1566
  source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
1472
- version,
1567
+ version: semanticVersion,
1568
+ ref: gitRef,
1473
1569
  resolved: repoUrl,
1474
1570
  commit: cacheResult.commit
1475
1571
  });
@@ -1479,12 +1575,13 @@ class SkillManager {
1479
1575
  }
1480
1576
  const successCount = Array.from(results.values()).filter((r)=>r.success).length;
1481
1577
  const failCount = results.size - successCount;
1482
- if (0 === failCount) logger.success(`Installed ${skillName}@${version} to ${successCount} agent(s)`);
1483
- else logger.warn(`Installed ${skillName}@${version} to ${successCount} agent(s), ${failCount} failed`);
1578
+ const displayVersion = semanticVersion !== gitRef ? `${semanticVersion} (${gitRef})` : gitRef;
1579
+ if (0 === failCount) logger_logger.success(`Installed ${skillName}@${displayVersion} to ${successCount} agent(s)`);
1580
+ else logger_logger.warn(`Installed ${skillName}@${displayVersion} to ${successCount} agent(s), ${failCount} failed`);
1484
1581
  const skill = {
1485
1582
  name: skillName,
1486
1583
  path: sourcePath,
1487
- version,
1584
+ version: semanticVersion,
1488
1585
  source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`
1489
1586
  };
1490
1587
  return {
@@ -1524,10 +1621,233 @@ class SkillManager {
1524
1621
  if (!this.isGlobal) this.lockManager.remove(name);
1525
1622
  if (!this.isGlobal && this.config.exists()) this.config.removeSkill(name);
1526
1623
  const successCount = Array.from(results.values()).filter((r)=>r).length;
1527
- logger.success(`Uninstalled ${name} from ${successCount} agent(s)`);
1624
+ logger_logger.success(`Uninstalled ${name} from ${successCount} agent(s)`);
1528
1625
  return results;
1529
1626
  }
1530
1627
  }
1628
+ const SUBCOMMANDS = [
1629
+ {
1630
+ name: 'install',
1631
+ description: 'Install a skill or all skills from skills.json'
1632
+ },
1633
+ {
1634
+ name: 'uninstall',
1635
+ description: 'Uninstall a skill'
1636
+ },
1637
+ {
1638
+ name: 'update',
1639
+ description: 'Update installed skills'
1640
+ },
1641
+ {
1642
+ name: 'info',
1643
+ description: 'Show skill details'
1644
+ },
1645
+ {
1646
+ name: 'list',
1647
+ description: 'List installed skills'
1648
+ },
1649
+ {
1650
+ name: 'link',
1651
+ description: 'Link a local skill for development'
1652
+ },
1653
+ {
1654
+ name: 'unlink',
1655
+ description: 'Unlink a linked skill'
1656
+ },
1657
+ {
1658
+ name: 'init',
1659
+ description: 'Initialize skills.json'
1660
+ },
1661
+ {
1662
+ name: 'outdated',
1663
+ description: 'Check for outdated skills'
1664
+ },
1665
+ {
1666
+ name: 'completion',
1667
+ description: 'Setup shell completion'
1668
+ }
1669
+ ];
1670
+ const SKILL_COMPLETION_COMMANDS = [
1671
+ 'info',
1672
+ 'uninstall',
1673
+ 'update'
1674
+ ];
1675
+ const LINKED_SKILL_COMMANDS = [
1676
+ 'unlink'
1677
+ ];
1678
+ function getAgentNames() {
1679
+ return Object.keys(agents);
1680
+ }
1681
+ function getInstalledSkillNames() {
1682
+ try {
1683
+ const skillManager = new SkillManager();
1684
+ const skills = skillManager.list();
1685
+ return skills.map((s)=>s.name);
1686
+ } catch {
1687
+ return [];
1688
+ }
1689
+ }
1690
+ function getLinkedSkillNames() {
1691
+ try {
1692
+ const skillManager = new SkillManager();
1693
+ const skills = skillManager.list();
1694
+ return skills.filter((s)=>s.isLinked).map((s)=>s.name);
1695
+ } catch {
1696
+ return [];
1697
+ }
1698
+ }
1699
+ function handleCompletion() {
1700
+ const env = __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].parseEnv(process.env);
1701
+ if (!env.complete) return;
1702
+ const { prev, line } = env;
1703
+ const parts = line.trim().split(/\s+/);
1704
+ const command = parts[1];
1705
+ if (1 === parts.length || 2 === parts.length && !line.endsWith(' ')) {
1706
+ const completions = SUBCOMMANDS.map((c)=>({
1707
+ name: c.name,
1708
+ description: c.description
1709
+ }));
1710
+ __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log(completions);
1711
+ return;
1712
+ }
1713
+ if (SKILL_COMPLETION_COMMANDS.includes(command)) {
1714
+ if (parts.length > 2 && line.endsWith(' ')) {
1715
+ __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log([]);
1716
+ return;
1717
+ }
1718
+ if (parts.length > 3) {
1719
+ __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log([]);
1720
+ return;
1721
+ }
1722
+ const skills = getInstalledSkillNames();
1723
+ __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log(skills);
1724
+ return;
1725
+ }
1726
+ if (LINKED_SKILL_COMMANDS.includes(command)) {
1727
+ if (parts.length > 2 && line.endsWith(' ')) {
1728
+ __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log([]);
1729
+ return;
1730
+ }
1731
+ if (parts.length > 3) {
1732
+ __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log([]);
1733
+ return;
1734
+ }
1735
+ const skills = getLinkedSkillNames();
1736
+ __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log(skills);
1737
+ return;
1738
+ }
1739
+ if ('install' === command && ('-a' === prev || '--agent' === prev)) {
1740
+ const agentNames = getAgentNames();
1741
+ __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log(agentNames);
1742
+ return;
1743
+ }
1744
+ if ('install' === command) {
1745
+ const { last } = env;
1746
+ if (last.startsWith('-')) {
1747
+ const options = [
1748
+ {
1749
+ name: '-f',
1750
+ description: 'Force reinstall'
1751
+ },
1752
+ {
1753
+ name: '--force',
1754
+ description: 'Force reinstall'
1755
+ },
1756
+ {
1757
+ name: '-g',
1758
+ description: 'Install globally'
1759
+ },
1760
+ {
1761
+ name: '--global',
1762
+ description: 'Install globally'
1763
+ },
1764
+ {
1765
+ name: '-a',
1766
+ description: 'Specify target agents'
1767
+ },
1768
+ {
1769
+ name: '--agent',
1770
+ description: 'Specify target agents'
1771
+ },
1772
+ {
1773
+ name: '-y',
1774
+ description: 'Skip confirmation'
1775
+ },
1776
+ {
1777
+ name: '--yes',
1778
+ description: 'Skip confirmation'
1779
+ },
1780
+ {
1781
+ name: '--all',
1782
+ description: 'Install to all agents'
1783
+ }
1784
+ ];
1785
+ __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log(options);
1786
+ return;
1787
+ }
1788
+ __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log([]);
1789
+ return;
1790
+ }
1791
+ __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log([]);
1792
+ }
1793
+ const completionCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('completion').description('Setup shell completion for reskill').argument('[action]', 'Action: install, uninstall, or shell name (bash, zsh, fish)').action(async (action)=>{
1794
+ const env = __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].parseEnv(process.env);
1795
+ if (env.complete) {
1796
+ handleCompletion();
1797
+ return;
1798
+ }
1799
+ if (!action) {
1800
+ logger_logger.log('Shell completion for reskill');
1801
+ logger_logger.newline();
1802
+ logger_logger.log('Usage:');
1803
+ logger_logger.log(' reskill completion install Install completion (interactive)');
1804
+ logger_logger.log(' reskill completion uninstall Remove completion');
1805
+ logger_logger.newline();
1806
+ logger_logger.log('Supported shells: bash, zsh, fish');
1807
+ logger_logger.newline();
1808
+ logger_logger.log('After installation, restart your shell or run:');
1809
+ logger_logger.log(' source ~/.bashrc # for bash');
1810
+ logger_logger.log(' source ~/.zshrc # for zsh');
1811
+ return;
1812
+ }
1813
+ if ('install' === action) {
1814
+ try {
1815
+ await __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].install({
1816
+ name: 'reskill',
1817
+ completer: 'reskill'
1818
+ });
1819
+ logger_logger.success('Completion installed successfully!');
1820
+ logger_logger.log('Restart your shell or source your shell config file.');
1821
+ } catch (error) {
1822
+ logger_logger.error(`Failed to install completion: ${error.message}`);
1823
+ process.exit(1);
1824
+ }
1825
+ return;
1826
+ }
1827
+ if ('uninstall' === action) {
1828
+ try {
1829
+ await __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].uninstall({
1830
+ name: 'reskill'
1831
+ });
1832
+ logger_logger.success('Completion uninstalled successfully!');
1833
+ } catch (error) {
1834
+ logger_logger.error(`Failed to uninstall completion: ${error.message}`);
1835
+ process.exit(1);
1836
+ }
1837
+ return;
1838
+ }
1839
+ logger_logger.error(`Unknown action: ${action}`);
1840
+ logger_logger.log('Use "reskill completion install" or "reskill completion uninstall"');
1841
+ process.exit(1);
1842
+ });
1843
+ function maybeHandleCompletion() {
1844
+ const env = __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].parseEnv(process.env);
1845
+ if (env.complete) {
1846
+ handleCompletion();
1847
+ return true;
1848
+ }
1849
+ return false;
1850
+ }
1531
1851
  const infoCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('info').description('Show skill details').argument('<skill>', 'Skill name').option('-j, --json', 'Output as JSON').action((skillName, options)=>{
1532
1852
  const skillManager = new SkillManager();
1533
1853
  const info = skillManager.getInfo(skillName);
@@ -1536,41 +1856,41 @@ const infoCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('info').de
1536
1856
  return;
1537
1857
  }
1538
1858
  if (!info.installed && !info.config) {
1539
- logger.error(`Skill ${skillName} not found`);
1859
+ logger_logger.error(`Skill ${skillName} not found`);
1540
1860
  process.exit(1);
1541
1861
  }
1542
- logger.log(`Skill: ${skillName}`);
1543
- logger.newline();
1862
+ logger_logger.log(`Skill: ${skillName}`);
1863
+ logger_logger.newline();
1544
1864
  if (info.config) {
1545
- logger.log("Configuration (skills.json):");
1546
- logger.log(` Reference: ${info.config}`);
1865
+ logger_logger.log("Configuration (skills.json):");
1866
+ logger_logger.log(` Reference: ${info.config}`);
1547
1867
  }
1548
1868
  if (info.locked) {
1549
- logger.log("Locked Version (skills.lock):");
1550
- logger.log(` Version: ${info.locked.version}`);
1551
- logger.log(` Source: ${info.locked.source}`);
1552
- logger.log(` Commit: ${info.locked.commit}`);
1553
- logger.log(` Installed: ${info.locked.installedAt}`);
1869
+ logger_logger.log("Locked Version (skills.lock):");
1870
+ logger_logger.log(` Version: ${info.locked.version}`);
1871
+ logger_logger.log(` Source: ${info.locked.source}`);
1872
+ logger_logger.log(` Commit: ${info.locked.commit}`);
1873
+ logger_logger.log(` Installed: ${info.locked.installedAt}`);
1554
1874
  }
1555
1875
  if (info.installed) {
1556
- logger.log("Installed:");
1557
- logger.log(` Path: ${info.installed.path}`);
1558
- logger.log(` Version: ${info.installed.version}`);
1559
- logger.log(` Linked: ${info.installed.isLinked ? 'Yes' : 'No'}`);
1876
+ logger_logger.log("Installed:");
1877
+ logger_logger.log(` Path: ${info.installed.path}`);
1878
+ logger_logger.log(` Version: ${info.installed.version}`);
1879
+ logger_logger.log(` Linked: ${info.installed.isLinked ? 'Yes' : 'No'}`);
1560
1880
  if (info.installed.metadata) {
1561
1881
  const meta = info.installed.metadata;
1562
- logger.log("Metadata (skill.json):");
1563
- if (meta.description) logger.log(` Description: ${meta.description}`);
1564
- if (meta.author) logger.log(` Author: ${meta.author}`);
1565
- if (meta.license) logger.log(` License: ${meta.license}`);
1566
- if (meta.keywords?.length) logger.log(` Keywords: ${meta.keywords.join(', ')}`);
1882
+ logger_logger.log("Metadata (skill.json):");
1883
+ if (meta.description) logger_logger.log(` Description: ${meta.description}`);
1884
+ if (meta.author) logger_logger.log(` Author: ${meta.author}`);
1885
+ if (meta.license) logger_logger.log(` License: ${meta.license}`);
1886
+ if (meta.keywords?.length) logger_logger.log(` Keywords: ${meta.keywords.join(', ')}`);
1567
1887
  }
1568
- } else logger.warn(`Skill ${skillName} is not installed`);
1888
+ } else logger_logger.warn(`Skill ${skillName} is not installed`);
1569
1889
  });
1570
1890
  const initCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('init').description('Initialize a new skills.json configuration').option('-n, --name <name>', 'Project name').option('-r, --registry <registry>', 'Default registry', 'github').option('-d, --install-dir <dir>', 'Skills installation directory', '.skills').option('-y, --yes', 'Skip prompts and use defaults').action(async (options)=>{
1571
1891
  const configLoader = new ConfigLoader();
1572
1892
  if (configLoader.exists()) {
1573
- logger.warn('skills.json already exists');
1893
+ logger_logger.warn('skills.json already exists');
1574
1894
  return;
1575
1895
  }
1576
1896
  const config = configLoader.create({
@@ -1580,16 +1900,16 @@ const initCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('init').de
1580
1900
  installDir: options.installDir
1581
1901
  }
1582
1902
  });
1583
- logger.success('Created skills.json');
1584
- logger.newline();
1585
- logger.log('Configuration:');
1586
- logger.log(` Name: ${config.name || '(not set)'}`);
1587
- logger.log(` Default registry: ${config.defaults?.registry}`);
1588
- logger.log(` Install directory: ${config.defaults?.installDir}`);
1589
- logger.newline();
1590
- logger.log('Next steps:');
1591
- logger.log(' reskill install <skill> Install a skill');
1592
- logger.log(' reskill list List installed skills');
1903
+ logger_logger.success('Created skills.json');
1904
+ logger_logger.newline();
1905
+ logger_logger.log('Configuration:');
1906
+ logger_logger.log(` Name: ${config.name || '(not set)'}`);
1907
+ logger_logger.log(` Default registry: ${config.defaults?.registry}`);
1908
+ logger_logger.log(` Install directory: ${config.defaults?.installDir}`);
1909
+ logger_logger.newline();
1910
+ logger_logger.log('Next steps:');
1911
+ logger_logger.log(' reskill install <skill> Install a skill');
1912
+ logger_logger.log(' reskill list List installed skills');
1593
1913
  });
1594
1914
  function formatAgentNames(agentTypes, maxShow = 5) {
1595
1915
  const names = agentTypes.map((a)=>agents[a].displayName);
@@ -1842,9 +2162,9 @@ const linkCmd = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('link').descri
1842
2162
  const skillManager = new SkillManager();
1843
2163
  try {
1844
2164
  const linked = skillManager.link(localPath, options.name);
1845
- logger.log(`Linked skill available at: ${linked.path}`);
2165
+ logger_logger.log(`Linked skill available at: ${linked.path}`);
1846
2166
  } catch (error) {
1847
- logger.error(error.message);
2167
+ logger_logger.error(error.message);
1848
2168
  process.exit(1);
1849
2169
  }
1850
2170
  });
@@ -1863,7 +2183,7 @@ const listCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('list').al
1863
2183
  const skills = skillManager.list();
1864
2184
  if (0 === skills.length) {
1865
2185
  const location = isGlobal ? 'globally' : 'in this project';
1866
- logger.info(`No skills installed ${location}`);
2186
+ logger_logger.info(`No skills installed ${location}`);
1867
2187
  return;
1868
2188
  }
1869
2189
  if (options.json) {
@@ -1871,8 +2191,8 @@ const listCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('list').al
1871
2191
  return;
1872
2192
  }
1873
2193
  const locationLabel = isGlobal ? __WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(' (global)') : '';
1874
- logger.log(`Installed Skills (${skillManager.getInstallDir()})${locationLabel}:`);
1875
- logger.newline();
2194
+ logger_logger.log(`Installed Skills (${skillManager.getInstallDir()})${locationLabel}:`);
2195
+ logger_logger.newline();
1876
2196
  const headers = [
1877
2197
  'Name',
1878
2198
  'Version',
@@ -1883,19 +2203,19 @@ const listCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('list').al
1883
2203
  skill.isLinked ? `${skill.version} (linked)` : skill.version,
1884
2204
  skill.source || '-'
1885
2205
  ]);
1886
- logger.table(headers, rows);
1887
- logger.newline();
1888
- logger.log(`Total: ${skills.length} skill(s)`);
2206
+ logger_logger.table(headers, rows);
2207
+ logger_logger.newline();
2208
+ logger_logger.log(`Total: ${skills.length} skill(s)`);
1889
2209
  });
1890
2210
  const outdatedCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('outdated').description('Check for outdated skills').option('-j, --json', 'Output as JSON').action(async (options)=>{
1891
2211
  const configLoader = new ConfigLoader();
1892
2212
  if (!configLoader.exists()) {
1893
- logger.error("skills.json not found. Run 'reskill init' first.");
2213
+ logger_logger.error("skills.json not found. Run 'reskill init' first.");
1894
2214
  process.exit(1);
1895
2215
  }
1896
2216
  const skills = configLoader.getSkills();
1897
2217
  if (0 === Object.keys(skills).length) {
1898
- logger.info('No skills defined in skills.json');
2218
+ logger_logger.info('No skills defined in skills.json');
1899
2219
  return;
1900
2220
  }
1901
2221
  const skillManager = new SkillManager();
@@ -1909,11 +2229,11 @@ const outdatedCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('outda
1909
2229
  }
1910
2230
  const outdated = results.filter((r)=>r.updateAvailable);
1911
2231
  if (0 === outdated.length) {
1912
- logger.success('All skills are up to date!');
2232
+ logger_logger.success('All skills are up to date!');
1913
2233
  return;
1914
2234
  }
1915
- logger["package"]('Checking for updates...');
1916
- logger.newline();
2235
+ logger_logger["package"]('Checking for updates...');
2236
+ logger_logger.newline();
1917
2237
  const headers = [
1918
2238
  'Skill',
1919
2239
  'Current',
@@ -1926,30 +2246,66 @@ const outdatedCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('outda
1926
2246
  r.latest,
1927
2247
  r.updateAvailable ? __WEBPACK_EXTERNAL_MODULE_chalk__["default"].yellow('⬆️ Update available') : __WEBPACK_EXTERNAL_MODULE_chalk__["default"].green('✅ Up to date')
1928
2248
  ]);
1929
- logger.table(headers, rows);
1930
- logger.newline();
2249
+ logger_logger.table(headers, rows);
2250
+ logger_logger.newline();
1931
2251
  if (outdated.length > 0) {
1932
- logger.log(`Run ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan('reskill update')} to update all skills`);
1933
- logger.log(`Or ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan('reskill update <skill>')} to update a specific skill`);
2252
+ logger_logger.log(`Run ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan('reskill update')} to update all skills`);
2253
+ logger_logger.log(`Or ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan('reskill update <skill>')} to update a specific skill`);
1934
2254
  }
1935
2255
  } catch (error) {
1936
2256
  spinner.fail('Check failed');
1937
- logger.error(error.message);
2257
+ logger_logger.error(error.message);
1938
2258
  process.exit(1);
1939
2259
  }
1940
2260
  });
1941
- const uninstallCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('uninstall').alias('un').alias('remove').alias('rm').description('Uninstall a skill').argument('<skill>', 'Skill name to uninstall').option('-g, --global', 'Uninstall from global installation (~/.claude/skills)').action((skillName, options)=>{
2261
+ const uninstallCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('uninstall').alias('un').alias('remove').alias('rm').description('Uninstall a skill').argument('<skill>', 'Skill name to uninstall').option('-g, --global', 'Uninstall from global installation (~/.claude/skills)').option('-y, --yes', 'Skip confirmation prompts').action(async (skillName, options)=>{
1942
2262
  const isGlobal = options.global || false;
2263
+ const skipConfirm = options.yes || false;
1943
2264
  const skillManager = new SkillManager(void 0, {
1944
2265
  global: isGlobal
1945
2266
  });
1946
- const result = skillManager.uninstall(skillName);
1947
- if (!result) process.exit(1);
2267
+ console.log();
2268
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.intro(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].bgCyan.black(' reskill '));
2269
+ const installer = new Installer({
2270
+ cwd: process.cwd(),
2271
+ global: isGlobal
2272
+ });
2273
+ const allAgentTypes = Object.keys(agents);
2274
+ const installedAgents = allAgentTypes.filter((agent)=>installer.isInstalled(skillName, agent));
2275
+ if (0 === installedAgents.length) {
2276
+ const location = isGlobal ? '(global)' : '';
2277
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.warn(`Skill ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(skillName)} is not installed ${location}`.trim());
2278
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.outro('Done');
2279
+ process.exit(0);
2280
+ }
2281
+ const summaryLines = [];
2282
+ summaryLines.push(`${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(skillName)}`);
2283
+ summaryLines.push(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('→')} ${installedAgents.map((a)=>agents[a].displayName).join(', ')}`);
2284
+ summaryLines.push(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('Scope:')} ${isGlobal ? 'Global' : 'Project'}`);
2285
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.note(summaryLines.join('\n'), 'Uninstallation Summary');
2286
+ if (!skipConfirm) {
2287
+ const confirmed = await __WEBPACK_EXTERNAL_MODULE__clack_prompts__.confirm({
2288
+ message: 'Proceed with uninstallation?'
2289
+ });
2290
+ if (__WEBPACK_EXTERNAL_MODULE__clack_prompts__.isCancel(confirmed) || !confirmed) {
2291
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.cancel('Uninstallation cancelled');
2292
+ process.exit(0);
2293
+ }
2294
+ }
2295
+ const results = skillManager.uninstallFromAgents(skillName, installedAgents);
2296
+ const successCount = Array.from(results.values()).filter((r)=>r).length;
2297
+ if (successCount > 0) __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.success(`Uninstalled ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(skillName)} from ${successCount} agent(s)`);
2298
+ else {
2299
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.error(`Failed to uninstall ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(skillName)}`);
2300
+ process.exit(1);
2301
+ }
2302
+ console.log();
2303
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.outro(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green('Done!'));
1948
2304
  });
1949
2305
  const updateCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('update').alias('up').description('Update installed skills').argument('[skill]', 'Skill name to update (updates all if not specified)').action(async (skill)=>{
1950
2306
  const configLoader = new ConfigLoader();
1951
2307
  if (!configLoader.exists()) {
1952
- logger.error("skills.json not found. Run 'reskill init' first.");
2308
+ logger_logger.error("skills.json not found. Run 'reskill init' first.");
1953
2309
  process.exit(1);
1954
2310
  }
1955
2311
  const skillManager = new SkillManager();
@@ -1958,17 +2314,18 @@ const updateCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('update'
1958
2314
  const updated = await skillManager.update(skill);
1959
2315
  spinner.stop();
1960
2316
  if (0 === updated.length) {
1961
- logger.info('No skills to update');
2317
+ logger_logger.info('No skills to update');
1962
2318
  return;
1963
2319
  }
1964
- logger.success(`Updated ${updated.length} skill(s):`);
1965
- for (const s of updated)logger.log(` - ${s.name}@${s.version}`);
2320
+ logger_logger.success(`Updated ${updated.length} skill(s):`);
2321
+ for (const s of updated)logger_logger.log(` - ${s.name}@${s.version}`);
1966
2322
  } catch (error) {
1967
2323
  spinner.fail('Update failed');
1968
- logger.error(error.message);
2324
+ logger_logger.error(error.message);
1969
2325
  process.exit(1);
1970
2326
  }
1971
2327
  });
2328
+ if (maybeHandleCompletion()) process.exit(0);
1972
2329
  const cli_rslib_entry_dirname = (0, __WEBPACK_EXTERNAL_MODULE_node_path__.dirname)((0, __WEBPACK_EXTERNAL_MODULE_node_url__.fileURLToPath)(import.meta.url));
1973
2330
  const packageJson = JSON.parse((0, external_node_fs_.readFileSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(cli_rslib_entry_dirname, '../../package.json'), 'utf-8'));
1974
2331
  const program = new __WEBPACK_EXTERNAL_MODULE_commander__.Command();
@@ -1982,4 +2339,9 @@ program.addCommand(outdatedCommand);
1982
2339
  program.addCommand(uninstallCommand);
1983
2340
  program.addCommand(linkCommand);
1984
2341
  program.addCommand(unlinkCommand);
1985
- program.parse();
2342
+ program.addCommand(completionCommand);
2343
+ const updateCheckPromise = checkForUpdate(packageJson.name, packageJson.version);
2344
+ program.parseAsync().then(async ()=>{
2345
+ const result = await updateCheckPromise;
2346
+ if (result?.hasUpdate) logger_logger.log(formatUpdateMessage(result));
2347
+ });