@empjs/skill 1.0.6 → 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/README.md +19 -5
- package/dist/index.cjs +180 -117
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +180 -117
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7,14 +7,16 @@ import { dirname, join } from "path";
|
|
|
7
7
|
import { fileURLToPath } from "url";
|
|
8
8
|
|
|
9
9
|
// src/commands/agents.ts
|
|
10
|
-
import
|
|
10
|
+
import fs2 from "fs";
|
|
11
11
|
import os2 from "os";
|
|
12
12
|
import chalk from "chalk";
|
|
13
13
|
|
|
14
14
|
// src/config/agents.ts
|
|
15
|
+
import fs from "fs";
|
|
15
16
|
import os from "os";
|
|
16
17
|
import path from "path";
|
|
17
18
|
var HOME = os.homedir();
|
|
19
|
+
var CONFIG_HOME = process.env.XDG_CONFIG_HOME || path.join(HOME, ".config");
|
|
18
20
|
function getAgentSkillsDirs(agent, cwd) {
|
|
19
21
|
if (agent.skillsDirs) {
|
|
20
22
|
if (typeof agent.skillsDirs === "function") {
|
|
@@ -29,21 +31,44 @@ function getAgentSkillsDirs(agent, cwd) {
|
|
|
29
31
|
}
|
|
30
32
|
var AGENTS = [
|
|
31
33
|
{
|
|
32
|
-
name: "
|
|
33
|
-
displayName: "
|
|
34
|
-
|
|
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
|
+
},
|
|
35
41
|
enabled: true
|
|
36
42
|
},
|
|
37
43
|
{
|
|
38
|
-
name: "
|
|
39
|
-
displayName: "
|
|
40
|
-
|
|
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
|
+
},
|
|
41
52
|
enabled: true
|
|
42
53
|
},
|
|
43
54
|
{
|
|
44
|
-
name: "
|
|
45
|
-
displayName: "
|
|
46
|
-
skillsDir: path.join(HOME, ".
|
|
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
|
+
},
|
|
47
72
|
enabled: true
|
|
48
73
|
},
|
|
49
74
|
{
|
|
@@ -52,9 +77,27 @@ var AGENTS = [
|
|
|
52
77
|
skillsDir: path.join(HOME, ".cline", "skills"),
|
|
53
78
|
enabled: true
|
|
54
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
|
+
},
|
|
55
98
|
{
|
|
56
99
|
name: "gemini",
|
|
57
|
-
displayName: "Gemini
|
|
100
|
+
displayName: "Gemini",
|
|
58
101
|
skillsDir: path.join(HOME, ".gemini", "skills"),
|
|
59
102
|
enabled: true
|
|
60
103
|
},
|
|
@@ -65,47 +108,31 @@ var AGENTS = [
|
|
|
65
108
|
enabled: true
|
|
66
109
|
},
|
|
67
110
|
{
|
|
68
|
-
name: "
|
|
69
|
-
displayName: "
|
|
70
|
-
skillsDir: path.join(
|
|
111
|
+
name: "goose",
|
|
112
|
+
displayName: "Goose",
|
|
113
|
+
skillsDir: path.join(CONFIG_HOME, "goose", "skills"),
|
|
71
114
|
enabled: true
|
|
72
115
|
},
|
|
73
116
|
{
|
|
74
|
-
name: "
|
|
75
|
-
displayName: "
|
|
76
|
-
|
|
77
|
-
const dirs = [];
|
|
78
|
-
dirs.push(path.join(HOME, ".gemini", "antigravity", "skills"));
|
|
79
|
-
if (cwd) {
|
|
80
|
-
dirs.push(path.join(cwd, ".agent", "skills"));
|
|
81
|
-
}
|
|
82
|
-
if (cwd) {
|
|
83
|
-
dirs.push(path.join(cwd, ".shared", "skills"));
|
|
84
|
-
}
|
|
85
|
-
return dirs;
|
|
86
|
-
},
|
|
117
|
+
name: "kilo",
|
|
118
|
+
displayName: "Kilo Code",
|
|
119
|
+
skillsDir: path.join(HOME, ".kilocode", "skills"),
|
|
87
120
|
enabled: true
|
|
88
121
|
},
|
|
89
122
|
{
|
|
90
123
|
name: "kiro",
|
|
91
|
-
displayName: "Kiro",
|
|
124
|
+
displayName: "Kiro CLI",
|
|
92
125
|
skillsDir: path.join(HOME, ".kiro", "skills"),
|
|
93
126
|
enabled: true
|
|
94
127
|
},
|
|
95
128
|
{
|
|
96
|
-
name: "
|
|
97
|
-
displayName: "
|
|
98
|
-
skillsDir: path.join(
|
|
99
|
-
enabled: true
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
name: "qoder",
|
|
103
|
-
displayName: "Qoder",
|
|
104
|
-
skillsDir: path.join(HOME, ".qoder", "skills"),
|
|
129
|
+
name: "opencode",
|
|
130
|
+
displayName: "OpenCode",
|
|
131
|
+
skillsDir: path.join(CONFIG_HOME, "opencode", "skills"),
|
|
105
132
|
enabled: true
|
|
106
133
|
},
|
|
107
134
|
{
|
|
108
|
-
name: "
|
|
135
|
+
name: "roo",
|
|
109
136
|
displayName: "Roo Code",
|
|
110
137
|
skillsDir: path.join(HOME, ".roo", "skills"),
|
|
111
138
|
enabled: true
|
|
@@ -116,6 +143,24 @@ var AGENTS = [
|
|
|
116
143
|
skillsDir: path.join(HOME, ".trae", "skills"),
|
|
117
144
|
enabled: true
|
|
118
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
|
+
},
|
|
119
164
|
{
|
|
120
165
|
name: "continue",
|
|
121
166
|
displayName: "Continue",
|
|
@@ -141,7 +186,7 @@ function agents() {
|
|
|
141
186
|
} else {
|
|
142
187
|
console.log(chalk.gray(` Directories${dirsInfo}:`));
|
|
143
188
|
for (const dir of skillsDirs) {
|
|
144
|
-
const exists =
|
|
189
|
+
const exists = fs2.existsSync(dir);
|
|
145
190
|
const status = exists ? chalk.green("\u2713") : chalk.gray("\u25CB");
|
|
146
191
|
const pathColor = exists ? chalk.white : chalk.gray;
|
|
147
192
|
console.log(` ${status} ${pathColor(dir)}`);
|
|
@@ -150,7 +195,7 @@ function agents() {
|
|
|
150
195
|
console.log("");
|
|
151
196
|
}
|
|
152
197
|
console.log(chalk.bold("\u{1F4E6} Shared Skills Directory:"));
|
|
153
|
-
const sharedExists =
|
|
198
|
+
const sharedExists = fs2.existsSync(SHARED_SKILLS_DIR);
|
|
154
199
|
const sharedStatus = sharedExists ? chalk.green("\u2713") : chalk.gray("\u25CB");
|
|
155
200
|
const sharedPathColor = sharedExists ? chalk.white : chalk.gray;
|
|
156
201
|
console.log(` ${sharedStatus} ${sharedPathColor(SHARED_SKILLS_DIR)}`);
|
|
@@ -164,7 +209,7 @@ function agents() {
|
|
|
164
209
|
|
|
165
210
|
// src/commands/install.ts
|
|
166
211
|
import { exec as exec2 } from "child_process";
|
|
167
|
-
import
|
|
212
|
+
import fs6 from "fs";
|
|
168
213
|
import os3 from "os";
|
|
169
214
|
import path5 from "path";
|
|
170
215
|
import { promisify as promisify2 } from "util";
|
|
@@ -296,6 +341,10 @@ var Logger = class {
|
|
|
296
341
|
if (this.spinner) this.spinner.stop();
|
|
297
342
|
console.log(chalk2.red("\u2717"), message);
|
|
298
343
|
}
|
|
344
|
+
dim(message) {
|
|
345
|
+
if (this.spinner) this.spinner.stop();
|
|
346
|
+
console.log(chalk2.dim(" " + message));
|
|
347
|
+
}
|
|
299
348
|
start(message) {
|
|
300
349
|
if (this.spinner) this.spinner.stop();
|
|
301
350
|
this.spinner = ora(message).start();
|
|
@@ -332,7 +381,7 @@ var Logger = class {
|
|
|
332
381
|
var logger = new Logger();
|
|
333
382
|
|
|
334
383
|
// src/utils/paths.ts
|
|
335
|
-
import
|
|
384
|
+
import fs3 from "fs";
|
|
336
385
|
import path2 from "path";
|
|
337
386
|
function getSharedSkillPath(skillName) {
|
|
338
387
|
return path2.join(SHARED_SKILLS_DIR, skillName);
|
|
@@ -346,8 +395,8 @@ function getAgentSkillPaths(agentName, skillName, cwd) {
|
|
|
346
395
|
return skillsDirs.map((dir) => path2.join(dir, skillName));
|
|
347
396
|
}
|
|
348
397
|
function ensureSharedDir() {
|
|
349
|
-
if (!
|
|
350
|
-
|
|
398
|
+
if (!fs3.existsSync(SHARED_SKILLS_DIR)) {
|
|
399
|
+
fs3.mkdirSync(SHARED_SKILLS_DIR, { recursive: true });
|
|
351
400
|
}
|
|
352
401
|
}
|
|
353
402
|
function detectInstalledAgents(cwd) {
|
|
@@ -355,7 +404,7 @@ function detectInstalledAgents(cwd) {
|
|
|
355
404
|
try {
|
|
356
405
|
const skillsDirs = getAgentSkillsDirs(agent, cwd);
|
|
357
406
|
return skillsDirs.some((dir) => {
|
|
358
|
-
return
|
|
407
|
+
return fs3.existsSync(dir) || fs3.existsSync(path2.dirname(dir));
|
|
359
408
|
});
|
|
360
409
|
} catch {
|
|
361
410
|
return false;
|
|
@@ -376,7 +425,7 @@ function extractSkillName(nameOrPath) {
|
|
|
376
425
|
|
|
377
426
|
// src/utils/registry.ts
|
|
378
427
|
import { exec } from "child_process";
|
|
379
|
-
import
|
|
428
|
+
import fs4 from "fs";
|
|
380
429
|
import path3 from "path";
|
|
381
430
|
import { promisify } from "util";
|
|
382
431
|
var execAsync = promisify(exec);
|
|
@@ -384,7 +433,7 @@ function findNpmrc(startDir) {
|
|
|
384
433
|
let currentDir = path3.resolve(startDir);
|
|
385
434
|
while (currentDir !== path3.dirname(currentDir)) {
|
|
386
435
|
const npmrcPath = path3.join(currentDir, ".npmrc");
|
|
387
|
-
if (
|
|
436
|
+
if (fs4.existsSync(npmrcPath)) {
|
|
388
437
|
return npmrcPath;
|
|
389
438
|
}
|
|
390
439
|
currentDir = path3.dirname(currentDir);
|
|
@@ -393,7 +442,7 @@ function findNpmrc(startDir) {
|
|
|
393
442
|
}
|
|
394
443
|
function parseNpmrc(npmrcPath) {
|
|
395
444
|
try {
|
|
396
|
-
const content =
|
|
445
|
+
const content = fs4.readFileSync(npmrcPath, "utf-8");
|
|
397
446
|
const lines = content.split("\n");
|
|
398
447
|
for (const line of lines) {
|
|
399
448
|
const trimmed = line.trim();
|
|
@@ -436,11 +485,11 @@ async function getRegistry(cwd = process.cwd()) {
|
|
|
436
485
|
}
|
|
437
486
|
|
|
438
487
|
// src/utils/symlink.ts
|
|
439
|
-
import
|
|
488
|
+
import fs5 from "fs";
|
|
440
489
|
import path4 from "path";
|
|
441
490
|
function createSymlink(skillName, agent, cwd) {
|
|
442
491
|
const source = getSharedSkillPath(skillName);
|
|
443
|
-
if (!
|
|
492
|
+
if (!fs5.existsSync(source)) {
|
|
444
493
|
logger.error(`Skill not found: ${source}`);
|
|
445
494
|
return false;
|
|
446
495
|
}
|
|
@@ -448,19 +497,19 @@ function createSymlink(skillName, agent, cwd) {
|
|
|
448
497
|
let successCount = 0;
|
|
449
498
|
for (const target of targets) {
|
|
450
499
|
const targetDir = path4.dirname(target);
|
|
451
|
-
if (!
|
|
500
|
+
if (!fs5.existsSync(targetDir)) {
|
|
452
501
|
try {
|
|
453
|
-
|
|
502
|
+
fs5.mkdirSync(targetDir, { recursive: true });
|
|
454
503
|
} catch (error) {
|
|
455
504
|
logger.error(`Failed to create directory ${targetDir}: ${error.message}`);
|
|
456
505
|
continue;
|
|
457
506
|
}
|
|
458
507
|
}
|
|
459
|
-
if (
|
|
508
|
+
if (fs5.existsSync(target)) {
|
|
460
509
|
try {
|
|
461
|
-
const stats =
|
|
510
|
+
const stats = fs5.lstatSync(target);
|
|
462
511
|
if (stats.isSymbolicLink()) {
|
|
463
|
-
|
|
512
|
+
fs5.unlinkSync(target);
|
|
464
513
|
} else {
|
|
465
514
|
logger.warn(`Target exists but is not a symlink, skipping: ${target}`);
|
|
466
515
|
continue;
|
|
@@ -471,7 +520,7 @@ function createSymlink(skillName, agent, cwd) {
|
|
|
471
520
|
}
|
|
472
521
|
}
|
|
473
522
|
try {
|
|
474
|
-
|
|
523
|
+
fs5.symlinkSync(source, target, "dir");
|
|
475
524
|
successCount++;
|
|
476
525
|
} catch (error) {
|
|
477
526
|
logger.error(`Failed to create symlink at ${target}: ${error.message}`);
|
|
@@ -488,13 +537,13 @@ function removeSymlink(skillName, agent, cwd) {
|
|
|
488
537
|
const targets = getAgentSkillPaths(agent.name, skillName, cwd);
|
|
489
538
|
let removedCount = 0;
|
|
490
539
|
for (const target of targets) {
|
|
491
|
-
if (!
|
|
540
|
+
if (!fs5.existsSync(target)) {
|
|
492
541
|
continue;
|
|
493
542
|
}
|
|
494
543
|
try {
|
|
495
|
-
const stats =
|
|
544
|
+
const stats = fs5.lstatSync(target);
|
|
496
545
|
if (stats.isSymbolicLink()) {
|
|
497
|
-
|
|
546
|
+
fs5.unlinkSync(target);
|
|
498
547
|
removedCount++;
|
|
499
548
|
} else {
|
|
500
549
|
logger.warn(`Not a symlink: ${target}`);
|
|
@@ -512,7 +561,7 @@ function removeSymlink(skillName, agent, cwd) {
|
|
|
512
561
|
}
|
|
513
562
|
function isSymlink(filePath) {
|
|
514
563
|
try {
|
|
515
|
-
const stats =
|
|
564
|
+
const stats = fs5.lstatSync(filePath);
|
|
516
565
|
return stats.isSymbolicLink();
|
|
517
566
|
} catch {
|
|
518
567
|
return false;
|
|
@@ -520,7 +569,7 @@ function isSymlink(filePath) {
|
|
|
520
569
|
}
|
|
521
570
|
function readSymlink(filePath) {
|
|
522
571
|
try {
|
|
523
|
-
return
|
|
572
|
+
return fs5.readlinkSync(filePath);
|
|
524
573
|
} catch {
|
|
525
574
|
return null;
|
|
526
575
|
}
|
|
@@ -549,12 +598,25 @@ async function execWithTimeout(command, timeout = 12e4, env) {
|
|
|
549
598
|
throw error;
|
|
550
599
|
}
|
|
551
600
|
}
|
|
601
|
+
function shortenPath(p) {
|
|
602
|
+
const home = os3.homedir();
|
|
603
|
+
return p.startsWith(home) ? p.replace(home, "~") : p;
|
|
604
|
+
}
|
|
552
605
|
async function install(skillNameOrPath, options = {}) {
|
|
553
|
-
|
|
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
|
+
}
|
|
554
613
|
ensureSharedDir();
|
|
555
614
|
let skillPath;
|
|
556
615
|
let skillName;
|
|
557
|
-
if (
|
|
616
|
+
if (process.env.DEBUG_ESKILL) {
|
|
617
|
+
logger.dim(`[DEBUG] isGitUrl=${isGit}, parseGitUrl=${parseGitUrl(skillNameOrPath) ? "ok" : "null"}`);
|
|
618
|
+
}
|
|
619
|
+
if (isGit) {
|
|
558
620
|
const gitInfo = parseGitUrl(skillNameOrPath);
|
|
559
621
|
if (!gitInfo) {
|
|
560
622
|
logger.error(`Invalid git URL: ${skillNameOrPath}`);
|
|
@@ -566,21 +628,17 @@ async function install(skillNameOrPath, options = {}) {
|
|
|
566
628
|
const cloneDir = path5.join(tempDir, "repo");
|
|
567
629
|
try {
|
|
568
630
|
const timeout = options.timeout || 12e4;
|
|
569
|
-
const
|
|
570
|
-
|
|
571
|
-
if (gitInfo.
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
logger.infoWithoutStop(`Path: ${gitInfo.path}`);
|
|
576
|
-
}
|
|
577
|
-
logger.infoWithoutStop(`Timeout: ${timeout / 1e3}s`);
|
|
578
|
-
fs5.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 });
|
|
579
637
|
const branchFlag = gitInfo.branch ? `-b ${gitInfo.branch}` : "";
|
|
580
638
|
const cloneCommand = branchFlag ? `git clone ${branchFlag} ${gitInfo.gitUrl} ${cloneDir} --depth 1 --quiet` : `git clone ${gitInfo.gitUrl} ${cloneDir} --depth 1 --quiet`;
|
|
581
639
|
try {
|
|
582
640
|
await execWithTimeout(cloneCommand, timeout);
|
|
583
|
-
spinner.succeed(`
|
|
641
|
+
spinner.succeed(`Cloned successfully`);
|
|
584
642
|
} catch (error) {
|
|
585
643
|
spinner.fail("Clone failed");
|
|
586
644
|
if (error.message.includes("timeout")) {
|
|
@@ -597,7 +655,7 @@ async function install(skillNameOrPath, options = {}) {
|
|
|
597
655
|
}
|
|
598
656
|
if (gitInfo.path) {
|
|
599
657
|
skillPath = path5.join(cloneDir, gitInfo.path);
|
|
600
|
-
if (!
|
|
658
|
+
if (!fs6.existsSync(skillPath)) {
|
|
601
659
|
logger.error(`Path not found in repository: ${gitInfo.path}`);
|
|
602
660
|
logger.info(`Repository cloned to: ${cloneDir}`);
|
|
603
661
|
process.exit(1);
|
|
@@ -606,7 +664,7 @@ async function install(skillNameOrPath, options = {}) {
|
|
|
606
664
|
skillPath = cloneDir;
|
|
607
665
|
}
|
|
608
666
|
const skillMdPath = path5.join(skillPath, "SKILL.md");
|
|
609
|
-
if (!
|
|
667
|
+
if (!fs6.existsSync(skillMdPath)) {
|
|
610
668
|
logger.warn(`Warning: SKILL.md not found in ${skillPath}`);
|
|
611
669
|
logger.info("The directory may not be a valid skill package");
|
|
612
670
|
}
|
|
@@ -628,16 +686,16 @@ Tried to clone: ${gitInfo.gitUrl}`);
|
|
|
628
686
|
}
|
|
629
687
|
process.exit(1);
|
|
630
688
|
}
|
|
631
|
-
} else if (options.link ||
|
|
689
|
+
} else if (options.link || fs6.existsSync(skillNameOrPath)) {
|
|
632
690
|
skillPath = path5.resolve(skillNameOrPath);
|
|
633
|
-
if (!
|
|
691
|
+
if (!fs6.existsSync(skillPath)) {
|
|
634
692
|
logger.error(`Path not found: ${skillPath}`);
|
|
635
693
|
process.exit(1);
|
|
636
694
|
}
|
|
637
695
|
const pkgPath = path5.join(skillPath, "package.json");
|
|
638
|
-
if (
|
|
696
|
+
if (fs6.existsSync(pkgPath)) {
|
|
639
697
|
try {
|
|
640
|
-
const pkg = JSON.parse(
|
|
698
|
+
const pkg = JSON.parse(fs6.readFileSync(pkgPath, "utf-8"));
|
|
641
699
|
skillName = extractSkillName(pkg.name);
|
|
642
700
|
} catch {
|
|
643
701
|
skillName = extractSkillName(path5.basename(skillPath));
|
|
@@ -654,12 +712,12 @@ Tried to clone: ${gitInfo.gitUrl}`);
|
|
|
654
712
|
const spinner = logger.start(`Installing ${skillNameOrPath}...`);
|
|
655
713
|
logger.infoWithoutStop(`Registry: ${registry}`);
|
|
656
714
|
logger.infoWithoutStop(`Timeout: ${timeout / 1e3}s`);
|
|
657
|
-
|
|
715
|
+
fs6.mkdirSync(tempDir, { recursive: true });
|
|
658
716
|
logger.updateSpinner(`Downloading ${skillNameOrPath} from ${registry}...`);
|
|
659
717
|
const homeDir = process.env.HOME || process.env.USERPROFILE || os3.homedir();
|
|
660
718
|
const npmCacheDir = path5.join(homeDir, ".npm");
|
|
661
719
|
const npmConfigPrefix = path5.join(homeDir, ".npm-global");
|
|
662
|
-
|
|
720
|
+
fs6.mkdirSync(npmCacheDir, { recursive: true });
|
|
663
721
|
const installCommand = `npm install ${skillNameOrPath} --prefix ${tempDir} --registry=${registry} --no-save --silent --no-bin-links --prefer-offline`;
|
|
664
722
|
const env = {
|
|
665
723
|
...process.env,
|
|
@@ -740,7 +798,7 @@ Tried to clone: ${gitInfo.gitUrl}`);
|
|
|
740
798
|
process.exit(1);
|
|
741
799
|
}
|
|
742
800
|
skillPath = path5.join(tempDir, "node_modules", skillNameOrPath);
|
|
743
|
-
if (!
|
|
801
|
+
if (!fs6.existsSync(skillPath)) {
|
|
744
802
|
logger.error(`Failed to download package: ${skillNameOrPath}`);
|
|
745
803
|
process.exit(1);
|
|
746
804
|
}
|
|
@@ -750,18 +808,19 @@ Tried to clone: ${gitInfo.gitUrl}`);
|
|
|
750
808
|
}
|
|
751
809
|
}
|
|
752
810
|
const targetPath = getSharedSkillPath(skillName);
|
|
753
|
-
if (
|
|
811
|
+
if (fs6.existsSync(targetPath)) {
|
|
754
812
|
if (options.force) {
|
|
755
813
|
logger.warn("Removing existing installation...");
|
|
756
|
-
|
|
814
|
+
fs6.rmSync(targetPath, { recursive: true, force: true });
|
|
757
815
|
} else {
|
|
758
|
-
logger.error(`Skill already exists
|
|
759
|
-
logger.
|
|
816
|
+
logger.error(`Skill already exists`);
|
|
817
|
+
logger.dim(`Location: ${shortenPath(targetPath)}`);
|
|
818
|
+
logger.dim(`Tip: Add --force to overwrite`);
|
|
760
819
|
process.exit(1);
|
|
761
820
|
}
|
|
762
821
|
}
|
|
763
822
|
if (options.link) {
|
|
764
|
-
|
|
823
|
+
fs6.symlinkSync(skillPath, targetPath, "dir");
|
|
765
824
|
logger.success(`Linked to shared directory (dev mode)`);
|
|
766
825
|
} else {
|
|
767
826
|
copyDir(skillPath, targetPath);
|
|
@@ -775,21 +834,25 @@ Tried to clone: ${gitInfo.gitUrl}`);
|
|
|
775
834
|
logger.info("Skill installed to shared directory, but not linked to any agent");
|
|
776
835
|
logger.info("");
|
|
777
836
|
logger.info("Supported agents:");
|
|
778
|
-
logger.info("
|
|
779
|
-
logger.info("
|
|
780
|
-
logger.info("
|
|
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');
|
|
781
841
|
return;
|
|
782
842
|
}
|
|
783
843
|
let targetAgents = installedAgents;
|
|
784
844
|
if (options.agent && options.agent !== "all") {
|
|
785
|
-
const agent =
|
|
845
|
+
const agent = AGENTS.find((a) => a.name === options.agent && a.enabled);
|
|
786
846
|
if (!agent) {
|
|
787
|
-
logger.error(`
|
|
847
|
+
logger.error(`Unknown agent: ${options.agent}`);
|
|
788
848
|
logger.info(`
|
|
789
|
-
|
|
849
|
+
Supported agents: ${AGENTS.filter((a) => a.enabled).map((a) => a.name).join(", ")}`);
|
|
790
850
|
process.exit(1);
|
|
791
851
|
}
|
|
792
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
|
+
}
|
|
793
856
|
}
|
|
794
857
|
logger.info("\nCreating symlinks...");
|
|
795
858
|
let successCount = 0;
|
|
@@ -807,8 +870,8 @@ Linked to ${successCount}/${targetAgents.length} agents`);
|
|
|
807
870
|
}
|
|
808
871
|
}
|
|
809
872
|
function copyDir(src, dest) {
|
|
810
|
-
|
|
811
|
-
const entries =
|
|
873
|
+
fs6.mkdirSync(dest, { recursive: true });
|
|
874
|
+
const entries = fs6.readdirSync(src, { withFileTypes: true });
|
|
812
875
|
for (const entry of entries) {
|
|
813
876
|
const srcPath = path5.join(src, entry.name);
|
|
814
877
|
const destPath = path5.join(dest, entry.name);
|
|
@@ -818,23 +881,23 @@ function copyDir(src, dest) {
|
|
|
818
881
|
if (entry.isDirectory()) {
|
|
819
882
|
copyDir(srcPath, destPath);
|
|
820
883
|
} else {
|
|
821
|
-
|
|
884
|
+
fs6.copyFileSync(srcPath, destPath);
|
|
822
885
|
}
|
|
823
886
|
}
|
|
824
887
|
}
|
|
825
888
|
|
|
826
889
|
// src/commands/list.ts
|
|
827
|
-
import
|
|
890
|
+
import fs7 from "fs";
|
|
828
891
|
import path6 from "path";
|
|
829
892
|
import chalk3 from "chalk";
|
|
830
893
|
function list() {
|
|
831
|
-
if (!
|
|
894
|
+
if (!fs7.existsSync(SHARED_SKILLS_DIR)) {
|
|
832
895
|
logger.info("No skills installed");
|
|
833
896
|
logger.info(`
|
|
834
897
|
To install a skill, run: ${chalk3.cyan("eskill install <skill-name>")}`);
|
|
835
898
|
return;
|
|
836
899
|
}
|
|
837
|
-
const skills =
|
|
900
|
+
const skills = fs7.readdirSync(SHARED_SKILLS_DIR);
|
|
838
901
|
if (skills.length === 0) {
|
|
839
902
|
logger.info("No skills installed");
|
|
840
903
|
logger.info(`
|
|
@@ -847,15 +910,15 @@ Installed skills in ${SHARED_SKILLS_DIR}:
|
|
|
847
910
|
for (const skill of skills) {
|
|
848
911
|
const skillPath = path6.join(SHARED_SKILLS_DIR, skill);
|
|
849
912
|
try {
|
|
850
|
-
const stats =
|
|
913
|
+
const stats = fs7.lstatSync(skillPath);
|
|
851
914
|
if (!stats.isDirectory() && !stats.isSymbolicLink()) {
|
|
852
915
|
continue;
|
|
853
916
|
}
|
|
854
917
|
let version2 = "unknown";
|
|
855
918
|
const pkgPath = path6.join(skillPath, "package.json");
|
|
856
|
-
if (
|
|
919
|
+
if (fs7.existsSync(pkgPath)) {
|
|
857
920
|
try {
|
|
858
|
-
const pkgContent =
|
|
921
|
+
const pkgContent = fs7.readFileSync(pkgPath, "utf-8");
|
|
859
922
|
const pkg = JSON.parse(pkgContent);
|
|
860
923
|
if (pkg.version && typeof pkg.version === "string") {
|
|
861
924
|
version2 = pkg.version;
|
|
@@ -865,9 +928,9 @@ Installed skills in ${SHARED_SKILLS_DIR}:
|
|
|
865
928
|
}
|
|
866
929
|
if (version2 === "unknown") {
|
|
867
930
|
const skillMdPath = path6.join(skillPath, "SKILL.md");
|
|
868
|
-
if (
|
|
931
|
+
if (fs7.existsSync(skillMdPath)) {
|
|
869
932
|
try {
|
|
870
|
-
const skillMdContent =
|
|
933
|
+
const skillMdContent = fs7.readFileSync(skillMdPath, "utf-8");
|
|
871
934
|
const frontmatterMatch = skillMdContent.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
872
935
|
if (frontmatterMatch) {
|
|
873
936
|
const frontmatter = frontmatterMatch[1];
|
|
@@ -885,8 +948,8 @@ Installed skills in ${SHARED_SKILLS_DIR}:
|
|
|
885
948
|
const targetPath = readSymlink(skillPath);
|
|
886
949
|
if (targetPath) {
|
|
887
950
|
const targetPkgPath = path6.join(targetPath, "package.json");
|
|
888
|
-
if (
|
|
889
|
-
const pkg = JSON.parse(
|
|
951
|
+
if (fs7.existsSync(targetPkgPath)) {
|
|
952
|
+
const pkg = JSON.parse(fs7.readFileSync(targetPkgPath, "utf-8"));
|
|
890
953
|
if (pkg.version && typeof pkg.version === "string") {
|
|
891
954
|
version2 = pkg.version;
|
|
892
955
|
}
|
|
@@ -905,7 +968,7 @@ Installed skills in ${SHARED_SKILLS_DIR}:
|
|
|
905
968
|
const skillsDirs = getAgentSkillsDirs(agent, cwd);
|
|
906
969
|
const hasSymlink = skillsDirs.some((dir) => {
|
|
907
970
|
const agentSkillPath = path6.join(dir, skill);
|
|
908
|
-
if (
|
|
971
|
+
if (fs7.existsSync(agentSkillPath) && isSymlink(agentSkillPath)) {
|
|
909
972
|
const target = readSymlink(agentSkillPath);
|
|
910
973
|
return target === skillPath;
|
|
911
974
|
}
|
|
@@ -933,11 +996,11 @@ Installed skills in ${SHARED_SKILLS_DIR}:
|
|
|
933
996
|
}
|
|
934
997
|
|
|
935
998
|
// src/commands/remove.ts
|
|
936
|
-
import
|
|
999
|
+
import fs8 from "fs";
|
|
937
1000
|
async function remove(skillName, options = {}) {
|
|
938
1001
|
const extractedName = extractSkillName(skillName);
|
|
939
1002
|
const sharedPath = getSharedSkillPath(extractedName);
|
|
940
|
-
const skillExists =
|
|
1003
|
+
const skillExists = fs8.existsSync(sharedPath);
|
|
941
1004
|
if (!skillExists) {
|
|
942
1005
|
logger.error(`Skill not found: ${extractedName}`);
|
|
943
1006
|
logger.info(`Location: ${sharedPath}`);
|
|
@@ -947,11 +1010,11 @@ async function remove(skillName, options = {}) {
|
|
|
947
1010
|
const installedAgents = detectInstalledAgents(cwd);
|
|
948
1011
|
let targetAgents = installedAgents;
|
|
949
1012
|
if (options.agent && options.agent !== "all") {
|
|
950
|
-
const agent =
|
|
1013
|
+
const agent = AGENTS.find((a) => a.name === options.agent && a.enabled);
|
|
951
1014
|
if (!agent) {
|
|
952
|
-
logger.error(`
|
|
1015
|
+
logger.error(`Unknown agent: ${options.agent}`);
|
|
953
1016
|
logger.info(`
|
|
954
|
-
|
|
1017
|
+
Supported agents: ${AGENTS.filter((a) => a.enabled).map((a) => a.name).join(", ")}`);
|
|
955
1018
|
process.exit(1);
|
|
956
1019
|
}
|
|
957
1020
|
targetAgents = [agent];
|
|
@@ -973,12 +1036,12 @@ Installed agents: ${installedAgents.map((a) => a.name).join(", ")}`);
|
|
|
973
1036
|
}
|
|
974
1037
|
logger.info("Removing skill from shared directory...");
|
|
975
1038
|
try {
|
|
976
|
-
const stats =
|
|
1039
|
+
const stats = fs8.lstatSync(sharedPath);
|
|
977
1040
|
if (stats.isSymbolicLink()) {
|
|
978
|
-
|
|
1041
|
+
fs8.unlinkSync(sharedPath);
|
|
979
1042
|
logger.success("Removed symlink from shared directory");
|
|
980
1043
|
} else {
|
|
981
|
-
|
|
1044
|
+
fs8.rmSync(sharedPath, { recursive: true, force: true });
|
|
982
1045
|
logger.success("Removed skill from shared directory");
|
|
983
1046
|
}
|
|
984
1047
|
} catch (error) {
|
|
@@ -989,7 +1052,7 @@ Installed agents: ${installedAgents.map((a) => a.name).join(", ")}`);
|
|
|
989
1052
|
for (const agent of AGENTS) {
|
|
990
1053
|
const agentSkillPaths = getAgentSkillPaths(agent.name, extractedName, cwd);
|
|
991
1054
|
const hasSymlink = agentSkillPaths.some((path7) => {
|
|
992
|
-
return
|
|
1055
|
+
return fs8.existsSync(path7) && isSymlink(path7);
|
|
993
1056
|
});
|
|
994
1057
|
if (hasSymlink) {
|
|
995
1058
|
remainingSymlinks.push(agent.displayName);
|