reskill 0.1.0 → 0.12.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 (41) hide show
  1. package/README.md +161 -104
  2. package/README.zh-CN.md +257 -0
  3. package/dist/cli/commands/index.d.ts +3 -3
  4. package/dist/cli/commands/index.d.ts.map +1 -1
  5. package/dist/cli/commands/info.d.ts +1 -1
  6. package/dist/cli/commands/init.d.ts +1 -1
  7. package/dist/cli/commands/install.d.ts +12 -4
  8. package/dist/cli/commands/install.d.ts.map +1 -1
  9. package/dist/cli/commands/list.d.ts +1 -1
  10. package/dist/cli/commands/list.d.ts.map +1 -1
  11. package/dist/cli/commands/outdated.d.ts +1 -1
  12. package/dist/cli/commands/outdated.d.ts.map +1 -1
  13. package/dist/cli/commands/uninstall.d.ts +1 -1
  14. package/dist/cli/commands/update.d.ts +1 -1
  15. package/dist/cli/index.js +999 -353
  16. package/dist/core/agent-registry.d.ts +54 -0
  17. package/dist/core/agent-registry.d.ts.map +1 -0
  18. package/dist/core/cache-manager.d.ts +20 -16
  19. package/dist/core/cache-manager.d.ts.map +1 -1
  20. package/dist/core/config-loader.d.ts +18 -18
  21. package/dist/core/config-loader.d.ts.map +1 -1
  22. package/dist/core/git-resolver.d.ts +23 -23
  23. package/dist/core/git-resolver.d.ts.map +1 -1
  24. package/dist/core/index.d.ts +8 -2
  25. package/dist/core/index.d.ts.map +1 -1
  26. package/dist/core/installer.d.ts +96 -0
  27. package/dist/core/installer.d.ts.map +1 -0
  28. package/dist/core/lock-manager.d.ts +17 -17
  29. package/dist/core/lock-manager.d.ts.map +1 -1
  30. package/dist/core/skill-manager.d.ts +83 -24
  31. package/dist/core/skill-manager.d.ts.map +1 -1
  32. package/dist/core/skill-parser.d.ts +116 -0
  33. package/dist/core/skill-parser.d.ts.map +1 -0
  34. package/dist/index.d.ts +4 -2
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +951 -323
  37. package/dist/types/index.d.ts +96 -74
  38. package/dist/types/index.d.ts.map +1 -1
  39. package/dist/utils/fs.d.ts +30 -0
  40. package/dist/utils/fs.d.ts.map +1 -1
  41. package/package.json +29 -13
package/dist/cli/index.js CHANGED
@@ -3,10 +3,12 @@ import * as __WEBPACK_EXTERNAL_MODULE_node_fs__ from "node:fs";
3
3
  import * as __WEBPACK_EXTERNAL_MODULE_commander__ from "commander";
4
4
  import * as __WEBPACK_EXTERNAL_MODULE_node_path__ from "node:path";
5
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";
6
+ import * as __WEBPACK_EXTERNAL_MODULE_node_os__ from "node:os";
8
7
  import * as __WEBPACK_EXTERNAL_MODULE_node_child_process__ from "node:child_process";
9
8
  import * as __WEBPACK_EXTERNAL_MODULE_node_util__ from "node:util";
9
+ import * as __WEBPACK_EXTERNAL_MODULE_semver__ from "semver";
10
+ import * as __WEBPACK_EXTERNAL_MODULE__clack_prompts__ from "@clack/prompts";
11
+ import * as __WEBPACK_EXTERNAL_MODULE_ora__ from "ora";
10
12
  var __webpack_modules__ = {
11
13
  "node:fs": function(module) {
12
14
  module.exports = __WEBPACK_EXTERNAL_MODULE_node_fs__;
@@ -35,7 +37,7 @@ function writeJson(filePath, data, indent = 2) {
35
37
  if (!exists(dir)) external_node_fs_.mkdirSync(dir, {
36
38
  recursive: true
37
39
  });
38
- external_node_fs_.writeFileSync(filePath, JSON.stringify(data, null, indent) + '\n', 'utf-8');
40
+ external_node_fs_.writeFileSync(filePath, `${JSON.stringify(data, null, indent)}\n`, 'utf-8');
39
41
  }
40
42
  function ensureDir(dirPath) {
41
43
  if (!exists(dirPath)) external_node_fs_.mkdirSync(dirPath, {
@@ -102,115 +104,12 @@ function getGlobalSkillsDir() {
102
104
  const home = getHomeDir();
103
105
  return __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.claude', 'skills');
104
106
  }
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
- }
107
+ function shortenPath(fullPath, cwd) {
108
+ const home = getHomeDir();
109
+ const currentDir = cwd || process.cwd();
110
+ if (fullPath.startsWith(home)) return fullPath.replace(home, '~');
111
+ if (fullPath.startsWith(currentDir)) return `.${fullPath.slice(currentDir.length)}`;
112
+ return fullPath;
214
113
  }
215
114
  const logger = {
216
115
  info (message) {
@@ -253,30 +152,139 @@ const logger = {
253
152
  }
254
153
  }
255
154
  };
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;
155
+ const agent_registry_home = (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)();
156
+ const agents = {
157
+ amp: {
158
+ name: 'amp',
159
+ displayName: 'Amp',
160
+ skillsDir: '.agents/skills',
161
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/agents/skills'),
162
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/amp'))
163
+ },
164
+ antigravity: {
165
+ name: 'antigravity',
166
+ displayName: 'Antigravity',
167
+ skillsDir: '.agent/skills',
168
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.gemini/antigravity/skills'),
169
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(process.cwd(), '.agent')) || (0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.gemini/antigravity'))
170
+ },
171
+ 'claude-code': {
172
+ name: 'claude-code',
173
+ displayName: 'Claude Code',
174
+ skillsDir: '.claude/skills',
175
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.claude/skills'),
176
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.claude'))
177
+ },
178
+ clawdbot: {
179
+ name: 'clawdbot',
180
+ displayName: 'Clawdbot',
181
+ skillsDir: 'skills',
182
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.clawdbot/skills'),
183
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.clawdbot'))
184
+ },
185
+ codex: {
186
+ name: 'codex',
187
+ displayName: 'Codex',
188
+ skillsDir: '.codex/skills',
189
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.codex/skills'),
190
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.codex'))
191
+ },
192
+ cursor: {
193
+ name: 'cursor',
194
+ displayName: 'Cursor',
195
+ skillsDir: '.cursor/skills',
196
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.cursor/skills'),
197
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.cursor'))
198
+ },
199
+ droid: {
200
+ name: 'droid',
201
+ displayName: 'Droid',
202
+ skillsDir: '.factory/skills',
203
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.factory/skills'),
204
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.factory/skills'))
205
+ },
206
+ 'gemini-cli': {
207
+ name: 'gemini-cli',
208
+ displayName: 'Gemini CLI',
209
+ skillsDir: '.gemini/skills',
210
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.gemini/skills'),
211
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.gemini'))
212
+ },
213
+ 'github-copilot': {
214
+ name: 'github-copilot',
215
+ displayName: 'GitHub Copilot',
216
+ skillsDir: '.github/skills',
217
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.copilot/skills'),
218
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(process.cwd(), '.github')) || (0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.copilot'))
219
+ },
220
+ goose: {
221
+ name: 'goose',
222
+ displayName: 'Goose',
223
+ skillsDir: '.goose/skills',
224
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/goose/skills'),
225
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/goose'))
226
+ },
227
+ kilo: {
228
+ name: 'kilo',
229
+ displayName: 'Kilo Code',
230
+ skillsDir: '.kilocode/skills',
231
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.kilocode/skills'),
232
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.kilocode'))
233
+ },
234
+ 'kiro-cli': {
235
+ name: 'kiro-cli',
236
+ displayName: 'Kiro CLI',
237
+ skillsDir: '.kiro/skills',
238
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.kiro/skills'),
239
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.kiro'))
240
+ },
241
+ opencode: {
242
+ name: 'opencode',
243
+ displayName: 'OpenCode',
244
+ skillsDir: '.opencode/skills',
245
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/opencode/skills'),
246
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/opencode')) || (0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.claude/skills'))
247
+ },
248
+ roo: {
249
+ name: 'roo',
250
+ displayName: 'Roo Code',
251
+ skillsDir: '.roo/skills',
252
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.roo/skills'),
253
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.roo'))
254
+ },
255
+ trae: {
256
+ name: 'trae',
257
+ displayName: 'Trae',
258
+ skillsDir: '.trae/skills',
259
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.trae/skills'),
260
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.trae'))
261
+ },
262
+ windsurf: {
263
+ name: 'windsurf',
264
+ displayName: 'Windsurf',
265
+ skillsDir: '.windsurf/skills',
266
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.codeium/windsurf/skills'),
267
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.codeium/windsurf'))
268
+ },
269
+ neovate: {
270
+ name: 'neovate',
271
+ displayName: 'Neovate',
272
+ skillsDir: '.neovate/skills',
273
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.neovate/skills'),
274
+ detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.neovate'))
261
275
  }
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
- });
276
+ };
277
+ async function detectInstalledAgents() {
278
+ const installed = [];
279
+ for (const [type, config] of Object.entries(agents))if (await config.detectInstalled()) installed.push(type);
280
+ return installed;
281
+ }
282
+ function getAgentConfig(type) {
283
+ return agents[type];
284
+ }
285
+ function isValidAgentType(type) {
286
+ return type in agents;
287
+ }
280
288
  const execAsync = (0, __WEBPACK_EXTERNAL_MODULE_node_util__.promisify)(__WEBPACK_EXTERNAL_MODULE_node_child_process__.exec);
