reskill 0.1.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.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +199 -0
  3. package/dist/cli/commands/index.d.ts +9 -0
  4. package/dist/cli/commands/index.d.ts.map +1 -0
  5. package/dist/cli/commands/info.d.ts +7 -0
  6. package/dist/cli/commands/info.d.ts.map +1 -0
  7. package/dist/cli/commands/init.d.ts +7 -0
  8. package/dist/cli/commands/init.d.ts.map +1 -0
  9. package/dist/cli/commands/install.d.ts +11 -0
  10. package/dist/cli/commands/install.d.ts.map +1 -0
  11. package/dist/cli/commands/link.d.ts +5 -0
  12. package/dist/cli/commands/link.d.ts.map +1 -0
  13. package/dist/cli/commands/list.d.ts +7 -0
  14. package/dist/cli/commands/list.d.ts.map +1 -0
  15. package/dist/cli/commands/outdated.d.ts +7 -0
  16. package/dist/cli/commands/outdated.d.ts.map +1 -0
  17. package/dist/cli/commands/uninstall.d.ts +7 -0
  18. package/dist/cli/commands/uninstall.d.ts.map +1 -0
  19. package/dist/cli/commands/update.d.ts +7 -0
  20. package/dist/cli/commands/update.d.ts.map +1 -0
  21. package/dist/cli/index.d.ts +3 -0
  22. package/dist/cli/index.d.ts.map +1 -0
  23. package/dist/cli/index.js +1293 -0
  24. package/dist/core/cache-manager.d.ts +80 -0
  25. package/dist/core/cache-manager.d.ts.map +1 -0
  26. package/dist/core/config-loader.d.ts +76 -0
  27. package/dist/core/config-loader.d.ts.map +1 -0
  28. package/dist/core/git-resolver.d.ts +73 -0
  29. package/dist/core/git-resolver.d.ts.map +1 -0
  30. package/dist/core/index.d.ts +7 -0
  31. package/dist/core/index.d.ts.map +1 -0
  32. package/dist/core/lock-manager.d.ts +75 -0
  33. package/dist/core/lock-manager.d.ts.map +1 -0
  34. package/dist/core/skill-manager.d.ts +98 -0
  35. package/dist/core/skill-manager.d.ts.map +1 -0
  36. package/dist/index.d.ts +9 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +1033 -0
  39. package/dist/types/index.d.ts +213 -0
  40. package/dist/types/index.d.ts.map +1 -0
  41. package/dist/utils/fs.d.ts +86 -0
  42. package/dist/utils/fs.d.ts.map +1 -0
  43. package/dist/utils/git.d.ts +112 -0
  44. package/dist/utils/git.d.ts.map +1 -0
  45. package/dist/utils/index.d.ts +4 -0
  46. package/dist/utils/index.d.ts.map +1 -0
  47. package/dist/utils/logger.d.ts +43 -0
  48. package/dist/utils/logger.d.ts.map +1 -0
  49. package/package.json +69 -0
