@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.cjs CHANGED
@@ -23,82 +23,20 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  mod
24
24
  ));
25
25
 
26
- // node_modules/tsup/assets/cjs_shims.js
26
+ // ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/cjs_shims.js
27
27
  var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
28
28
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
29
29
 
30
30
  // src/index.ts
31
31
  var import_commander = require("commander");
32
32
  var import_fs = require("fs");
33
- var import_url = require("url");
34
33
  var import_path = require("path");
34
+ var import_url = require("url");
35
35
 
36
- // src/commands/install.ts
37
- var import_node_child_process2 = require("child_process");
38
- var import_node_util2 = require("util");
39
- var import_node_fs4 = __toESM(require("fs"), 1);
40
- var import_node_path5 = __toESM(require("path"), 1);
36
+ // src/commands/agents.ts
37
+ var import_node_fs = __toESM(require("fs"), 1);
41
38
  var import_node_os2 = __toESM(require("os"), 1);
42
-
43
- // src/utils/logger.ts
44
39
  var import_chalk = __toESM(require("chalk"), 1);
45
- var import_ora = __toESM(require("ora"), 1);
46
- var Logger = class {
47
- spinner = null;
48
- info(message) {
49
- if (this.spinner) this.spinner.stop();
50
- console.log(import_chalk.default.blue("\u2139"), message);
51
- }
52
- success(message) {
53
- if (this.spinner) this.spinner.stop();
54
- console.log(import_chalk.default.green("\u2713"), message);
55
- }
56
- warn(message) {
57
- if (this.spinner) this.spinner.stop();
58
- console.log(import_chalk.default.yellow("\u26A0"), message);
59
- }
60
- error(message) {
61
- if (this.spinner) this.spinner.stop();
62
- console.log(import_chalk.default.red("\u2717"), message);
63
- }
64
- start(message) {
65
- if (this.spinner) this.spinner.stop();
66
- this.spinner = (0, import_ora.default)(message).start();
67
- return this.spinner;
68
- }
69
- stopSpinner() {
70
- if (this.spinner) {
71
- this.spinner.stop();
72
- this.spinner = null;
73
- }
74
- }
75
- /**
76
- * Update spinner text without stopping it
77
- */
78
- updateSpinner(message) {
79
- if (this.spinner) {
80
- this.spinner.text = message;
81
- }
82
- }
83
- /**
84
- * Log info without stopping spinner (for background info)
85
- */
86
- infoWithoutStop(message) {
87
- if (this.spinner) {
88
- const currentText = this.spinner.text;
89
- this.spinner.stop();
90
- console.log(import_chalk.default.blue("\u2139"), message);
91
- this.spinner.start(currentText);
92
- } else {
93
- console.log(import_chalk.default.blue("\u2139"), message);
94
- }
95
- }
96
- };
97
- var logger = new Logger();
98
-
99
- // src/utils/paths.ts
100
- var import_node_fs = __toESM(require("fs"), 1);
101
- var import_node_path2 = __toESM(require("path"), 1);
102
40
 
103
41
  // src/config/agents.ts
104
42
  var import_node_os = __toESM(require("os"), 1);