281
289
  class GitCloneError extends Error {
282
290
  repoUrl;
@@ -288,7 +296,7 @@ class GitCloneError extends Error {
288
296
  if (isAuthError) {
289
297
  message += '\n\nTip: For private repos, ensure git SSH keys or credentials are configured:';
290
298
  message += '\n - SSH: Check ~/.ssh/id_rsa or ~/.ssh/id_ed25519';
291
- message += '\n - HTTPS: Run \'git config --global credential.helper store\'';
299
+ message += "\n - HTTPS: Run 'git config --global credential.helper store'";
292
300
  message += '\n - Or use a personal access token in the URL';
293
301
  }
294
302
  super(message);
@@ -447,6 +455,229 @@ function parseGitUrl(url) {
447
455
  }
448
456
  return null;
449
457
  }
458
+ class CacheManager {
459
+ cacheDir;
460
+ constructor(cacheDir){
461
+ this.cacheDir = cacheDir || getCacheDir();
462
+ }
463
+ getCacheDir() {
464
+ return this.cacheDir;
465
+ }
466
+ getSkillCachePath(parsed, version) {
467
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, parsed.registry, parsed.owner, parsed.repo, version);
468
+ }
469
+ getCachePath(parsed, version) {
470
+ return this.getSkillCachePath(parsed, version);
471
+ }
472
+ isCached(parsed, version) {
473
+ const cachePath = this.getSkillCachePath(parsed, version);
474
+ return exists(cachePath) && isDirectory(cachePath);
475
+ }
476
+ async get(parsed, version) {
477
+ const cachePath = this.getSkillCachePath(parsed, version);
478
+ if (!this.isCached(parsed, version)) return null;
479
+ const commitFile = __WEBPACK_EXTERNAL_MODULE_node_path__.join(cachePath, '.reskill-commit');
480
+ let commit = '';
481
+ try {
482
+ const fs = await import("node:fs");
483
+ if (exists(commitFile)) commit = fs.readFileSync(commitFile, 'utf-8').trim();
484
+ } catch {}
485
+ return {
486
+ path: cachePath,
487
+ commit
488
+ };
489
+ }
490
+ async cache(repoUrl, parsed, ref, version) {
491
+ const cachePath = this.getSkillCachePath(parsed, version);
492
+ if (exists(cachePath)) remove(cachePath);
493
+ ensureDir(__WEBPACK_EXTERNAL_MODULE_node_path__.dirname(cachePath));
494
+ const tempPath = `${cachePath}.tmp`;
495
+ remove(tempPath);
496
+ await clone(repoUrl, tempPath, {
497
+ depth: 1,
498
+ branch: ref
499
+ });
500
+ const commit = await getCurrentCommit(tempPath);
501
+ if (parsed.subPath) {
502
+ const subDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(tempPath, parsed.subPath);
503
+ if (!exists(subDir)) {
504
+ remove(tempPath);
505
+ throw new Error(`Subpath ${parsed.subPath} not found in repository`);
506
+ }
507
+ copyDir(subDir, cachePath, {
508
+ exclude: [
509
+ '.git'
510
+ ]
511
+ });
512
+ } else copyDir(tempPath, cachePath, {
513
+ exclude: [
514
+ '.git'
515
+ ]
516
+ });
517
+ const fs = await import("node:fs");
518
+ fs.writeFileSync(__WEBPACK_EXTERNAL_MODULE_node_path__.join(cachePath, '.reskill-commit'), commit);
519
+ remove(tempPath);
520
+ return {
521
+ path: cachePath,
522
+ commit
523
+ };
524
+ }
525
+ async copyTo(parsed, version, destPath) {
526
+ const cached = await this.get(parsed, version);
527
+ if (!cached) throw new Error(`Skill ${parsed.raw} version ${version} not found in cache`);
528
+ if (exists(destPath)) remove(destPath);
529
+ copyDir(cached.path, destPath, {
530
+ exclude: [
531
+ '.reskill-commit'
532
+ ]
533
+ });
534
+ }
535
+ clearSkill(parsed, version) {
536
+ if (version) {
537
+ const cachePath = this.getSkillCachePath(parsed, version);
538
+ remove(cachePath);
539
+ } else {
540
+ const skillDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, parsed.registry, parsed.owner, parsed.repo);
541
+ remove(skillDir);
542
+ }
543
+ }
544
+ clearAll() {
545
+ remove(this.cacheDir);
546
+ }
547
+ getStats() {
548
+ if (!exists(this.cacheDir)) return {
549
+ totalSkills: 0,
550
+ registries: []
551
+ };
552
+ const registries = listDir(this.cacheDir).filter((name)=>isDirectory(__WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, name)));
553
+ let totalSkills = 0;
554
+ for (const registry of registries){
555
+ const registryPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, registry);
556
+ const owners = listDir(registryPath).filter((name)=>isDirectory(__WEBPACK_EXTERNAL_MODULE_node_path__.join(registryPath, name)));
557
+ for (const owner of owners){
558
+ const ownerPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(registryPath, owner);
559
+ const repos = listDir(ownerPath).filter((name)=>isDirectory(__WEBPACK_EXTERNAL_MODULE_node_path__.join(ownerPath, name)));
560
+ totalSkills += repos.length;
561
+ }
562
+ }
563
+ return {
564
+ totalSkills,
565
+ registries
566
+ };
567
+ }
568
+ }
569
+ const DEFAULT_SKILLS_JSON = {
570
+ skills: {},
571
+ defaults: {
572
+ registry: 'github',
573
+ installDir: '.skills'
574
+ }
575
+ };
576
+ const DEFAULT_REGISTRIES = {
577
+ github: 'https://github.com',
578
+ gitlab: 'https://gitlab.com'
579
+ };
580
+ class ConfigLoader {
581
+ projectRoot;
582
+ configPath;
583
+ config = null;
584
+ constructor(projectRoot){
585
+ this.projectRoot = projectRoot || process.cwd();
586
+ this.configPath = getSkillsJsonPath(this.projectRoot);
587
+ }
588
+ getProjectRoot() {
589
+ return this.projectRoot;
590
+ }
591
+ getConfigPath() {
592
+ return this.configPath;
593
+ }
594
+ exists() {
595
+ return exists(this.configPath);
596
+ }
597
+ load() {
598
+ if (this.config) return this.config;
599
+ if (!this.exists()) throw new Error(`skills.json not found in ${this.projectRoot}. Run 'reskill init' first.`);
600
+ try {
601
+ this.config = readJson(this.configPath);
602
+ return this.config;
603
+ } catch (error) {
604
+ throw new Error(`Failed to parse skills.json: ${error.message}`);
605
+ }
606
+ }
607
+ reload() {
608
+ this.config = null;
609
+ return this.load();
610
+ }
611
+ save(config) {
612
+ const toSave = config || this.config;
613
+ if (!toSave) throw new Error('No config to save');
614
+ writeJson(this.configPath, toSave);
615
+ this.config = toSave;
616
+ }
617
+ create(options) {
618
+ const config = {
619
+ ...DEFAULT_SKILLS_JSON,
620
+ ...options,
621
+ skills: options?.skills || {},
622
+ defaults: {
623
+ ...DEFAULT_SKILLS_JSON.defaults,
624
+ ...options?.defaults
625
+ }
626
+ };
627
+ this.save(config);
628
+ return config;
629
+ }
630
+ getDefaults() {
631
+ const config = this.config || (this.exists() ? this.load() : DEFAULT_SKILLS_JSON);
632
+ return {
633
+ registry: config.defaults?.registry || 'github',
634
+ installDir: config.defaults?.installDir || '.skills',
635
+ targetAgents: config.defaults?.targetAgents || [],
636
+ installMode: config.defaults?.installMode || 'symlink'
637
+ };
638
+ }
639
+ getRegistryUrl(registryName) {
640
+ const config = this.config || (this.exists() ? this.load() : DEFAULT_SKILLS_JSON);
641
+ if (config.registries?.[registryName]) return config.registries[registryName];
642
+ if (DEFAULT_REGISTRIES[registryName]) return DEFAULT_REGISTRIES[registryName];
643
+ return `https://${registryName}`;
644
+ }
645
+ getInstallDir() {
646
+ const defaults = this.getDefaults();
647
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.projectRoot, defaults.installDir);
648
+ }
649
+ addSkill(name, ref) {
650
+ if (!this.config) this.load();
651
+ if (this.config) this.config.skills[name] = ref;
652
+ this.save();
653
+ }
654
+ removeSkill(name) {
655
+ if (!this.config) this.load();
656
+ if (this.config?.skills[name]) {
657
+ delete this.config.skills[name];
658
+ this.save();
659
+ return true;
660
+ }
661
+ return false;
662
+ }
663
+ getSkills() {
664
+ if (!this.config) {
665
+ if (!this.exists()) return {};
666
+ this.load();
667
+ }
668
+ return {
669
+ ...this.config?.skills
670
+ };
671
+ }
672
+ hasSkill(name) {
673
+ const skills = this.getSkills();
674
+ return name in skills;
675
+ }
676
+ getSkillRef(name) {
677
+ const skills = this.getSkills();
678
+ return skills[name];
679
+ }
680
+ }
450
681
  class GitResolver {
451
682
  defaultRegistry;
452
683
  constructor(defaultRegistry = 'github'){
@@ -619,112 +850,197 @@ class GitResolver {
619
850
  };
620
851
  }
621
852
  }
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);
853
+ const installer_AGENTS_DIR = '.agents';
854
+ const installer_SKILLS_SUBDIR = 'skills';
855
+ function installer_sanitizeName(name) {
856
+ let sanitized = name.replace(/[/\\:\0]/g, '');
857
+ sanitized = sanitized.replace(/^[.\s]+|[.\s]+$/g, '');
858
+ sanitized = sanitized.replace(/^\.+/, '');
859
+ if (!sanitized || 0 === sanitized.length) sanitized = 'unnamed-skill';
860
+ if (sanitized.length > 255) sanitized = sanitized.substring(0, 255);
861
+ return sanitized;
862
+ }
863
+ function installer_isPathSafe(basePath, targetPath) {
864
+ const normalizedBase = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(basePath));
865
+ const normalizedTarget = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(targetPath));
866
+ return normalizedTarget.startsWith(normalizedBase + __WEBPACK_EXTERNAL_MODULE_node_path__.sep) || normalizedTarget === normalizedBase;
867
+ }
868
+ function installer_getCanonicalSkillsDir(isGlobal, cwd) {
869
+ const baseDir = isGlobal ? (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)() : cwd || process.cwd();
870
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, installer_AGENTS_DIR, installer_SKILLS_SUBDIR);
871
+ }
872
+ function installer_ensureDir(dirPath) {
873
+ if (!external_node_fs_.existsSync(dirPath)) external_node_fs_.mkdirSync(dirPath, {
874
+ recursive: true
875
+ });
876
+ }
877
+ function installer_remove(targetPath) {
878
+ if (external_node_fs_.existsSync(targetPath)) external_node_fs_.rmSync(targetPath, {
879
+ recursive: true,
880
+ force: true
881
+ });
882
+ }
883
+ function copyDirectory(src, dest, options) {
884
+ const exclude = new Set(options?.exclude || [
885
+ 'README.md',
886
+ 'metadata.json'
887
+ ]);
888
+ installer_ensureDir(dest);
889
+ const entries = external_node_fs_.readdirSync(src, {
890
+ withFileTypes: true
891
+ });
892
+ for (const entry of entries){
893
+ if (exclude.has(entry.name) || entry.name.startsWith('_')) continue;
894
+ const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
895
+ const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
896
+ if (entry.isDirectory()) copyDirectory(srcPath, destPath, options);
897
+ else external_node_fs_.copyFileSync(srcPath, destPath);
636
898
  }
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 = '';
899
+ }
900
+ async function installer_createSymlink(target, linkPath) {
901
+ try {
642
902
  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
- ]
903
+ const stats = external_node_fs_.lstatSync(linkPath);
904
+ if (stats.isSymbolicLink()) {
905
+ const existingTarget = external_node_fs_.readlinkSync(linkPath);
906
+ if (__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(existingTarget) === __WEBPACK_EXTERNAL_MODULE_node_path__.resolve(target)) return true;
907
+ external_node_fs_.rmSync(linkPath);
908
+ } else external_node_fs_.rmSync(linkPath, {
909
+ recursive: true
672
910
  });
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);
911
+ } catch (err) {
912
+ if (err && 'object' == typeof err && 'code' in err) {
913
+ if ('ELOOP' === err.code) try {
914
+ external_node_fs_.rmSync(linkPath, {
915
+ force: true
916
+ });
917
+ } catch {}
918
+ }
703
919
  }
