@empjs/skill 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3,80 +3,20 @@
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
5
  import { readFileSync } from "fs";
6
- import { fileURLToPath } from "url";
7
6
  import { dirname, join } from "path";
7
+ import { fileURLToPath } from "url";
8
8
 
9
- // src/commands/install.ts
10
- import { exec as exec2 } from "child_process";
11
- import { promisify as promisify2 } from "util";
12
- import fs4 from "fs";
13
- import path5 from "path";
9
+ // src/commands/agents.ts
10
+ import fs2 from "fs";
14
11
  import os2 from "os";
15
-
16
- // src/utils/logger.ts
17
12
  import chalk from "chalk";
18
- import ora from "ora";
19
- var Logger = class {
20
- spinner = null;
21
- info(message) {
22
- if (this.spinner) this.spinner.stop();
23
- console.log(chalk.blue("\u2139"), message);
24
- }
25
- success(message) {
26
- if (this.spinner) this.spinner.stop();
27
- console.log(chalk.green("\u2713"), message);
28
- }
29
- warn(message) {
30
- if (this.spinner) this.spinner.stop();
31
- console.log(chalk.yellow("\u26A0"), message);
32
- }
33
- error(message) {
34
- if (this.spinner) this.spinner.stop();
35
- console.log(chalk.red("\u2717"), message);
36
- }
37
- start(message) {
38
- if (this.spinner) this.spinner.stop();
39
- this.spinner = ora(message).start();
40
- return this.spinner;
41
- }
42
- stopSpinner() {
43
- if (this.spinner) {
44
- this.spinner.stop();
45
- this.spinner = null;
46
- }
47
- }
48
- /**
49
- * Update spinner text without stopping it
50
- */
51
- updateSpinner(message) {
52
- if (this.spinner) {
53
- this.spinner.text = message;
54
- }
55
- }
56
- /**
57
- * Log info without stopping spinner (for background info)
58
- */
59
- infoWithoutStop(message) {
60
- if (this.spinner) {
61
- const currentText = this.spinner.text;
62
- this.spinner.stop();
63
- console.log(chalk.blue("\u2139"), message);
64
- this.spinner.start(currentText);
65
- } else {
66
- console.log(chalk.blue("\u2139"), message);
67
- }
68
- }
69
- };
70
- var logger = new Logger();
71
-
72
- // src/utils/paths.ts
73
- import fs from "fs";
74
- import path2 from "path";
75
13
 
76
14
  // src/config/agents.ts
15
+ import fs from "fs";
77
16
  import os from "os";
78
17
  import path from "path";
79
18
  var HOME = os.homedir();
