@empjs/skill 1.0.5 → 1.0.6

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,75 +3,13 @@
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 fs 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
77
15
  import os from "os";
@@ -189,7 +127,213 @@ var SHARED_SKILLS_DIR = path.join(HOME, ".emp-agent", "skills");
189
127
  var CONFIG_FILE = path.join(HOME, ".emp-agent", "config.json");
190
128
  var CACHE_DIR = path.join(HOME, ".emp-agent", "cache");
191
129
 
130
+ // src/commands/agents.ts
131
+ function agents() {
132
+ const cwd = process.cwd();
133
+ console.log(chalk.bold("\n\u{1F4CB} Supported AI Agents:\n"));
134
+ for (const agent of AGENTS) {
135
+ const skillsDirs = getAgentSkillsDirs(agent, cwd);
136
+ const dirsInfo = skillsDirs.length > 1 ? ` (${skillsDirs.length} directories)` : "";
137
+ console.log(chalk.bold(agent.displayName));
138
+ console.log(chalk.gray(` Name: ${agent.name}`));
139
+ if (skillsDirs.length === 0) {
140
+ console.log(chalk.yellow(" \u26A0\uFE0F No directories configured"));
141
+ } else {
142
+ console.log(chalk.gray(` Directories${dirsInfo}:`));
143
+ for (const dir of skillsDirs) {
144
+ const exists = fs.existsSync(dir);
145
+ const status = exists ? chalk.green("\u2713") : chalk.gray("\u25CB");
146
+ const pathColor = exists ? chalk.white : chalk.gray;
147
+ console.log(` ${status} ${pathColor(dir)}`);
148
+ }
149
+ }
150
+ console.log("");
151
+ }
152
+ console.log(chalk.bold("\u{1F4E6} Shared Skills Directory:"));
153
+ const sharedExists = fs.existsSync(SHARED_SKILLS_DIR);
154
+ const sharedStatus = sharedExists ? chalk.green("\u2713") : chalk.gray("\u25CB");
155
+ const sharedPathColor = sharedExists ? chalk.white : chalk.gray;
156
+ console.log(` ${sharedStatus} ${sharedPathColor(SHARED_SKILLS_DIR)}`);
157
+ console.log("");
158
+ const home = os2.homedir();
159
+ if (cwd !== home) {
160
+ console.log(chalk.gray(`Current working directory: ${cwd}`));
161
+ console.log(chalk.gray("(Project-level directories are shown above)\n"));
162
+ }
163
+ }
164
+
165
+ // src/commands/install.ts
166
+ import { exec as exec2 } from "child_process";
167
+ import fs5 from "fs";
168
+ import os3 from "os";
169
+ import path5 from "path";
170
+ import { promisify as promisify2 } from "util";
171
+
172
+ // src/utils/git.ts
173
+ function parseGitUrl(url) {
174
+ const githubPatterns = [
175
+ // https://github.com/owner/repo/tree/branch/path/to/dir
176
+ /^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)(?:\/(.+))?$/,
177
+ // https://github.com/owner/repo
178
+ /^https?:\/\/github\.com\/([^/]+)\/([^/]+)(?:\/)?$/,
179
+ // git@github.com:owner/repo.git
180
+ /^git@github\.com:([^/]+)\/([^/]+)(?:\.git)?$/
181
+ ];
182
+ const gitlabPatterns = [
183
+ // https://host/group/repo/-/tree/branch/path (self-hosted + gitlab.com)
184
+ /^https?:\/\/([^/]+)\/(.+)\/-\/tree\/([^/]+)(?:\/(.+))?$/,
185
+ // https://gitlab.com/owner/repo
186
+ /^https?:\/\/gitlab\.com\/([^/]+)\/([^/]+)(?:\/)?$/,
187
+ // git@gitlab.com:owner/repo.git or git@host:group/repo.git
188
+ /^git@([^:]+):(.+)(?:\.git)?$/
189
+ ];
190
+ for (let i = 0; i < githubPatterns.length; i++) {
191
+ const pattern = githubPatterns[i];
192
+ const match = url.match(pattern);
193
+ if (match) {
194
+ const owner = match[1];
195
+ const repo = match[2].replace(/\.git$/, "");
196
+ let branch;
197
+ let path7;
198
+ if (i === 0) {
199
+ branch = match[3];
200
+ path7 = match[4];
201
+ } else if (i === 1) {
202
+ branch = "main";
203
+ } else {
204
+ branch = "main";
205
+ }
206
+ const gitUrl = `https://github.com/${owner}/${repo}.git`;
207
+ return {
208
+ type: "github",
209
+ owner,
210
+ repo,
211
+ branch,
212
+ path: path7,
213
+ gitUrl,
214
+ installUrl: gitUrl
215
+ // Will be used for git clone
216
+ };
217
+ }
218
+ }
219
+ for (let i = 0; i < gitlabPatterns.length; i++) {
220
+ const pattern = gitlabPatterns[i];
221
+ const match = url.match(pattern);
222
+ if (match) {
223
+ let owner;
224
+ let repo;
225
+ let branch;
226
+ let path7;
227
+ let gitUrl;
228
+ if (i === 0) {
229
+ const host = match[1];
230
+ const repoPath = match[2].replace(/\.git$/, "");
231
+ branch = match[3];
232
+ path7 = match[4];
233
+ const parts = repoPath.split("/");
234
+ repo = parts.pop() || repoPath;
235
+ owner = parts.join("/") || repo;
236
+ gitUrl = `https://${host}/${repoPath}.git`;
237
+ } else if (i === 1) {
238
+ owner = match[1];
239
+ repo = match[2].replace(/\.git$/, "");
240
+ branch = "main";
241
+ gitUrl = `https://gitlab.com/${owner}/${repo}.git`;
242
+ } else {
243
+ const host = match[1];
244
+ const repoPath = match[2].replace(/\.git$/, "");
245
+ branch = "main";
246
+ const parts = repoPath.split("/");
247
+ repo = parts.pop() || repoPath;
248
+ owner = parts.join("/") || repo;
249
+ gitUrl = `https://${host}/${repoPath}.git`;
250
+ }
251
+ return {
252
+ type: "gitlab",
253
+ owner,
254
+ repo,
255
+ branch,
256
+ path: path7,
257
+ gitUrl,
258
+ installUrl: gitUrl
259
+ };
260
+ }
261
+ }
262
+ if (url.startsWith("git+") || url.startsWith("git://")) {
263
+ return {
264
+ type: "other",
265
+ owner: "",
266
+ repo: "",
267
+ gitUrl: url.replace(/^git\+/, ""),
268
+ installUrl: url.startsWith("git+") ? url : `git+${url}`
269
+ };
270
+ }
271
+ return null;
272
+ }
273
+ function isGitUrl(str) {
274
+ return str.includes("github.com") || str.includes("gitlab.com") || str.includes("/-/tree/") || // GitLab web URL pattern (self-hosted)
275
+ str.startsWith("git@") || str.startsWith("git+") || str.startsWith("git://");
276
+ }
277
+
278
+ // src/utils/logger.ts
279
+ import chalk2 from "chalk";
280
+ import ora from "ora";
281
+ var Logger = class {
282
+ spinner = null;
283
+ info(message) {
284
+ if (this.spinner) this.spinner.stop();
285
+ console.log(chalk2.blue("\u2139"), message);
286
+ }
287
+ success(message) {
288
+ if (this.spinner) this.spinner.stop();
289
+ console.log(chalk2.green("\u2713"), message);
290
+ }
291
+ warn(message) {
292
+ if (this.spinner) this.spinner.stop();
293
+ console.log(chalk2.yellow("\u26A0"), message);
294
+ }
295
+ error(message) {
296
+ if (this.spinner) this.spinner.stop();
297
+ console.log(chalk2.red("\u2717"), message);
298
+ }
299
+ start(message) {
300
+ if (this.spinner) this.spinner.stop();
301
+ this.spinner = ora(message).start();
302
+ return this.spinner;
303
+ }
304
+ stopSpinner() {
305
+ if (this.spinner) {
306
+ this.spinner.stop();
307
+ this.spinner = null;
308
+ }
309
+ }
310
+ /**
311
+ * Update spinner text without stopping it
312
+ */
313
+ updateSpinner(message) {
314
+ if (this.spinner) {
315
+ this.spinner.text = message;
316
+ }
317
+ }
318
+ /**
319
+ * Log info without stopping spinner (for background info)
320
+ */
321
+ infoWithoutStop(message) {
322
+ if (this.spinner) {
323
+ const currentText = this.spinner.text;
324
+ this.spinner.stop();
325
+ console.log(chalk2.blue("\u2139"), message);
326
+ this.spinner.start(currentText);
327
+ } else {
328
+ console.log(chalk2.blue("\u2139"), message);
329
+ }
330
+ }
331
+ };
332
+ var logger = new Logger();
333
+
192
334
  // src/utils/paths.ts