920
+ const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
921
+ installer_ensureDir(linkDir);
922
+ const relativePath = __WEBPACK_EXTERNAL_MODULE_node_path__.relative(linkDir, target);
923
+ const symlinkType = 'win32' === (0, __WEBPACK_EXTERNAL_MODULE_node_os__.platform)() ? 'junction' : void 0;
924
+ external_node_fs_.symlinkSync(relativePath, linkPath, symlinkType);
925
+ return true;
926
+ } catch {
927
+ return false;
704
928
  }
705
- clearAll() {
706
- remove(this.cacheDir);
707
- }
708
- getStats() {
709
- if (!exists(this.cacheDir)) return {
710
- totalSkills: 0,
711
- registries: []
929
+ }
930
+ class Installer {
931
+ cwd;
932
+ isGlobal;
933
+ constructor(options = {}){
934
+ this.cwd = options.cwd || process.cwd();
935
+ this.isGlobal = options.global || false;
936
+ }
937
+ getCanonicalPath(skillName) {
938
+ const sanitized = installer_sanitizeName(skillName);
939
+ const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
940
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
941
+ }
942
+ getAgentSkillPath(skillName, agentType) {
943
+ const agent = getAgentConfig(agentType);
944
+ const sanitized = installer_sanitizeName(skillName);
945
+ const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
946
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
947
+ }
948
+ async installForAgent(sourcePath, skillName, agentType, options = {}) {
949
+ const agent = getAgentConfig(agentType);
950
+ const installMode = options.mode || 'symlink';
951
+ const sanitized = installer_sanitizeName(skillName);
952
+ const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
953
+ const canonicalDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
954
+ const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
955
+ const agentDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
956
+ if (!installer_isPathSafe(canonicalBase, canonicalDir)) return {
957
+ success: false,
958
+ path: agentDir,
959
+ mode: installMode,
960
+ error: 'Invalid skill name: potential path traversal detected'
712
961
  };
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;
962
+ if (!installer_isPathSafe(agentBase, agentDir)) return {
963
+ success: false,
964
+ path: agentDir,
965
+ mode: installMode,
966
+ error: 'Invalid skill name: potential path traversal detected'
967
+ };
968
+ try {
969
+ if ('copy' === installMode) {
970
+ installer_ensureDir(agentDir);
971
+ installer_remove(agentDir);
972
+ copyDirectory(sourcePath, agentDir);
973
+ return {
974
+ success: true,
975
+ path: agentDir,
976
+ mode: 'copy'
977
+ };
978
+ }
979
+ installer_ensureDir(canonicalDir);
980
+ installer_remove(canonicalDir);
981
+ copyDirectory(sourcePath, canonicalDir);
982
+ const symlinkCreated = await installer_createSymlink(canonicalDir, agentDir);
983
+ if (!symlinkCreated) {
984
+ try {
985
+ installer_remove(agentDir);
986
+ } catch {}
987
+ installer_ensureDir(agentDir);
988
+ copyDirectory(sourcePath, agentDir);
989
+ return {
990
+ success: true,
991
+ path: agentDir,
992
+ canonicalPath: canonicalDir,
993
+ mode: 'symlink',
994
+ symlinkFailed: true
995
+ };
722
996
  }
997
+ return {
998
+ success: true,
999
+ path: agentDir,
1000
+ canonicalPath: canonicalDir,
1001
+ mode: 'symlink'
1002
+ };
1003
+ } catch (error) {
1004
+ return {
1005
+ success: false,
1006
+ path: agentDir,
1007
+ mode: installMode,
1008
+ error: error instanceof Error ? error.message : 'Unknown error'
1009
+ };
1010
+ }
1011
+ }
1012
+ async installToAgents(sourcePath, skillName, targetAgents, options = {}) {
1013
+ const results = new Map();
1014
+ for (const agent of targetAgents){
1015
+ const result = await this.installForAgent(sourcePath, skillName, agent, options);
1016
+ results.set(agent, result);
723
1017
  }
724
- return {
725
- totalSkills,
726
- registries
727
- };
1018
+ return results;
1019
+ }
1020
+ isInstalled(skillName, agentType) {
1021
+ const skillPath = this.getAgentSkillPath(skillName, agentType);
1022
+ return external_node_fs_.existsSync(skillPath);
1023
+ }
1024
+ uninstallFromAgent(skillName, agentType) {
1025
+ const skillPath = this.getAgentSkillPath(skillName, agentType);
1026
+ if (!external_node_fs_.existsSync(skillPath)) return false;
1027
+ installer_remove(skillPath);
1028
+ return true;
1029
+ }
1030
+ uninstallFromAgents(skillName, targetAgents) {
1031
+ const results = new Map();
1032
+ for (const agent of targetAgents)results.set(agent, this.uninstallFromAgent(skillName, agent));
1033
+ const canonicalPath = this.getCanonicalPath(skillName);
1034
+ if (external_node_fs_.existsSync(canonicalPath)) installer_remove(canonicalPath);
1035
+ return results;
1036
+ }
1037
+ listInstalledSkills(agentType) {
1038
+ const agent = getAgentConfig(agentType);
1039
+ const skillsDir = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
1040
+ if (!external_node_fs_.existsSync(skillsDir)) return [];
1041
+ return external_node_fs_.readdirSync(skillsDir, {
1042
+ withFileTypes: true
1043
+ }).filter((entry)=>entry.isDirectory() || entry.isSymbolicLink()).map((entry)=>entry.name);
728
1044
  }
729
1045
  }
730
1046
  const LOCKFILE_VERSION = 1;
@@ -853,8 +1169,17 @@ class SkillManager {
853
1169
  if (this.isGlobal) return getGlobalSkillsDir();
854
1170
  return this.config.getInstallDir();
855
1171
  }
1172
+ getCanonicalSkillsDir() {
1173
+ const home = process.env.HOME || process.env.USERPROFILE || '';
1174
+ const baseDir = this.isGlobal ? home : this.projectRoot;
1175
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, '.agents', 'skills');
1176
+ }
856
1177
  getSkillPath(name) {
857
- return __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getInstallDir(), name);
1178
+ const canonicalPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getCanonicalSkillsDir(), name);
1179
+ if (exists(canonicalPath)) return canonicalPath;
1180
+ const legacyPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getInstallDir(), name);
1181
+ if (exists(legacyPath)) return legacyPath;
1182
+ return canonicalPath;
858
1183
  }