@@ -216,7 +154,213 @@ var SHARED_SKILLS_DIR = import_node_path.default.join(HOME, ".emp-agent", "skill
216
154
  var CONFIG_FILE = import_node_path.default.join(HOME, ".emp-agent", "config.json");
217
155
  var CACHE_DIR = import_node_path.default.join(HOME, ".emp-agent", "cache");
218
156
 
157
+ // src/commands/agents.ts
158
+ function agents() {
159
+ const cwd = process.cwd();
160
+ console.log(import_chalk.default.bold("\n\u{1F4CB} Supported AI Agents:\n"));
161
+ for (const agent of AGENTS) {
162
+ const skillsDirs = getAgentSkillsDirs(agent, cwd);
163
+ const dirsInfo = skillsDirs.length > 1 ? ` (${skillsDirs.length} directories)` : "";
164
+ console.log(import_chalk.default.bold(agent.displayName));
165
+ console.log(import_chalk.default.gray(` Name: ${agent.name}`));
166
+ if (skillsDirs.length === 0) {
167
+ console.log(import_chalk.default.yellow(" \u26A0\uFE0F No directories configured"));
168
+ } else {
169
+ console.log(import_chalk.default.gray(` Directories${dirsInfo}:`));
170
+ for (const dir of skillsDirs) {
171
+ const exists = import_node_fs.default.existsSync(dir);
172
+ const status = exists ? import_chalk.default.green("\u2713") : import_chalk.default.gray("\u25CB");
173
+ const pathColor = exists ? import_chalk.default.white : import_chalk.default.gray;
174
+ console.log(` ${status} ${pathColor(dir)}`);
175
+ }
176
+ }
177
+ console.log("");
178
+ }
179
+ console.log(import_chalk.default.bold("\u{1F4E6} Shared Skills Directory:"));
180
+ const sharedExists = import_node_fs.default.existsSync(SHARED_SKILLS_DIR);
181
+ const sharedStatus = sharedExists ? import_chalk.default.green("\u2713") : import_chalk.default.gray("\u25CB");
182
+ const sharedPathColor = sharedExists ? import_chalk.default.white : import_chalk.default.gray;
183
+ console.log(` ${sharedStatus} ${sharedPathColor(SHARED_SKILLS_DIR)}`);
184
+ console.log("");
185
+ const home = import_node_os2.default.homedir();
186
+ if (cwd !== home) {
187
+ console.log(import_chalk.default.gray(`Current working directory: ${cwd}`));
188
+ console.log(import_chalk.default.gray("(Project-level directories are shown above)\n"));
189
+ }
190
+ }
191
+
192
+ // src/commands/install.ts
193
+ var import_node_child_process2 = require("child_process");
194
+ var import_node_fs5 = __toESM(require("fs"), 1);
195
+ var import_node_os3 = __toESM(require("os"), 1);
196
+ var import_node_path5 = __toESM(require("path"), 1);
197
+ var import_node_util2 = require("util");
198
+
199
+ // src/utils/git.ts
200
+ function parseGitUrl(url) {
201
+ const githubPatterns = [
202
+ // https://github.com/owner/repo/tree/branch/path/to/dir
203
+ /^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)(?:\/(.+))?$/,
204
+ // https://github.com/owner/repo
205
+ /^https?:\/\/github\.com\/([^/]+)\/([^/]+)(?:\/)?$/,
206
+ // git@github.com:owner/repo.git
207
+ /^git@github\.com:([^/]+)\/([^/]+)(?:\.git)?$/
208
+ ];
209
+ const gitlabPatterns = [
210
+ // https://host/group/repo/-/tree/branch/path (self-hosted + gitlab.com)
211
+ /^https?:\/\/([^/]+)\/(.+)\/-\/tree\/([^/]+)(?:\/(.+))?$/,
212
+ // https://gitlab.com/owner/repo
213
+ /^https?:\/\/gitlab\.com\/([^/]+)\/([^/]+)(?:\/)?$/,
214
+ // git@gitlab.com:owner/repo.git or git@host:group/repo.git
215
+ /^git@([^:]+):(.+)(?:\.git)?$/
216
+ ];
217
+ for (let i = 0; i < githubPatterns.length; i++) {
218
+ const pattern = githubPatterns[i];
219
+ const match = url.match(pattern);
220
+ if (match) {
221
+ const owner = match[1];
222
+ const repo = match[2].replace(/\.git$/, "");
223
+ let branch;
224
+ let path7;
225
+ if (i === 0) {
226
+ branch = match[3];
227
+ path7 = match[4];
228
+ } else if (i === 1) {
229
+ branch = "main";
230
+ } else {
231
+ branch = "main";
232
+ }
233
+ const gitUrl = `https://github.com/${owner}/${repo}.git`;
234
+ return {
235
+ type: "github",
236
+ owner,
237
+ repo,
238
+ branch,
239
+ path: path7,
240
+ gitUrl,
241
+ installUrl: gitUrl
242
+ // Will be used for git clone
243
+ };
244
+ }
245
+ }
246
+ for (let i = 0; i < gitlabPatterns.length; i++) {
247
+ const pattern = gitlabPatterns[i];
248
+ const match = url.match(pattern);
249
+ if (match) {
250
+ let owner;
251
+ let repo;
252
+ let branch;
253
+ let path7;
254
+ let gitUrl;
255
+ if (i === 0) {
256
+ const host = match[1];
257
+ const repoPath = match[2].replace(/\.git$/, "");
258
+ branch = match[3];
259
+ path7 = match[4];
260
+ const parts = repoPath.split("/");
261
+ repo = parts.pop() || repoPath;
262
+ owner = parts.join("/") || repo;
263
+ gitUrl = `https://${host}/${repoPath}.git`;
264
+ } else if (i === 1) {
265
+ owner = match[1];
266
+ repo = match[2].replace(/\.git$/, "");
267
+ branch = "main";
268
+ gitUrl = `https://gitlab.com/${owner}/${repo}.git`;
269
+ } else {
270
+ const host = match[1];
271
+ const repoPath = match[2].replace(/\.git$/, "");
272
+ branch = "main";
273
+ const parts = repoPath.split("/");
274
+ repo = parts.pop() || repoPath;
275
+ owner = parts.join("/") || repo;
276
+ gitUrl = `https://${host}/${repoPath}.git`;
277
+ }
278
+ return {
279
+ type: "gitlab",
280
+ owner,
281
+ repo,
282
+ branch,
283
+ path: path7,
284
+ gitUrl,
285
+ installUrl: gitUrl
286
+ };
287
+ }
288
+ }
289
+ if (url.startsWith("git+") || url.startsWith("git://")) {
290
+ return {
291
+ type: "other",
292
+ owner: "",
293
+ repo: "",
294
+ gitUrl: url.replace(/^git\+/, ""),
295
+ installUrl: url.startsWith("git+") ? url : `git+${url}`
296
+ };
297
+ }
298
+ return null;
299
+ }
300
+ function isGitUrl(str) {
301
+ return str.includes("github.com") || str.includes("gitlab.com") || str.includes("/-/tree/") || // GitLab web URL pattern (self-hosted)
302
+ str.startsWith("git@") || str.startsWith("git+") || str.startsWith("git://");
303
+ }
304
+
305
+ // src/utils/logger.ts
306
+ var import_chalk2 = __toESM(require("chalk"), 1);
307
+ var import_ora = __toESM(require("ora"), 1);
308
+ var Logger = class {
309
+ spinner = null;
310
+ info(message) {
311
+ if (this.spinner) this.spinner.stop();
312
+ console.log(import_chalk2.default.blue("\u2139"), message);
313
+ }
314
+ success(message) {
315
+ if (this.spinner) this.spinner.stop();
316
+ console.log(import_chalk2.default.green("\u2713"), message);
317
+ }
318
+ warn(message) {
319
+ if (this.spinner) this.spinner.stop();
320
+ console.log(import_chalk2.default.yellow("\u26A0"), message);
321
+ }
322
+ error(message) {
323
+ if (this.spinner) this.spinner.stop();
324
+ console.log(import_chalk2.default.red("\u2717"), message);
325
+ }
326
+ start(message) {
327
+ if (this.spinner) this.spinner.stop();
328
+ this.spinner = (0, import_ora.default)(message).start();
329
+ return this.spinner;
330
+ }
331
+ stopSpinner() {
332
+ if (this.spinner) {
333
+ this.spinner.stop();
334
+ this.spinner = null;
335
+ }
336
+ }
337
+ /**
338
+ * Update spinner text without stopping it
339
+ */
340
+ updateSpinner(message) {
341
+ if (this.spinner) {
342
+ this.spinner.text = message;
343
+ }
344
+ }
345
+ /**
346
+ * Log info without stopping spinner (for background info)
347
+ */
348
+ infoWithoutStop(message) {
349
+ if (this.spinner) {
350
+ const currentText = this.spinner.text;
351
+ this.spinner.stop();
352
+ console.log(import_chalk2.default.blue("\u2139"), message);
353
+ this.spinner.start(currentText);
354
+ } else {
355
+ console.log(import_chalk2.default.blue("\u2139"), message);
356
+ }
357
+ }
358
+ };
359
+ var logger = new Logger();
360
+
219
361
  // src/utils/paths.ts