335
+ import fs2 from "fs";
336
+ import path2 from "path";
193
337
  function getSharedSkillPath(skillName) {
194
338
  return path2.join(SHARED_SKILLS_DIR, skillName);
195
339
  }
@@ -202,8 +346,8 @@ function getAgentSkillPaths(agentName, skillName, cwd) {
202
346
  return skillsDirs.map((dir) => path2.join(dir, skillName));
203
347
  }
204
348
  function ensureSharedDir() {
205
- if (!fs.existsSync(SHARED_SKILLS_DIR)) {
206
- fs.mkdirSync(SHARED_SKILLS_DIR, { recursive: true });
349
+ if (!fs2.existsSync(SHARED_SKILLS_DIR)) {
350
+ fs2.mkdirSync(SHARED_SKILLS_DIR, { recursive: true });
207
351
  }
208
352
  }
209
353
  function detectInstalledAgents(cwd) {
@@ -211,7 +355,7 @@ function detectInstalledAgents(cwd) {
211
355
  try {
212
356
  const skillsDirs = getAgentSkillsDirs(agent, cwd);
213
357
  return skillsDirs.some((dir) => {
214
- return fs.existsSync(dir) || fs.existsSync(path2.dirname(dir));
358
+ return fs2.existsSync(dir) || fs2.existsSync(path2.dirname(dir));
215
359
  });
216
360
  } catch {
217
361
  return false;
@@ -230,32 +374,93 @@ function extractSkillName(nameOrPath) {
230
374
  return path2.basename(nameOrPath);
231
375
  }
232
376
 
233
- // src/utils/symlink.ts
234
- import fs2 from "fs";
377
+ // src/utils/registry.ts
378
+ import { exec } from "child_process";
379
+ import fs3 from "fs";
235
380
  import path3 from "path";
381
+ import { promisify } from "util";
382
+ var execAsync = promisify(exec);
383
+ function findNpmrc(startDir) {
384
+ let currentDir = path3.resolve(startDir);
385
+ while (currentDir !== path3.dirname(currentDir)) {
386
+ const npmrcPath = path3.join(currentDir, ".npmrc");
387
+ if (fs3.existsSync(npmrcPath)) {
388
+ return npmrcPath;
389
+ }
390
+ currentDir = path3.dirname(currentDir);
391
+ }
392
+ return null;
393
+ }
394
+ function parseNpmrc(npmrcPath) {
395
+ try {
396
+ const content = fs3.readFileSync(npmrcPath, "utf-8");
397
+ const lines = content.split("\n");
398
+ for (const line of lines) {
399
+ const trimmed = line.trim();
400
+ if (!trimmed || trimmed.startsWith("#")) {
401
+ continue;
402
+ }
403
+ const registryMatch = trimmed.match(/^(?:@[^:]+:)?registry\s*=\s*(.+)$/);
404
+ if (registryMatch) {
405
+ return registryMatch[1].trim();
406
+ }
407
+ }
408
+ } catch (error) {
409
+ }
410
+ return null;
411
+ }
412
+ async function getGlobalRegistry() {
413
+ try {
414
+ const { stdout } = await execAsync("npm config get registry");
415
+ const registry = stdout.trim();
416
+ if (registry && registry !== "undefined") {
417
+ return registry;
418
+ }
419
+ } catch (error) {
420
+ }
421
+ return null;
422
+ }
423
+ async function getRegistry(cwd = process.cwd()) {
424
+ const npmrcPath = findNpmrc(cwd);
425
+ if (npmrcPath) {
426
+ const registry = parseNpmrc(npmrcPath);
427
+ if (registry) {
428
+ return registry;
429
+ }
430
+ }
431
+ const globalRegistry = await getGlobalRegistry();
432
+ if (globalRegistry) {
433
+ return globalRegistry;
434
+ }
435
+ return "https://registry.npmjs.org/";
436
+ }
437
+
438
+ // src/utils/symlink.ts
439
+ import fs4 from "fs";
440
+ import path4 from "path";
236
441
  function createSymlink(skillName, agent, cwd) {
237
442
  const source = getSharedSkillPath(skillName);
238
- if (!fs2.existsSync(source)) {
443
+ if (!fs4.existsSync(source)) {
239
444
  logger.error(`Skill not found: ${source}`);
240
445
  return false;
241
446
  }
242
447
  const targets = getAgentSkillPaths(agent.name, skillName, cwd);
243
448
  let successCount = 0;
244
449
  for (const target of targets) {
245
- const targetDir = path3.dirname(target);
246
- if (!fs2.existsSync(targetDir)) {
450
+ const targetDir = path4.dirname(target);
451
+ if (!fs4.existsSync(targetDir)) {
247
452
  try {
248
- fs2.mkdirSync(targetDir, { recursive: true });
453
+ fs4.mkdirSync(targetDir, { recursive: true });
249
454
  } catch (error) {
250
455
  logger.error(`Failed to create directory ${targetDir}: ${error.message}`);
251
456
  continue;
252
457
  }
253
458
  }
254
- if (fs2.existsSync(target)) {
459
+ if (fs4.existsSync(target)) {
255
460
  try {
256
- const stats = fs2.lstatSync(target);
461
+ const stats = fs4.lstatSync(target);
257
462
  if (stats.isSymbolicLink()) {
258
- fs2.unlinkSync(target);
463
+ fs4.unlinkSync(target);
259
464
  } else {
260
465
  logger.warn(`Target exists but is not a symlink, skipping: ${target}`);
261
466
  continue;
@@ -266,7 +471,7 @@ function createSymlink(skillName, agent, cwd) {
266
471
  }
267
472
  }
268
473
  try {
269
- fs2.symlinkSync(source, target, "dir");
474
+ fs4.symlinkSync(source, target, "dir");
270
475
  successCount++;
271
476
  } catch (error) {
272
477
  logger.error(`Failed to create symlink at ${target}: ${error.message}`);
@@ -283,13 +488,13 @@ function removeSymlink(skillName, agent, cwd) {
283
488
  const targets = getAgentSkillPaths(agent.name, skillName, cwd);
284
489
  let removedCount = 0;
285
490
  for (const target of targets) {
286
- if (!fs2.existsSync(target)) {
491
+ if (!fs4.existsSync(target)) {
287
492
  continue;
288
493
  }
289
494
  try {
290
- const stats = fs2.lstatSync(target);
495
+ const stats = fs4.lstatSync(target);
291
496
  if (stats.isSymbolicLink()) {
292
- fs2.unlinkSync(target);
497
+ fs4.unlinkSync(target);
293
498
  removedCount++;
294
499
  } else {
295
500
  logger.warn(`Not a symlink: ${target}`);
@@ -307,7 +512,7 @@ function removeSymlink(skillName, agent, cwd) {
307
512
  }
308
513
  function isSymlink(filePath) {
309
514
  try {
310
- const stats = fs2.lstatSync(filePath);
515
+ const stats = fs4.lstatSync(filePath);
311
516
  return stats.isSymbolicLink();
312
517
  } catch {
313
518
  return false;
@@ -315,164 +520,12 @@ function isSymlink(filePath) {
315
520
  }
316
521
  function readSymlink(filePath) {
317
522
  try {
318
- return fs2.readlinkSync(filePath);
523
+ return fs4.readlinkSync(filePath);
319
524
  } catch {
320
525
  return null;
321
526
  }
322
527
  }
323
528
 
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
529
  // src/commands/install.ts
477
530
  var execAsync2 = promisify2(exec2);
478
531
  async function execWithTimeout(command, timeout = 12e4, env) {
@@ -484,10 +537,7 @@ async function execWithTimeout(command, timeout = 12e4, env) {
484
537
  });
485
538
  try {
486
539
  const execOptions = env ? { env } : {};
487
- const result = await Promise.race([
488
- execAsync2(command, execOptions),
489
- timeoutPromise
490
- ]);
540
+ const result = await Promise.race([execAsync2(command, execOptions), timeoutPromise]);
491
541
  if (timeoutId) {
492
542
  clearTimeout(timeoutId);
493
543
  }
@@ -525,7 +575,7 @@ async function install(skillNameOrPath, options = {}) {
525
575
  logger.infoWithoutStop(`Path: ${gitInfo.path}`);
526
576
  }
527
577
  logger.infoWithoutStop(`Timeout: ${timeout / 1e3}s`);
528
- fs4.mkdirSync(tempDir, { recursive: true });
578
+ fs5.mkdirSync(tempDir, { recursive: true });
529
579
  const branchFlag = gitInfo.branch ? `-b ${gitInfo.branch}` : "";
530
580
  const cloneCommand = branchFlag ? `git clone ${branchFlag} ${gitInfo.gitUrl} ${cloneDir} --depth 1 --quiet` : `git clone ${gitInfo.gitUrl} ${cloneDir} --depth 1 --quiet`;
531
581
  try {
@@ -547,7 +597,7 @@ async function install(skillNameOrPath, options = {}) {
547
597
  }
548
598
  if (gitInfo.path) {
549
599
  skillPath = path5.join(cloneDir, gitInfo.path);
550
- if (!fs4.existsSync(skillPath)) {
600
+ if (!fs5.existsSync(skillPath)) {
551
601
  logger.error(`Path not found in repository: ${gitInfo.path}`);
552
602
  logger.info(`Repository cloned to: ${cloneDir}`);
553
603
  process.exit(1);
@@ -556,7 +606,7 @@ async function install(skillNameOrPath, options = {}) {
556
606
  skillPath = cloneDir;
557
607
  }
558
608
  const skillMdPath = path5.join(skillPath, "SKILL.md");
559
- if (!fs4.existsSync(skillMdPath)) {
609
+ if (!fs5.existsSync(skillMdPath)) {
560
610
  logger.warn(`Warning: SKILL.md not found in ${skillPath}`);
561
611
  logger.info("The directory may not be a valid skill package");
562
612
  }
@@ -578,16 +628,16 @@ Tried to clone: ${gitInfo.gitUrl}`);
578
628
  }
579
629
  process.exit(1);
580
630
  }
581
- } else if (options.link || fs4.existsSync(skillNameOrPath)) {
631
+ } else if (options.link || fs5.existsSync(skillNameOrPath)) {
582
632
  skillPath = path5.resolve(skillNameOrPath);
583
- if (!fs4.existsSync(skillPath)) {
633
+ if (!fs5.existsSync(skillPath)) {
584
634
  logger.error(`Path not found: ${skillPath}`);
585
635
  process.exit(1);
586
636
  }
587
637
  const pkgPath = path5.join(skillPath, "package.json");
588
- if (fs4.existsSync(pkgPath)) {
638
+ if (fs5.existsSync(pkgPath)) {
589
639
  try {
590
- const pkg = JSON.parse(fs4.readFileSync(pkgPath, "utf-8"));
640
+ const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
591
641
  skillName = extractSkillName(pkg.name);
592
642
  } catch {
593
643
  skillName = extractSkillName(path5.basename(skillPath));
@@ -604,12 +654,12 @@ Tried to clone: ${gitInfo.gitUrl}`);
604
654
  const spinner = logger.start(`Installing ${skillNameOrPath}...`);
605
655
  logger.infoWithoutStop(`Registry: ${registry}`);
606
656
  logger.infoWithoutStop(`Timeout: ${timeout / 1e3}s`);
607
- fs4.mkdirSync(tempDir, { recursive: true });
657
+ fs5.mkdirSync(tempDir, { recursive: true });
608
658
  logger.updateSpinner(`Downloading ${skillNameOrPath} from ${registry}...`);
609
- const homeDir = process.env.HOME || process.env.USERPROFILE || os2.homedir();
659
+ const homeDir = process.env.HOME || process.env.USERPROFILE || os3.homedir();
610
660
  const npmCacheDir = path5.join(homeDir, ".npm");
611
661
  const npmConfigPrefix = path5.join(homeDir, ".npm-global");
612
- fs4.mkdirSync(npmCacheDir, { recursive: true });
662
+ fs5.mkdirSync(npmCacheDir, { recursive: true });
613
663
  const installCommand = `npm install ${skillNameOrPath} --prefix ${tempDir} --registry=${registry} --no-save --silent --no-bin-links --prefer-offline`;
614
664
  const env = {
615
665
  ...process.env,
@@ -634,7 +684,9 @@ Tried to clone: ${gitInfo.gitUrl}`);
634
684
  logger.info("");
635
685
  logger.info("Suggestions:");
636
686
  logger.info(` - Try again: eskill add ${skillNameOrPath}`);
637
- logger.info(` - Use a different registry: eskill add ${skillNameOrPath} --registry=https://registry.npmjs.org/`);
687
+ logger.info(
688
+ ` - Use a different registry: eskill add ${skillNameOrPath} --registry=https://registry.npmjs.org/`
689
+ );
638
690
  logger.info(` - Increase timeout: eskill add ${skillNameOrPath} --timeout=300000`);
639
691
  } else if (errorMessage.includes("EACCES") || errorMessage.includes("permission denied") || errorMessage.includes("Permission denied")) {
640
692
  logger.error("Permission denied error detected");
@@ -673,7 +725,9 @@ Tried to clone: ${gitInfo.gitUrl}`);
673
725
  logger.info("Please check:");
674
726
  logger.info(" - Your internet connection");
675
727
  logger.info(` - Registry accessibility: ${registry}`);
676
- logger.info(` - Try a different registry: eskill add ${skillNameOrPath} --registry=https://registry.npmjs.org/`);
728
+ logger.info(
729
+ ` - Try a different registry: eskill add ${skillNameOrPath} --registry=https://registry.npmjs.org/`
730
+ );
677
731
  } else {
678
732
  logger.error(`Failed to download: ${errorMessage}`);
679
733
  logger.info("");
@@ -686,7 +740,7 @@ Tried to clone: ${gitInfo.gitUrl}`);
686
740
  process.exit(1);
687
741
  }
688
742
  skillPath = path5.join(tempDir, "node_modules", skillNameOrPath);
689
- if (!fs4.existsSync(skillPath)) {
743
+ if (!fs5.existsSync(skillPath)) {
690
744
  logger.error(`Failed to download package: ${skillNameOrPath}`);
691
745
  process.exit(1);
692
746
  }
@@ -696,10 +750,10 @@ Tried to clone: ${gitInfo.gitUrl}`);
696
750
  }
697
751
  }
698
752
  const targetPath = getSharedSkillPath(skillName);
699
- if (fs4.existsSync(targetPath)) {
753
+ if (fs5.existsSync(targetPath)) {
700
754
  if (options.force) {
701
755
  logger.warn("Removing existing installation...");
702
- fs4.rmSync(targetPath, { recursive: true, force: true });
756
+ fs5.rmSync(targetPath, { recursive: true, force: true });
703
757
  } else {
704
758
  logger.error(`Skill already exists: ${targetPath}`);
705
759
  logger.info("Use --force to overwrite");
@@ -707,7 +761,7 @@ Tried to clone: ${gitInfo.gitUrl}`);
707
761
  }
708
762
  }
709
763
  if (options.link) {
710
- fs4.symlinkSync(skillPath, targetPath, "dir");
764
+ fs5.symlinkSync(skillPath, targetPath, "dir");
711
765
  logger.success(`Linked to shared directory (dev mode)`);
712
766
  } else {
713
767
  copyDir(skillPath, targetPath);
@@ -753,8 +807,8 @@ Linked to ${successCount}/${targetAgents.length} agents`);
753
807
  }
754
808
  }
755
809
  function copyDir(src, dest) {
756
- fs4.mkdirSync(dest, { recursive: true });
757
- const entries = fs4.readdirSync(src, { withFileTypes: true });
810
+ fs5.mkdirSync(dest, { recursive: true });
811
+ const entries = fs5.readdirSync(src, { withFileTypes: true });
758
812
  for (const entry of entries) {
759
813
  const srcPath = path5.join(src, entry.name);
760
814
  const destPath = path5.join(dest, entry.name);
@@ -764,44 +818,44 @@ function copyDir(src, dest) {
764
818
  if (entry.isDirectory()) {
765
819
  copyDir(srcPath, destPath);
766
820
  } else {
767
- fs4.copyFileSync(srcPath, destPath);
821
+ fs5.copyFileSync(srcPath, destPath);
768
822
  }
769
823
  }
770
824
  }
771
825
 
772
826
  // src/commands/list.ts
773
- import fs5 from "fs";
827
+ import fs6 from "fs";
774
828
  import path6 from "path";
775
- import chalk2 from "chalk";
829
+ import chalk3 from "chalk";
776
830
  function list() {
777
- if (!fs5.existsSync(SHARED_SKILLS_DIR)) {
831
+ if (!fs6.existsSync(SHARED_SKILLS_DIR)) {
778
832
  logger.info("No skills installed");
779
833
  logger.info(`
780
- To install a skill, run: ${chalk2.cyan("eskill install <skill-name>")}`);
834
+ To install a skill, run: ${chalk3.cyan("eskill install <skill-name>")}`);
781
835
  return;
782
836
  }
783
- const skills = fs5.readdirSync(SHARED_SKILLS_DIR);
837
+ const skills = fs6.readdirSync(SHARED_SKILLS_DIR);
784
838
  if (skills.length === 0) {
785
839
  logger.info("No skills installed");
786
840
  logger.info(`
787
- To install a skill, run: ${chalk2.cyan("eskill install <skill-name>")}`);
841
+ To install a skill, run: ${chalk3.cyan("eskill install <skill-name>")}`);
788
842
  return;
789
843
  }
790
- console.log(chalk2.bold(`
844
+ console.log(chalk3.bold(`
791
845
  Installed skills in ${SHARED_SKILLS_DIR}:
792
846
  `));
793
847
  for (const skill of skills) {
794
848
  const skillPath = path6.join(SHARED_SKILLS_DIR, skill);
795
849
  try {
796
- const stats = fs5.lstatSync(skillPath);
850
+ const stats = fs6.lstatSync(skillPath);
797
851
  if (!stats.isDirectory() && !stats.isSymbolicLink()) {
798
852
  continue;
799
853
  }
800
854
  let version2 = "unknown";
801
855
  const pkgPath = path6.join(skillPath, "package.json");
802
- if (fs5.existsSync(pkgPath)) {
856
+ if (fs6.existsSync(pkgPath)) {
803
857
  try {
804
- const pkgContent = fs5.readFileSync(pkgPath, "utf-8");
858
+ const pkgContent = fs6.readFileSync(pkgPath, "utf-8");
805
859
  const pkg = JSON.parse(pkgContent);
806
860
  if (pkg.version && typeof pkg.version === "string") {
807
861
  version2 = pkg.version;
@@ -811,9 +865,9 @@ Installed skills in ${SHARED_SKILLS_DIR}:
811
865
  }
812
866
  if (version2 === "unknown") {
813
867
  const skillMdPath = path6.join(skillPath, "SKILL.md");
814
- if (fs5.existsSync(skillMdPath)) {
868
+ if (fs6.existsSync(skillMdPath)) {
815
869
  try {
816
- const skillMdContent = fs5.readFileSync(skillMdPath, "utf-8");
870
+ const skillMdContent = fs6.readFileSync(skillMdPath, "utf-8");
817
871
  const frontmatterMatch = skillMdContent.match(/^---\s*\n([\s\S]*?)\n---/);
818
872
  if (frontmatterMatch) {
819
873
  const frontmatter = frontmatterMatch[1];
@@ -831,8 +885,8 @@ Installed skills in ${SHARED_SKILLS_DIR}:
831
885
  const targetPath = readSymlink(skillPath);
832
886
  if (targetPath) {
833
887
  const targetPkgPath = path6.join(targetPath, "package.json");
834
- if (fs5.existsSync(targetPkgPath)) {
835
- const pkg = JSON.parse(fs5.readFileSync(targetPkgPath, "utf-8"));
888
+ if (fs6.existsSync(targetPkgPath)) {
889
+ const pkg = JSON.parse(fs6.readFileSync(targetPkgPath, "utf-8"));
836
890
  if (pkg.version && typeof pkg.version === "string") {
837
891
  version2 = pkg.version;
838
892
  }
@@ -842,16 +896,16 @@ Installed skills in ${SHARED_SKILLS_DIR}:
842
896
  }
843
897
  }
844
898
  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}`);
899
+ const devTag = isDev ? chalk3.yellow(" (dev)") : "";
900
+ const versionDisplay = version2 !== "unknown" ? chalk3.gray(`(v${version2})`) : "";
901
+ console.log(chalk3.green("\u{1F4E6}") + ` ${chalk3.bold(skill)}${versionDisplay ? " " + versionDisplay : ""}${devTag}`);
848
902
  const cwd = process.cwd();
849
903
  const linkedAgents = [];
850
904
  for (const agent of AGENTS) {
851
905
  const skillsDirs = getAgentSkillsDirs(agent, cwd);
852
906
  const hasSymlink = skillsDirs.some((dir) => {
853
907
  const agentSkillPath = path6.join(dir, skill);
854
- if (fs5.existsSync(agentSkillPath) && isSymlink(agentSkillPath)) {
908
+ if (fs6.existsSync(agentSkillPath) && isSymlink(agentSkillPath)) {
855
909
  const target = readSymlink(agentSkillPath);
856
910
  return target === skillPath;
857
911
  }
@@ -862,29 +916,28 @@ Installed skills in ${SHARED_SKILLS_DIR}:
862
916
  }
863
917
  }
864
918
  if (linkedAgents.length > 0) {
865
- console.log(chalk2.gray(` \u2192 Linked to: ${linkedAgents.join(", ")}`));
919
+ console.log(chalk3.gray(` \u2192 Linked to: ${linkedAgents.join(", ")}`));
866
920
  } else {
867
- console.log(chalk2.yellow(` \u2192 Not linked to any agent`));
921
+ console.log(chalk3.yellow(` \u2192 Not linked to any agent`));
868
922
  }
869
923
  if (isDev) {
870
924
  const target = readSymlink(skillPath);
871
925
  if (target) {
872
- console.log(chalk2.gray(` \u2192 Source: ${target}`));
926
+ console.log(chalk3.gray(` \u2192 Source: ${target}`));
873
927
  }
874
928
  }
875
929
  console.log("");
876
930
  } catch (error) {
877
- continue;
878
931
  }
879
932
  }
880
933
  }
881
934
 
882
935
  // src/commands/remove.ts
883
- import fs6 from "fs";
936
+ import fs7 from "fs";
884
937
  async function remove(skillName, options = {}) {
885
938
  const extractedName = extractSkillName(skillName);
886
939
  const sharedPath = getSharedSkillPath(extractedName);
887
- const skillExists = fs6.existsSync(sharedPath);
940
+ const skillExists = fs7.existsSync(sharedPath);
888
941
  if (!skillExists) {
889
942
  logger.error(`Skill not found: ${extractedName}`);
890
943
  logger.info(`Location: ${sharedPath}`);
@@ -920,12 +973,12 @@ Installed agents: ${installedAgents.map((a) => a.name).join(", ")}`);
920
973
  }
921
974
  logger.info("Removing skill from shared directory...");
922
975
  try {
923
- const stats = fs6.lstatSync(sharedPath);
976
+ const stats = fs7.lstatSync(sharedPath);
924
977
  if (stats.isSymbolicLink()) {
925
- fs6.unlinkSync(sharedPath);
978
+ fs7.unlinkSync(sharedPath);
926
979
  logger.success("Removed symlink from shared directory");
927
980
  } else {
928
- fs6.rmSync(sharedPath, { recursive: true, force: true });
981
+ fs7.rmSync(sharedPath, { recursive: true, force: true });
929
982
  logger.success("Removed skill from shared directory");
930
983
  }
931
984
  } catch (error) {
@@ -936,7 +989,7 @@ Installed agents: ${installedAgents.map((a) => a.name).join(", ")}`);
936
989
  for (const agent of AGENTS) {
937
990
  const agentSkillPaths = getAgentSkillPaths(agent.name, extractedName, cwd);
938
991
  const hasSymlink = agentSkillPaths.some((path7) => {
939
- return fs6.existsSync(path7) && isSymlink(path7);
992
+ return fs7.existsSync(path7) && isSymlink(path7);
940
993
  });
941
994
  if (hasSymlink) {
942
995
  remainingSymlinks.push(agent.displayName);
@@ -954,44 +1007,6 @@ Installed agents: ${installedAgents.map((a) => a.name).join(", ")}`);
954
1007
  }
955
1008
  }
956
1009
 
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
1010
  // src/index.ts
996
1011
  var __filename2 = fileURLToPath(import.meta.url);
997
1012
  var __dirname2 = dirname(__filename2);
@@ -1000,7 +1015,11 @@ var packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
1000
1015
  var version = packageJson.version;
1001
1016
  var program = new Command();
1002
1017
  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) => {
1018
+ 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(
1019
+ "-t, --timeout <ms>",
1020
+ "Timeout in milliseconds (default: 180000 for npm, 120000 for git)",
1021
+ (value) => Number.parseInt(value, 10)
1022
+ ).action(async (skill, options) => {
1004
1023
  try {
1005
1024
  await install(skill, options);
1006
1025
  } catch (error) {