@@ -0,0 +1,1293 @@
1
+ #!/usr/bin/env node
2
+ import * as __WEBPACK_EXTERNAL_MODULE_node_fs__ from "node:fs";
3
+ import * as __WEBPACK_EXTERNAL_MODULE_commander__ from "commander";
4
+ import * as __WEBPACK_EXTERNAL_MODULE_node_path__ from "node:path";
5
+ import * as __WEBPACK_EXTERNAL_MODULE_chalk__ from "chalk";
6
+ import * as __WEBPACK_EXTERNAL_MODULE_ora__ from "ora";
7
+ import * as __WEBPACK_EXTERNAL_MODULE_semver__ from "semver";
8
+ import * as __WEBPACK_EXTERNAL_MODULE_node_child_process__ from "node:child_process";
9
+ import * as __WEBPACK_EXTERNAL_MODULE_node_util__ from "node:util";
10
+ var __webpack_modules__ = {
11
+ "node:fs": function(module) {
12
+ module.exports = __WEBPACK_EXTERNAL_MODULE_node_fs__;
13
+ }
14
+ };
15
+ var __webpack_module_cache__ = {};
16
+ function __webpack_require__(moduleId) {
17
+ var cachedModule = __webpack_module_cache__[moduleId];
18
+ if (void 0 !== cachedModule) return cachedModule.exports;
19
+ var module = __webpack_module_cache__[moduleId] = {
20
+ exports: {}
21
+ };
22
+ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
23
+ return module.exports;
24
+ }
25
+ var external_node_fs_ = __webpack_require__("node:fs");
26
+ function exists(filePath) {
27
+ return external_node_fs_.existsSync(filePath);
28
+ }
29
+ function readJson(filePath) {
30
+ const content = external_node_fs_.readFileSync(filePath, 'utf-8');
31
+ return JSON.parse(content);
32
+ }
33
+ function writeJson(filePath, data, indent = 2) {
34
+ const dir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(filePath);
35
+ if (!exists(dir)) external_node_fs_.mkdirSync(dir, {
36
+ recursive: true
37
+ });
38
+ external_node_fs_.writeFileSync(filePath, JSON.stringify(data, null, indent) + '\n', 'utf-8');
39
+ }
40
+ function ensureDir(dirPath) {
41
+ if (!exists(dirPath)) external_node_fs_.mkdirSync(dirPath, {
42
+ recursive: true
43
+ });
44
+ }
45
+ function remove(targetPath) {
46
+ if (exists(targetPath)) external_node_fs_.rmSync(targetPath, {
47
+ recursive: true,
48
+ force: true
49
+ });
50
+ }
51
+ function copyDir(src, dest, options) {
52
+ const exclude = options?.exclude || [];
53
+ ensureDir(dest);
54
+ const entries = external_node_fs_.readdirSync(src, {
55
+ withFileTypes: true
56
+ });
57
+ for (const entry of entries){
58
+ if (exclude.includes(entry.name)) continue;
59
+ const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
60
+ const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
61
+ if (entry.isDirectory()) copyDir(srcPath, destPath, options);
62
+ else external_node_fs_.copyFileSync(srcPath, destPath);
63
+ }
64
+ }
65
+ function listDir(dirPath) {
66
+ if (!exists(dirPath)) return [];
67
+ return external_node_fs_.readdirSync(dirPath);
68
+ }
69
+ function isDirectory(targetPath) {
70
+ if (!exists(targetPath)) return false;
71
+ return external_node_fs_.statSync(targetPath).isDirectory();
72
+ }
73
+ function isSymlink(targetPath) {
74
+ if (!exists(targetPath)) return false;
75
+ return external_node_fs_.lstatSync(targetPath).isSymbolicLink();
76
+ }
77
+ function createSymlink(target, linkPath) {
78
+ const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
79
+ ensureDir(linkDir);
80
+ if (exists(linkPath)) remove(linkPath);
81
+ external_node_fs_.symlinkSync(target, linkPath, 'dir');
82
+ }
83
+ function getRealPath(linkPath) {
84
+ return external_node_fs_.realpathSync(linkPath);
85
+ }
86
+ function getSkillsJsonPath(projectRoot) {
87
+ const root = projectRoot || process.cwd();
88
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(root, 'skills.json');
89
+ }
90
+ function getSkillsLockPath(projectRoot) {
91
+ const root = projectRoot || process.cwd();
92
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(root, 'skills.lock');
93
+ }
94
+ function getCacheDir() {
95
+ const home = process.env.HOME || process.env.USERPROFILE || '';
96
+ return process.env.RESKILL_CACHE_DIR || __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.reskill-cache');
97
+ }
98
+ function getHomeDir() {
99
+ return process.env.HOME || process.env.USERPROFILE || '';
100
+ }
101
+ function getGlobalSkillsDir() {
102
+ const home = getHomeDir();
103
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.claude', 'skills');
104
+ }
105
+ const DEFAULT_SKILLS_JSON = {
106
+ skills: {},
107
+ defaults: {
108
+ registry: 'github',
109
+ installDir: '.skills'
110
+ }
111
+ };
112
+ const DEFAULT_REGISTRIES = {
113
+ github: 'https://github.com',
114
+ gitlab: 'https://gitlab.com'
115
+ };
116
+ class ConfigLoader {
117
+ projectRoot;
118
+ configPath;
119
+ config = null;
120
+ constructor(projectRoot){
121
+ this.projectRoot = projectRoot || process.cwd();
122
+ this.configPath = getSkillsJsonPath(this.projectRoot);
123
+ }
124
+ getProjectRoot() {
125
+ return this.projectRoot;
126
+ }
127
+ getConfigPath() {
128
+ return this.configPath;
129
+ }
130
+ exists() {
131
+ return exists(this.configPath);
132
+ }
133
+ load() {
134
+ if (this.config) return this.config;
135
+ if (!this.exists()) throw new Error(`skills.json not found in ${this.projectRoot}. Run 'reskill init' first.`);
136
+ try {
137
+ this.config = readJson(this.configPath);
138
+ return this.config;
139
+ } catch (error) {
140
+ throw new Error(`Failed to parse skills.json: ${error.message}`);
141
+ }
142
+ }
143
+ reload() {
144
+ this.config = null;
145
+ return this.load();
146
+ }
147
+ save(config) {
148
+ const toSave = config || this.config;
149
+ if (!toSave) throw new Error('No config to save');
150
+ writeJson(this.configPath, toSave);
151
+ this.config = toSave;
152
+ }
153
+ create(options) {
154
+ const config = {
155
+ ...DEFAULT_SKILLS_JSON,
156
+ ...options,
157
+ skills: options?.skills || {},
158
+ defaults: {
159
+ ...DEFAULT_SKILLS_JSON.defaults,
160
+ ...options?.defaults
161
+ }
162
+ };
163
+ this.save(config);
164
+ return config;
165
+ }
166
+ getDefaults() {
167
+ const config = this.config || (this.exists() ? this.load() : DEFAULT_SKILLS_JSON);
168
+ return {
169
+ registry: config.defaults?.registry || DEFAULT_SKILLS_JSON.defaults.registry,
170
+ installDir: config.defaults?.installDir || DEFAULT_SKILLS_JSON.defaults.installDir
171
+ };
172
+ }
173
+ getRegistryUrl(registryName) {
174
+ const config = this.config || (this.exists() ? this.load() : DEFAULT_SKILLS_JSON);
175
+ if (config.registries?.[registryName]) return config.registries[registryName];
176
+ if (DEFAULT_REGISTRIES[registryName]) return DEFAULT_REGISTRIES[registryName];
177
+ return `https://${registryName}`;
178
+ }
179
+ getInstallDir() {
180
+ const defaults = this.getDefaults();
181
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.projectRoot, defaults.installDir);
182
+ }
183
+ addSkill(name, ref) {
184
+ if (!this.config) this.load();
185
+ this.config.skills[name] = ref;
186
+ this.save();
187
+ }
188
+ removeSkill(name) {
189
+ if (!this.config) this.load();
190
+ if (this.config.skills[name]) {
191
+ delete this.config.skills[name];
192
+ this.save();
193
+ return true;
194
+ }
195
+ return false;
196
+ }
197
+ getSkills() {
198
+ if (!this.config) {
199
+ if (!this.exists()) return {};
200
+ this.load();
201
+ }
202
+ return {
203
+ ...this.config.skills
204
+ };
205
+ }
206
+ hasSkill(name) {
207
+ const skills = this.getSkills();
208
+ return name in skills;
209
+ }
210
+ getSkillRef(name) {
211
+ const skills = this.getSkills();
212
+ return skills[name];
213
+ }
214
+ }
215
+ const logger = {
216
+ info (message) {
217
+ console.log(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].blue('ℹ'), message);
218
+ },
219
+ success (message) {
220
+ console.log(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green('✅'), message);
221
+ },
222
+ warn (message) {
223
+ console.log(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].yellow('⚠️'), message);
224
+ },
225
+ error (message) {
226
+ console.error(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].red('❌'), message);
227
+ },
228
+ debug (message) {
229
+ if (process.env.DEBUG || process.env.VERBOSE) console.log(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].gray('🔍'), __WEBPACK_EXTERNAL_MODULE_chalk__["default"].gray(message));
230
+ },
231
+ package (message) {
232
+ console.log(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan('📦'), message);
233
+ },
234
+ log (message) {
235
+ console.log(message);
236
+ },
237
+ newline () {
238
+ console.log();
239
+ },
240
+ table (headers, rows) {
241
+ const widths = headers.map((h, i)=>{
242
+ const colValues = [
243
+ h,
244
+ ...rows.map((r)=>r[i] || '')
245
+ ];
246
+ return Math.max(...colValues.map((v)=>v.length));
247
+ });
248
+ const headerRow = headers.map((h, i)=>h.padEnd(widths[i])).join(' ');
249
+ console.log(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].bold(headerRow));
250
+ for (const row of rows){
251
+ const rowStr = row.map((cell, i)=>(cell || '').padEnd(widths[i])).join(' ');
252
+ console.log(rowStr);
253
+ }
254
+ }
255
+ };
256
+ 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)=>{
257
+ const configLoader = new ConfigLoader();
258
+ if (configLoader.exists()) {
259
+ logger.warn('skills.json already exists');
260
+ return;
261
+ }
262
+ const config = configLoader.create({
263
+ name: options.name,
264
+ defaults: {
265
+ registry: options.registry,
266
+ installDir: options.installDir
267
+ }
268
+ });
269
+ logger.success('Created skills.json');
270
+ logger.newline();
271
+ logger.log('Configuration:');
272
+ logger.log(` Name: ${config.name || '(not set)'}`);
273
+ logger.log(` Default registry: ${config.defaults?.registry}`);
274
+ logger.log(` Install directory: ${config.defaults?.installDir}`);
275
+ logger.newline();
276
+ logger.log('Next steps:');
277
+ logger.log(' reskill install <skill> Install a skill');
278
+ logger.log(' reskill list List installed skills');
279
+ });
280
+ const execAsync = (0, __WEBPACK_EXTERNAL_MODULE_node_util__.promisify)(__WEBPACK_EXTERNAL_MODULE_node_child_process__.exec);
281
+ class GitCloneError extends Error {
282
+ repoUrl;
283
+ originalError;
284
+ isAuthError;
285
+ constructor(repoUrl, originalError){
286
+ const isAuthError = GitCloneError.isAuthenticationError(originalError.message);
287
+ let message = `Failed to clone repository: ${repoUrl}`;
288
+ if (isAuthError) {
289
+ message += '\n\nTip: For private repos, ensure git SSH keys or credentials are configured:';
290
+ message += '\n - SSH: Check ~/.ssh/id_rsa or ~/.ssh/id_ed25519';
291
+ message += '\n - HTTPS: Run \'git config --global credential.helper store\'';
292
+ message += '\n - Or use a personal access token in the URL';
293
+ }
294
+ super(message);
295
+ this.name = 'GitCloneError';
296
+ this.repoUrl = repoUrl;
297
+ this.originalError = originalError;
298
+ this.isAuthError = isAuthError;
299
+ }
300
+ static isAuthenticationError(message) {
301
+ const authPatterns = [
302
+ /permission denied/i,
303
+ /could not read from remote/i,
304
+ /authentication failed/i,
305
+ /fatal: repository.*not found/i,
306
+ /host key verification failed/i,
307
+ /access denied/i,
308
+ /unauthorized/i,
309
+ /403/,
310
+ /401/
311
+ ];
312
+ return authPatterns.some((pattern)=>pattern.test(message));
313
+ }
314
+ }
315
+ async function git(args, cwd) {
316
+ const { stdout } = await execAsync(`git ${args.join(' ')}`, {
317
+ cwd,
318
+ encoding: 'utf-8'
319
+ });
320
+ return stdout.trim();
321
+ }
322
+ async function getRemoteTags(repoUrl) {
323
+ try {
324
+ const output = await git([
325
+ 'ls-remote',
326
+ '--tags',
327
+ '--refs',
328
+ repoUrl
329
+ ]);
330
+ if (!output) return [];
331
+ const tags = [];
332
+ const lines = output.split('\n');
333
+ for (const line of lines){
334
+ const [commit, ref] = line.split('\t');
335
+ if (commit && ref) {
336
+ const tagName = ref.replace('refs/tags/', '');
337
+ tags.push({
338
+ name: tagName,
339
+ commit
340
+ });
341
+ }
342
+ }
343
+ return tags;
344
+ } catch {
345
+ return [];
346
+ }
347
+ }
348
+ async function getLatestTag(repoUrl) {
349
+ const tags = await getRemoteTags(repoUrl);
350
+ if (0 === tags.length) return null;
351
+ const sortedTags = tags.sort((a, b)=>{
352
+ const aVer = a.name.replace(/^v/, '');
353
+ const bVer = b.name.replace(/^v/, '');
354
+ return compareVersions(bVer, aVer);
355
+ });
356
+ return sortedTags[0];
357
+ }
358
+ async function clone(repoUrl, destPath, options) {
359
+ const args = [
360
+ 'clone'
361
+ ];
362
+ if (options?.depth) args.push('--depth', options.depth.toString());
363
+ if (options?.branch) args.push('--branch', options.branch);
364
+ args.push(repoUrl, destPath);
365
+ try {
366
+ await git(args);
367
+ } catch (error) {
368
+ throw new GitCloneError(repoUrl, error);
369
+ }
370
+ }
371
+ async function getCurrentCommit(cwd) {
372
+ return git([
373
+ 'rev-parse',
374
+ 'HEAD'
375
+ ], cwd);
376
+ }
377
+ async function getDefaultBranch(repoUrl) {
378
+ try {
379
+ const output = await git([
380
+ 'ls-remote',
381
+ '--symref',
382
+ repoUrl,
383
+ 'HEAD'
384
+ ]);
385
+ const match = output.match(/ref: refs\/heads\/(\S+)/);
386
+ return match ? match[1] : 'main';
387
+ } catch {
388
+ return 'main';
389
+ }
390
+ }
391
+ function compareVersions(a, b) {
392
+ const aParts = a.split('.').map((p)=>parseInt(p, 10) || 0);
393
+ const bParts = b.split('.').map((p)=>parseInt(p, 10) || 0);
394
+ const maxLength = Math.max(aParts.length, bParts.length);
395
+ for(let i = 0; i < maxLength; i++){
396
+ const aPart = aParts[i] || 0;
397
+ const bPart = bParts[i] || 0;
398
+ if (aPart > bPart) return 1;
399
+ if (aPart < bPart) return -1;
400
+ }
401
+ return 0;
402
+ }
403
+ function buildRepoUrl(registry, ownerRepo) {
404
+ const registryUrls = {
405
+ github: 'https://github.com',
406
+ gitlab: 'https://gitlab.com'
407
+ };
408
+ const baseUrl = registryUrls[registry] || `https://${registry}`;
409
+ return `${baseUrl}/${ownerRepo}`;
410
+ }
411
+ function isGitUrl(source) {
412
+ return source.startsWith('git@') || source.startsWith('git://') || source.startsWith('http://') || source.startsWith('https://') || source.endsWith('.git');
413
+ }
414
+ function parseGitUrl(url) {
415
+ const cleanUrl = url.replace(/\.git$/, '');
416
+ const sshMatch = cleanUrl.match(/^git@([^:]+):(.+)$/);
417
+ if (sshMatch) {
418
+ const [, host, path] = sshMatch;
419
+ const parts = path.split('/');
420
+ if (parts.length >= 2) {
421
+ const owner = parts.slice(0, -1).join('/');
422
+ const repo = parts[parts.length - 1];
423
+ return {
424
+ host,
425
+ owner,
426
+ repo,
427
+ url,
428
+ type: 'ssh'
429
+ };
430
+ }
431
+ }
432
+ const httpMatch = cleanUrl.match(/^(https?|git):\/\/([^/]+)\/(.+)$/);
433
+ if (httpMatch) {
434
+ const [, protocol, host, path] = httpMatch;
435
+ const parts = path.split('/');
436
+ if (parts.length >= 2) {
437
+ const owner = parts.slice(0, -1).join('/');
438
+ const repo = parts[parts.length - 1];
439
+ return {
440
+ host,
441
+ owner,
442
+ repo,
443
+ url,
444
+ type: 'git' === protocol ? 'git' : 'https'
445
+ };
446
+ }
447
+ }
448
+ return null;
449
+ }
450
+ class GitResolver {
451
+ defaultRegistry;
452
+ constructor(defaultRegistry = 'github'){
453
+ this.defaultRegistry = defaultRegistry;
454
+ }
455
+ parseRef(ref) {
456
+ const raw = ref;
457
+ if (isGitUrl(ref)) return this.parseGitUrlRef(ref);
458
+ let remaining = ref;
459
+ let registry = this.defaultRegistry;
460
+ let version;
461
+ const registryMatch = remaining.match(/^([a-zA-Z0-9.-]+):(.+)$/);
462
+ if (registryMatch) {
463
+ registry = registryMatch[1];
464
+ remaining = registryMatch[2];
465
+ }
466
+ const atIndex = remaining.lastIndexOf('@');
467
+ if (atIndex > 0) {
468
+ version = remaining.slice(atIndex + 1);
469
+ remaining = remaining.slice(0, atIndex);
470
+ }
471
+ const parts = remaining.split('/');
472
+ if (parts.length < 2) throw new Error(`Invalid skill reference: ${ref}. Expected format: owner/repo[@version]`);
473
+ const owner = parts[0];
474
+ const repo = parts[1];
475
+ const subPath = parts.length > 2 ? parts.slice(2).join('/') : void 0;
476
+ return {
477
+ registry,
478
+ owner,
479
+ repo,
480
+ subPath,
481
+ version,
482
+ raw
483
+ };
484
+ }
485
+ parseGitUrlRef(ref) {
486
+ const raw = ref;
487
+ let gitUrl = ref;
488
+ let version;
489
+ let subPath;
490
+ const gitSuffixIndex = ref.indexOf('.git');
491
+ if (-1 !== gitSuffixIndex) {
492
+ const afterGit = ref.slice(gitSuffixIndex + 4);
493
+ if (afterGit) {
494
+ const atIndex = afterGit.lastIndexOf('@');
495
+ if (-1 !== atIndex) {
496
+ version = afterGit.slice(atIndex + 1);
497
+ const pathPart = afterGit.slice(0, atIndex);
498
+ if (pathPart.startsWith('/')) subPath = pathPart.slice(1);
499
+ } else if (afterGit.startsWith('/')) subPath = afterGit.slice(1);
500
+ gitUrl = ref.slice(0, gitSuffixIndex + 4);
501
+ }
502
+ } else {
503
+ const atIndex = ref.lastIndexOf('@');
504
+ if (atIndex > 4) {
505
+ version = ref.slice(atIndex + 1);
506
+ gitUrl = ref.slice(0, atIndex);
507
+ }
508
+ }
509
+ const parsed = parseGitUrl(gitUrl);
510
+ if (!parsed) throw new Error(`Invalid Git URL: ${ref}. Expected format: git@host:owner/repo.git or https://host/owner/repo.git`);
511
+ return {
512
+ registry: parsed.host,
513
+ owner: parsed.owner,
514
+ repo: parsed.repo,
515
+ subPath,
516
+ version,
517
+ raw,
518
+ gitUrl
519
+ };
520
+ }
521
+ parseVersion(versionSpec) {
522
+ if (!versionSpec) return {
523
+ type: 'branch',
524
+ value: 'main',
525
+ raw: ''
526
+ };
527
+ const raw = versionSpec;
528
+ if ('latest' === versionSpec) return {
529
+ type: 'latest',
530
+ value: 'latest',
531
+ raw
532
+ };
533
+ if (versionSpec.startsWith('branch:')) return {
534
+ type: 'branch',
535
+ value: versionSpec.slice(7),
536
+ raw
537
+ };
538
+ if (versionSpec.startsWith('commit:')) return {
539
+ type: 'commit',
540
+ value: versionSpec.slice(7),
541
+ raw
542
+ };
543
+ if (/^[\^~><]/.test(versionSpec)) return {
544
+ type: 'range',
545
+ value: versionSpec,
546
+ raw
547
+ };
548
+ return {
549
+ type: 'exact',
550
+ value: versionSpec,
551
+ raw
552
+ };
553
+ }
554
+ buildRepoUrl(parsed) {
555
+ if (parsed.gitUrl) return parsed.gitUrl;
556
+ return buildRepoUrl(parsed.registry, `${parsed.owner}/${parsed.repo}`);
557
+ }
558
+ async resolveVersion(repoUrl, versionSpec) {
559
+ switch(versionSpec.type){
560
+ case 'exact':
561
+ return {
562
+ ref: versionSpec.value
563
+ };
564
+ case 'latest':
565
+ {
566
+ const latestTag = await getLatestTag(repoUrl);
567
+ if (!latestTag) {
568
+ const defaultBranch = await getDefaultBranch(repoUrl);
569
+ return {
570
+ ref: defaultBranch
571
+ };
572
+ }
573
+ return {
574
+ ref: latestTag.name,
575
+ commit: latestTag.commit
576
+ };
577
+ }
578
+ case 'range':
579
+ {
580
+ const tags = await getRemoteTags(repoUrl);
581
+ const matchingTags = tags.filter((tag)=>{
582
+ const version = tag.name.replace(/^v/, '');
583
+ return __WEBPACK_EXTERNAL_MODULE_semver__.satisfies(version, versionSpec.value);
584
+ });
585
+ if (0 === matchingTags.length) throw new Error(`No version found matching ${versionSpec.raw} for ${repoUrl}`);
586
+ matchingTags.sort((a, b)=>{
587
+ const aVer = a.name.replace(/^v/, '');
588
+ const bVer = b.name.replace(/^v/, '');
589
+ return __WEBPACK_EXTERNAL_MODULE_semver__.compare(bVer, aVer);
590
+ });
591
+ return {
592
+ ref: matchingTags[0].name,
593
+ commit: matchingTags[0].commit
594
+ };
595
+ }
596
+ case 'branch':
597
+ return {
598
+ ref: versionSpec.value
599
+ };
600
+ case 'commit':
601
+ return {
602
+ ref: versionSpec.value,
603
+ commit: versionSpec.value
604
+ };
605
+ default:
606
+ throw new Error(`Unknown version type: ${versionSpec.type}`);
607
+ }
608
+ }
609
+ async resolve(ref) {
610
+ const parsed = this.parseRef(ref);
611
+ const repoUrl = this.buildRepoUrl(parsed);
612
+ const versionSpec = this.parseVersion(parsed.version);
613
+ const resolved = await this.resolveVersion(repoUrl, versionSpec);
614
+ return {
615
+ parsed,
616
+ repoUrl,
617
+ ref: resolved.ref,
618
+ commit: resolved.commit
619
+ };
620
+ }
621
+ }
622
+ class CacheManager {
623
+ cacheDir;
624
+ constructor(cacheDir){
625
+ this.cacheDir = cacheDir || getCacheDir();
626
+ }
627
+ getCacheDir() {
628
+ return this.cacheDir;
629
+ }
630
+ getSkillCachePath(parsed, version) {
631
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, parsed.registry, parsed.owner, parsed.repo, version);
632
+ }
633
+ isCached(parsed, version) {
634
+ const cachePath = this.getSkillCachePath(parsed, version);
635
+ return exists(cachePath) && isDirectory(cachePath);
636
+ }
637
+ async get(parsed, version) {
638
+ const cachePath = this.getSkillCachePath(parsed, version);
639
+ if (!this.isCached(parsed, version)) return null;
640
+ const commitFile = __WEBPACK_EXTERNAL_MODULE_node_path__.join(cachePath, '.reskill-commit');
641
+ let commit = '';
642
+ try {
643
+ const fs = await import("node:fs");
644
+ if (exists(commitFile)) commit = fs.readFileSync(commitFile, 'utf-8').trim();
645
+ } catch {}
646
+ return {
647
+ path: cachePath,
648
+ commit
649
+ };
650
+ }
651
+ async cache(repoUrl, parsed, ref, version) {
652
+ const cachePath = this.getSkillCachePath(parsed, version);
653
+ if (exists(cachePath)) remove(cachePath);
654
+ ensureDir(__WEBPACK_EXTERNAL_MODULE_node_path__.dirname(cachePath));
655
+ const tempPath = `${cachePath}.tmp`;
656
+ remove(tempPath);
657
+ await clone(repoUrl, tempPath, {
658
+ depth: 1,
659
+ branch: ref
660
+ });
661
+ const commit = await getCurrentCommit(tempPath);
662
+ if (parsed.subPath) {
663
+ const subDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(tempPath, parsed.subPath);
664
+ if (!exists(subDir)) {
665
+ remove(tempPath);
666
+ throw new Error(`Subpath ${parsed.subPath} not found in repository`);
667
+ }
668
+ copyDir(subDir, cachePath, {
669
+ exclude: [
670
+ '.git'
671
+ ]
672
+ });
673
+ } else copyDir(tempPath, cachePath, {
674
+ exclude: [
675
+ '.git'
676
+ ]
677
+ });
678
+ const fs = await import("node:fs");
679
+ fs.writeFileSync(__WEBPACK_EXTERNAL_MODULE_node_path__.join(cachePath, '.reskill-commit'), commit);
680
+ remove(tempPath);
681
+ return {
682
+ path: cachePath,
683
+ commit
684
+ };
685
+ }
686
+ async copyTo(parsed, version, destPath) {
687
+ const cached = await this.get(parsed, version);
688
+ if (!cached) throw new Error(`Skill ${parsed.raw} version ${version} not found in cache`);
689
+ if (exists(destPath)) remove(destPath);
690
+ copyDir(cached.path, destPath, {
691
+ exclude: [
692
+ '.reskill-commit'
693
+ ]
694
+ });
695
+ }
696
+ clearSkill(parsed, version) {
697
+ if (version) {
698
+ const cachePath = this.getSkillCachePath(parsed, version);
699
+ remove(cachePath);
700
+ } else {
701
+ const skillDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, parsed.registry, parsed.owner, parsed.repo);
702
+ remove(skillDir);
703
+ }
704
+ }
705
+ clearAll() {
706
+ remove(this.cacheDir);
707
+ }
708
+ getStats() {
709
+ if (!exists(this.cacheDir)) return {
710
+ totalSkills: 0,
711
+ registries: []
712
+ };
713
+ const registries = listDir(this.cacheDir).filter((name)=>isDirectory(__WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, name)));
714
+ let totalSkills = 0;
715
+ for (const registry of registries){
716
+ const registryPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, registry);
717
+ const owners = listDir(registryPath).filter((name)=>isDirectory(__WEBPACK_EXTERNAL_MODULE_node_path__.join(registryPath, name)));
718
+ for (const owner of owners){
719
+ const ownerPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(registryPath, owner);
720
+ const repos = listDir(ownerPath).filter((name)=>isDirectory(__WEBPACK_EXTERNAL_MODULE_node_path__.join(ownerPath, name)));
721
+ totalSkills += repos.length;
722
+ }
723
+ }
724
+ return {
725
+ totalSkills,
726
+ registries
727
+ };
728
+ }
729
+ }
730
+ const LOCKFILE_VERSION = 1;
731
+ class LockManager {
732
+ projectRoot;
733
+ lockPath;
734
+ lockData = null;
735
+ constructor(projectRoot){
736
+ this.projectRoot = projectRoot || process.cwd();
737
+ this.lockPath = getSkillsLockPath(this.projectRoot);
738
+ }
739
+ getLockPath() {
740
+ return this.lockPath;
741
+ }
742
+ exists() {
743
+ return exists(this.lockPath);
744
+ }
745
+ load() {
746
+ if (this.lockData) return this.lockData;
747
+ if (!this.exists()) {
748
+ this.lockData = {
749
+ lockfileVersion: LOCKFILE_VERSION,
750
+ skills: {}
751
+ };
752
+ return this.lockData;
753
+ }
754
+ try {
755
+ this.lockData = readJson(this.lockPath);
756
+ return this.lockData;
757
+ } catch (error) {
758
+ throw new Error(`Failed to parse skills.lock: ${error.message}`);
759
+ }
760
+ }
761
+ reload() {
762
+ this.lockData = null;
763
+ return this.load();
764
+ }
765
+ save(lockToSave) {
766
+ const toSave = lockToSave || this.lockData;
767
+ if (!toSave) throw new Error('No lock to save');
768
+ writeJson(this.lockPath, toSave);
769
+ this.lockData = toSave;
770
+ }
771
+ get(name) {
772
+ const lock = this.load();
773
+ return lock.skills[name];
774
+ }
775
+ set(name, skill) {
776
+ const lock = this.load();
777
+ lock.skills[name] = skill;
778
+ this.save();
779
+ }
780
+ remove(name) {
781
+ const lock = this.load();
782
+ if (lock.skills[name]) {
783
+ delete lock.skills[name];
784
+ this.save();
785
+ return true;
786
+ }
787
+ return false;
788
+ }
789
+ lockSkill(name, options) {
790
+ const lockedSkill = {
791
+ source: options.source,
792
+ version: options.version,
793
+ resolved: options.resolved,
794
+ commit: options.commit,
795
+ installedAt: new Date().toISOString()
796
+ };
797
+ this.set(name, lockedSkill);
798
+ return lockedSkill;
799
+ }
800
+ getAll() {
801
+ const lock = this.load();
802
+ return {
803
+ ...lock.skills
804
+ };
805
+ }
806
+ has(name) {
807
+ const lock = this.load();
808
+ return name in lock.skills;
809
+ }
810
+ isVersionMatch(name, version) {
811
+ const locked = this.get(name);
812
+ if (!locked) return false;
813
+ return locked.version === version;
814
+ }
815
+ clear() {
816
+ this.lockData = {
817
+ lockfileVersion: LOCKFILE_VERSION,
818
+ skills: {}
819
+ };
820
+ this.save();
821
+ }
822
+ delete() {
823
+ if (this.exists()) {
824
+ const fs = __webpack_require__("node:fs");
825
+ fs.unlinkSync(this.lockPath);
826
+ }
827
+ this.lockData = null;
828
+ }
829
+ }
830
+ class SkillManager {
831
+ projectRoot;
832
+ resolver;
833
+ cache;
834
+ config;
835
+ lockManager;
836
+ isGlobal;
837
+ constructor(projectRoot, options){
838
+ this.projectRoot = projectRoot || process.cwd();
839
+ this.isGlobal = options?.global || false;
840
+ this.config = new ConfigLoader(this.projectRoot);
841
+ this.lockManager = new LockManager(this.projectRoot);
842
+ this.cache = new CacheManager();
843
+ const defaults = this.config.getDefaults();
844
+ this.resolver = new GitResolver(defaults.registry);
845
+ }
846
+ isGlobalMode() {
847
+ return this.isGlobal;
848
+ }
849
+ getProjectRoot() {
850
+ return this.projectRoot;
851
+ }
852
+ getInstallDir() {
853
+ if (this.isGlobal) return getGlobalSkillsDir();
854
+ return this.config.getInstallDir();
855
+ }
856
+ getSkillPath(name) {
857
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getInstallDir(), name);
858
+ }
859
+ async install(ref, options = {}) {
860
+ const { force = false, save = true } = options;
861
+ const resolved = await this.resolver.resolve(ref);
862
+ const { parsed, repoUrl } = resolved;
863
+ const version = resolved.ref;
864
+ const skillName = parsed.subPath ? __WEBPACK_EXTERNAL_MODULE_node_path__.basename(parsed.subPath) : parsed.repo;
865
+ const skillPath = this.getSkillPath(skillName);
866
+ if (exists(skillPath) && !force) {
867
+ const locked = this.lockManager.get(skillName);
868
+ if (locked && locked.version === version) {
869
+ logger.info(`${skillName}@${version} is already installed`);
870
+ return this.getInstalledSkill(skillName);
871
+ }
872
+ if (!force) {
873
+ logger.warn(`${skillName} is already installed. Use --force to reinstall.`);
874
+ return this.getInstalledSkill(skillName);
875
+ }
876
+ }
877
+ logger["package"](`Installing ${skillName}@${version}...`);
878
+ let cacheResult = await this.cache.get(parsed, version);
879
+ if (cacheResult) logger.debug(`Using cached ${skillName}@${version}`);
880
+ else {
881
+ logger.debug(`Caching ${skillName}@${version} from ${repoUrl}`);
882
+ cacheResult = await this.cache.cache(repoUrl, parsed, version, version);
883
+ }
884
+ ensureDir(this.getInstallDir());
885
+ if (exists(skillPath)) remove(skillPath);
886
+ await this.cache.copyTo(parsed, version, skillPath);
887
+ if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
888
+ source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? '/' + parsed.subPath : ''}`,
889
+ version,
890
+ resolved: repoUrl,
891
+ commit: cacheResult.commit
892
+ });
893
+ if (!this.isGlobal && save && this.config.exists()) this.config.addSkill(skillName, ref);
894
+ const locationHint = this.isGlobal ? '(global)' : '';
895
+ logger.success(`Installed ${skillName}@${version} to ${skillPath} ${locationHint}`.trim());
896
+ return this.getInstalledSkill(skillName);
897
+ }
898
+ async installAll(options = {}) {
899
+ const skills = this.config.getSkills();
900
+ const installed = [];
901
+ for (const [name, ref] of Object.entries(skills))try {
902
+ const skill = await this.install(ref, {
903
+ ...options,
904
+ save: false
905
+ });
906
+ installed.push(skill);
907
+ } catch (error) {
908
+ logger.error(`Failed to install ${name}: ${error.message}`);
909
+ }
910
+ return installed;
911
+ }
912
+ uninstall(name) {
913
+ const skillPath = this.getSkillPath(name);
914
+ if (!exists(skillPath)) {
915
+ const location = this.isGlobal ? '(global)' : '';
916
+ logger.warn(`Skill ${name} is not installed ${location}`.trim());
917
+ return false;
918
+ }
919
+ remove(skillPath);
920
+ if (!this.isGlobal) this.lockManager.remove(name);
921
+ if (!this.isGlobal && this.config.exists()) this.config.removeSkill(name);
922
+ const locationHint = this.isGlobal ? '(global)' : '';
923
+ logger.success(`Uninstalled ${name} ${locationHint}`.trim());
924
+ return true;
925
+ }
926
+ async update(name) {
927
+ const updated = [];
928
+ if (name) {
929
+ const ref = this.config.getSkillRef(name);
930
+ if (!ref) {
931
+ logger.error(`Skill ${name} not found in skills.json`);
932
+ return [];
933
+ }
934
+ const skill = await this.install(ref, {
935
+ force: true,
936
+ save: false
937
+ });
938
+ updated.push(skill);
939
+ } else {
940
+ const skills = this.config.getSkills();
941
+ for (const [skillName, ref] of Object.entries(skills))try {
942
+ const skill = await this.install(ref, {
943
+ force: true,
944
+ save: false
945
+ });
946
+ updated.push(skill);
947
+ } catch (error) {
948
+ logger.error(`Failed to update ${skillName}: ${error.message}`);
949
+ }
950
+ }
951
+ return updated;
952
+ }
953
+ link(localPath, name) {
954
+ const absolutePath = __WEBPACK_EXTERNAL_MODULE_node_path__.resolve(localPath);
955
+ if (!exists(absolutePath)) throw new Error(`Path ${localPath} does not exist`);
956
+ const skillJsonPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(absolutePath, 'skill.json');
957
+ let skillName = name || __WEBPACK_EXTERNAL_MODULE_node_path__.basename(absolutePath);
958
+ if (exists(skillJsonPath)) try {
959
+ const skillJson = readJson(skillJsonPath);
960
+ skillName = name || skillJson.name || skillName;
961
+ } catch {}
962
+ const linkPath = this.getSkillPath(skillName);
963
+ ensureDir(this.getInstallDir());
964
+ createSymlink(absolutePath, linkPath);
965
+ logger.success(`Linked ${skillName} → ${absolutePath}`);
966
+ return {
967
+ name: skillName,
968
+ path: linkPath,
969
+ version: 'local',
970
+ source: absolutePath,
971
+ isLinked: true
972
+ };
973
+ }
974
+ unlink(name) {
975
+ const skillPath = this.getSkillPath(name);
976
+ if (!exists(skillPath)) {
977
+ logger.warn(`Skill ${name} is not installed`);
978
+ return false;
979
+ }
980
+ if (!isSymlink(skillPath)) {
981
+ logger.warn(`Skill ${name} is not a linked skill`);
982
+ return false;
983
+ }
984
+ remove(skillPath);
985
+ logger.success(`Unlinked ${name}`);
986
+ return true;
987
+ }
988
+ list() {
989
+ const installDir = this.getInstallDir();
990
+ if (!exists(installDir)) return [];
991
+ const skills = [];
992
+ const dirs = listDir(installDir);
993
+ for (const name of dirs){
994
+ const skillPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(installDir, name);
995
+ if (!isDirectory(skillPath)) continue;
996
+ const skill = this.getInstalledSkill(name);
997
+ if (skill) skills.push(skill);
998
+ }
999
+ return skills;
1000
+ }
1001
+ getInstalledSkill(name) {
1002
+ const skillPath = this.getSkillPath(name);
1003
+ if (!exists(skillPath)) return null;
1004
+ const isLinked = isSymlink(skillPath);
1005
+ const locked = this.lockManager.get(name);
1006
+ let metadata;
1007
+ const skillJsonPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(skillPath, 'skill.json');
1008
+ if (exists(skillJsonPath)) try {
1009
+ metadata = readJson(skillJsonPath);
1010
+ } catch {}
1011
+ return {
1012
+ name,
1013
+ path: skillPath,
1014
+ version: isLinked ? 'local' : locked?.version || metadata?.version || 'unknown',
1015
+ source: isLinked ? getRealPath(skillPath) : locked?.source || '',
1016
+ metadata,
1017
+ isLinked
1018
+ };
1019
+ }
1020
+ getInfo(name) {
1021
+ return {
1022
+ installed: this.getInstalledSkill(name),
1023
+ locked: this.lockManager.get(name),
1024
+ config: this.config.getSkillRef(name)
1025
+ };
1026
+ }
1027
+ async checkOutdated() {
1028
+ const results = [];
1029
+ const skills = this.config.getSkills();
1030
+ for (const [name, ref] of Object.entries(skills))try {
1031
+ const locked = this.lockManager.get(name);
1032
+ const current = locked?.version || 'unknown';
1033
+ const parsed = this.resolver.parseRef(ref);
1034
+ const repoUrl = this.resolver.buildRepoUrl(parsed);
1035
+ const latestResolved = await this.resolver.resolveVersion(repoUrl, {
1036
+ type: 'latest',
1037
+ value: 'latest',
1038
+ raw: 'latest'
1039
+ });
1040
+ const latest = latestResolved.ref;
1041
+ const updateAvailable = current !== latest && 'unknown' !== current;
1042
+ results.push({
1043
+ name,
1044
+ current,
1045
+ latest,
1046
+ updateAvailable
1047
+ });
1048
+ } catch (error) {
1049
+ logger.debug(`Failed to check ${name}: ${error.message}`);
1050
+ results.push({
1051
+ name,
1052
+ current: 'unknown',
1053
+ latest: 'unknown',
1054
+ updateAvailable: false
1055
+ });
1056
+ }
1057
+ return results;
1058
+ }
1059
+ }
1060
+ const installCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('install').alias('i').description('Install a skill or all skills from skills.json').argument('[skill]', 'Skill reference (e.g., github:user/skill@v1.0.0 or git@github.com:user/repo.git)').option('-f, --force', 'Force reinstall even if already installed').option('-g, --global', 'Install globally to ~/.claude/skills').option('--no-save', 'Do not save to skills.json').action(async (skill, options)=>{
1061
+ const isGlobal = options.global || false;
1062
+ const configLoader = new ConfigLoader();
1063
+ const skillManager = new SkillManager(void 0, {
1064
+ global: isGlobal
1065
+ });
1066
+ if (isGlobal) logger.info(`Installing to ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(getGlobalSkillsDir())} ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('(global)')}`);
1067
+ if (skill) {
1068
+ const spinner = (0, __WEBPACK_EXTERNAL_MODULE_ora__["default"])(`Installing ${skill}...`).start();
1069
+ try {
1070
+ const installed = await skillManager.install(skill, {
1071
+ force: options.force,
1072
+ save: options.save && !isGlobal,
1073
+ global: isGlobal
1074
+ });
1075
+ const location = isGlobal ? __WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(' (global)') : '';
1076
+ spinner.succeed(`Installed ${installed.name}@${installed.version}${location}`);
1077
+ } catch (error) {
1078
+ spinner.fail('Installation failed');
1079
+ logger.error(error.message);
1080
+ process.exit(1);
1081
+ }
1082
+ } else {
1083
+ if (isGlobal) {
1084
+ logger.error('Cannot install all skills globally. Please specify a skill to install.');
1085
+ process.exit(1);
1086
+ }
1087
+ if (!configLoader.exists()) {
1088
+ logger.error("skills.json not found. Run 'reskill init' first.");
1089
+ process.exit(1);
1090
+ }
1091
+ const skills = configLoader.getSkills();
1092
+ if (0 === Object.keys(skills).length) {
1093
+ logger.info('No skills defined in skills.json');
1094
+ return;
1095
+ }
1096
+ logger["package"]('Installing all skills from skills.json...');
1097
+ const spinner = (0, __WEBPACK_EXTERNAL_MODULE_ora__["default"])('Installing...').start();
1098
+ try {
1099
+ const installed = await skillManager.installAll({
1100
+ force: options.force
1101
+ });
1102
+ spinner.stop();
1103
+ logger.newline();
1104
+ logger.success(`Installed ${installed.length} skill(s)`);
1105
+ } catch (error) {
1106
+ spinner.fail('Installation failed');
1107
+ logger.error(error.message);
1108
+ process.exit(1);
1109
+ }
1110
+ }
1111
+ });
1112
+ const listCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('list').alias('ls').description('List installed skills').option('-j, --json', 'Output as JSON').option('-g, --global', 'List globally installed skills').action((options)=>{
1113
+ const isGlobal = options.global || false;
1114
+ const skillManager = new SkillManager(void 0, {
1115
+ global: isGlobal
1116
+ });
1117
+ const skills = skillManager.list();
1118
+ if (0 === skills.length) {
1119
+ const location = isGlobal ? 'globally' : 'in this project';
1120
+ logger.info(`No skills installed ${location}`);
1121
+ return;
1122
+ }
1123
+ if (options.json) {
1124
+ console.log(JSON.stringify(skills, null, 2));
1125
+ return;
1126
+ }
1127
+ const locationLabel = isGlobal ? __WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(' (global)') : '';
1128
+ logger.log(`Installed Skills (${skillManager.getInstallDir()})${locationLabel}:`);
1129
+ logger.newline();
1130
+ const headers = [
1131
+ 'Name',
1132
+ 'Version',
1133
+ 'Source'
1134
+ ];
1135
+ const rows = skills.map((skill)=>[
1136
+ skill.name,
1137
+ skill.isLinked ? `${skill.version} (linked)` : skill.version,
1138
+ skill.source || '-'
1139
+ ]);
1140
+ logger.table(headers, rows);
1141
+ logger.newline();
1142
+ logger.log(`Total: ${skills.length} skill(s)`);
1143
+ });
1144
+ 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)=>{
1145
+ const skillManager = new SkillManager();
1146
+ const info = skillManager.getInfo(skillName);
1147
+ if (options.json) {
1148
+ console.log(JSON.stringify(info, null, 2));
1149
+ return;
1150
+ }
1151
+ if (!info.installed && !info.config) {
1152
+ logger.error(`Skill ${skillName} not found`);
1153
+ process.exit(1);
1154
+ }
1155
+ logger.log(`Skill: ${skillName}`);
1156
+ logger.newline();
1157
+ if (info.config) {
1158
+ logger.log("Configuration (skills.json):");
1159
+ logger.log(` Reference: ${info.config}`);
1160
+ }
1161
+ if (info.locked) {
1162
+ logger.log("Locked Version (skills.lock):");
1163
+ logger.log(` Version: ${info.locked.version}`);
1164
+ logger.log(` Source: ${info.locked.source}`);
1165
+ logger.log(` Commit: ${info.locked.commit}`);
1166
+ logger.log(` Installed: ${info.locked.installedAt}`);
1167
+ }
1168
+ if (info.installed) {
1169
+ logger.log("Installed:");
1170
+ logger.log(` Path: ${info.installed.path}`);
1171
+ logger.log(` Version: ${info.installed.version}`);
1172
+ logger.log(` Linked: ${info.installed.isLinked ? 'Yes' : 'No'}`);
1173
+ if (info.installed.metadata) {
1174
+ const meta = info.installed.metadata;
1175
+ logger.log("Metadata (skill.json):");
1176
+ if (meta.description) logger.log(` Description: ${meta.description}`);
1177
+ if (meta.author) logger.log(` Author: ${meta.author}`);
1178
+ if (meta.license) logger.log(` License: ${meta.license}`);
1179
+ if (meta.keywords?.length) logger.log(` Keywords: ${meta.keywords.join(', ')}`);
1180
+ }
1181
+ } else logger.warn(`Skill ${skillName} is not installed`);
1182
+ });
1183
+ 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)=>{
1184
+ const configLoader = new ConfigLoader();
1185
+ if (!configLoader.exists()) {
1186
+ logger.error("skills.json not found. Run 'reskill init' first.");
1187
+ process.exit(1);
1188
+ }
1189
+ const skillManager = new SkillManager();
1190
+ const spinner = (0, __WEBPACK_EXTERNAL_MODULE_ora__["default"])(skill ? `Updating ${skill}...` : 'Updating all skills...').start();
1191
+ try {
1192
+ const updated = await skillManager.update(skill);
1193
+ spinner.stop();
1194
+ if (0 === updated.length) {
1195
+ logger.info('No skills to update');
1196
+ return;
1197
+ }
1198
+ logger.success(`Updated ${updated.length} skill(s):`);
1199
+ for (const s of updated)logger.log(` - ${s.name}@${s.version}`);
1200
+ } catch (error) {
1201
+ spinner.fail('Update failed');
1202
+ logger.error(error.message);
1203
+ process.exit(1);
1204
+ }
1205
+ });
1206
+ const outdatedCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('outdated').description('Check for outdated skills').option('-j, --json', 'Output as JSON').action(async (options)=>{
1207
+ const configLoader = new ConfigLoader();
1208
+ if (!configLoader.exists()) {
1209
+ logger.error("skills.json not found. Run 'reskill init' first.");
1210
+ process.exit(1);
1211
+ }
1212
+ const skills = configLoader.getSkills();
1213
+ if (0 === Object.keys(skills).length) {
1214
+ logger.info('No skills defined in skills.json');
1215
+ return;
1216
+ }
1217
+ const skillManager = new SkillManager();
1218
+ const spinner = (0, __WEBPACK_EXTERNAL_MODULE_ora__["default"])('Checking for updates...').start();
1219
+ try {
1220
+ const results = await skillManager.checkOutdated();
1221
+ spinner.stop();
1222
+ if (options.json) {
1223
+ console.log(JSON.stringify(results, null, 2));
1224
+ return;
1225
+ }
1226
+ const outdated = results.filter((r)=>r.updateAvailable);
1227
+ if (0 === outdated.length) {
1228
+ logger.success('All skills are up to date!');
1229
+ return;
1230
+ }
1231
+ logger["package"]('Checking for updates...');
1232
+ logger.newline();
1233
+ const headers = [
1234
+ 'Skill',
1235
+ 'Current',
1236
+ 'Latest',
1237
+ 'Status'
1238
+ ];
1239
+ const rows = results.map((r)=>[
1240
+ r.name,
1241
+ r.current,
1242
+ r.latest,
1243
+ r.updateAvailable ? __WEBPACK_EXTERNAL_MODULE_chalk__["default"].yellow('⬆️ Update available') : __WEBPACK_EXTERNAL_MODULE_chalk__["default"].green('✅ Up to date')
1244
+ ]);
1245
+ logger.table(headers, rows);
1246
+ logger.newline();
1247
+ if (outdated.length > 0) {
1248
+ logger.log(`Run ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan('reskill update')} to update all skills`);
1249
+ logger.log(`Or ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan('reskill update <skill>')} to update a specific skill`);
1250
+ }
1251
+ } catch (error) {
1252
+ spinner.fail('Check failed');
1253
+ logger.error(error.message);
1254
+ process.exit(1);
1255
+ }
1256
+ });
1257
+ 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)=>{
1258
+ const isGlobal = options.global || false;
1259
+ const skillManager = new SkillManager(void 0, {
1260
+ global: isGlobal
1261
+ });
1262
+ const result = skillManager.uninstall(skillName);
1263
+ if (!result) process.exit(1);
1264
+ });
1265
+ const linkCmd = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('link').description('Link a local skill for development').argument('<path>', 'Path to local skill directory').option('-n, --name <name>', 'Custom skill name').action((localPath, options)=>{
1266
+ const skillManager = new SkillManager();
1267
+ try {
1268
+ const linked = skillManager.link(localPath, options.name);
1269
+ logger.log(`Linked skill available at: ${linked.path}`);
1270
+ } catch (error) {
1271
+ logger.error(error.message);
1272
+ process.exit(1);
1273
+ }
1274
+ });
1275
+ const unlinkCmd = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('unlink').description('Unlink a linked skill').argument('<skill>', 'Skill name to unlink').action((skillName)=>{
1276
+ const skillManager = new SkillManager();
1277
+ const result = skillManager.unlink(skillName);
1278
+ if (!result) process.exit(1);
1279
+ });
1280
+ const linkCommand = linkCmd;
1281
+ const unlinkCommand = unlinkCmd;
1282
+ const program = new __WEBPACK_EXTERNAL_MODULE_commander__.Command();
1283
+ program.name('reskill').description('AI Skills Package Manager - Git-based skills management for AI agents').version('0.1.0');
1284
+ program.addCommand(initCommand);
1285
+ program.addCommand(installCommand);
1286
+ program.addCommand(listCommand);
1287
+ program.addCommand(infoCommand);
1288
+ program.addCommand(updateCommand);
1289
+ program.addCommand(outdatedCommand);
1290
+ program.addCommand(uninstallCommand);
1291
+ program.addCommand(linkCommand);
1292
+ program.addCommand(unlinkCommand);
1293
+ program.parse();