@empjs/skill 1.0.6 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -34,14 +34,16 @@ var import_path = require("path");
34
34
  var import_url = require("url");
35
35
 
36
36
  // src/commands/agents.ts
37
- var import_node_fs = __toESM(require("fs"), 1);
37
+ var import_node_fs2 = __toESM(require("fs"), 1);
38
38
  var import_node_os2 = __toESM(require("os"), 1);
39
39
  var import_chalk = __toESM(require("chalk"), 1);
40
40
 
41
41
  // src/config/agents.ts
42
+ var import_node_fs = __toESM(require("fs"), 1);
42
43
  var import_node_os = __toESM(require("os"), 1);
43
44
  var import_node_path = __toESM(require("path"), 1);
44
45
  var HOME = import_node_os.default.homedir();
46
+ var CONFIG_HOME = process.env.XDG_CONFIG_HOME || import_node_path.default.join(HOME, ".config");
45
47
  function getAgentSkillsDirs(agent, cwd) {
46
48
  if (agent.skillsDirs) {
47
49
  if (typeof agent.skillsDirs === "function") {
@@ -56,21 +58,44 @@ function getAgentSkillsDirs(agent, cwd) {
56
58
  }
57
59
  var AGENTS = [
58
60
  {
59
- name: "claude",
60
- displayName: "Claude Code",
61
- skillsDir: import_node_path.default.join(HOME, ".claude", "skills"),
61
+ name: "amp",
62
+ displayName: "AMP",
63
+ skillsDirs: (cwd) => {
64
+ const dirs = [import_node_path.default.join(CONFIG_HOME, "agents", "skills")];
65
+ if (cwd) dirs.push(import_node_path.default.join(cwd, ".agents", "skills"));
66
+ return dirs;
67
+ },
62
68
  enabled: true
63
69
  },
64
70
  {
65
- name: "cursor",
66
- displayName: "Cursor",
67
- skillsDir: import_node_path.default.join(HOME, ".cursor", "skills"),
71
+ name: "antigravity",
72
+ displayName: "Antigravity",
73
+ skillsDirs: (cwd) => {
74
+ const dirs = [import_node_path.default.join(HOME, ".gemini", "antigravity", "skills")];
75
+ if (cwd) dirs.push(import_node_path.default.join(cwd, ".agent", "skills"));
76
+ if (cwd) dirs.push(import_node_path.default.join(cwd, ".shared", "skills"));
77
+ return dirs;
78
+ },
68
79
  enabled: true
69
80
  },
70
81
  {
71
- name: "windsurf",
72
- displayName: "Windsurf",
73
- skillsDir: import_node_path.default.join(HOME, ".windsurf", "skills"),
82
+ name: "claude",
83
+ displayName: "Claude Code",
84
+ skillsDir: import_node_path.default.join(process.env.CLAUDE_CONFIG_DIR?.trim() || import_node_path.default.join(HOME, ".claude"), "skills"),
85
+ enabled: true
86
+ },
87
+ {
88
+ name: "clawdbot",
89
+ displayName: "ClawdBot",
90
+ skillsDirs: () => {
91
+ const openclaw = import_node_path.default.join(HOME, ".openclaw", "skills");
92
+ const clawdbot = import_node_path.default.join(HOME, ".clawdbot", "skills");
93
+ const moltbot = import_node_path.default.join(HOME, ".moltbot", "skills");
94
+ if (import_node_fs.default.existsSync(import_node_path.default.join(HOME, ".openclaw"))) return [openclaw];
95
+ if (import_node_fs.default.existsSync(import_node_path.default.join(HOME, ".clawdbot"))) return [clawdbot];
96
+ if (import_node_fs.default.existsSync(import_node_path.default.join(HOME, ".moltbot"))) return [moltbot];
97
+ return [openclaw];
98
+ },
74
99
  enabled: true
75
100
  },
76
101
  {
@@ -79,9 +104,29 @@ var AGENTS = [
79
104
  skillsDir: import_node_path.default.join(HOME, ".cline", "skills"),
80
105
  enabled: true
81
106
  },
107
+ {
108
+ name: "codex",
109
+ displayName: "Codex",
110
+ skillsDir: import_node_path.default.join(process.env.CODEX_HOME?.trim() || import_node_path.default.join(HOME, ".codex"), "skills"),
111
+ enabled: true
112
+ },
113
+ {
114
+ name: "cursor",
115
+ displayName: "Cursor",
116
+ skillsDir: import_node_path.default.join(HOME, ".cursor", "skills"),
117
+ enabled: true,
118
+ /** Cursor does not follow symlinks to discover skills (known bug). Use copy instead. */
119
+ useCopyInsteadOfSymlink: true
120
+ },
121
+ {
122
+ name: "droid",
123
+ displayName: "Droid",
124
+ skillsDir: import_node_path.default.join(HOME, ".factory", "skills"),
125
+ enabled: true
126
+ },
82
127
  {
83
128
  name: "gemini",
84
- displayName: "Gemini Code",
129
+ displayName: "Gemini",
85
130
  skillsDir: import_node_path.default.join(HOME, ".gemini", "skills"),
86
131
  enabled: true
87
132
  },
@@ -92,47 +137,31 @@ var AGENTS = [
92
137
  enabled: true
93
138
  },
94
139
  {
95
- name: "opencode",
96
- displayName: "OpenCode",
97
- skillsDir: import_node_path.default.join(HOME, ".opencode", "skills"),
140
+ name: "goose",
141
+ displayName: "Goose",
142
+ skillsDir: import_node_path.default.join(CONFIG_HOME, "goose", "skills"),
98
143
  enabled: true
99
144
  },
100
145
  {
101
- name: "antigravity",
102
- displayName: "Antigravity",
103
- skillsDirs: (cwd) => {
104
- const dirs = [];
105
- dirs.push(import_node_path.default.join(HOME, ".gemini", "antigravity", "skills"));
106
- if (cwd) {
107
- dirs.push(import_node_path.default.join(cwd, ".agent", "skills"));
108
- }
109
- if (cwd) {
110
- dirs.push(import_node_path.default.join(cwd, ".shared", "skills"));
111
- }
112
- return dirs;
113
- },
146
+ name: "kilo",
147
+ displayName: "Kilo Code",
148
+ skillsDir: import_node_path.default.join(HOME, ".kilocode", "skills"),
114
149
  enabled: true
115
150
  },
116
151
  {
117
152
  name: "kiro",
118
- displayName: "Kiro",
153
+ displayName: "Kiro CLI",
119
154
  skillsDir: import_node_path.default.join(HOME, ".kiro", "skills"),
120
155
  enabled: true
121
156
  },
122
157
  {
123
- name: "codex",
124
- displayName: "Codex CLI",
125
- skillsDir: import_node_path.default.join(HOME, ".codex", "skills"),
126
- enabled: true
127
- },
128
- {
129
- name: "qoder",
130
- displayName: "Qoder",
131
- skillsDir: import_node_path.default.join(HOME, ".qoder", "skills"),
158
+ name: "opencode",
159
+ displayName: "OpenCode",
160
+ skillsDir: import_node_path.default.join(CONFIG_HOME, "opencode", "skills"),
132
161
  enabled: true
133
162
  },
134
163
  {
135
- name: "roocode",
164
+ name: "roo",
136
165
  displayName: "Roo Code",
137
166
  skillsDir: import_node_path.default.join(HOME, ".roo", "skills"),
138
167
  enabled: true
@@ -143,6 +172,24 @@ var AGENTS = [
143
172
  skillsDir: import_node_path.default.join(HOME, ".trae", "skills"),
144
173
  enabled: true
145
174
  },
175
+ {
176
+ name: "windsurf",
177
+ displayName: "Windsurf",
178
+ skillsDirs: () => {
179
+ const dirs = [];
180
+ dirs.push(import_node_path.default.join(HOME, ".windsurf", "skills"));
181
+ dirs.push(import_node_path.default.join(HOME, ".codeium", "windsurf", "skills"));
182
+ return dirs;
183
+ },
184
+ enabled: true
185
+ },
186
+ // Additional agents
187
+ {
188
+ name: "qoder",
189
+ displayName: "Qoder",
190
+ skillsDir: import_node_path.default.join(HOME, ".qoder", "skills"),
191
+ enabled: true
192
+ },
146
193
  {
147
194
  name: "continue",
148
195
  displayName: "Continue",
@@ -168,7 +215,7 @@ function agents() {
168
215
  } else {
169
216
  console.log(import_chalk.default.gray(` Directories${dirsInfo}:`));
170
217
  for (const dir of skillsDirs) {
171
- const exists = import_node_fs.default.existsSync(dir);
218
+ const exists = import_node_fs2.default.existsSync(dir);
172
219
  const status = exists ? import_chalk.default.green("\u2713") : import_chalk.default.gray("\u25CB");
173
220
  const pathColor = exists ? import_chalk.default.white : import_chalk.default.gray;
174
221
  console.log(` ${status} ${pathColor(dir)}`);
@@ -177,7 +224,7 @@ function agents() {
177
224
  console.log("");
178
225
  }
179
226
  console.log(import_chalk.default.bold("\u{1F4E6} Shared Skills Directory:"));
180
- const sharedExists = import_node_fs.default.existsSync(SHARED_SKILLS_DIR);
227
+ const sharedExists = import_node_fs2.default.existsSync(SHARED_SKILLS_DIR);
181
228
  const sharedStatus = sharedExists ? import_chalk.default.green("\u2713") : import_chalk.default.gray("\u25CB");
182
229
  const sharedPathColor = sharedExists ? import_chalk.default.white : import_chalk.default.gray;
183
230
  console.log(` ${sharedStatus} ${sharedPathColor(SHARED_SKILLS_DIR)}`);
@@ -191,7 +238,7 @@ function agents() {
191
238
 
192
239
  // src/commands/install.ts
193
240
  var import_node_child_process2 = require("child_process");
194
- var import_node_fs5 = __toESM(require("fs"), 1);
241
+ var import_node_fs6 = __toESM(require("fs"), 1);
195
242
  var import_node_os3 = __toESM(require("os"), 1);
196
243
  var import_node_path5 = __toESM(require("path"), 1);
197
244
  var import_node_util2 = require("util");
@@ -323,6 +370,10 @@ var Logger = class {
323
370
  if (this.spinner) this.spinner.stop();
324
371
  console.log(import_chalk2.default.red("\u2717"), message);
325
372
  }
373
+ dim(message) {
374
+ if (this.spinner) this.spinner.stop();
375
+ console.log(import_chalk2.default.dim(" " + message));
376
+ }
326
377
  start(message) {
327
378
  if (this.spinner) this.spinner.stop();
328
379
  this.spinner = (0, import_ora.default)(message).start();
@@ -359,7 +410,7 @@ var Logger = class {
359
410
  var logger = new Logger();
360
411
 
361
412
  // src/utils/paths.ts
362
- var import_node_fs2 = __toESM(require("fs"), 1);
413
+ var import_node_fs3 = __toESM(require("fs"), 1);
363
414
  var import_node_path2 = __toESM(require("path"), 1);
364
415
  function getSharedSkillPath(skillName) {
365
416
  return import_node_path2.default.join(SHARED_SKILLS_DIR, skillName);
@@ -373,8 +424,8 @@ function getAgentSkillPaths(agentName, skillName, cwd) {
373
424
  return skillsDirs.map((dir) => import_node_path2.default.join(dir, skillName));
374
425
  }
375
426
  function ensureSharedDir() {
376
- if (!import_node_fs2.default.existsSync(SHARED_SKILLS_DIR)) {
377
- import_node_fs2.default.mkdirSync(SHARED_SKILLS_DIR, { recursive: true });
427
+ if (!import_node_fs3.default.existsSync(SHARED_SKILLS_DIR)) {
428
+ import_node_fs3.default.mkdirSync(SHARED_SKILLS_DIR, { recursive: true });
378
429
  }
379
430
  }
380
431
  function detectInstalledAgents(cwd) {
@@ -382,7 +433,7 @@ function detectInstalledAgents(cwd) {
382
433
  try {
383
434
  const skillsDirs = getAgentSkillsDirs(agent, cwd);
384
435
  return skillsDirs.some((dir) => {
385
- return import_node_fs2.default.existsSync(dir) || import_node_fs2.default.existsSync(import_node_path2.default.dirname(dir));
436
+ return import_node_fs3.default.existsSync(dir) || import_node_fs3.default.existsSync(import_node_path2.default.dirname(dir));
386
437
  });
387
438
  } catch {
388
439
  return false;
@@ -403,7 +454,7 @@ function extractSkillName(nameOrPath) {
403
454
 
404
455
  // src/utils/registry.ts
405
456
  var import_node_child_process = require("child_process");
406
- var import_node_fs3 = __toESM(require("fs"), 1);
457
+ var import_node_fs4 = __toESM(require("fs"), 1);
407
458
  var import_node_path3 = __toESM(require("path"), 1);
408
459
  var import_node_util = require("util");
409
460
  var execAsync = (0, import_node_util.promisify)(import_node_child_process.exec);
@@ -411,7 +462,7 @@ function findNpmrc(startDir) {
411
462
  let currentDir = import_node_path3.default.resolve(startDir);
412
463
  while (currentDir !== import_node_path3.default.dirname(currentDir)) {
413
464
  const npmrcPath = import_node_path3.default.join(currentDir, ".npmrc");
414
- if (import_node_fs3.default.existsSync(npmrcPath)) {
465
+ if (import_node_fs4.default.existsSync(npmrcPath)) {
415
466
  return npmrcPath;
416
467
  }
417
468
  currentDir = import_node_path3.default.dirname(currentDir);
@@ -420,7 +471,7 @@ function findNpmrc(startDir) {
420
471
  }
421
472
  function parseNpmrc(npmrcPath) {
422
473
  try {
423
- const content = import_node_fs3.default.readFileSync(npmrcPath, "utf-8");
474
+ const content = import_node_fs4.default.readFileSync(npmrcPath, "utf-8");
424
475
  const lines = content.split("\n");
425
476
  for (const line of lines) {
426
477
  const trimmed = line.trim();
@@ -463,33 +514,50 @@ async function getRegistry(cwd = process.cwd()) {
463
514
  }
464
515
 
465
516
  // src/utils/symlink.ts
466
- var import_node_fs4 = __toESM(require("fs"), 1);
517
+ var import_node_fs5 = __toESM(require("fs"), 1);
467
518
  var import_node_path4 = __toESM(require("path"), 1);
519
+ function copyDir(src, dest) {
520
+ import_node_fs5.default.mkdirSync(dest, { recursive: true });
521
+ const entries = import_node_fs5.default.readdirSync(src, { withFileTypes: true });
522
+ for (const entry of entries) {
523
+ if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
524
+ const srcPath = import_node_path4.default.join(src, entry.name);
525
+ const destPath = import_node_path4.default.join(dest, entry.name);
526
+ if (entry.isDirectory()) {
527
+ copyDir(srcPath, destPath);
528
+ } else {
529
+ import_node_fs5.default.copyFileSync(srcPath, destPath);
530
+ }
531
+ }
532
+ }
468
533
  function createSymlink(skillName, agent, cwd) {
469
534
  const source = getSharedSkillPath(skillName);
470
- if (!import_node_fs4.default.existsSync(source)) {
535
+ if (!import_node_fs5.default.existsSync(source)) {
471
536
  logger.error(`Skill not found: ${source}`);
472
537
  return false;
473
538
  }
474
539
  const targets = getAgentSkillPaths(agent.name, skillName, cwd);
540
+ const useCopy = agent.useCopyInsteadOfSymlink === true;
475
541
  let successCount = 0;
476
542
  for (const target of targets) {
477
543
  const targetDir = import_node_path4.default.dirname(target);
478
- if (!import_node_fs4.default.existsSync(targetDir)) {
544
+ if (!import_node_fs5.default.existsSync(targetDir)) {
479
545
  try {
480
- import_node_fs4.default.mkdirSync(targetDir, { recursive: true });
546
+ import_node_fs5.default.mkdirSync(targetDir, { recursive: true });
481
547
  } catch (error) {
482
548
  logger.error(`Failed to create directory ${targetDir}: ${error.message}`);
483
549
  continue;
484
550
  }
485
551
  }
486
- if (import_node_fs4.default.existsSync(target)) {
552
+ if (import_node_fs5.default.existsSync(target)) {
487
553
  try {
488
- const stats = import_node_fs4.default.lstatSync(target);
554
+ const stats = import_node_fs5.default.lstatSync(target);
489
555
  if (stats.isSymbolicLink()) {
490
- import_node_fs4.default.unlinkSync(target);
556
+ import_node_fs5.default.unlinkSync(target);
557
+ } else if (stats.isDirectory()) {
558
+ import_node_fs5.default.rmSync(target, { recursive: true, force: true });
491
559
  } else {
492
- logger.warn(`Target exists but is not a symlink, skipping: ${target}`);
560
+ logger.warn(`Target exists but is not a symlink/dir, skipping: ${target}`);
493
561
  continue;
494
562
  }
495
563
  } catch (error) {
@@ -498,10 +566,14 @@ function createSymlink(skillName, agent, cwd) {
498
566
  }
499
567
  }
500
568
  try {
501
- import_node_fs4.default.symlinkSync(source, target, "dir");
569
+ if (useCopy) {
570
+ copyDir(source, target);
571
+ } else {
572
+ import_node_fs5.default.symlinkSync(source, target, "dir");
573
+ }
502
574
  successCount++;
503
575
  } catch (error) {
504
- logger.error(`Failed to create symlink at ${target}: ${error.message}`);
576
+ logger.error(`Failed to ${useCopy ? "copy" : "symlink"} at ${target}: ${error.message}`);
505
577
  }
506
578
  }
507
579
  if (successCount > 0) {
@@ -515,19 +587,22 @@ function removeSymlink(skillName, agent, cwd) {
515
587
  const targets = getAgentSkillPaths(agent.name, skillName, cwd);
516
588
  let removedCount = 0;
517
589
  for (const target of targets) {
518
- if (!import_node_fs4.default.existsSync(target)) {
590
+ if (!import_node_fs5.default.existsSync(target)) {
519
591
  continue;
520
592
  }
521
593
  try {
522
- const stats = import_node_fs4.default.lstatSync(target);
594
+ const stats = import_node_fs5.default.lstatSync(target);
523
595
  if (stats.isSymbolicLink()) {
524
- import_node_fs4.default.unlinkSync(target);
596
+ import_node_fs5.default.unlinkSync(target);
597
+ removedCount++;
598
+ } else if (stats.isDirectory()) {
599
+ import_node_fs5.default.rmSync(target, { recursive: true, force: true });
525
600
  removedCount++;
526
601
  } else {
527
- logger.warn(`Not a symlink: ${target}`);
602
+ logger.warn(`Not a symlink or directory: ${target}`);
528
603
  }
529
604
  } catch (error) {
530
- logger.error(`Failed to remove symlink at ${target}: ${error.message}`);
605
+ logger.error(`Failed to remove at ${target}: ${error.message}`);
531
606
  }
532
607
  }
533
608
  if (removedCount > 0) {
@@ -539,7 +614,7 @@ function removeSymlink(skillName, agent, cwd) {
539
614
  }
540
615
  function isSymlink(filePath) {
541
616
  try {
542
- const stats = import_node_fs4.default.lstatSync(filePath);
617
+ const stats = import_node_fs5.default.lstatSync(filePath);
543
618
  return stats.isSymbolicLink();
544
619
  } catch {
545
620
  return false;
@@ -547,7 +622,7 @@ function isSymlink(filePath) {
547
622
  }
548
623
  function readSymlink(filePath) {
549
624
  try {
550
- return import_node_fs4.default.readlinkSync(filePath);
625
+ return import_node_fs5.default.readlinkSync(filePath);
551
626
  } catch {
552
627
  return null;
553
628
  }
@@ -577,11 +652,20 @@ async function execWithTimeout(command, timeout = 12e4, env) {
577
652
  }
578
653
  }
579
654
  async function install(skillNameOrPath, options = {}) {
580
- logger.info(`Installing skill: ${skillNameOrPath}`);
655
+ const isGit = isGitUrl(skillNameOrPath);
656
+ if (isGit) {
657
+ logger.info("Installing from Git URL");
658
+ logger.dim(skillNameOrPath);
659
+ } else {
660
+ logger.info(`Installing skill: ${skillNameOrPath}`);
661
+ }
581
662
  ensureSharedDir();
582
663
  let skillPath;
583
664
  let skillName;
584
- if (isGitUrl(skillNameOrPath)) {
665
+ if (process.env.DEBUG_ESKILL) {
666
+ logger.dim(`[DEBUG] isGitUrl=${isGit}, parseGitUrl=${parseGitUrl(skillNameOrPath) ? "ok" : "null"}`);
667
+ }
668
+ if (isGit) {
585
669
  const gitInfo = parseGitUrl(skillNameOrPath);
586
670
  if (!gitInfo) {
587
671
  logger.error(`Invalid git URL: ${skillNameOrPath}`);
@@ -593,21 +677,17 @@ async function install(skillNameOrPath, options = {}) {
593
677
  const cloneDir = import_node_path5.default.join(tempDir, "repo");
594
678
  try {
595
679
  const timeout = options.timeout || 12e4;
596
- const spinner = logger.start(`Cloning ${gitInfo.gitUrl}...`);
597
- logger.infoWithoutStop(`Repository: ${gitInfo.gitUrl}`);
598
- if (gitInfo.branch) {
599
- logger.infoWithoutStop(`Branch: ${gitInfo.branch}`);
600
- }
601
- if (gitInfo.path) {
602
- logger.infoWithoutStop(`Path: ${gitInfo.path}`);
603
- }
604
- logger.infoWithoutStop(`Timeout: ${timeout / 1e3}s`);
605
- import_node_fs5.default.mkdirSync(tempDir, { recursive: true });
680
+ const gitDetails = [`${gitInfo.gitUrl}`];
681
+ if (gitInfo.branch) gitDetails.push(`branch: ${gitInfo.branch}`);
682
+ if (gitInfo.path) gitDetails.push(`path: ${gitInfo.path}`);
683
+ logger.dim(gitDetails.join(" \xB7 "));
684
+ const spinner = logger.start(`Cloning...`);
685
+ import_node_fs6.default.mkdirSync(tempDir, { recursive: true });
606
686
  const branchFlag = gitInfo.branch ? `-b ${gitInfo.branch}` : "";
607
687
  const cloneCommand = branchFlag ? `git clone ${branchFlag} ${gitInfo.gitUrl} ${cloneDir} --depth 1 --quiet` : `git clone ${gitInfo.gitUrl} ${cloneDir} --depth 1 --quiet`;
608
688
  try {
609
689
  await execWithTimeout(cloneCommand, timeout);
610
- spinner.succeed(`Repository cloned successfully`);
690
+ spinner.succeed(`Cloned successfully`);
611
691
  } catch (error) {
612
692
  spinner.fail("Clone failed");
613
693
  if (error.message.includes("timeout")) {
@@ -624,7 +704,7 @@ async function install(skillNameOrPath, options = {}) {
624
704
  }
625
705
  if (gitInfo.path) {
626
706
  skillPath = import_node_path5.default.join(cloneDir, gitInfo.path);
627
- if (!import_node_fs5.default.existsSync(skillPath)) {
707
+ if (!import_node_fs6.default.existsSync(skillPath)) {
628
708
  logger.error(`Path not found in repository: ${gitInfo.path}`);
629
709
  logger.info(`Repository cloned to: ${cloneDir}`);
630
710
  process.exit(1);
@@ -633,7 +713,7 @@ async function install(skillNameOrPath, options = {}) {
633
713
  skillPath = cloneDir;
634
714
  }
635
715
  const skillMdPath = import_node_path5.default.join(skillPath, "SKILL.md");
636
- if (!import_node_fs5.default.existsSync(skillMdPath)) {
716
+ if (!import_node_fs6.default.existsSync(skillMdPath)) {
637
717
  logger.warn(`Warning: SKILL.md not found in ${skillPath}`);
638
718
  logger.info("The directory may not be a valid skill package");
639
719
  }
@@ -655,16 +735,16 @@ Tried to clone: ${gitInfo.gitUrl}`);
655
735
  }
656
736
  process.exit(1);
657
737
  }
658
- } else if (options.link || import_node_fs5.default.existsSync(skillNameOrPath)) {
738
+ } else if (options.link || import_node_fs6.default.existsSync(skillNameOrPath)) {
659
739
  skillPath = import_node_path5.default.resolve(skillNameOrPath);
660
- if (!import_node_fs5.default.existsSync(skillPath)) {
740
+ if (!import_node_fs6.default.existsSync(skillPath)) {
661
741
  logger.error(`Path not found: ${skillPath}`);
662
742
  process.exit(1);
663
743
  }
664
744
  const pkgPath = import_node_path5.default.join(skillPath, "package.json");
665
- if (import_node_fs5.default.existsSync(pkgPath)) {
745
+ if (import_node_fs6.default.existsSync(pkgPath)) {
666
746
  try {
667
- const pkg = JSON.parse(import_node_fs5.default.readFileSync(pkgPath, "utf-8"));
747
+ const pkg = JSON.parse(import_node_fs6.default.readFileSync(pkgPath, "utf-8"));
668
748
  skillName = extractSkillName(pkg.name);
669
749
  } catch {
670
750
  skillName = extractSkillName(import_node_path5.default.basename(skillPath));
@@ -681,12 +761,12 @@ Tried to clone: ${gitInfo.gitUrl}`);
681
761
  const spinner = logger.start(`Installing ${skillNameOrPath}...`);
682
762
  logger.infoWithoutStop(`Registry: ${registry}`);
683
763
  logger.infoWithoutStop(`Timeout: ${timeout / 1e3}s`);
684
- import_node_fs5.default.mkdirSync(tempDir, { recursive: true });
764
+ import_node_fs6.default.mkdirSync(tempDir, { recursive: true });
685
765
  logger.updateSpinner(`Downloading ${skillNameOrPath} from ${registry}...`);
686
766
  const homeDir = process.env.HOME || process.env.USERPROFILE || import_node_os3.default.homedir();
687
767
  const npmCacheDir = import_node_path5.default.join(homeDir, ".npm");
688
768
  const npmConfigPrefix = import_node_path5.default.join(homeDir, ".npm-global");
689
- import_node_fs5.default.mkdirSync(npmCacheDir, { recursive: true });
769
+ import_node_fs6.default.mkdirSync(npmCacheDir, { recursive: true });
690
770
  const installCommand = `npm install ${skillNameOrPath} --prefix ${tempDir} --registry=${registry} --no-save --silent --no-bin-links --prefer-offline`;
691
771
  const env = {
692
772
  ...process.env,
@@ -767,7 +847,7 @@ Tried to clone: ${gitInfo.gitUrl}`);
767
847
  process.exit(1);
768
848
  }
769
849
  skillPath = import_node_path5.default.join(tempDir, "node_modules", skillNameOrPath);
770
- if (!import_node_fs5.default.existsSync(skillPath)) {
850
+ if (!import_node_fs6.default.existsSync(skillPath)) {
771
851
  logger.error(`Failed to download package: ${skillNameOrPath}`);
772
852
  process.exit(1);
773
853
  }
@@ -777,21 +857,24 @@ Tried to clone: ${gitInfo.gitUrl}`);
777
857
  }
778
858
  }
779
859
  const targetPath = getSharedSkillPath(skillName);
780
- if (import_node_fs5.default.existsSync(targetPath)) {
860
+ const sourceIsTarget = import_node_path5.default.resolve(skillPath) === import_node_path5.default.resolve(targetPath);
861
+ const alreadyExists = import_node_fs6.default.existsSync(targetPath) && !sourceIsTarget;
862
+ if (alreadyExists) {
781
863
  if (options.force) {
782
864
  logger.warn("Removing existing installation...");
783
- import_node_fs5.default.rmSync(targetPath, { recursive: true, force: true });
865
+ import_node_fs6.default.rmSync(targetPath, { recursive: true, force: true });
784
866
  } else {
785
- logger.error(`Skill already exists: ${targetPath}`);
786
- logger.info("Use --force to overwrite");
787
- process.exit(1);
867
+ logger.info(`Skill already exists, updating agent links...`);
788
868
  }
789
869
  }
790
- if (options.link) {
791
- import_node_fs5.default.symlinkSync(skillPath, targetPath, "dir");
870
+ if (sourceIsTarget) {
871
+ logger.info(`Skill already in shared directory, updating agent links...`);
872
+ } else if (alreadyExists && !options.force) {
873
+ } else if (options.link) {
874
+ import_node_fs6.default.symlinkSync(skillPath, targetPath, "dir");
792
875
  logger.success(`Linked to shared directory (dev mode)`);
793
876
  } else {
794
- copyDir(skillPath, targetPath);
877
+ copyDir2(skillPath, targetPath);
795
878
  logger.success(`Installed to shared directory`);
796
879
  }
797
880
  logger.info(`\u{1F4CD} Location: ${targetPath}`);
@@ -802,21 +885,25 @@ Tried to clone: ${gitInfo.gitUrl}`);
802
885
  logger.info("Skill installed to shared directory, but not linked to any agent");
803
886
  logger.info("");
804
887
  logger.info("Supported agents:");
805
- logger.info(" - Claude Code (~/.claude/skills)");
806
- logger.info(" - Cursor (~/.cursor/skills)");
807
- logger.info(" - Windsurf (~/.windsurf/skills)");
888
+ logger.info(" AMP, Antigravity, Claude Code, ClawdBot, Cline, Codex, Cursor, Droid,");
889
+ logger.info(" Gemini, GitHub Copilot, Goose, Kilo, Kiro CLI, OpenCode, Roo, Trae, Windsurf");
890
+ logger.info("");
891
+ logger.info('Run "eskill agents" to see all agent directories');
808
892
  return;
809
893
  }
810
894
  let targetAgents = installedAgents;
811
895
  if (options.agent && options.agent !== "all") {
812
- const agent = installedAgents.find((a) => a.name === options.agent);
896
+ const agent = AGENTS.find((a) => a.name === options.agent && a.enabled);
813
897
  if (!agent) {
814
- logger.error(`Agent not installed: ${options.agent}`);
898
+ logger.error(`Unknown agent: ${options.agent}`);
815
899
  logger.info(`
816
- Installed agents: ${installedAgents.map((a) => a.name).join(", ")}`);
900
+ Supported agents: ${AGENTS.filter((a) => a.enabled).map((a) => a.name).join(", ")}`);
817
901
  process.exit(1);
818
902
  }
819
903
  targetAgents = [agent];
904
+ if (!installedAgents.find((a) => a.name === options.agent)) {
905
+ logger.info(`Note: ${agent.displayName} directory will be created if not exists`);
906
+ }
820
907
  }
821
908
  logger.info("\nCreating symlinks...");
822
909
  let successCount = 0;
@@ -833,9 +920,9 @@ Linked to ${successCount}/${targetAgents.length} agents`);
833
920
  logger.info("\n\u{1F4A1} Dev mode: changes to source files will reflect immediately");
834
921
  }
835
922
  }
836
- function copyDir(src, dest) {
837
- import_node_fs5.default.mkdirSync(dest, { recursive: true });
838
- const entries = import_node_fs5.default.readdirSync(src, { withFileTypes: true });
923
+ function copyDir2(src, dest) {
924
+ import_node_fs6.default.mkdirSync(dest, { recursive: true });
925
+ const entries = import_node_fs6.default.readdirSync(src, { withFileTypes: true });
839
926
  for (const entry of entries) {
840
927
  const srcPath = import_node_path5.default.join(src, entry.name);
841
928
  const destPath = import_node_path5.default.join(dest, entry.name);
@@ -843,25 +930,25 @@ function copyDir(src, dest) {
843
930
  continue;
844
931
  }
845
932
  if (entry.isDirectory()) {
846
- copyDir(srcPath, destPath);
933
+ copyDir2(srcPath, destPath);
847
934
  } else {
848
- import_node_fs5.default.copyFileSync(srcPath, destPath);
935
+ import_node_fs6.default.copyFileSync(srcPath, destPath);
849
936
  }
850
937
  }
851
938
  }
852
939
 
853
940
  // src/commands/list.ts
854
- var import_node_fs6 = __toESM(require("fs"), 1);
941
+ var import_node_fs7 = __toESM(require("fs"), 1);
855
942
  var import_node_path6 = __toESM(require("path"), 1);
856
943
  var import_chalk3 = __toESM(require("chalk"), 1);
857
944
  function list() {
858
- if (!import_node_fs6.default.existsSync(SHARED_SKILLS_DIR)) {
945
+ if (!import_node_fs7.default.existsSync(SHARED_SKILLS_DIR)) {
859
946
  logger.info("No skills installed");
860
947
  logger.info(`
861
948
  To install a skill, run: ${import_chalk3.default.cyan("eskill install <skill-name>")}`);
862
949
  return;
863
950
  }
864
- const skills = import_node_fs6.default.readdirSync(SHARED_SKILLS_DIR);
951
+ const skills = import_node_fs7.default.readdirSync(SHARED_SKILLS_DIR);
865
952
  if (skills.length === 0) {
866
953
  logger.info("No skills installed");
867
954
  logger.info(`
@@ -874,15 +961,15 @@ Installed skills in ${SHARED_SKILLS_DIR}:
874
961
  for (const skill of skills) {
875
962
  const skillPath = import_node_path6.default.join(SHARED_SKILLS_DIR, skill);
876
963
  try {
877
- const stats = import_node_fs6.default.lstatSync(skillPath);
964
+ const stats = import_node_fs7.default.lstatSync(skillPath);
878
965
  if (!stats.isDirectory() && !stats.isSymbolicLink()) {
879
966
  continue;
880
967
  }
881
968
  let version2 = "unknown";
882
969
  const pkgPath = import_node_path6.default.join(skillPath, "package.json");
883
- if (import_node_fs6.default.existsSync(pkgPath)) {
970
+ if (import_node_fs7.default.existsSync(pkgPath)) {
884
971
  try {
885
- const pkgContent = import_node_fs6.default.readFileSync(pkgPath, "utf-8");
972
+ const pkgContent = import_node_fs7.default.readFileSync(pkgPath, "utf-8");
886
973
  const pkg = JSON.parse(pkgContent);
887
974
  if (pkg.version && typeof pkg.version === "string") {
888
975
  version2 = pkg.version;
@@ -892,9 +979,9 @@ Installed skills in ${SHARED_SKILLS_DIR}:
892
979
  }
893
980
  if (version2 === "unknown") {
894
981
  const skillMdPath = import_node_path6.default.join(skillPath, "SKILL.md");
895
- if (import_node_fs6.default.existsSync(skillMdPath)) {
982
+ if (import_node_fs7.default.existsSync(skillMdPath)) {
896
983
  try {
897
- const skillMdContent = import_node_fs6.default.readFileSync(skillMdPath, "utf-8");
984
+ const skillMdContent = import_node_fs7.default.readFileSync(skillMdPath, "utf-8");
898
985
  const frontmatterMatch = skillMdContent.match(/^---\s*\n([\s\S]*?)\n---/);
899
986
  if (frontmatterMatch) {
900
987
  const frontmatter = frontmatterMatch[1];
@@ -912,8 +999,8 @@ Installed skills in ${SHARED_SKILLS_DIR}:
912
999
  const targetPath = readSymlink(skillPath);
913
1000
  if (targetPath) {
914
1001
  const targetPkgPath = import_node_path6.default.join(targetPath, "package.json");
915
- if (import_node_fs6.default.existsSync(targetPkgPath)) {
916
- const pkg = JSON.parse(import_node_fs6.default.readFileSync(targetPkgPath, "utf-8"));
1002
+ if (import_node_fs7.default.existsSync(targetPkgPath)) {
1003
+ const pkg = JSON.parse(import_node_fs7.default.readFileSync(targetPkgPath, "utf-8"));
917
1004
  if (pkg.version && typeof pkg.version === "string") {
918
1005
  version2 = pkg.version;
919
1006
  }
@@ -930,15 +1017,19 @@ Installed skills in ${SHARED_SKILLS_DIR}:
930
1017
  const linkedAgents = [];
931
1018
  for (const agent of AGENTS) {
932
1019
  const skillsDirs = getAgentSkillsDirs(agent, cwd);
933
- const hasSymlink = skillsDirs.some((dir) => {
1020
+ const hasRef = skillsDirs.some((dir) => {
934
1021
  const agentSkillPath = import_node_path6.default.join(dir, skill);
935
- if (import_node_fs6.default.existsSync(agentSkillPath) && isSymlink(agentSkillPath)) {
1022
+ if (!import_node_fs7.default.existsSync(agentSkillPath)) return false;
1023
+ if (isSymlink(agentSkillPath)) {
936
1024
  const target = readSymlink(agentSkillPath);
937
1025
  return target === skillPath;
938
1026
  }
1027
+ if (agent.useCopyInsteadOfSymlink) {
1028
+ return import_node_fs7.default.statSync(agentSkillPath).isDirectory();
1029
+ }
939
1030
  return false;
940
1031
  });
941
- if (hasSymlink) {
1032
+ if (hasRef) {
942
1033
  linkedAgents.push(agent.displayName);
943
1034
  }
944
1035
  }
@@ -960,11 +1051,11 @@ Installed skills in ${SHARED_SKILLS_DIR}:
960
1051
  }
961
1052
 
962
1053
  // src/commands/remove.ts
963
- var import_node_fs7 = __toESM(require("fs"), 1);
1054
+ var import_node_fs8 = __toESM(require("fs"), 1);
964
1055
  async function remove(skillName, options = {}) {
965
1056
  const extractedName = extractSkillName(skillName);
966
1057
  const sharedPath = getSharedSkillPath(extractedName);
967
- const skillExists = import_node_fs7.default.existsSync(sharedPath);
1058
+ const skillExists = import_node_fs8.default.existsSync(sharedPath);
968
1059
  if (!skillExists) {
969
1060
  logger.error(`Skill not found: ${extractedName}`);
970
1061
  logger.info(`Location: ${sharedPath}`);
@@ -974,11 +1065,11 @@ async function remove(skillName, options = {}) {
974
1065
  const installedAgents = detectInstalledAgents(cwd);
975
1066
  let targetAgents = installedAgents;
976
1067
  if (options.agent && options.agent !== "all") {
977
- const agent = installedAgents.find((a) => a.name === options.agent);
1068
+ const agent = AGENTS.find((a) => a.name === options.agent && a.enabled);
978
1069
  if (!agent) {
979
- logger.error(`Agent not installed: ${options.agent}`);
1070
+ logger.error(`Unknown agent: ${options.agent}`);
980
1071
  logger.info(`
981
- Installed agents: ${installedAgents.map((a) => a.name).join(", ")}`);
1072
+ Supported agents: ${AGENTS.filter((a) => a.enabled).map((a) => a.name).join(", ")}`);
982
1073
  process.exit(1);
983
1074
  }
984
1075
  targetAgents = [agent];
@@ -1000,35 +1091,33 @@ Installed agents: ${installedAgents.map((a) => a.name).join(", ")}`);
1000
1091
  }
1001
1092
  logger.info("Removing skill from shared directory...");
1002
1093
  try {
1003
- const stats = import_node_fs7.default.lstatSync(sharedPath);
1094
+ const stats = import_node_fs8.default.lstatSync(sharedPath);
1004
1095
  if (stats.isSymbolicLink()) {
1005
- import_node_fs7.default.unlinkSync(sharedPath);
1096
+ import_node_fs8.default.unlinkSync(sharedPath);
1006
1097
  logger.success("Removed symlink from shared directory");
1007
1098
  } else {
1008
- import_node_fs7.default.rmSync(sharedPath, { recursive: true, force: true });
1099
+ import_node_fs8.default.rmSync(sharedPath, { recursive: true, force: true });
1009
1100
  logger.success("Removed skill from shared directory");
1010
1101
  }
1011
1102
  } catch (error) {
1012
1103
  logger.error(`Failed to remove skill: ${error.message}`);
1013
1104
  process.exit(1);
1014
1105
  }
1015
- const remainingSymlinks = [];
1106
+ const remainingRefs = [];
1016
1107
  for (const agent of AGENTS) {
1017
1108
  const agentSkillPaths = getAgentSkillPaths(agent.name, extractedName, cwd);
1018
- const hasSymlink = agentSkillPaths.some((path7) => {
1019
- return import_node_fs7.default.existsSync(path7) && isSymlink(path7);
1020
- });
1021
- if (hasSymlink) {
1022
- remainingSymlinks.push(agent.displayName);
1109
+ const hasRef = agentSkillPaths.some((p) => import_node_fs8.default.existsSync(p));
1110
+ if (hasRef) {
1111
+ remainingRefs.push(agent.displayName);
1023
1112
  }
1024
1113
  }
1025
- if (remainingSymlinks.length > 0) {
1114
+ if (remainingRefs.length > 0) {
1026
1115
  logger.warn(`
1027
- \u26A0\uFE0F Warning: Found remaining symlinks in:`);
1028
- for (const agentName of remainingSymlinks) {
1116
+ \u26A0\uFE0F Warning: Found remaining references in:`);
1117
+ for (const agentName of remainingRefs) {
1029
1118
  logger.info(` - ${agentName}`);
1030
1119
  }
1031
- logger.info("\nYou may need to manually remove these symlinks");
1120
+ logger.info("\nYou may need to manually remove these");
1032
1121
  } else {
1033
1122
  logger.success(`\u2705 Skill "${extractedName}" removed successfully!`);
1034
1123
  }