362
+ var import_node_fs2 = __toESM(require("fs"), 1);
363
+ var import_node_path2 = __toESM(require("path"), 1);
220
364
  function getSharedSkillPath(skillName) {
221
365
  return import_node_path2.default.join(SHARED_SKILLS_DIR, skillName);
222
366
  }
@@ -229,8 +373,8 @@ function getAgentSkillPaths(agentName, skillName, cwd) {
229
373
  return skillsDirs.map((dir) => import_node_path2.default.join(dir, skillName));
230
374
  }
231
375
  function ensureSharedDir() {
232
- if (!import_node_fs.default.existsSync(SHARED_SKILLS_DIR)) {
233
- import_node_fs.default.mkdirSync(SHARED_SKILLS_DIR, { recursive: true });
376
+ if (!import_node_fs2.default.existsSync(SHARED_SKILLS_DIR)) {
377
+ import_node_fs2.default.mkdirSync(SHARED_SKILLS_DIR, { recursive: true });
234
378
  }
235
379
  }
236
380
  function detectInstalledAgents(cwd) {
@@ -238,7 +382,7 @@ function detectInstalledAgents(cwd) {
238
382
  try {
239
383
  const skillsDirs = getAgentSkillsDirs(agent, cwd);
240
384
  return skillsDirs.some((dir) => {
241
- return import_node_fs.default.existsSync(dir) || import_node_fs.default.existsSync(import_node_path2.default.dirname(dir));
385
+ return import_node_fs2.default.existsSync(dir) || import_node_fs2.default.existsSync(import_node_path2.default.dirname(dir));
242
386
  });
243
387
  } catch {
244
388
  return false;
@@ -257,32 +401,93 @@ function extractSkillName(nameOrPath) {
257
401
  return import_node_path2.default.basename(nameOrPath);
258
402
  }
259
403
 
260
- // src/utils/symlink.ts
261
- var import_node_fs2 = __toESM(require("fs"), 1);
404
+ // src/utils/registry.ts
405
+ var import_node_child_process = require("child_process");
406
+ var import_node_fs3 = __toESM(require("fs"), 1);
262
407
  var import_node_path3 = __toESM(require("path"), 1);
408
+ var import_node_util = require("util");
409
+ var execAsync = (0, import_node_util.promisify)(import_node_child_process.exec);
410
+ function findNpmrc(startDir) {
411
+ let currentDir = import_node_path3.default.resolve(startDir);
412
+ while (currentDir !== import_node_path3.default.dirname(currentDir)) {
413
+ const npmrcPath = import_node_path3.default.join(currentDir, ".npmrc");
414
+ if (import_node_fs3.default.existsSync(npmrcPath)) {
415
+ return npmrcPath;
416
+ }
417
+ currentDir = import_node_path3.default.dirname(currentDir);
418
+ }
419
+ return null;
420
+ }
421
+ function parseNpmrc(npmrcPath) {
422
+ try {
423
+ const content = import_node_fs3.default.readFileSync(npmrcPath, "utf-8");
424
+ const lines = content.split("\n");
425
+ for (const line of lines) {
426
+ const trimmed = line.trim();
427
+ if (!trimmed || trimmed.startsWith("#")) {
428
+ continue;
429
+ }
430
+ const registryMatch = trimmed.match(/^(?:@[^:]+:)?registry\s*=\s*(.+)$/);
431
+ if (registryMatch) {
432
+ return registryMatch[1].trim();
433
+ }
434
+ }
435
+ } catch (error) {
436
+ }
437
+ return null;
438
+ }
439
+ async function getGlobalRegistry() {
440
+ try {
441
+ const { stdout } = await execAsync("npm config get registry");
442
+ const registry = stdout.trim();
443
+ if (registry && registry !== "undefined") {
444
+ return registry;
445
+ }
446
+ } catch (error) {
447
+ }
448
+ return null;
449
+ }
450
+ async function getRegistry(cwd = process.cwd()) {
451
+ const npmrcPath = findNpmrc(cwd);
452
+ if (npmrcPath) {
453
+ const registry = parseNpmrc(npmrcPath);
454
+ if (registry) {
455
+ return registry;
456
+ }
457
+ }
458
+ const globalRegistry = await getGlobalRegistry();
459
+ if (globalRegistry) {
460
+ return globalRegistry;
461
+ }
462
+ return "https://registry.npmjs.org/";
463
+ }
464
+
465
+ // src/utils/symlink.ts
466
+ var import_node_fs4 = __toESM(require("fs"), 1);
467
+ var import_node_path4 = __toESM(require("path"), 1);
263
468
  function createSymlink(skillName, agent, cwd) {
264
469
  const source = getSharedSkillPath(skillName);
265
- if (!import_node_fs2.default.existsSync(source)) {
470
+ if (!import_node_fs4.default.existsSync(source)) {
266
471
  logger.error(`Skill not found: ${source}`);
267
472
  return false;
268
473
  }
269
474
  const targets = getAgentSkillPaths(agent.name, skillName, cwd);
270
475
  let successCount = 0;
271
476
  for (const target of targets) {
272
- const targetDir = import_node_path3.default.dirname(target);
273
- if (!import_node_fs2.default.existsSync(targetDir)) {
477
+ const targetDir = import_node_path4.default.dirname(target);
478
+ if (!import_node_fs4.default.existsSync(targetDir)) {
274
479
  try {
275
- import_node_fs2.default.mkdirSync(targetDir, { recursive: true });
480
+ import_node_fs4.default.mkdirSync(targetDir, { recursive: true });
276
481
  } catch (error) {
277
482
  logger.error(`Failed to create directory ${targetDir}: ${error.message}`);
278
483
  continue;
279
484
  }
280
485
  }
281
- if (import_node_fs2.default.existsSync(target)) {
486
+ if (import_node_fs4.default.existsSync(target)) {
282
487
  try {
283
- const stats = import_node_fs2.default.lstatSync(target);
488
+ const stats = import_node_fs4.default.lstatSync(target);
284
489
  if (stats.isSymbolicLink()) {
285
- import_node_fs2.default.unlinkSync(target);
490
+ import_node_fs4.default.unlinkSync(target);
286
491
  } else {
287
492
  logger.warn(`Target exists but is not a symlink, skipping: ${target}`);
288
493
  continue;
@@ -293,7 +498,7 @@ function createSymlink(skillName, agent, cwd) {
293
498
  }
294
499
  }
295
500
  try {
296
- import_node_fs2.default.symlinkSync(source, target, "dir");
501
+ import_node_fs4.default.symlinkSync(source, target, "dir");
297
502
  successCount++;
298
503
  } catch (error) {
299
504
  logger.error(`Failed to create symlink at ${target}: ${error.message}`);
@@ -310,13 +515,13 @@ function removeSymlink(skillName, agent, cwd) {
310
515
  const targets = getAgentSkillPaths(agent.name, skillName, cwd);
311
516
  let removedCount = 0;
312
517
  for (const target of targets) {
313
- if (!import_node_fs2.default.existsSync(target)) {
518
+ if (!import_node_fs4.default.existsSync(target)) {
314
519
  continue;
315
520
  }
316
521
  try {
317
- const stats = import_node_fs2.default.lstatSync(target);
522
+ const stats = import_node_fs4.default.lstatSync(target);
318
523
  if (stats.isSymbolicLink()) {
319
- import_node_fs2.default.unlinkSync(target);
524
+ import_node_fs4.default.unlinkSync(target);
320
525
  removedCount++;
321
526
  } else {
322
527
  logger.warn(`Not a symlink: ${target}`);
@@ -334,7 +539,7 @@ function removeSymlink(skillName, agent, cwd) {
334
539
  }
335
540
  function isSymlink(filePath) {
336
541
  try {
337
- const stats = import_node_fs2.default.lstatSync(filePath);
542
+ const stats = import_node_fs4.default.lstatSync(filePath);
338
543
  return stats.isSymbolicLink();
339
544
  } catch {
340
545
  return false;
@@ -342,164 +547,12 @@ function isSymlink(filePath) {
342
547
  }
343
548
  function readSymlink(filePath) {
344
549
  try {
345
- return import_node_fs2.default.readlinkSync(filePath);
550
+ return import_node_fs4.default.readlinkSync(filePath);
346
551
  } catch {
347
552
  return null;
348
553
  }
349
554
  }
350
555
 
351
- // src/utils/registry.ts
352
- var import_node_child_process = require("child_process");
353
- var import_node_util = require("util");
354
- var import_node_fs3 = __toESM(require("fs"), 1);
355
- var import_node_path4 = __toESM(require("path"), 1);
356
- var execAsync = (0, import_node_util.promisify)(import_node_child_process.exec);
357
- function findNpmrc(startDir) {
358
- let currentDir = import_node_path4.default.resolve(startDir);
359
- while (currentDir !== import_node_path4.default.dirname(currentDir)) {
360
- const npmrcPath = import_node_path4.default.join(currentDir, ".npmrc");
361
- if (import_node_fs3.default.existsSync(npmrcPath)) {
362
- return npmrcPath;
363
- }
364
- currentDir = import_node_path4.default.dirname(currentDir);
365
- }
366
- return null;
367
- }
368
- function parseNpmrc(npmrcPath) {
369
- try {
370
- const content = import_node_fs3.default.readFileSync(npmrcPath, "utf-8");
371
- const lines = content.split("\n");
372
- for (const line of lines) {
373
- const trimmed = line.trim();
374
- if (!trimmed || trimmed.startsWith("#")) {
375
- continue;
376
- }
377
- const registryMatch = trimmed.match(/^(?:@[^:]+:)?registry\s*=\s*(.+)$/);
378
- if (registryMatch) {
379
- return registryMatch[1].trim();
380
- }
381
- }
382
- } catch (error) {
383
- }
384
- return null;
385
- }
386
- async function getGlobalRegistry() {
387
- try {
388
- const { stdout } = await execAsync("npm config get registry");
389
- const registry = stdout.trim();
390
- if (registry && registry !== "undefined") {
391
- return registry;
392
- }
393
- } catch (error) {
394
- }
395
- return null;
396
- }
397
- async function getRegistry(cwd = process.cwd()) {
398
- const npmrcPath = findNpmrc(cwd);
399
- if (npmrcPath) {
400
- const registry = parseNpmrc(npmrcPath);
401
- if (registry) {
402
- return registry;
403
- }
404
- }
405
- const globalRegistry = await getGlobalRegistry();
406
- if (globalRegistry) {
407
- return globalRegistry;
408
- }
409
- return "https://registry.npmjs.org/";
410
- }
411
-
412
- // src/utils/git.ts
413
- function parseGitUrl(url) {
414
- const githubPatterns = [
415
- // https://github.com/owner/repo/tree/branch/path/to/dir
416
- /^https?:\/\/github\.com\/([^\/]+)\/([^\/]+)\/tree\/([^\/]+)(?:\/(.+))?$/,
417
- // https://github.com/owner/repo
418
- /^https?:\/\/github\.com\/([^\/]+)\/([^\/]+)(?:\/)?$/,
419
- // git@github.com:owner/repo.git
420
- /^git@github\.com:([^\/]+)\/([^\/]+)(?:\.git)?$/
421
- ];
422
- const gitlabPatterns = [
423
- // https://gitlab.com/owner/repo/-/tree/branch/path/to/dir
424
- /^https?:\/\/gitlab\.com\/([^\/]+)\/([^\/]+)\/-\/tree\/([^\/]+)(?:\/(.+))?$/,
425
- // https://gitlab.com/owner/repo
426
- /^https?:\/\/gitlab\.com\/([^\/]+)\/([^\/]+)(?:\/)?$/,
427
- // git@gitlab.com:owner/repo.git
428
- /^git@gitlab\.com:([^\/]+)\/([^\/]+)(?:\.git)?$/
429
- ];
430
- for (let i = 0; i < githubPatterns.length; i++) {
431
- const pattern = githubPatterns[i];
432
- const match = url.match(pattern);
433
- if (match) {
434
- const owner = match[1];
435
- const repo = match[2].replace(/\.git$/, "");
436
- let branch;
437
- let path7;
438
- if (i === 0) {
439
- branch = match[3];
440
- path7 = match[4];
441
- } else if (i === 1) {
442
- branch = "main";
443
- } else {
444
- branch = "main";
445
- }
446
- const gitUrl = `https://github.com/${owner}/${repo}.git`;
447
- return {
448
- type: "github",
449
- owner,
450
- repo,
451
- branch,
452
- path: path7,
453
- gitUrl,
454
- installUrl: gitUrl
455
- // Will be used for git clone
456
- };
457
- }
458
- }
459
- for (let i = 0; i < gitlabPatterns.length; i++) {
460
- const pattern = gitlabPatterns[i];
461
- const match = url.match(pattern);
462
- if (match) {
463
- const owner = match[1];
464
- const repo = match[2].replace(/\.git$/, "");
465
- let branch;
466
- let path7;
467
- if (i === 0) {
468
- branch = match[3];
469
- path7 = match[4];
470
- } else if (i === 1) {
471
- branch = "main";
472
- } else {
473
- branch = "main";
474
- }
475
- const gitUrl = `https://gitlab.com/${owner}/${repo}.git`;
476
- return {
477
- type: "gitlab",
478
- owner,
479
- repo,
480
- branch,
481
- path: path7,
482
- gitUrl,
483
- installUrl: gitUrl
484
- // Will be used for git clone
485
- };
486
- }
487
- }
488
- if (url.startsWith("git+") || url.startsWith("git://")) {
489
- return {
490
- type: "other",
491
- owner: "",
492
- repo: "",
493
- gitUrl: url.replace(/^git\+/, ""),
494
- installUrl: url.startsWith("git+") ? url : `git+${url}`
495
- };
496
- }
497
- return null;
498
- }
499
- function isGitUrl(str) {
500
- return str.includes("github.com") || str.includes("gitlab.com") || str.startsWith("git@") || str.startsWith("git+") || str.startsWith("git://");
501
- }
502
-
503
556
  // src/commands/install.ts
504
557
  var execAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.exec);
505
558
  async function execWithTimeout(command, timeout = 12e4, env) {
@@ -511,10 +564,7 @@ async function execWithTimeout(command, timeout = 12e4, env) {
511
564
  });
512
565
  try {
513
566
  const execOptions = env ? { env } : {};
514
- const result = await Promise.race([
515
- execAsync2(command, execOptions),
516
- timeoutPromise
517
- ]);
567
+ const result = await Promise.race([execAsync2(command, execOptions), timeoutPromise]);
518
568
  if (timeoutId) {
519
569
  clearTimeout(timeoutId);
520
570
  }
@@ -552,7 +602,7 @@ async function install(skillNameOrPath, options = {}) {
552
602
  logger.infoWithoutStop(`Path: ${gitInfo.path}`);
553
603
  }
554
604
  logger.infoWithoutStop(`Timeout: ${timeout / 1e3}s`);
555
- import_node_fs4.default.mkdirSync(tempDir, { recursive: true });
605
+ import_node_fs5.default.mkdirSync(tempDir, { recursive: true });
556
606
  const branchFlag = gitInfo.branch ? `-b ${gitInfo.branch}` : "";
557
607
  const cloneCommand = branchFlag ? `git clone ${branchFlag} ${gitInfo.gitUrl} ${cloneDir} --depth 1 --quiet` : `git clone ${gitInfo.gitUrl} ${cloneDir} --depth 1 --quiet`;
558
608
  try {
@@ -574,7 +624,7 @@ async function install(skillNameOrPath, options = {}) {
574
624
  }
575
625
  if (gitInfo.path) {
576
626
  skillPath = import_node_path5.default.join(cloneDir, gitInfo.path);
577
- if (!import_node_fs4.default.existsSync(skillPath)) {
627
+ if (!import_node_fs5.default.existsSync(skillPath)) {
578
628
  logger.error(`Path not found in repository: ${gitInfo.path}`);
579
629
  logger.info(`Repository cloned to: ${cloneDir}`);
580
630
  process.exit(1);
@@ -583,7 +633,7 @@ async function install(skillNameOrPath, options = {}) {
583
633
  skillPath = cloneDir;
584
634
  }
585
635
  const skillMdPath = import_node_path5.default.join(skillPath, "SKILL.md");
586
- if (!import_node_fs4.default.existsSync(skillMdPath)) {
636
+ if (!import_node_fs5.default.existsSync(skillMdPath)) {
587
637
  logger.warn(`Warning: SKILL.md not found in ${skillPath}`);
588
638
  logger.info("The directory may not be a valid skill package");
589
639
  }
@@ -605,16 +655,16 @@ Tried to clone: ${gitInfo.gitUrl}`);
605
655
  }
606
656
  process.exit(1);
607
657
  }
608
- } else if (options.link || import_node_fs4.default.existsSync(skillNameOrPath)) {
658
+ } else if (options.link || import_node_fs5.default.existsSync(skillNameOrPath)) {
609
659
  skillPath = import_node_path5.default.resolve(skillNameOrPath);
610
- if (!import_node_fs4.default.existsSync(skillPath)) {
660
+ if (!import_node_fs5.default.existsSync(skillPath)) {
611
661
  logger.error(`Path not found: ${skillPath}`);
612
662
  process.exit(1);
613
663
  }
614
664
  const pkgPath = import_node_path5.default.join(skillPath, "package.json");
615
- if (import_node_fs4.default.existsSync(pkgPath)) {
665
+ if (import_node_fs5.default.existsSync(pkgPath)) {
616
666
  try {
617
- const pkg = JSON.parse(import_node_fs4.default.readFileSync(pkgPath, "utf-8"));
667
+ const pkg = JSON.parse(import_node_fs5.default.readFileSync(pkgPath, "utf-8"));
618
668
  skillName = extractSkillName(pkg.name);
619
669
  } catch {
620
670
  skillName = extractSkillName(import_node_path5.default.basename(skillPath));
@@ -631,12 +681,12 @@ Tried to clone: ${gitInfo.gitUrl}`);
631
681
  const spinner = logger.start(`Installing ${skillNameOrPath}...`);
632
682
  logger.infoWithoutStop(`Registry: ${registry}`);
633
683
  logger.infoWithoutStop(`Timeout: ${timeout / 1e3}s`);
634
- import_node_fs4.default.mkdirSync(tempDir, { recursive: true });
684
+ import_node_fs5.default.mkdirSync(tempDir, { recursive: true });
635
685
  logger.updateSpinner(`Downloading ${skillNameOrPath} from ${registry}...`);
636
- const homeDir = process.env.HOME || process.env.USERPROFILE || import_node_os2.default.homedir();
686
+ const homeDir = process.env.HOME || process.env.USERPROFILE || import_node_os3.default.homedir();
637
687
  const npmCacheDir = import_node_path5.default.join(homeDir, ".npm");
638
688
  const npmConfigPrefix = import_node_path5.default.join(homeDir, ".npm-global");
639
- import_node_fs4.default.mkdirSync(npmCacheDir, { recursive: true });
689
+ import_node_fs5.default.mkdirSync(npmCacheDir, { recursive: true });
640
690
  const installCommand = `npm install ${skillNameOrPath} --prefix ${tempDir} --registry=${registry} --no-save --silent --no-bin-links --prefer-offline`;
641
691
  const env = {
642
692
  ...process.env,
@@ -661,7 +711,9 @@ Tried to clone: ${gitInfo.gitUrl}`);
661
711
  logger.info("");
662
712
  logger.info("Suggestions:");
663
713
  logger.info(` - Try again: eskill add ${skillNameOrPath}`);
664
- logger.info(` - Use a different registry: eskill add ${skillNameOrPath} --registry=https://registry.npmjs.org/`);
714
+ logger.info(
715
+ ` - Use a different registry: eskill add ${skillNameOrPath} --registry=https://registry.npmjs.org/`
716
+ );
665
717
  logger.info(` - Increase timeout: eskill add ${skillNameOrPath} --timeout=300000`);
666
718
  } else if (errorMessage.includes("EACCES") || errorMessage.includes("permission denied") || errorMessage.includes("Permission denied")) {
667
719
  logger.error("Permission denied error detected");
@@ -700,7 +752,9 @@ Tried to clone: ${gitInfo.gitUrl}`);
700
752
  logger.info("Please check:");
701
753
  logger.info(" - Your internet connection");
702
754
  logger.info(` - Registry accessibility: ${registry}`);
703
- logger.info(` - Try a different registry: eskill add ${skillNameOrPath} --registry=https://registry.npmjs.org/`);
755
+ logger.info(
756
+ ` - Try a different registry: eskill add ${skillNameOrPath} --registry=https://registry.npmjs.org/`
757
+ );
704
758
  } else {
705
759
  logger.error(`Failed to download: ${errorMessage}`);
706
760
  logger.info("");
@@ -713,7 +767,7 @@ Tried to clone: ${gitInfo.gitUrl}`);
713
767
  process.exit(1);
714
768
  }
715
769
  skillPath = import_node_path5.default.join(tempDir, "node_modules", skillNameOrPath);
716
- if (!import_node_fs4.default.existsSync(skillPath)) {
770
+ if (!import_node_fs5.default.existsSync(skillPath)) {
717
771
  logger.error(`Failed to download package: ${skillNameOrPath}`);
718
772
  process.exit(1);
719
773
  }
@@ -723,10 +777,10 @@ Tried to clone: ${gitInfo.gitUrl}`);
723
777
  }
724
778
  }
725
779
  const targetPath = getSharedSkillPath(skillName);
726
- if (import_node_fs4.default.existsSync(targetPath)) {
780
+ if (import_node_fs5.default.existsSync(targetPath)) {
727
781
  if (options.force) {
728
782
  logger.warn("Removing existing installation...");
729
- import_node_fs4.default.rmSync(targetPath, { recursive: true, force: true });
783
+ import_node_fs5.default.rmSync(targetPath, { recursive: true, force: true });
730
784
  } else {
731
785
  logger.error(`Skill already exists: ${targetPath}`);
732
786
  logger.info("Use --force to overwrite");
@@ -734,7 +788,7 @@ Tried to clone: ${gitInfo.gitUrl}`);
734
788
  }
735
789
  }
736
790
  if (options.link) {
737
- import_node_fs4.default.symlinkSync(skillPath, targetPath, "dir");
791
+ import_node_fs5.default.symlinkSync(skillPath, targetPath, "dir");
738
792
  logger.success(`Linked to shared directory (dev mode)`);
739
793
  } else {
740
794
  copyDir(skillPath, targetPath);
@@ -780,8 +834,8 @@ Linked to ${successCount}/${targetAgents.length} agents`);
780
834
  }
781
835
  }
782
836
  function copyDir(src, dest) {
783
- import_node_fs4.default.mkdirSync(dest, { recursive: true });
784
- const entries = import_node_fs4.default.readdirSync(src, { withFileTypes: true });
837
+ import_node_fs5.default.mkdirSync(dest, { recursive: true });
838
+ const entries = import_node_fs5.default.readdirSync(src, { withFileTypes: true });
785
839
  for (const entry of entries) {
786
840
  const srcPath = import_node_path5.default.join(src, entry.name);
787
841
  const destPath = import_node_path5.default.join(dest, entry.name);
@@ -791,44 +845,44 @@ function copyDir(src, dest) {
791
845
  if (entry.isDirectory()) {
792
846
  copyDir(srcPath, destPath);
793
847
  } else {
794
- import_node_fs4.default.copyFileSync(srcPath, destPath);
848
+ import_node_fs5.default.copyFileSync(srcPath, destPath);
795
849
  }
796
850
  }
797
851
  }
798
852
 
799
853
  // src/commands/list.ts
800
- var import_node_fs5 = __toESM(require("fs"), 1);
854
+ var import_node_fs6 = __toESM(require("fs"), 1);
801
855
  var import_node_path6 = __toESM(require("path"), 1);
802
- var import_chalk2 = __toESM(require("chalk"), 1);
856
+ var import_chalk3 = __toESM(require("chalk"), 1);
803
857
  function list() {
804
- if (!import_node_fs5.default.existsSync(SHARED_SKILLS_DIR)) {
858
+ if (!import_node_fs6.default.existsSync(SHARED_SKILLS_DIR)) {
805
859
  logger.info("No skills installed");
806
860
  logger.info(`
807
- To install a skill, run: ${import_chalk2.default.cyan("eskill install <skill-name>")}`);
861
+ To install a skill, run: ${import_chalk3.default.cyan("eskill install <skill-name>")}`);
808
862
  return;
809
863
  }
810
- const skills = import_node_fs5.default.readdirSync(SHARED_SKILLS_DIR);
864
+ const skills = import_node_fs6.default.readdirSync(SHARED_SKILLS_DIR);
811
865
  if (skills.length === 0) {
812
866
  logger.info("No skills installed");
813
867
  logger.info(`
814
- To install a skill, run: ${import_chalk2.default.cyan("eskill install <skill-name>")}`);
868
+ To install a skill, run: ${import_chalk3.default.cyan("eskill install <skill-name>")}`);
815
869
  return;
816
870
  }
817
- console.log(import_chalk2.default.bold(`
871
+ console.log(import_chalk3.default.bold(`
818
872
  Installed skills in ${SHARED_SKILLS_DIR}:
819
873
  `));
820
874
  for (const skill of skills) {
821
875
  const skillPath = import_node_path6.default.join(SHARED_SKILLS_DIR, skill);
822
876
  try {
823
- const stats = import_node_fs5.default.lstatSync(skillPath);
877
+ const stats = import_node_fs6.default.lstatSync(skillPath);
824
878
  if (!stats.isDirectory() && !stats.isSymbolicLink()) {
825
879
  continue;
826
880
  }
827
881
  let version2 = "unknown";
828
882
  const pkgPath = import_node_path6.default.join(skillPath, "package.json");
829
- if (import_node_fs5.default.existsSync(pkgPath)) {
883
+ if (import_node_fs6.default.existsSync(pkgPath)) {
830
884
  try {
831
- const pkgContent = import_node_fs5.default.readFileSync(pkgPath, "utf-8");
885
+ const pkgContent = import_node_fs6.default.readFileSync(pkgPath, "utf-8");
832
886
  const pkg = JSON.parse(pkgContent);
833
887
  if (pkg.version && typeof pkg.version === "string") {
834
888
  version2 = pkg.version;
@@ -838,9 +892,9 @@ Installed skills in ${SHARED_SKILLS_DIR}:
838
892
  }
839
893
  if (version2 === "unknown") {
840
894
  const skillMdPath = import_node_path6.default.join(skillPath, "SKILL.md");
841
- if (import_node_fs5.default.existsSync(skillMdPath)) {
895
+ if (import_node_fs6.default.existsSync(skillMdPath)) {
842
896
  try {
843
- const skillMdContent = import_node_fs5.default.readFileSync(skillMdPath, "utf-8");
897
+ const skillMdContent = import_node_fs6.default.readFileSync(skillMdPath, "utf-8");
844
898
  const frontmatterMatch = skillMdContent.match(/^---\s*\n([\s\S]*?)\n---/);
845
899
  if (frontmatterMatch) {
846
900
  const frontmatter = frontmatterMatch[1];
@@ -858,8 +912,8 @@ Installed skills in ${SHARED_SKILLS_DIR}:
858
912
  const targetPath = readSymlink(skillPath);
859
913
  if (targetPath) {
860
914
  const targetPkgPath = import_node_path6.default.join(targetPath, "package.json");
861
- if (import_node_fs5.default.existsSync(targetPkgPath)) {
862
- const pkg = JSON.parse(import_node_fs5.default.readFileSync(targetPkgPath, "utf-8"));
915
+ if (import_node_fs6.default.existsSync(targetPkgPath)) {
916
+ const pkg = JSON.parse(import_node_fs6.default.readFileSync(targetPkgPath, "utf-8"));
863
917
  if (pkg.version && typeof pkg.version === "string") {
864
918
  version2 = pkg.version;
865
919
  }
@@ -869,16 +923,16 @@ Installed skills in ${SHARED_SKILLS_DIR}:
869
923
  }
870
924
  }
871
925
  const isDev = isSymlink(skillPath);
872
- const devTag = isDev ? import_chalk2.default.yellow(" (dev)") : "";
873
- const versionDisplay = version2 !== "unknown" ? import_chalk2.default.gray(`(v${version2})`) : "";
874
- console.log(import_chalk2.default.green("\u{1F4E6}") + ` ${import_chalk2.default.bold(skill)}${versionDisplay ? " " + versionDisplay : ""}${devTag}`);
926
+ const devTag = isDev ? import_chalk3.default.yellow(" (dev)") : "";
927
+ const versionDisplay = version2 !== "unknown" ? import_chalk3.default.gray(`(v${version2})`) : "";
928
+ console.log(import_chalk3.default.green("\u{1F4E6}") + ` ${import_chalk3.default.bold(skill)}${versionDisplay ? " " + versionDisplay : ""}${devTag}`);
875
929
  const cwd = process.cwd();
876
930
  const linkedAgents = [];
877
931
  for (const agent of AGENTS) {
878
932
  const skillsDirs = getAgentSkillsDirs(agent, cwd);
879
933
  const hasSymlink = skillsDirs.some((dir) => {
880
934
  const agentSkillPath = import_node_path6.default.join(dir, skill);
881
- if (import_node_fs5.default.existsSync(agentSkillPath) && isSymlink(agentSkillPath)) {
935
+ if (import_node_fs6.default.existsSync(agentSkillPath) && isSymlink(agentSkillPath)) {
882
936
  const target = readSymlink(agentSkillPath);
883
937
  return target === skillPath;
884
938
  }
@@ -889,29 +943,28 @@ Installed skills in ${SHARED_SKILLS_DIR}:
889
943
  }
890
944
  }
891
945
  if (linkedAgents.length > 0) {
892
- console.log(import_chalk2.default.gray(` \u2192 Linked to: ${linkedAgents.join(", ")}`));
946
+ console.log(import_chalk3.default.gray(` \u2192 Linked to: ${linkedAgents.join(", ")}`));
893
947
  } else {
894
- console.log(import_chalk2.default.yellow(` \u2192 Not linked to any agent`));
948
+ console.log(import_chalk3.default.yellow(` \u2192 Not linked to any agent`));
895
949
  }
896
950
  if (isDev) {
897
951
  const target = readSymlink(skillPath);
898
952
  if (target) {
899
- console.log(import_chalk2.default.gray(` \u2192 Source: ${target}`));
953
+ console.log(import_chalk3.default.gray(` \u2192 Source: ${target}`));
900
954
  }
901
955
  }
902
956
  console.log("");
903
957
  } catch (error) {
904
- continue;
905
958
  }
906
959
  }
907
960
  }
908
961
 
909
962
  // src/commands/remove.ts
910
- var import_node_fs6 = __toESM(require("fs"), 1);
963
+ var import_node_fs7 = __toESM(require("fs"), 1);
911
964
  async function remove(skillName, options = {}) {
912
965
  const extractedName = extractSkillName(skillName);
913
966
  const sharedPath = getSharedSkillPath(extractedName);
914
- const skillExists = import_node_fs6.default.existsSync(sharedPath);
967
+ const skillExists = import_node_fs7.default.existsSync(sharedPath);
915
968
  if (!skillExists) {
916
969
  logger.error(`Skill not found: ${extractedName}`);
917
970
  logger.info(`Location: ${sharedPath}`);
@@ -947,12 +1000,12 @@ Installed agents: ${installedAgents.map((a) => a.name).join(", ")}`);
947
1000
  }
948
1001
  logger.info("Removing skill from shared directory...");
949
1002
  try {
950
- const stats = import_node_fs6.default.lstatSync(sharedPath);
1003
+ const stats = import_node_fs7.default.lstatSync(sharedPath);
951
1004
  if (stats.isSymbolicLink()) {
952
- import_node_fs6.default.unlinkSync(sharedPath);
1005
+ import_node_fs7.default.unlinkSync(sharedPath);
953
1006
  logger.success("Removed symlink from shared directory");
954
1007
  } else {
955
- import_node_fs6.default.rmSync(sharedPath, { recursive: true, force: true });
1008
+ import_node_fs7.default.rmSync(sharedPath, { recursive: true, force: true });
956
1009
  logger.success("Removed skill from shared directory");
957
1010
  }
958
1011
  } catch (error) {
@@ -963,7 +1016,7 @@ Installed agents: ${installedAgents.map((a) => a.name).join(", ")}`);
963
1016
  for (const agent of AGENTS) {
964
1017
  const agentSkillPaths = getAgentSkillPaths(agent.name, extractedName, cwd);
965
1018
  const hasSymlink = agentSkillPaths.some((path7) => {
966
- return import_node_fs6.default.existsSync(path7) && isSymlink(path7);
1019
+ return import_node_fs7.default.existsSync(path7) && isSymlink(path7);
967
1020
  });
968
1021
  if (hasSymlink) {
969
1022
  remainingSymlinks.push(agent.displayName);
@@ -981,44 +1034,6 @@ Installed agents: ${installedAgents.map((a) => a.name).join(", ")}`);
981
1034
  }
982
1035
  }
983
1036
 
984
- // src/commands/agents.ts
985
- var import_chalk3 = __toESM(require("chalk"), 1);
986
- var import_node_fs7 = __toESM(require("fs"), 1);
987
- var import_node_os3 = __toESM(require("os"), 1);
988
- function agents() {
989
- const cwd = process.cwd();
990
- console.log(import_chalk3.default.bold("\n\u{1F4CB} Supported AI Agents:\n"));
991
- for (const agent of AGENTS) {
992
- const skillsDirs = getAgentSkillsDirs(agent, cwd);
993
- const dirsInfo = skillsDirs.length > 1 ? ` (${skillsDirs.length} directories)` : "";
994
- console.log(import_chalk3.default.bold(agent.displayName));
995
- console.log(import_chalk3.default.gray(` Name: ${agent.name}`));
996
- if (skillsDirs.length === 0) {
997
- console.log(import_chalk3.default.yellow(" \u26A0\uFE0F No directories configured"));
998
- } else {
999
- console.log(import_chalk3.default.gray(` Directories${dirsInfo}:`));
1000
- for (const dir of skillsDirs) {
1001
- const exists = import_node_fs7.default.existsSync(dir);
1002
- const status = exists ? import_chalk3.default.green("\u2713") : import_chalk3.default.gray("\u25CB");
1003
- const pathColor = exists ? import_chalk3.default.white : import_chalk3.default.gray;
1004
- console.log(` ${status} ${pathColor(dir)}`);
1005
- }
1006
- }
1007
- console.log("");
1008
- }
1009
- console.log(import_chalk3.default.bold("\u{1F4E6} Shared Skills Directory:"));
1010
- const sharedExists = import_node_fs7.default.existsSync(SHARED_SKILLS_DIR);
1011
- const sharedStatus = sharedExists ? import_chalk3.default.green("\u2713") : import_chalk3.default.gray("\u25CB");
1012
- const sharedPathColor = sharedExists ? import_chalk3.default.white : import_chalk3.default.gray;
1013
- console.log(` ${sharedStatus} ${sharedPathColor(SHARED_SKILLS_DIR)}`);
1014
- console.log("");
1015
- const home = import_node_os3.default.homedir();
1016
- if (cwd !== home) {
1017
- console.log(import_chalk3.default.gray(`Current working directory: ${cwd}`));
1018
- console.log(import_chalk3.default.gray("(Project-level directories are shown above)\n"));
1019
- }
1020
- }
1021
-
1022
1037
  // src/index.ts
1023
1038
  var __filename2 = (0, import_url.fileURLToPath)(importMetaUrl);
1024
1039
  var __dirname = (0, import_path.dirname)(__filename2);
@@ -1027,7 +1042,11 @@ var packageJson = JSON.parse((0, import_fs.readFileSync)(packageJsonPath, "utf-8
1027
1042
  var version = packageJson.version;
1028
1043
  var program = new import_commander.Command();
1029
1044
  program.name("eskill").description("Unified CLI tool for managing AI agent skills").version(version);
1030
- 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) => {
1045
+ 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(
1046
+ "-t, --timeout <ms>",
1047
+ "Timeout in milliseconds (default: 180000 for npm, 120000 for git)",
1048
+ (value) => Number.parseInt(value, 10)
1049
+ ).action(async (skill, options) => {
1031
1050
  try {
1032
1051
  await install(skill, options);
1033
1052
  } catch (error) {