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