859
1184
  async install(ref, options = {}) {
860
1185
  const { force = false, save = true } = options;
@@ -867,11 +1192,13 @@ class SkillManager {
867
1192
  const locked = this.lockManager.get(skillName);
868
1193
  if (locked && locked.version === version) {
869
1194
  logger.info(`${skillName}@${version} is already installed`);
870
- return this.getInstalledSkill(skillName);
1195
+ const installed = this.getInstalledSkill(skillName);
1196
+ if (installed) return installed;
871
1197
  }
872
1198
  if (!force) {
873
1199
  logger.warn(`${skillName} is already installed. Use --force to reinstall.`);
874
- return this.getInstalledSkill(skillName);
1200
+ const installed = this.getInstalledSkill(skillName);
1201
+ if (installed) return installed;
875
1202
  }
876
1203
  }
877
1204
  logger["package"](`Installing ${skillName}@${version}...`);
@@ -885,7 +1212,7 @@ class SkillManager {
885
1212
  if (exists(skillPath)) remove(skillPath);
886
1213
  await this.cache.copyTo(parsed, version, skillPath);
887
1214
  if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
888
- source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? '/' + parsed.subPath : ''}`,
1215
+ source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
889
1216
  version,
890
1217
  resolved: repoUrl,
891
1218
  commit: cacheResult.commit
@@ -893,7 +1220,9 @@ class SkillManager {
893
1220
  if (!this.isGlobal && save && this.config.exists()) this.config.addSkill(skillName, ref);
894
1221
  const locationHint = this.isGlobal ? '(global)' : '';
895
1222
  logger.success(`Installed ${skillName}@${version} to ${skillPath} ${locationHint}`.trim());
896
- return this.getInstalledSkill(skillName);
1223
+ const installed = this.getInstalledSkill(skillName);
1224
+ if (!installed) throw new Error(`Failed to get installed skill info for ${skillName}`);
1225
+ return installed;
897
1226
  }
898
1227
  async installAll(options = {}) {
899
1228
  const skills = this.config.getSkills();
@@ -960,7 +1289,7 @@ class SkillManager {
960
1289
  skillName = name || skillJson.name || skillName;
961
1290
  } catch {}
962
1291
  const linkPath = this.getSkillPath(skillName);
963
- ensureDir(this.getInstallDir());
1292
+ ensureDir(__WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath));
964
1293
  createSymlink(absolutePath, linkPath);
965
1294
  logger.success(`Linked ${skillName} → ${absolutePath}`);
966
1295
  return {
@@ -986,20 +1315,36 @@ class SkillManager {
986
1315
  return true;
987
1316
  }
988
1317
  list() {
989
- const installDir = this.getInstallDir();
990
- if (!exists(installDir)) return [];
991
1318
  const skills = [];
992
- const dirs = listDir(installDir);
993
- for (const name of dirs){
994
- const skillPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(installDir, name);
1319
+ const seenNames = new Set();
1320
+ const canonicalDir = this.getCanonicalSkillsDir();
1321
+ if (exists(canonicalDir)) for (const name of listDir(canonicalDir)){
1322
+ const skillPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalDir, name);
1323
+ if (!isDirectory(skillPath)) continue;
1324
+ const skill = this.getInstalledSkillFromPath(name, skillPath);
1325
+ if (skill) {
1326
+ skills.push(skill);
1327
+ seenNames.add(name);
1328
+ }
1329
+ }
1330
+ const legacyDir = this.getInstallDir();
1331
+ if (exists(legacyDir) && legacyDir !== canonicalDir) for (const name of listDir(legacyDir)){
1332
+ if (seenNames.has(name)) continue;
1333
+ const skillPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(legacyDir, name);
995
1334
  if (!isDirectory(skillPath)) continue;
996
- const skill = this.getInstalledSkill(name);
997
- if (skill) skills.push(skill);
1335
+ if (isSymlink(skillPath)) try {
1336
+ const realPath = getRealPath(skillPath);
1337
+ if (realPath.includes(__WEBPACK_EXTERNAL_MODULE_node_path__.join('.agents', 'skills'))) continue;
1338
+ } catch {}
1339
+ const skill = this.getInstalledSkillFromPath(name, skillPath);
1340
+ if (skill) {
1341
+ skills.push(skill);
1342
+ seenNames.add(name);
1343
+ }
998
1344
  }
999
1345
  return skills;
1000
1346
  }
1001
- getInstalledSkill(name) {
1002
- const skillPath = this.getSkillPath(name);
1347
+ getInstalledSkillFromPath(name, skillPath) {
1003
1348
  if (!exists(skillPath)) return null;
1004
1349
  const isLinked = isSymlink(skillPath);
1005
1350
  const locked = this.lockManager.get(name);
@@ -1017,6 +1362,13 @@ class SkillManager {
1017
1362
  isLinked
1018
1363
  };
1019
1364
  }
1365
+ getInstalledSkill(name) {
1366
+ const canonicalPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getCanonicalSkillsDir(), name);
1367
+ if (exists(canonicalPath)) return this.getInstalledSkillFromPath(name, canonicalPath);
1368
+ const legacyPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getInstallDir(), name);
1369
+ if (exists(legacyPath)) return this.getInstalledSkillFromPath(name, legacyPath);
1370
+ return null;
1371
+ }
1020
1372
  getInfo(name) {
1021
1373
  return {
1022
1374
  installed: this.getInstalledSkill(name),
@@ -1056,91 +1408,85 @@ class SkillManager {
1056
1408
  }
1057
1409
  return results;
1058
1410
  }
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);
1411
+ async installToAgents(ref, targetAgents, options = {}) {
1412
+ const { save = true, mode = 'symlink' } = options;
1413
+ const resolved = await this.resolver.resolve(ref);
1414
+ const { parsed, repoUrl } = resolved;
1415
+ const version = resolved.ref;
1416
+ const skillName = parsed.subPath ? __WEBPACK_EXTERNAL_MODULE_node_path__.basename(parsed.subPath) : parsed.repo;
1417
+ logger["package"](`Installing ${skillName}@${version} to ${targetAgents.length} agent(s)...`);
1418
+ let cacheResult = await this.cache.get(parsed, version);
1419
+ if (cacheResult) logger.debug(`Using cached ${skillName}@${version}`);
1420
+ else {
1421
+ logger.debug(`Caching ${skillName}@${version} from ${repoUrl}`);
1422
+ cacheResult = await this.cache.cache(repoUrl, parsed, version, version);
1109
1423
  }
1424
+ const sourcePath = this.cache.getCachePath(parsed, version);
1425
+ const installer = new Installer({
1426
+ cwd: this.projectRoot,
1427
+ global: this.isGlobal
1428
+ });
1429
+ const results = await installer.installToAgents(sourcePath, skillName, targetAgents, {
1430
+ mode: mode
1431
+ });
1432
+ if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
1433
+ source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
1434
+ version,
1435
+ resolved: repoUrl,
1436
+ commit: cacheResult.commit
1437
+ });
1438
+ if (!this.isGlobal && save && this.config.exists()) this.config.addSkill(skillName, ref);
1439
+ const successCount = Array.from(results.values()).filter((r)=>r.success).length;
1440
+ const failCount = results.size - successCount;
1441
+ if (0 === failCount) logger.success(`Installed ${skillName}@${version} to ${successCount} agent(s)`);
1442
+ else logger.warn(`Installed ${skillName}@${version} to ${successCount} agent(s), ${failCount} failed`);
1443
+ const skill = {
1444
+ name: skillName,
1445
+ path: sourcePath,
1446
+ version,
1447
+ source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`
1448
+ };
1449
+ return {
1450
+ skill,
1451
+ results
1452
+ };
1110
1453
  }
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;
1454
+ async getDefaultTargetAgents() {
1455
+ const defaults = this.config.getDefaults();
1456
+ if (defaults.targetAgents && defaults.targetAgents.length > 0) return defaults.targetAgents.filter(isValidAgentType);
1457
+ return detectInstalledAgents();
1122
1458
  }