19
+ var CONFIG_HOME = process.env.XDG_CONFIG_HOME || path.join(HOME, ".config");
80
20
  function getAgentSkillsDirs(agent, cwd) {
81
21
  if (agent.skillsDirs) {
82
22
  if (typeof agent.skillsDirs === "function") {
@@ -91,21 +31,44 @@ function getAgentSkillsDirs(agent, cwd) {
91
31
  }
92
32
  var AGENTS = [
93
33
  {
94
- name: "claude",
95
- displayName: "Claude Code",
96
- skillsDir: path.join(HOME, ".claude", "skills"),
34
+ name: "amp",
35
+ displayName: "AMP",
36
+ skillsDirs: (cwd) => {
37
+ const dirs = [path.join(CONFIG_HOME, "agents", "skills")];
38
+ if (cwd) dirs.push(path.join(cwd, ".agents", "skills"));
39
+ return dirs;
40
+ },
97
41
  enabled: true
98
42
  },
99
43
  {
100
- name: "cursor",
101
- displayName: "Cursor",
102
- skillsDir: path.join(HOME, ".cursor", "skills"),
44
+ name: "antigravity",
45
+ displayName: "Antigravity",
46
+ skillsDirs: (cwd) => {
47
+ const dirs = [path.join(HOME, ".gemini", "antigravity", "skills")];
48
+ if (cwd) dirs.push(path.join(cwd, ".agent", "skills"));
49
+ if (cwd) dirs.push(path.join(cwd, ".shared", "skills"));
50
+ return dirs;
51
+ },
103
52
  enabled: true
104
53
  },
105
54
  {
106
- name: "windsurf",
107
- displayName: "Windsurf",
108
- skillsDir: path.join(HOME, ".windsurf", "skills"),
55
+ name: "claude",
56
+ displayName: "Claude Code",
57
+ skillsDir: path.join(process.env.CLAUDE_CONFIG_DIR?.trim() || path.join(HOME, ".claude"), "skills"),
58
+ enabled: true
59
+ },
60
+ {
61
+ name: "clawdbot",
62
+ displayName: "ClawdBot",
63
+ skillsDirs: () => {
64
+ const openclaw = path.join(HOME, ".openclaw", "skills");
65
+ const clawdbot = path.join(HOME, ".clawdbot", "skills");
66
+ const moltbot = path.join(HOME, ".moltbot", "skills");
67
+ if (fs.existsSync(path.join(HOME, ".openclaw"))) return [openclaw];
68
+ if (fs.existsSync(path.join(HOME, ".clawdbot"))) return [clawdbot];
69
+ if (fs.existsSync(path.join(HOME, ".moltbot"))) return [moltbot];
70
+ return [openclaw];
71
+ },
109
72
  enabled: true
110
73
  },
111
74
  {
@@ -114,9 +77,27 @@ var AGENTS = [
114
77
  skillsDir: path.join(HOME, ".cline", "skills"),
115
78
  enabled: true
116
79
  },
80
+ {
81
+ name: "codex",
82
+ displayName: "Codex",
83
+ skillsDir: path.join(process.env.CODEX_HOME?.trim() || path.join(HOME, ".codex"), "skills"),
84
+ enabled: true
85
+ },
86
+ {
87
+ name: "cursor",
88
+ displayName: "Cursor",
89
+ skillsDir: path.join(HOME, ".cursor", "skills"),
90
+ enabled: true
91
+ },
92
+ {
93
+ name: "droid",
94
+ displayName: "Droid",
95
+ skillsDir: path.join(HOME, ".factory", "skills"),
96
+ enabled: true
97
+ },
117
98
  {
118
99
  name: "gemini",
119
- displayName: "Gemini Code",
100
+ displayName: "Gemini",
120
101
  skillsDir: path.join(HOME, ".gemini", "skills"),
121
102
  enabled: true
122
103
  },
@@ -127,47 +108,31 @@ var AGENTS = [
127
108
  enabled: true
128
109
  },
129
110
  {
130
- name: "opencode",
131
- displayName: "OpenCode",
132
- skillsDir: path.join(HOME, ".opencode", "skills"),
111
+ name: "goose",
112
+ displayName: "Goose",
113
+ skillsDir: path.join(CONFIG_HOME, "goose", "skills"),
133
114
  enabled: true
134
115
  },
135
116
  {
136
- name: "antigravity",
137
- displayName: "Antigravity",
138
- skillsDirs: (cwd) => {
139
- const dirs = [];
140
- dirs.push(path.join(HOME, ".gemini", "antigravity", "skills"));
141
- if (cwd) {
142
- dirs.push(path.join(cwd, ".agent", "skills"));
143
- }
144
- if (cwd) {
145
- dirs.push(path.join(cwd, ".shared", "skills"));
146
- }
147
- return dirs;
148
- },
117
+ name: "kilo",
118
+ displayName: "Kilo Code",
119
+ skillsDir: path.join(HOME, ".kilocode", "skills"),
149
120
  enabled: true
150
121
  },
151
122
  {
152
123
  name: "kiro",
153
- displayName: "Kiro",
124
+ displayName: "Kiro CLI",
154
125
  skillsDir: path.join(HOME, ".kiro", "skills"),
155
126
  enabled: true
156
127
  },
157
128
  {
158
- name: "codex",
159
- displayName: "Codex CLI",
160
- skillsDir: path.join(HOME, ".codex", "skills"),
161
- enabled: true
162
- },
163
- {
164
- name: "qoder",
165
- displayName: "Qoder",
166
- skillsDir: path.join(HOME, ".qoder", "skills"),
129
+ name: "opencode",
130
+ displayName: "OpenCode",
131
+ skillsDir: path.join(CONFIG_HOME, "opencode", "skills"),
167
132
  enabled: true
168
133
  },
169
134
  {
170
- name: "roocode",
135
+ name: "roo",
171
136
  displayName: "Roo Code",
172
137
  skillsDir: path.join(HOME, ".roo", "skills"),
173
138
  enabled: true
@@ -178,18 +143,246 @@ var AGENTS = [
178
143
  skillsDir: path.join(HOME, ".trae", "skills"),
179
144
  enabled: true
180
145
  },
146
+ {
147
+ name: "windsurf",
148
+ displayName: "Windsurf",
149
+ skillsDirs: () => {
150
+ const dirs = [];
151
+ dirs.push(path.join(HOME, ".windsurf", "skills"));
152
+ dirs.push(path.join(HOME, ".codeium", "windsurf", "skills"));
153
+ return dirs;
154
+ },
155
+ enabled: true
156
+ },
157
+ // Additional agents
158
+ {
159
+ name: "qoder",
160
+ displayName: "Qoder",
161
+ skillsDir: path.join(HOME, ".qoder", "skills"),
162
+ enabled: true
163
+ },
181
164
  {
182
165
  name: "continue",
183
166
  displayName: "Continue",
184
167
  skillsDir: path.join(HOME, ".continue", "skills"),
185
168
  enabled: true
186
169
  }
187
- ];
188
- var SHARED_SKILLS_DIR = path.join(HOME, ".emp-agent", "skills");
189
- var CONFIG_FILE = path.join(HOME, ".emp-agent", "config.json");
190
- var CACHE_DIR = path.join(HOME, ".emp-agent", "cache");
170
+ ];
171
+ var SHARED_SKILLS_DIR = path.join(HOME, ".emp-agent", "skills");
172
+ var CONFIG_FILE = path.join(HOME, ".emp-agent", "config.json");
173
+ var CACHE_DIR = path.join(HOME, ".emp-agent", "cache");
174
+
175
+ // src/commands/agents.ts
176
+ function agents() {
177
+ const cwd = process.cwd();
178
+ console.log(chalk.bold("\n\u{1F4CB} Supported AI Agents:\n"));
179
+ for (const agent of AGENTS) {
180
+ const skillsDirs = getAgentSkillsDirs(agent, cwd);
181
+ const dirsInfo = skillsDirs.length > 1 ? ` (${skillsDirs.length} directories)` : "";
182
+ console.log(chalk.bold(agent.displayName));
183
+ console.log(chalk.gray(` Name: ${agent.name}`));
184
+ if (skillsDirs.length === 0) {
185
+ console.log(chalk.yellow(" \u26A0\uFE0F No directories configured"));
186
+ } else {
187
+ console.log(chalk.gray(` Directories${dirsInfo}:`));
188
+ for (const dir of skillsDirs) {
189
+ const exists = fs2.existsSync(dir);
190
+ const status = exists ? chalk.green("\u2713") : chalk.gray("\u25CB");
191
+ const pathColor = exists ? chalk.white : chalk.gray;
192
+ console.log(` ${status} ${pathColor(dir)}`);
193
+ }
194
+ }
195
+ console.log("");
196
+ }
197
+ console.log(chalk.bold("\u{1F4E6} Shared Skills Directory:"));
198
+ const sharedExists = fs2.existsSync(SHARED_SKILLS_DIR);
199
+ const sharedStatus = sharedExists ? chalk.green("\u2713") : chalk.gray("\u25CB");
200
+ const sharedPathColor = sharedExists ? chalk.white : chalk.gray;
201
+ console.log(` ${sharedStatus} ${sharedPathColor(SHARED_SKILLS_DIR)}`);
202
+ console.log("");
203
+ const home = os2.homedir();
204
+ if (cwd !== home) {
205
+ console.log(chalk.gray(`Current working directory: ${cwd}`));
206
+ console.log(chalk.gray("(Project-level directories are shown above)\n"));
207
+ }
208
+ }
209
+
210
+ // src/commands/install.ts
211
+ import { exec as exec2 } from "child_process";
212
+ import fs6 from "fs";
213
+ import os3 from "os";
214
+ import path5 from "path";
215
+ import { promisify as promisify2 } from "util";
216
+
217
+ // src/utils/git.ts
218
+ function parseGitUrl(url) {
219
+ const githubPatterns = [
220
+ // https://github.com/owner/repo/tree/branch/path/to/dir
221
+ /^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)(?:\/(.+))?$/,
222
+ // https://github.com/owner/repo
223
+ /^https?:\/\/github\.com\/([^/]+)\/([^/]+)(?:\/)?$/,
224
+ // git@github.com:owner/repo.git
225
+ /^git@github\.com:([^/]+)\/([^/]+)(?:\.git)?$/
226
+ ];
227
+ const gitlabPatterns = [
228
+ // https://host/group/repo/-/tree/branch/path (self-hosted + gitlab.com)
229
+ /^https?:\/\/([^/]+)\/(.+)\/-\/tree\/([^/]+)(?:\/(.+))?$/,
230
+ // https://gitlab.com/owner/repo
231
+ /^https?:\/\/gitlab\.com\/([^/]+)\/([^/]+)(?:\/)?$/,
232
+ // git@gitlab.com:owner/repo.git or git@host:group/repo.git
233
+ /^git@([^:]+):(.+)(?:\.git)?$/
234
+ ];
235
+ for (let i = 0; i < githubPatterns.length; i++) {
236
+ const pattern = githubPatterns[i];
237
+ const match = url.match(pattern);
238
+ if (match) {
239
+ const owner = match[1];
240
+ const repo = match[2].replace(/\.git$/, "");
241
+ let branch;
242
+ let path7;
243
+ if (i === 0) {
244
+ branch = match[3];
245
+ path7 = match[4];
246
+ } else if (i === 1) {
247
+ branch = "main";
248
+ } else {
249
+ branch = "main";
250
+ }
251
+ const gitUrl = `https://github.com/${owner}/${repo}.git`;
252
+ return {
253
+ type: "github",
254
+ owner,
255
+ repo,
256
+ branch,
257
+ path: path7,
258
+ gitUrl,
259
+ installUrl: gitUrl
260
+ // Will be used for git clone
261
+ };
262
+ }
263
+ }
264
+ for (let i = 0; i < gitlabPatterns.length; i++) {
265
+ const pattern = gitlabPatterns[i];
266
+ const match = url.match(pattern);
267
+ if (match) {
268
+ let owner;
269
+ let repo;
270
+ let branch;
271
+ let path7;
272
+ let gitUrl;
273
+ if (i === 0) {
274
+ const host = match[1];
275
+ const repoPath = match[2].replace(/\.git$/, "");
276
+ branch = match[3];
277
+ path7 = match[4];
278
+ const parts = repoPath.split("/");
279
+ repo = parts.pop() || repoPath;
280
+ owner = parts.join("/") || repo;
281
+ gitUrl = `https://${host}/${repoPath}.git`;
282
+ } else if (i === 1) {
283
+ owner = match[1];
284
+ repo = match[2].replace(/\.git$/, "");
285
+ branch = "main";
286
+ gitUrl = `https://gitlab.com/${owner}/${repo}.git`;
287
+ } else {
288
+ const host = match[1];
289
+ const repoPath = match[2].replace(/\.git$/, "");
290
+ branch = "main";
291
+ const parts = repoPath.split("/");
292
+ repo = parts.pop() || repoPath;
293
+ owner = parts.join("/") || repo;
294
+ gitUrl = `https://${host}/${repoPath}.git`;
295
+ }
296
+ return {
297
+ type: "gitlab",
298
+ owner,
299
+ repo,
300
+ branch,
301
+ path: path7,
302
+ gitUrl,
303
+ installUrl: gitUrl
304
+ };
305
+ }
306
+ }
307
+ if (url.startsWith("git+") || url.startsWith("git://")) {
308
+ return {
309
+ type: "other",
310
+ owner: "",
311
+ repo: "",
312
+ gitUrl: url.replace(/^git\+/, ""),
313
+ installUrl: url.startsWith("git+") ? url : `git+${url}`
314
+ };
315
+ }
316
+ return null;
317
+ }
318
+ function isGitUrl(str) {
319
+ return str.includes("github.com") || str.includes("gitlab.com") || str.includes("/-/tree/") || // GitLab web URL pattern (self-hosted)
320
+ str.startsWith("git@") || str.startsWith("git+") || str.startsWith("git://");
321
+ }
322
+
323
+ // src/utils/logger.ts
324
+ import chalk2 from "chalk";
325
+ import ora from "ora";
326
+ var Logger = class {
327
+ spinner = null;
328
+ info(message) {
329
+ if (this.spinner) this.spinner.stop();
330
+ console.log(chalk2.blue("\u2139"), message);
331
+ }
332
+ success(message) {
333
+ if (this.spinner) this.spinner.stop();
334
+ console.log(chalk2.green("\u2713"), message);
335
+ }
336
+ warn(message) {
337
+ if (this.spinner) this.spinner.stop();
338
+ console.log(chalk2.yellow("\u26A0"), message);
339
+ }
340
+ error(message) {
341
+ if (this.spinner) this.spinner.stop();
342
+ console.log(chalk2.red("\u2717"), message);
343
+ }
344
+ dim(message) {
345
+ if (this.spinner) this.spinner.stop();
346
+ console.log(chalk2.dim(" " + message));
347
+ }
348
+ start(message) {
349
+ if (this.spinner) this.spinner.stop();
350
+ this.spinner = ora(message).start();
351
+ return this.spinner;
352
+ }
353
+ stopSpinner() {
354
+ if (this.spinner) {
355
+ this.spinner.stop();
356
+ this.spinner = null;
357
+ }
358
+ }
359
+ /**
360
+ * Update spinner text without stopping it
361
+ */
362
+ updateSpinner(message) {
363
+ if (this.spinner) {
364
+ this.spinner.text = message;
365
+ }
366
+ }
367
+ /**
368
+ * Log info without stopping spinner (for background info)
369
+ */
370
+ infoWithoutStop(message) {
371
+ if (this.spinner) {
372
+ const currentText = this.spinner.text;
373
+ this.spinner.stop();
374
+ console.log(chalk2.blue("\u2139"), message);
375
+ this.spinner.start(currentText);
376
+ } else {
377
+ console.log(chalk2.blue("\u2139"), message);
378
+ }
379
+ }
380
+ };
381
+ var logger = new Logger();
191
382
 
192
383
  // src/utils/paths.ts
384
+ import fs3 from "fs";
385
+ import path2 from "path";
193
386
  function getSharedSkillPath(skillName) {
194
387
  return path2.join(SHARED_SKILLS_DIR, skillName);
195
388
  }
@@ -202,8 +395,8 @@ function getAgentSkillPaths(agentName, skillName, cwd) {
202
395
  return skillsDirs.map((dir) => path2.join(dir, skillName));
203
396
  }
204
397
  function ensureSharedDir() {
205
- if (!fs.existsSync(SHARED_SKILLS_DIR)) {
206
- fs.mkdirSync(SHARED_SKILLS_DIR, { recursive: true });
398
+ if (!fs3.existsSync(SHARED_SKILLS_DIR)) {
399
+ fs3.mkdirSync(SHARED_SKILLS_DIR, { recursive: true });
207
400
  }
208
401
  }
209
402
  function detectInstalledAgents(cwd) {
@@ -211,7 +404,7 @@ function detectInstalledAgents(cwd) {
211
404
  try {
212
405
  const skillsDirs = getAgentSkillsDirs(agent, cwd);
213
406
  return skillsDirs.some((dir) => {
214
- return fs.existsSync(dir) || fs.existsSync(path2.dirname(dir));
407
+ return fs3.existsSync(dir) || fs3.existsSync(path2.dirname(dir));
215
408
  });
216
409
  } catch {
217
410
  return false;
@@ -230,32 +423,93 @@ function extractSkillName(nameOrPath) {
230
423
  return path2.basename(nameOrPath);
231
424
  }
232
425
 
233
- // src/utils/symlink.ts
234
- import fs2 from "fs";
426
+ // src/utils/registry.ts
427
+ import { exec } from "child_process";
428
+ import fs4 from "fs";
235
429
  import path3 from "path";
430
+ import { promisify } from "util";
431
+ var execAsync = promisify(exec);
432
+ function findNpmrc(startDir) {
433
+ let currentDir = path3.resolve(startDir);
434
+ while (currentDir !== path3.dirname(currentDir)) {
435
+ const npmrcPath = path3.join(currentDir, ".npmrc");
436
+ if (fs4.existsSync(npmrcPath)) {
437
+ return npmrcPath;
438
+ }
439
+ currentDir = path3.dirname(currentDir);
440
+ }
441
+ return null;
442
+ }
443
+ function parseNpmrc(npmrcPath) {
444
+ try {
445
+ const content = fs4.readFileSync(npmrcPath, "utf-8");
446
+ const lines = content.split("\n");
447
+ for (const line of lines) {
448
+ const trimmed = line.trim();
449
+ if (!trimmed || trimmed.startsWith("#")) {
450
+ continue;
451
+ }
452
+ const registryMatch = trimmed.match(/^(?:@[^:]+:)?registry\s*=\s*(.+)$/);
453
+ if (registryMatch) {
454
+ return registryMatch[1].trim();
455
+ }
456
+ }
457
+ } catch (error) {
458
+ }
459
+ return null;
460
+ }
461
+ async function getGlobalRegistry() {
462
+ try {
463
+ const { stdout } = await execAsync("npm config get registry");
464
+ const registry = stdout.trim();
465
+ if (registry && registry !== "undefined") {
466
+ return registry;
467
+ }
468
+ } catch (error) {
469
+ }
470
+ return null;
471
+ }
472
+ async function getRegistry(cwd = process.cwd()) {
473
+ const npmrcPath = findNpmrc(cwd);
474
+ if (npmrcPath) {
475
+ const registry = parseNpmrc(npmrcPath);
476
+ if (registry) {
477
+ return registry;
478
+ }
479
+ }
480
+ const globalRegistry = await getGlobalRegistry();
481
+ if (globalRegistry) {
482
+ return globalRegistry;
483
+ }
484
+ return "https://registry.npmjs.org/";
485
+ }
486
+
487
+ // src/utils/symlink.ts
488
+ import fs5 from "fs";
489
+ import path4 from "path";
236
490
  function createSymlink(skillName, agent, cwd) {
237
491
  const source = getSharedSkillPath(skillName);
238
- if (!fs2.existsSync(source)) {
492
+ if (!fs5.existsSync(source)) {
239
493
  logger.error(`Skill not found: ${source}`);
240
494
  return false;
241
495
  }
242
496
  const targets = getAgentSkillPaths(agent.name, skillName, cwd);
243
497
  let successCount = 0;
244
498
  for (const target of targets) {
245
- const targetDir = path3.dirname(target);
246
- if (!fs2.existsSync(targetDir)) {
499
+ const targetDir = path4.dirname(target);
500
+ if (!fs5.existsSync(targetDir)) {
247
501
  try {
248
- fs2.mkdirSync(targetDir, { recursive: true });
502
+ fs5.mkdirSync(targetDir, { recursive: true });
249
503
  } catch (error) {
250
504
  logger.error(`Failed to create directory ${targetDir}: ${error.message}`);
251
505
  continue;
252
506
  }
253
507
  }
254
- if (fs2.existsSync(target)) {
508
+ if (fs5.existsSync(target)) {
255
509
  try {
256
- const stats = fs2.lstatSync(target);
510
+ const stats = fs5.lstatSync(target);
257
511
  if (stats.isSymbolicLink()) {
258
- fs2.unlinkSync(target);
512
+ fs5.unlinkSync(target);
259
513
  } else {
260
514
  logger.warn(`Target exists but is not a symlink, skipping: ${target}`);
261
515
  continue;
@@ -266,7 +520,7 @@ function createSymlink(skillName, agent, cwd) {
266
520
  }
267
521
  }
268
522
  try {
269
- fs2.symlinkSync(source, target, "dir");
523
+ fs5.symlinkSync(source, target, "dir");
270
524
  successCount++;
271
525
  } catch (error) {
272
526
  logger.error(`Failed to create symlink at ${target}: ${error.message}`);
@@ -283,13 +537,13 @@ function removeSymlink(skillName, agent, cwd) {
283
537
  const targets = getAgentSkillPaths(agent.name, skillName, cwd);
284
538
  let removedCount = 0;
285
539
  for (const target of targets) {
286
- if (!fs2.existsSync(target)) {
540
+ if (!fs5.existsSync(target)) {
287
541
  continue;
288
542
  }
289
543
  try {
290
- const stats = fs2.lstatSync(target);
544
+ const stats = fs5.lstatSync(target);
291
545
  if (stats.isSymbolicLink()) {
292
- fs2.unlinkSync(target);
546
+ fs5.unlinkSync(target);
293
547
  removedCount++;
294
548
  } else {
295
549
  logger.warn(`Not a symlink: ${target}`);
@@ -307,7 +561,7 @@ function removeSymlink(skillName, agent, cwd) {
307
561
  }
308
562
  function isSymlink(filePath) {
309
563
  try {
310
- const stats = fs2.lstatSync(filePath);
564
+ const stats = fs5.lstatSync(filePath);
311
565
  return stats.isSymbolicLink();
312
566
  } catch {
313
567
  return false;
@@ -315,164 +569,12 @@ function isSymlink(filePath) {
315
569
  }
316
570
  function readSymlink(filePath) {
317
571
  try {
318
- return fs2.readlinkSync(filePath);
572
+ return fs5.readlinkSync(filePath);
319
573
  } catch {
320
574
  return null;
321
575
  }
322
576
  }
323
577
 
324
- // src/utils/registry.ts
325
- import { exec } from "child_process";
326
- import { promisify } from "util";
327
- import fs3 from "fs";
328
- import path4 from "path";
329
- var execAsync = promisify(exec);
330
- function findNpmrc(startDir) {
331
- let currentDir = path4.resolve(startDir);
332
- while (currentDir !== path4.dirname(currentDir)) {
333
- const npmrcPath = path4.join(currentDir, ".npmrc");
334
- if (fs3.existsSync(npmrcPath)) {
335
- return npmrcPath;
336
- }
337
- currentDir = path4.dirname(currentDir);
338
- }
339
- return null;
340
- }
341
- function parseNpmrc(npmrcPath) {
342
- try {
343
- const content = fs3.readFileSync(npmrcPath, "utf-8");
344
- const lines = content.split("\n");
345
- for (const line of lines) {
346
- const trimmed = line.trim();
347
- if (!trimmed || trimmed.startsWith("#")) {
348
- continue;
349
- }
350
- const registryMatch = trimmed.match(/^(?:@[^:]+:)?registry\s*=\s*(.+)$/);
351
- if (registryMatch) {
352
- return registryMatch[1].trim();
353
- }
354
- }
355
- } catch (error) {
356
- }
357
- return null;
358
- }
359
- async function getGlobalRegistry() {
360
- try {
361
- const { stdout } = await execAsync("npm config get registry");
362
- const registry = stdout.trim();
363
- if (registry && registry !== "undefined") {
364
- return registry;
365
- }
366
- } catch (error) {
367
- }
368
- return null;
369
- }
370
- async function getRegistry(cwd = process.cwd()) {
371
- const npmrcPath = findNpmrc(cwd);
372
- if (npmrcPath) {
373
- const registry = parseNpmrc(npmrcPath);
374
- if (registry) {
375
- return registry;
376
- }
377
- }
378
- const globalRegistry = await getGlobalRegistry();
379
- if (globalRegistry) {
380
- return globalRegistry;
381
- }
382
- return "https://registry.npmjs.org/";
383
- }
384
-
385
- // src/utils/git.ts
386
- function parseGitUrl(url) {
387
- const githubPatterns = [
388
- // https://github.com/owner/repo/tree/branch/path/to/dir
389
- /^https?:\/\/github\.com\/([^\/]+)\/([^\/]+)\/tree\/([^\/]+)(?:\/(.+))?$/,
390
- // https://github.com/owner/repo
391
- /^https?:\/\/github\.com\/([^\/]+)\/([^\/]+)(?:\/)?$/,
392
- // git@github.com:owner/repo.git
393
- /^git@github\.com:([^\/]+)\/([^\/]+)(?:\.git)?$/
394
- ];
395
- const gitlabPatterns = [
396
- // https://gitlab.com/owner/repo/-/tree/branch/path/to/dir
397
- /^https?:\/\/gitlab\.com\/([^\/]+)\/([^\/]+)\/-\/tree\/([^\/]+)(?:\/(.+))?$/,
398
- // https://gitlab.com/owner/repo
399
- /^https?:\/\/gitlab\.com\/([^\/]+)\/([^\/]+)(?:\/)?$/,
400
- // git@gitlab.com:owner/repo.git
401
- /^git@gitlab\.com:([^\/]+)\/([^\/]+)(?:\.git)?$/
402
- ];
403
- for (let i = 0; i < githubPatterns.length; i++) {
404
- const pattern = githubPatterns[i];
405
- const match = url.match(pattern);
406
- if (match) {
407
- const owner = match[1];
408
- const repo = match[2].replace(/\.git$/, "");
409
- let branch;
410
- let path7;
411
- if (i === 0) {
412
- branch = match[3];
413
- path7 = match[4];
414
- } else if (i === 1) {
415
- branch = "main";
416
- } else {
417
- branch = "main";
418
- }
419
- const gitUrl = `https://github.com/${owner}/${repo}.git`;
420
- return {
421
- type: "github",
422
- owner,
423
- repo,
424
- branch,
425
- path: path7,
426
- gitUrl,
427
- installUrl: gitUrl
428
- // Will be used for git clone
429
- };
430
- }
431
- }
432
- for (let i = 0; i < gitlabPatterns.length; i++) {
433
- const pattern = gitlabPatterns[i];
434
- const match = url.match(pattern);
435
- if (match) {
436
- const owner = match[1];
437
- const repo = match[2].replace(/\.git$/, "");
438
- let branch;
439
- let path7;
440
- if (i === 0) {
441
- branch = match[3];
442
- path7 = match[4];
443
- } else if (i === 1) {
444
- branch = "main";
445
- } else {
446
- branch = "main";
447
- }
448
- const gitUrl = `https://gitlab.com/${owner}/${repo}.git`;
449
- return {
450
- type: "gitlab",
451
- owner,
452
- repo,
453
- branch,
454
- path: path7,
455
- gitUrl,
456
- installUrl: gitUrl
457
- // Will be used for git clone
458
- };
459
- }
460
- }
461
- if (url.startsWith("git+") || url.startsWith("git://")) {
462
- return {
463
- type: "other",
464
- owner: "",
465
- repo: "",
466
- gitUrl: url.replace(/^git\+/, ""),
467
- installUrl: url.startsWith("git+") ? url : `git+${url}`
468
- };
469
- }
470
- return null;
471
- }
472
- function isGitUrl(str) {
473
- return str.includes("github.com") || str.includes("gitlab.com") || str.startsWith("git@") || str.startsWith("git+") || str.startsWith("git://");
474
- }
475
-
476
578
  // src/commands/install.ts
477
579
  var execAsync2 = promisify2(exec2);
478
580
  async function execWithTimeout(command, timeout = 12e4, env) {
@@ -484,10 +586,7 @@ async function execWithTimeout(command, timeout = 12e4, env) {
484
586
  });
485
587
  try {
486
588
  const execOptions = env ? { env } : {};
487
- const result = await Promise.race([
488
- execAsync2(command, execOptions),
489
- timeoutPromise
490
- ]);
589
+ const result = await Promise.race([execAsync2(command, execOptions), timeoutPromise]);
491
590
  if (timeoutId) {
492
591
  clearTimeout(timeoutId);
493
592
  }
@@ -499,12 +598,25 @@ async function execWithTimeout(command, timeout = 12e4, env) {
499
598
  throw error;
500
599
  }
501
600
  }
601
+ function shortenPath(p) {
602
+ const home = os3.homedir();
603
+ return p.startsWith(home) ? p.replace(home, "~") : p;
604
+ }
502
605
  async function install(skillNameOrPath, options = {}) {
503
- logger.info(`Installing skill: ${skillNameOrPath}`);
606
+ const isGit = isGitUrl(skillNameOrPath);
607
+ if (isGit) {
608
+ logger.info("Installing from Git URL");
609
+ logger.dim(skillNameOrPath);
610
+ } else {
611
+ logger.info(`Installing skill: ${skillNameOrPath}`);
612
+ }
504
613
  ensureSharedDir();
505
614
  let skillPath;
506
615
  let skillName;
507
- if (isGitUrl(skillNameOrPath)) {
616
+ if (process.env.DEBUG_ESKILL) {
617
+ logger.dim(`[DEBUG] isGitUrl=${isGit}, parseGitUrl=${parseGitUrl(skillNameOrPath) ? "ok" : "null"}`);
618
+ }
619
+ if (isGit) {
508
620
  const gitInfo = parseGitUrl(skillNameOrPath);
509
621
  if (!gitInfo) {
510
622
  logger.error(`Invalid git URL: ${skillNameOrPath}`);
@@ -516,21 +628,17 @@ async function install(skillNameOrPath, options = {}) {
516
628
  const cloneDir = path5.join(tempDir, "repo");
517
629
  try {
518
630
  const timeout = options.timeout || 12e4;
519
- const spinner = logger.start(`Cloning ${gitInfo.gitUrl}...`);
520
- logger.infoWithoutStop(`Repository: ${gitInfo.gitUrl}`);
521
- if (gitInfo.branch) {
522
- logger.infoWithoutStop(`Branch: ${gitInfo.branch}`);
523
- }
524
- if (gitInfo.path) {
525
- logger.infoWithoutStop(`Path: ${gitInfo.path}`);
526
- }
527
- logger.infoWithoutStop(`Timeout: ${timeout / 1e3}s`);
528
- fs4.mkdirSync(tempDir, { recursive: true });
631
+ const gitDetails = [`${gitInfo.gitUrl}`];
632
+ if (gitInfo.branch) gitDetails.push(`branch: ${gitInfo.branch}`);
633
+ if (gitInfo.path) gitDetails.push(`path: ${gitInfo.path}`);
634
+ logger.dim(gitDetails.join(" \xB7 "));
635
+ const spinner = logger.start(`Cloning...`);
636
+ fs6.mkdirSync(tempDir, { recursive: true });
529
637
  const branchFlag = gitInfo.branch ? `-b ${gitInfo.branch}` : "";
530
638
  const cloneCommand = branchFlag ? `git clone ${branchFlag} ${gitInfo.gitUrl} ${cloneDir} --depth 1 --quiet` : `git clone ${gitInfo.gitUrl} ${cloneDir} --depth 1 --quiet`;
531
639
  try {
532
640
  await execWithTimeout(cloneCommand, timeout);
533
- spinner.succeed(`Repository cloned successfully`);
641
+ spinner.succeed(`Cloned successfully`);
534
642
  } catch (error) {
535
643
  spinner.fail("Clone failed");
536
644
  if (error.message.includes("timeout")) {
@@ -547,7 +655,7 @@ async function install(skillNameOrPath, options = {}) {
547
655
  }
548
656
  if (gitInfo.path) {
549
657
  skillPath = path5.join(cloneDir, gitInfo.path);
550
- if (!fs4.existsSync(skillPath)) {
658
+ if (!fs6.existsSync(skillPath)) {
551
659
  logger.error(`Path not found in repository: ${gitInfo.path}`);
552
660
  logger.info(`Repository cloned to: ${cloneDir}`);
553
661
  process.exit(1);
@@ -556,7 +664,7 @@ async function install(skillNameOrPath, options = {}) {
556
664
  skillPath = cloneDir;
557
665
  }
558
666
  const skillMdPath = path5.join(skillPath, "SKILL.md");
559
- if (!fs4.existsSync(skillMdPath)) {
667
+ if (!fs6.existsSync(skillMdPath)) {
560
668
  logger.warn(`Warning: SKILL.md not found in ${skillPath}`);
561
669
  logger.info("The directory may not be a valid skill package");
562
670
  }
@@ -578,16 +686,16 @@ Tried to clone: ${gitInfo.gitUrl}`);
578
686
  }
579
687
  process.exit(1);
580
688
  }
581
- } else if (options.link || fs4.existsSync(skillNameOrPath)) {
689
+ } else if (options.link || fs6.existsSync(skillNameOrPath)) {
582
690
  skillPath = path5.resolve(skillNameOrPath);
583
- if (!fs4.existsSync(skillPath)) {
691
+ if (!fs6.existsSync(skillPath)) {
584
692
  logger.error(`Path not found: ${skillPath}`);
585
693
  process.exit(1);
586
694
  }
587
695
  const pkgPath = path5.join(skillPath, "package.json");
588
- if (fs4.existsSync(pkgPath)) {
696
+ if (fs6.existsSync(pkgPath)) {
589
697
  try {
590
- const pkg = JSON.parse(fs4.readFileSync(pkgPath, "utf-8"));
698
+ const pkg = JSON.parse(fs6.readFileSync(pkgPath, "utf-8"));
591
699
  skillName = extractSkillName(pkg.name);
592
700
  } catch {
593
701
  skillName = extractSkillName(path5.basename(skillPath));
@@ -604,12 +712,12 @@ Tried to clone: ${gitInfo.gitUrl}`);
604
712
  const spinner = logger.start(`Installing ${skillNameOrPath}...`);
605
713
  logger.infoWithoutStop(`Registry: ${registry}`);
606
714
  logger.infoWithoutStop(`Timeout: ${timeout / 1e3}s`);
607
- fs4.mkdirSync(tempDir, { recursive: true });
715
+ fs6.mkdirSync(tempDir, { recursive: true });
608
716
  logger.updateSpinner(`Downloading ${skillNameOrPath} from ${registry}...`);
609
- const homeDir = process.env.HOME || process.env.USERPROFILE || os2.homedir();
717
+ const homeDir = process.env.HOME || process.env.USERPROFILE || os3.homedir();
610
718
  const npmCacheDir = path5.join(homeDir, ".npm");
611
719
  const npmConfigPrefix = path5.join(homeDir, ".npm-global");
612
- fs4.mkdirSync(npmCacheDir, { recursive: true });
720
+ fs6.mkdirSync(npmCacheDir, { recursive: true });
613
721
  const installCommand = `npm install ${skillNameOrPath} --prefix ${tempDir} --registry=${registry} --no-save --silent --no-bin-links --prefer-offline`;
614
722
  const env = {
615
723
  ...process.env,
@@ -634,7 +742,9 @@ Tried to clone: ${gitInfo.gitUrl}`);
634
742
  logger.info("");
635
743
  logger.info("Suggestions:");
636
744
  logger.info(` - Try again: eskill add ${skillNameOrPath}`);
637
- logger.info(` - Use a different registry: eskill add ${skillNameOrPath} --registry=https://registry.npmjs.org/`);
745
+ logger.info(
746
+ ` - Use a different registry: eskill add ${skillNameOrPath} --registry=https://registry.npmjs.org/`
747
+ );
638
748
  logger.info(` - Increase timeout: eskill add ${skillNameOrPath} --timeout=300000`);
639
749
  } else if (errorMessage.includes("EACCES") || errorMessage.includes("permission denied") || errorMessage.includes("Permission denied")) {
640
750
  logger.error("Permission denied error detected");
@@ -673,7 +783,9 @@ Tried to clone: ${gitInfo.gitUrl}`);
673
783
  logger.info("Please check:");
674
784
  logger.info(" - Your internet connection");
675
785
  logger.info(` - Registry accessibility: ${registry}`);
676
- logger.info(` - Try a different registry: eskill add ${skillNameOrPath} --registry=https://registry.npmjs.org/`);
786
+ logger.info(
787
+ ` - Try a different registry: eskill add ${skillNameOrPath} --registry=https://registry.npmjs.org/`
788
+ );
677
789
  } else {
678
790
  logger.error(`Failed to download: ${errorMessage}`);
679
791
  logger.info("");
@@ -686,7 +798,7 @@ Tried to clone: ${gitInfo.gitUrl}`);
686
798
  process.exit(1);
687
799
  }
688
800
  skillPath = path5.join(tempDir, "node_modules", skillNameOrPath);
689
- if (!fs4.existsSync(skillPath)) {
801
+ if (!fs6.existsSync(skillPath)) {
690
802
  logger.error(`Failed to download package: ${skillNameOrPath}`);
691
803
  process.exit(1);
692
804
  }
@@ -696,18 +808,19 @@ Tried to clone: ${gitInfo.gitUrl}`);
696
808
  }
697
809
  }
698
810
  const targetPath = getSharedSkillPath(skillName);
699
- if (fs4.existsSync(targetPath)) {
811
+ if (fs6.existsSync(targetPath)) {
700
812
  if (options.force) {
701
813
  logger.warn("Removing existing installation...");
702
- fs4.rmSync(targetPath, { recursive: true, force: true });
814
+ fs6.rmSync(targetPath, { recursive: true, force: true });
703
815
  } else {
704
- logger.error(`Skill already exists: ${targetPath}`);
705
- logger.info("Use --force to overwrite");
816
+ logger.error(`Skill already exists`);
817
+ logger.dim(`Location: ${shortenPath(targetPath)}`);
818
+ logger.dim(`Tip: Add --force to overwrite`);
706
819
  process.exit(1);
707
820
  }
708
821
  }
709
822
  if (options.link) {
710
- fs4.symlinkSync(skillPath, targetPath, "dir");
823
+ fs6.symlinkSync(skillPath, targetPath, "dir");
711
824
  logger.success(`Linked to shared directory (dev mode)`);
712
825
  } else {
713
826
  copyDir(skillPath, targetPath);
@@ -721,21 +834,25 @@ Tried to clone: ${gitInfo.gitUrl}`);
721
834
  logger.info("Skill installed to shared directory, but not linked to any agent");
722
835
  logger.info("");
723
836
  logger.info("Supported agents:");
724
- logger.info(" - Claude Code (~/.claude/skills)");
725
- logger.info(" - Cursor (~/.cursor/skills)");
726
- logger.info(" - Windsurf (~/.windsurf/skills)");
837
+ logger.info(" AMP, Antigravity, Claude Code, ClawdBot, Cline, Codex, Cursor, Droid,");
838
+ logger.info(" Gemini, GitHub Copilot, Goose, Kilo, Kiro CLI, OpenCode, Roo, Trae, Windsurf");
839
+ logger.info("");
840
+ logger.info('Run "eskill agents" to see all agent directories');
727
841
  return;
728
842
  }
729
843
  let targetAgents = installedAgents;
730
844
  if (options.agent && options.agent !== "all") {
731
- const agent = installedAgents.find((a) => a.name === options.agent);
845
+ const agent = AGENTS.find((a) => a.name === options.agent && a.enabled);
732
846
  if (!agent) {
733
- logger.error(`Agent not installed: ${options.agent}`);
847
+ logger.error(`Unknown agent: ${options.agent}`);
734
848
  logger.info(`
735
- Installed agents: ${installedAgents.map((a) => a.name).join(", ")}`);
849
+ Supported agents: ${AGENTS.filter((a) => a.enabled).map((a) => a.name).join(", ")}`);
736
850
  process.exit(1);
737
851
  }
738
852
  targetAgents = [agent];
853
+ if (!installedAgents.find((a) => a.name === options.agent)) {
854
+ logger.info(`Note: ${agent.displayName} directory will be created if not exists`);
855
+ }
739
856
  }
740
857
  logger.info("\nCreating symlinks...");
741
858
  let successCount = 0;
@@ -753,8 +870,8 @@ Linked to ${successCount}/${targetAgents.length} agents`);
753
870
  }
754
871
  }
755
872
  function copyDir(src, dest) {
756
- fs4.mkdirSync(dest, { recursive: true });
757
- const entries = fs4.readdirSync(src, { withFileTypes: true });
873
+ fs6.mkdirSync(dest, { recursive: true });
874
+ const entries = fs6.readdirSync(src, { withFileTypes: true });
758
875
  for (const entry of entries) {
759
876
  const srcPath = path5.join(src, entry.name);
760
877
  const destPath = path5.join(dest, entry.name);
@@ -764,44 +881,44 @@ function copyDir(src, dest) {
764
881
  if (entry.isDirectory()) {
765
882
  copyDir(srcPath, destPath);
766
883
  } else {
767
- fs4.copyFileSync(srcPath, destPath);
884
+ fs6.copyFileSync(srcPath, destPath);
768
885
  }
769
886
  }
770
887
  }
771
888
 
772
889
  // src/commands/list.ts
773
- import fs5 from "fs";
890
+ import fs7 from "fs";
774
891
  import path6 from "path";
775
- import chalk2 from "chalk";
892
+ import chalk3 from "chalk";
776
893
  function list() {
777
- if (!fs5.existsSync(SHARED_SKILLS_DIR)) {
894
+ if (!fs7.existsSync(SHARED_SKILLS_DIR)) {
778
895
  logger.info("No skills installed");
779
896
  logger.info(`
780
- To install a skill, run: ${chalk2.cyan("eskill install <skill-name>")}`);
897
+ To install a skill, run: ${chalk3.cyan("eskill install <skill-name>")}`);
781
898
  return;
782
899
  }
783
- const skills = fs5.readdirSync(SHARED_SKILLS_DIR);
900
+ const skills = fs7.readdirSync(SHARED_SKILLS_DIR);
784
901
  if (skills.length === 0) {
785
902
  logger.info("No skills installed");
786
903
  logger.info(`
787
- To install a skill, run: ${chalk2.cyan("eskill install <skill-name>")}`);
904
+ To install a skill, run: ${chalk3.cyan("eskill install <skill-name>")}`);
788
905
  return;
789
906
  }
790
- console.log(chalk2.bold(`
907
+ console.log(chalk3.bold(`
791
908
  Installed skills in ${SHARED_SKILLS_DIR}:
792
909
  `));
793
910
  for (const skill of skills) {
794
911
  const skillPath = path6.join(SHARED_SKILLS_DIR, skill);
795
912
  try {
796
- const stats = fs5.lstatSync(skillPath);
913
+ const stats = fs7.lstatSync(skillPath);
797
914
  if (!stats.isDirectory() && !stats.isSymbolicLink()) {
798
915
  continue;
799
916
  }
800
917
  let version2 = "unknown";
801
918
  const pkgPath = path6.join(skillPath, "package.json");
802
- if (fs5.existsSync(pkgPath)) {
919
+ if (fs7.existsSync(pkgPath)) {
803
920
  try {
804
- const pkgContent = fs5.readFileSync(pkgPath, "utf-8");
921
+ const pkgContent = fs7.readFileSync(pkgPath, "utf-8");
805
922
  const pkg = JSON.parse(pkgContent);
806
923
  if (pkg.version && typeof pkg.version === "string") {
807
924
  version2 = pkg.version;
@@ -811,9 +928,9 @@ Installed skills in ${SHARED_SKILLS_DIR}:
811
928
  }
812
929
  if (version2 === "unknown") {
813
930
  const skillMdPath = path6.join(skillPath, "SKILL.md");
814
- if (fs5.existsSync(skillMdPath)) {
931
+ if (fs7.existsSync(skillMdPath)) {
815
932
  try {
816
- const skillMdContent = fs5.readFileSync(skillMdPath, "utf-8");
933
+ const skillMdContent = fs7.readFileSync(skillMdPath, "utf-8");
817
934
  const frontmatterMatch = skillMdContent.match(/^---\s*\n([\s\S]*?)\n---/);
818
935
  if (frontmatterMatch) {
819
936
  const frontmatter = frontmatterMatch[1];
@@ -831,8 +948,8 @@ Installed skills in ${SHARED_SKILLS_DIR}:
831
948
  const targetPath = readSymlink(skillPath);
832
949
  if (targetPath) {
833
950
  const targetPkgPath = path6.join(targetPath, "package.json");
834
- if (fs5.existsSync(targetPkgPath)) {
835
- const pkg = JSON.parse(fs5.readFileSync(targetPkgPath, "utf-8"));
951
+ if (fs7.existsSync(targetPkgPath)) {
952
+ const pkg = JSON.parse(fs7.readFileSync(targetPkgPath, "utf-8"));
836
953
  if (pkg.version && typeof pkg.version === "string") {
837
954
  version2 = pkg.version;
838
955
  }
@@ -842,16 +959,16 @@ Installed skills in ${SHARED_SKILLS_DIR}:
842
959
  }
843
960
  }
844
961
  const isDev = isSymlink(skillPath);
845
- const devTag = isDev ? chalk2.yellow(" (dev)") : "";
846
- const versionDisplay = version2 !== "unknown" ? chalk2.gray(`(v${version2})`) : "";
847
- console.log(chalk2.green("\u{1F4E6}") + ` ${chalk2.bold(skill)}${versionDisplay ? " " + versionDisplay : ""}${devTag}`);
962
+ const devTag = isDev ? chalk3.yellow(" (dev)") : "";
963
+ const versionDisplay = version2 !== "unknown" ? chalk3.gray(`(v${version2})`) : "";
964
+ console.log(chalk3.green("\u{1F4E6}") + ` ${chalk3.bold(skill)}${versionDisplay ? " " + versionDisplay : ""}${devTag}`);
848
965
  const cwd = process.cwd();
849
966
  const linkedAgents = [];
850
967
  for (const agent of AGENTS) {
851
968
  const skillsDirs = getAgentSkillsDirs(agent, cwd);
852
969
  const hasSymlink = skillsDirs.some((dir) => {
853
970
  const agentSkillPath = path6.join(dir, skill);
854
- if (fs5.existsSync(agentSkillPath) && isSymlink(agentSkillPath)) {
971
+ if (fs7.existsSync(agentSkillPath) && isSymlink(agentSkillPath)) {
855
972
  const target = readSymlink(agentSkillPath);
856
973
  return target === skillPath;
857
974
  }
@@ -862,29 +979,28 @@ Installed skills in ${SHARED_SKILLS_DIR}:
862
979
  }
863
980
  }
864
981
  if (linkedAgents.length > 0) {
865
- console.log(chalk2.gray(` \u2192 Linked to: ${linkedAgents.join(", ")}`));
982
+ console.log(chalk3.gray(` \u2192 Linked to: ${linkedAgents.join(", ")}`));
866
983
  } else {
867
- console.log(chalk2.yellow(` \u2192 Not linked to any agent`));
984
+ console.log(chalk3.yellow(` \u2192 Not linked to any agent`));
868
985
  }
869
986
  if (isDev) {
870
987
  const target = readSymlink(skillPath);
871
988
  if (target) {
872
- console.log(chalk2.gray(` \u2192 Source: ${target}`));
989
+ console.log(chalk3.gray(` \u2192 Source: ${target}`));
873
990
  }
874
991
  }
875
992
  console.log("");
876
993
  } catch (error) {
877
- continue;
878
994
  }
879
995
  }
880
996
  }
881
997
 
882
998
  // src/commands/remove.ts
883
- import fs6 from "fs";
999
+ import fs8 from "fs";
884
1000
  async function remove(skillName, options = {}) {
885
1001
  const extractedName = extractSkillName(skillName);
886
1002
  const sharedPath = getSharedSkillPath(extractedName);
887
- const skillExists = fs6.existsSync(sharedPath);
1003
+ const skillExists = fs8.existsSync(sharedPath);
888
1004
  if (!skillExists) {
889
1005
  logger.error(`Skill not found: ${extractedName}`);
890
1006
  logger.info(`Location: ${sharedPath}`);
@@ -894,11 +1010,11 @@ async function remove(skillName, options = {}) {
894
1010
  const installedAgents = detectInstalledAgents(cwd);
895
1011
  let targetAgents = installedAgents;
896
1012
  if (options.agent && options.agent !== "all") {
897
- const agent = installedAgents.find((a) => a.name === options.agent);
1013
+ const agent = AGENTS.find((a) => a.name === options.agent && a.enabled);
898
1014
  if (!agent) {
899
- logger.error(`Agent not installed: ${options.agent}`);
1015
+ logger.error(`Unknown agent: ${options.agent}`);
900
1016
  logger.info(`
901
- Installed agents: ${installedAgents.map((a) => a.name).join(", ")}`);
1017
+ Supported agents: ${AGENTS.filter((a) => a.enabled).map((a) => a.name).join(", ")}`);
902
1018
  process.exit(1);
903
1019
  }
904
1020
  targetAgents = [agent];
@@ -920,12 +1036,12 @@ Installed agents: ${installedAgents.map((a) => a.name).join(", ")}`);
920
1036
  }
921
1037
  logger.info("Removing skill from shared directory...");
922
1038
  try {
923
- const stats = fs6.lstatSync(sharedPath);
1039
+ const stats = fs8.lstatSync(sharedPath);
924
1040
  if (stats.isSymbolicLink()) {
925
- fs6.unlinkSync(sharedPath);
1041
+ fs8.unlinkSync(sharedPath);
926
1042
  logger.success("Removed symlink from shared directory");
927
1043
  } else {
928
- fs6.rmSync(sharedPath, { recursive: true, force: true });
1044
+ fs8.rmSync(sharedPath, { recursive: true, force: true });
929
1045
  logger.success("Removed skill from shared directory");
930
1046
  }
931
1047
  } catch (error) {
@@ -936,7 +1052,7 @@ Installed agents: ${installedAgents.map((a) => a.name).join(", ")}`);
936
1052
  for (const agent of AGENTS) {
937
1053
  const agentSkillPaths = getAgentSkillPaths(agent.name, extractedName, cwd);
938
1054
  const hasSymlink = agentSkillPaths.some((path7) => {
939
- return fs6.existsSync(path7) && isSymlink(path7);
1055
+ return fs8.existsSync(path7) && isSymlink(path7);
940
1056
  });
941
1057
  if (hasSymlink) {
942
1058
  remainingSymlinks.push(agent.displayName);
@@ -954,44 +1070,6 @@ Installed agents: ${installedAgents.map((a) => a.name).join(", ")}`);
954
1070
  }
955
1071
  }
956
1072
 
957
- // src/commands/agents.ts
958
- import chalk3 from "chalk";
959
- import fs7 from "fs";
960
- import os3 from "os";
961
- function agents() {
962
- const cwd = process.cwd();
963
- console.log(chalk3.bold("\n\u{1F4CB} Supported AI Agents:\n"));
964
- for (const agent of AGENTS) {
965
- const skillsDirs = getAgentSkillsDirs(agent, cwd);
966
- const dirsInfo = skillsDirs.length > 1 ? ` (${skillsDirs.length} directories)` : "";
967
- console.log(chalk3.bold(agent.displayName));
968
- console.log(chalk3.gray(` Name: ${agent.name}`));
969
- if (skillsDirs.length === 0) {
970
- console.log(chalk3.yellow(" \u26A0\uFE0F No directories configured"));
971
- } else {
972
- console.log(chalk3.gray(` Directories${dirsInfo}:`));
973
- for (const dir of skillsDirs) {
974
- const exists = fs7.existsSync(dir);
975
- const status = exists ? chalk3.green("\u2713") : chalk3.gray("\u25CB");
976
- const pathColor = exists ? chalk3.white : chalk3.gray;
977
- console.log(` ${status} ${pathColor(dir)}`);
978
- }
979
- }
980
- console.log("");
981
- }
982
- console.log(chalk3.bold("\u{1F4E6} Shared Skills Directory:"));
983
- const sharedExists = fs7.existsSync(SHARED_SKILLS_DIR);
984
- const sharedStatus = sharedExists ? chalk3.green("\u2713") : chalk3.gray("\u25CB");
985
- const sharedPathColor = sharedExists ? chalk3.white : chalk3.gray;
986
- console.log(` ${sharedStatus} ${sharedPathColor(SHARED_SKILLS_DIR)}`);
987
- console.log("");
988
- const home = os3.homedir();
989
- if (cwd !== home) {
990
- console.log(chalk3.gray(`Current working directory: ${cwd}`));
991
- console.log(chalk3.gray("(Project-level directories are shown above)\n"));
992
- }
993
- }
994
-
995
1073
  // src/index.ts
996
1074
  var __filename2 = fileURLToPath(import.meta.url);
997
1075
  var __dirname2 = dirname(__filename2);
@@ -1000,7 +1078,11 @@ var packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
1000
1078
  var version = packageJson.version;
1001
1079
  var program = new Command();
1002
1080
  program.name("eskill").description("Unified CLI tool for managing AI agent skills").version(version);
1003
- program.command("install <skill>").alias("add").description("Install a skill from NPM, Git URL, or local directory").option("-a, --agent <name>", "Install for specific agent (claude, cursor, windsurf, or all)").option("-l, --link", "Dev mode: symlink from local directory").option("-f, --force", "Force reinstall if already exists").option("-r, --registry <url>", "NPM registry URL (overrides .npmrc and global config)").option("-t, --timeout <ms>", "Timeout in milliseconds (default: 180000 for npm, 120000 for git)", (value) => parseInt(value, 10)).action(async (skill, options) => {
1081
+ program.command("install <skill>").alias("add").description("Install a skill from NPM, Git URL, or local directory").option("-a, --agent <name>", "Install for specific agent (claude, cursor, windsurf, or all)").option("-l, --link", "Dev mode: symlink from local directory").option("-f, --force", "Force reinstall if already exists").option("-r, --registry <url>", "NPM registry URL (overrides .npmrc and global config)").option(
1082
+ "-t, --timeout <ms>",
1083
+ "Timeout in milliseconds (default: 180000 for npm, 120000 for git)",
1084
+ (value) => Number.parseInt(value, 10)
1085
+ ).action(async (skill, options) => {
1004
1086
  try {
1005
1087
  await install(skill, options);
1006
1088
  } catch (error) {