1123
- if (options.json) {
1124
- console.log(JSON.stringify(skills, null, 2));
1125
- return;
1459
+ getDefaultInstallMode() {
1460
+ const defaults = this.config.getDefaults();
1461
+ if ('copy' === defaults.installMode || 'symlink' === defaults.installMode) return defaults.installMode;
1462
+ return 'symlink';
1463
+ }
1464
+ validateAgentTypes(agentNames) {
1465
+ const valid = [];
1466
+ const invalid = [];
1467
+ for (const name of agentNames)if (isValidAgentType(name)) valid.push(name);
1468
+ else invalid.push(name);
1469
+ return {
1470
+ valid,
1471
+ invalid
1472
+ };
1126
1473
  }
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
- });
1474
+ getAllAgentTypes() {
1475
+ return Object.keys(agents);
1476
+ }
1477
+ uninstallFromAgents(name, targetAgents) {
1478
+ const installer = new Installer({
1479
+ cwd: this.projectRoot,
1480
+ global: this.isGlobal
1481
+ });
1482
+ const results = installer.uninstallFromAgents(name, targetAgents);
1483
+ if (!this.isGlobal) this.lockManager.remove(name);
1484
+ if (!this.isGlobal && this.config.exists()) this.config.removeSkill(name);
1485
+ const successCount = Array.from(results.values()).filter((r)=>r).length;
1486
+ logger.success(`Uninstalled ${name} from ${successCount} agent(s)`);
1487
+ return results;
1488
+ }
1489
+ }
1144
1490
  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
1491
  const skillManager = new SkillManager();
1146
1492
  const info = skillManager.getInfo(skillName);
@@ -1180,29 +1526,323 @@ const infoCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('info').de
1180
1526
  }
1181
1527
  } else logger.warn(`Skill ${skillName} is not installed`);
1182
1528
  });
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)=>{
1529
+ 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)=>{
1184
1530
  const configLoader = new ConfigLoader();
1185
- if (!configLoader.exists()) {
1186
- logger.error("skills.json not found. Run 'reskill init' first.");
1531
+ if (configLoader.exists()) {
1532
+ logger.warn('skills.json already exists');
1533
+ return;
1534
+ }
1535
+ const config = configLoader.create({
1536
+ name: options.name,
1537
+ defaults: {
1538
+ registry: options.registry,
1539
+ installDir: options.installDir
1540
+ }
1541
+ });
1542
+ logger.success('Created skills.json');
1543
+ logger.newline();
1544
+ logger.log('Configuration:');
1545
+ logger.log(` Name: ${config.name || '(not set)'}`);
1546
+ logger.log(` Default registry: ${config.defaults?.registry}`);
1547
+ logger.log(` Install directory: ${config.defaults?.installDir}`);
1548
+ logger.newline();
1549
+ logger.log('Next steps:');
1550
+ logger.log(' reskill install <skill> Install a skill');
1551
+ logger.log(' reskill list List installed skills');
1552
+ });
1553
+ function formatAgentNames(agentTypes, maxShow = 5) {
1554
+ const names = agentTypes.map((a)=>agents[a].displayName);
1555
+ if (names.length <= maxShow) return names.join(', ');
1556
+ const shown = names.slice(0, maxShow);
1557
+ const remaining = names.length - maxShow;
1558
+ return `${shown.join(', ')} +${remaining} more`;
1559
+ }
1560
+ 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 user home directory').option('--no-save', 'Do not save to skills.json').option('-a, --agent <agents...>', 'Specify target agents (e.g., cursor, claude-code)').option('--mode <mode>', 'Installation mode: symlink or copy').option('-y, --yes', 'Skip confirmation prompts').option('--all', 'Install to all agents (implies -y -g)').action(async (skill, options)=>{
1561
+ if (options.all) {
1562
+ options.yes = true;
1563
+ options.global = true;
1564
+ }
1565
+ const skipConfirm = options.yes || false;
1566
+ const configLoader = new ConfigLoader();
1567
+ const allAgentTypes = Object.keys(agents);
1568
+ console.log();
1569
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.intro(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].bgCyan.black(' reskill '));
1570
+ try {
1571
+ const spinner = __WEBPACK_EXTERNAL_MODULE__clack_prompts__.spinner();
1572
+ let targetAgents;
1573
+ if (options.all) {
1574
+ targetAgents = allAgentTypes;
1575
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.info(`Installing to all ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(targetAgents.length)} agents`);
1576
+ } else if (options.agent && options.agent.length > 0) {
1577
+ const validAgents = Object.keys(agents);
1578
+ const invalidAgents = options.agent.filter((a)=>!validAgents.includes(a));
1579
+ if (invalidAgents.length > 0) {
1580
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.error(`Invalid agents: ${invalidAgents.join(', ')}`);
1581
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.info(`Valid agents: ${validAgents.join(', ')}`);
1582
+ process.exit(1);
1583
+ }
1584
+ targetAgents = options.agent;
1585
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.info(`Installing to: ${formatAgentNames(targetAgents)}`);
1586
+ } else {
1587
+ spinner.start('Detecting installed agents...');
1588
+ const installedAgents = await detectInstalledAgents();
1589
+ spinner.stop(`Detected ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green(installedAgents.length)} agent${1 !== installedAgents.length ? 's' : ''}`);
1590
+ if (0 === installedAgents.length) {
1591
+ if (skipConfirm) {
1592
+ targetAgents = allAgentTypes;
1593
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.info('Installing to all agents (none detected)');
1594
+ } else {
1595
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.warn('No coding agents detected. You can still install skills.');
1596
+ const allAgentChoices = Object.entries(agents).map(([key, config])=>({
1597
+ value: key,
1598
+ label: config.displayName
1599
+ }));
1600
+ const selected = await __WEBPACK_EXTERNAL_MODULE__clack_prompts__.multiselect({
1601
+ message: 'Select agents to install skills to',
1602
+ options: allAgentChoices,
1603
+ required: true,
1604
+ initialValues: allAgentTypes
1605
+ });
1606
+ if (__WEBPACK_EXTERNAL_MODULE__clack_prompts__.isCancel(selected)) {
1607
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.cancel('Installation cancelled');
1608
+ process.exit(0);
1609
+ }
1610
+ targetAgents = selected;
1611
+ }
1612
+ } else if (1 === installedAgents.length || skipConfirm) {
1613
+ targetAgents = installedAgents;
1614
+ if (1 === installedAgents.length) __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.info(`Installing to: ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(agents[installedAgents[0]].displayName)}`);
1615
+ else __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.info(`Installing to: ${installedAgents.map((a)=>__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(agents[a].displayName)).join(', ')}`);
1616
+ } else {
1617
+ const agentChoices = installedAgents.map((a)=>({
1618
+ value: a,
1619
+ label: agents[a].displayName,
1620
+ hint: agents[a].skillsDir
1621
+ }));
1622
+ const selected = await __WEBPACK_EXTERNAL_MODULE__clack_prompts__.multiselect({
1623
+ message: 'Select agents to install skills to',
1624
+ options: agentChoices,
1625
+ required: true,
1626
+ initialValues: installedAgents
1627
+ });
1628
+ if (__WEBPACK_EXTERNAL_MODULE__clack_prompts__.isCancel(selected)) {
1629
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.cancel('Installation cancelled');
1630
+ process.exit(0);
1631
+ }
1632
+ targetAgents = selected;
1633
+ }
1634
+ }
1635
+ let installGlobally = options.global ?? false;
1636
+ if (void 0 === options.global && !skipConfirm) {
1637
+ const scope = await __WEBPACK_EXTERNAL_MODULE__clack_prompts__.select({
1638
+ message: 'Installation scope',
1639
+ options: [
1640
+ {
1641
+ value: false,
1642
+ label: 'Project',
1643
+ hint: 'Install in current directory (committed with your project)'
1644
+ },
1645
+ {
1646
+ value: true,
1647
+ label: 'Global',
1648
+ hint: 'Install in home directory (available across all projects)'
1649
+ }
1650
+ ]
1651
+ });
1652
+ if (__WEBPACK_EXTERNAL_MODULE__clack_prompts__.isCancel(scope)) {
1653
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.cancel('Installation cancelled');
1654
+ process.exit(0);
1655
+ }
1656
+ installGlobally = scope;
1657
+ }
1658
+ let installMode = options.mode || 'symlink';
1659
+ if (!options.mode && !skipConfirm) {
1660
+ const modeChoice = await __WEBPACK_EXTERNAL_MODULE__clack_prompts__.select({
1661
+ message: 'Installation method',
1662
+ options: [
1663
+ {
1664
+ value: 'symlink',
1665
+ label: 'Symlink (Recommended)',
1666
+ hint: 'Single source of truth, easy updates'
1667
+ },
1668
+ {
1669
+ value: 'copy',
1670
+ label: 'Copy to all agents',
1671
+ hint: 'Independent copies for each agent'
1672
+ }
1673
+ ]
1674
+ });
1675
+ if (__WEBPACK_EXTERNAL_MODULE__clack_prompts__.isCancel(modeChoice)) {
1676
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.cancel('Installation cancelled');
1677
+ process.exit(0);
1678
+ }
1679
+ installMode = modeChoice;
1680
+ }
1681
+ const skillManager = new SkillManager(void 0, {
1682
+ global: installGlobally
1683
+ });
1684
+ const cwd = process.cwd();
1685
+ if (skill) {
1686
+ const summaryLines = [];
1687
+ summaryLines.push(`${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(skill)}`);
1688
+ summaryLines.push(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('→')} ${formatAgentNames(targetAgents)}`);
1689
+ summaryLines.push(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('Scope:')} ${installGlobally ? 'Global' : 'Project'}${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(', Mode:')} ${installMode}`);
1690
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.note(summaryLines.join('\n'), 'Installation Summary');
1691
+ if (!skipConfirm) {
1692
+ const confirmed = await __WEBPACK_EXTERNAL_MODULE__clack_prompts__.confirm({
1693
+ message: 'Proceed with installation?'
1694
+ });
1695
+ if (__WEBPACK_EXTERNAL_MODULE__clack_prompts__.isCancel(confirmed) || !confirmed) {
1696
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.cancel('Installation cancelled');
1697
+ process.exit(0);
1698
+ }
1699
+ }
1700
+ spinner.start(`Installing ${skill}...`);
1701
+ const { skill: installed, results } = await skillManager.installToAgents(skill, targetAgents, {
1702
+ force: options.force,
1703
+ save: options.save && !installGlobally,
1704
+ mode: installMode
1705
+ });
1706
+ spinner.stop('Installation complete');
1707
+ const successful = Array.from(results.entries()).filter(([, r])=>r.success);
1708
+ const failed = Array.from(results.entries()).filter(([, r])=>!r.success);
1709
+ const symlinkFailed = successful.filter(([, r])=>'symlink' === r.mode && r.symlinkFailed);
1710
+ if (successful.length > 0) {
1711
+ const resultLines = [];
1712
+ const firstResult = successful[0][1];
1713
+ if ('copy' === firstResult.mode) {
1714
+ resultLines.push(`${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green('✓')} ${installed.name}@${installed.version} ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('(copied)')}`);
1715
+ for (const [, result] of successful){
1716
+ const shortPath = shortenPath(result.path, cwd);
1717
+ resultLines.push(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('→')} ${shortPath}`);
1718
+ }
1719
+ } else {
1720
+ if (firstResult.canonicalPath) {
1721
+ const shortPath = shortenPath(firstResult.canonicalPath, cwd);
1722
+ resultLines.push(`${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green('✓')} ${shortPath}`);
1723
+ } else resultLines.push(`${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green('✓')} ${installed.name}@${installed.version}`);
1724
+ const symlinked = successful.filter(([, r])=>!r.symlinkFailed).map(([a])=>agents[a].displayName);
1725
+ const copied = successful.filter(([, r])=>r.symlinkFailed).map(([a])=>agents[a].displayName);
1726
+ if (symlinked.length > 0) resultLines.push(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('symlink →')} ${symlinked.join(', ')}`);
1727
+ if (copied.length > 0) resultLines.push(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].yellow('copied →')} ${copied.join(', ')}`);
1728
+ }
1729
+ const title = __WEBPACK_EXTERNAL_MODULE_chalk__["default"].green(`Installed 1 skill to ${successful.length} agent${1 !== successful.length ? 's' : ''}`);
1730
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.note(resultLines.join('\n'), title);
1731
+ if (symlinkFailed.length > 0) {
1732
+ const copiedAgentNames = symlinkFailed.map(([a])=>agents[a].displayName);
1733
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.warn(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].yellow(`Symlinks failed for: ${copiedAgentNames.join(', ')}`));
1734
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.message(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(' Files were copied instead. On Windows, enable Developer Mode for symlink support.'));
1735
+ }
1736
+ }
1737
+ if (failed.length > 0) {
1738
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.error(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].red(`Failed to install to ${failed.length} agent(s)`));
1739
+ for (const [agent, result] of failed)__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.message(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].red('✗')} ${agents[agent].displayName}: ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(result.error)}`);
1740
+ }
1741
+ } else {
1742
+ if (installGlobally) {
1743
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.error('Cannot install all skills globally. Please specify a skill to install.');
1744
+ process.exit(1);
1745
+ }
1746
+ if (!configLoader.exists()) {
1747
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.error("skills.json not found. Run 'reskill init' first.");
1748
+ process.exit(1);
1749
+ }
1750
+ const skills = configLoader.getSkills();
1751
+ if (0 === Object.keys(skills).length) {
1752
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.info('No skills defined in skills.json');
1753
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.outro('Done');
1754
+ return;
1755
+ }
1756
+ const summaryLines = [];
1757
+ summaryLines.push(`${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(Object.keys(skills).length)} skill(s) → ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(targetAgents.length)} agent(s)`);
1758
+ summaryLines.push(`${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('Scope:')} ${installGlobally ? 'Global (~/)' : 'Project (./)'}${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(', Mode:')} ${installMode}`);
1759
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.note(summaryLines.join('\n'), 'Installation Summary');
1760
+ if (!skipConfirm) {
1761
+ const confirmed = await __WEBPACK_EXTERNAL_MODULE__clack_prompts__.confirm({
1762
+ message: 'Proceed with installation?'
1763
+ });
1764
+ if (__WEBPACK_EXTERNAL_MODULE__clack_prompts__.isCancel(confirmed) || !confirmed) {
1765
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.cancel('Installation cancelled');
1766
+ process.exit(0);
1767
+ }
1768
+ }
1769
+ spinner.start('Installing skills...');
1770
+ let totalInstalled = 0;
1771
+ let totalFailed = 0;
1772
+ for (const [name, ref] of Object.entries(skills))try {
1773
+ const { results } = await skillManager.installToAgents(ref, targetAgents, {
1774
+ force: options.force,
1775
+ save: false,
1776
+ mode: installMode
1777
+ });
1778
+ const successCount = Array.from(results.values()).filter((r)=>r.success).length;
1779
+ totalInstalled += successCount;
1780
+ totalFailed += results.size - successCount;
1781
+ } catch (error) {
1782
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.error(`Failed to install ${name}: ${error.message}`);
1783
+ totalFailed += targetAgents.length;
1784
+ }
1785
+ spinner.stop('Installation complete');
1786
+ if (0 === totalFailed) __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.success(`Installed ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green(Object.keys(skills).length)} skill(s) to ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green(targetAgents.length)} agent(s)`);
1787
+ else __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.warn(`Installed ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green(totalInstalled)} successfully, ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].red(totalFailed)} failed`);
1788
+ }
1789
+ console.log();
1790
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.outro(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green('Done!'));
1791
+ } catch (error) {
1792
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.error(error.message);
1793
+ __WEBPACK_EXTERNAL_MODULE__clack_prompts__.outro(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].red('Installation failed'));
1187
1794
  process.exit(1);
1188
1795
  }
1796
+ });
1797
+ 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)=>{
1189
1798
  const skillManager = new SkillManager();
1190
- const spinner = (0, __WEBPACK_EXTERNAL_MODULE_ora__["default"])(skill ? `Updating ${skill}...` : 'Updating all skills...').start();
1191
1799
  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}`);
1800
+ const linked = skillManager.link(localPath, options.name);
1801
+ logger.log(`Linked skill available at: ${linked.path}`);
1200
1802
  } catch (error) {
1201
- spinner.fail('Update failed');
1202
1803
  logger.error(error.message);
1203
1804
  process.exit(1);
1204
1805
  }
1205
1806
  });
1807
+ const unlinkCmd = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('unlink').description('Unlink a linked skill').argument('<skill>', 'Skill name to unlink').action((skillName)=>{
1808
+ const skillManager = new SkillManager();
1809
+ const result = skillManager.unlink(skillName);
1810
+ if (!result) process.exit(1);
1811
+ });
1812
+ const linkCommand = linkCmd;
1813
+ const unlinkCommand = unlinkCmd;
1814
+ 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)=>{
1815
+ const isGlobal = options.global || false;
1816
+ const skillManager = new SkillManager(void 0, {
1817
+ global: isGlobal
1818
+ });
1819
+ const skills = skillManager.list();
1820
+ if (0 === skills.length) {
1821
+ const location = isGlobal ? 'globally' : 'in this project';
1822
+ logger.info(`No skills installed ${location}`);
1823
+ return;
1824
+ }
1825
+ if (options.json) {
1826
+ console.log(JSON.stringify(skills, null, 2));
1827
+ return;
1828
+ }
1829
+ const locationLabel = isGlobal ? __WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(' (global)') : '';
1830
+ logger.log(`Installed Skills (${skillManager.getInstallDir()})${locationLabel}:`);
1831
+ logger.newline();
1832
+ const headers = [
1833
+ 'Name',
1834
+ 'Version',
1835
+ 'Source'
1836
+ ];
1837
+ const rows = skills.map((skill)=>[
1838
+ skill.name,
1839
+ skill.isLinked ? `${skill.version} (linked)` : skill.version,
1840
+ skill.source || '-'
1841
+ ]);
1842
+ logger.table(headers, rows);
1843
+ logger.newline();
1844
+ logger.log(`Total: ${skills.length} skill(s)`);
1845
+ });
1206
1846
  const outdatedCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('outdated').description('Check for outdated skills').option('-j, --json', 'Output as JSON').action(async (options)=>{
1207
1847
  const configLoader = new ConfigLoader();
1208
1848
  if (!configLoader.exists()) {
@@ -1262,23 +1902,29 @@ const uninstallCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('unin
1262
1902
  const result = skillManager.uninstall(skillName);
1263
1903
  if (!result) process.exit(1);
1264
1904
  });
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)=>{
1905
+ 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)=>{
1906
+ const configLoader = new ConfigLoader();
1907
+ if (!configLoader.exists()) {
1908
+ logger.error("skills.json not found. Run 'reskill init' first.");
1909
+ process.exit(1);
1910
+ }
1266
1911
  const skillManager = new SkillManager();
1912
+ const spinner = (0, __WEBPACK_EXTERNAL_MODULE_ora__["default"])(skill ? `Updating ${skill}...` : 'Updating all skills...').start();
1267
1913
  try {
1268
- const linked = skillManager.link(localPath, options.name);
1269
- logger.log(`Linked skill available at: ${linked.path}`);
1914
+ const updated = await skillManager.update(skill);
1915
+ spinner.stop();
1916
+ if (0 === updated.length) {
1917
+ logger.info('No skills to update');
1918
+ return;
1919
+ }
1920
+ logger.success(`Updated ${updated.length} skill(s):`);
1921
+ for (const s of updated)logger.log(` - ${s.name}@${s.version}`);
1270
1922
  } catch (error) {
1923
+ spinner.fail('Update failed');
1271
1924
  logger.error(error.message);
1272
1925
  process.exit(1);
1273
1926
  }
1274
1927
  });
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
1928
  const program = new __WEBPACK_EXTERNAL_MODULE_commander__.Command();
1283
1929
  program.name('reskill').description('AI Skills Package Manager - Git-based skills management for AI agents').version('0.1.0');
1284
1930
  program.addCommand(initCommand);