@codemcp/skills 2.0.0 → 2.1.1
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/api.js +22 -0
- package/dist/chunk-BF4FUODT.js +4890 -0
- package/dist/cli.js +260 -6507
- package/package.json +5 -2
- package/dist/chunk-EQ5IFWEC.js +0 -1537
- package/dist/dist-OKIOSA34.js +0 -42
|
@@ -0,0 +1,4890 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
20
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
21
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
22
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
23
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
|
+
mod
|
|
25
|
+
));
|
|
26
|
+
|
|
27
|
+
// ../../node_modules/.pnpm/sisteransi@1.0.5/node_modules/sisteransi/src/index.js
|
|
28
|
+
var require_src = __commonJS({
|
|
29
|
+
"../../node_modules/.pnpm/sisteransi@1.0.5/node_modules/sisteransi/src/index.js"(exports, module) {
|
|
30
|
+
"use strict";
|
|
31
|
+
var ESC = "\x1B";
|
|
32
|
+
var CSI = `${ESC}[`;
|
|
33
|
+
var beep = "\x07";
|
|
34
|
+
var cursor = {
|
|
35
|
+
to(x2, y3) {
|
|
36
|
+
if (!y3) return `${CSI}${x2 + 1}G`;
|
|
37
|
+
return `${CSI}${y3 + 1};${x2 + 1}H`;
|
|
38
|
+
},
|
|
39
|
+
move(x2, y3) {
|
|
40
|
+
let ret = "";
|
|
41
|
+
if (x2 < 0) ret += `${CSI}${-x2}D`;
|
|
42
|
+
else if (x2 > 0) ret += `${CSI}${x2}C`;
|
|
43
|
+
if (y3 < 0) ret += `${CSI}${-y3}A`;
|
|
44
|
+
else if (y3 > 0) ret += `${CSI}${y3}B`;
|
|
45
|
+
return ret;
|
|
46
|
+
},
|
|
47
|
+
up: (count = 1) => `${CSI}${count}A`,
|
|
48
|
+
down: (count = 1) => `${CSI}${count}B`,
|
|
49
|
+
forward: (count = 1) => `${CSI}${count}C`,
|
|
50
|
+
backward: (count = 1) => `${CSI}${count}D`,
|
|
51
|
+
nextLine: (count = 1) => `${CSI}E`.repeat(count),
|
|
52
|
+
prevLine: (count = 1) => `${CSI}F`.repeat(count),
|
|
53
|
+
left: `${CSI}G`,
|
|
54
|
+
hide: `${CSI}?25l`,
|
|
55
|
+
show: `${CSI}?25h`,
|
|
56
|
+
save: `${ESC}7`,
|
|
57
|
+
restore: `${ESC}8`
|
|
58
|
+
};
|
|
59
|
+
var scroll = {
|
|
60
|
+
up: (count = 1) => `${CSI}S`.repeat(count),
|
|
61
|
+
down: (count = 1) => `${CSI}T`.repeat(count)
|
|
62
|
+
};
|
|
63
|
+
var erase = {
|
|
64
|
+
screen: `${CSI}2J`,
|
|
65
|
+
up: (count = 1) => `${CSI}1J`.repeat(count),
|
|
66
|
+
down: (count = 1) => `${CSI}J`.repeat(count),
|
|
67
|
+
line: `${CSI}2K`,
|
|
68
|
+
lineEnd: `${CSI}K`,
|
|
69
|
+
lineStart: `${CSI}1K`,
|
|
70
|
+
lines(count) {
|
|
71
|
+
let clear = "";
|
|
72
|
+
for (let i = 0; i < count; i++)
|
|
73
|
+
clear += this.line + (i < count - 1 ? cursor.up() : "");
|
|
74
|
+
if (count)
|
|
75
|
+
clear += cursor.left;
|
|
76
|
+
return clear;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
module.exports = { cursor, scroll, erase, beep };
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// ../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js
|
|
84
|
+
var require_picocolors = __commonJS({
|
|
85
|
+
"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js"(exports, module) {
|
|
86
|
+
"use strict";
|
|
87
|
+
var p2 = process || {};
|
|
88
|
+
var argv = p2.argv || [];
|
|
89
|
+
var env2 = p2.env || {};
|
|
90
|
+
var isColorSupported = !(!!env2.NO_COLOR || argv.includes("--no-color")) && (!!env2.FORCE_COLOR || argv.includes("--color") || p2.platform === "win32" || (p2.stdout || {}).isTTY && env2.TERM !== "dumb" || !!env2.CI);
|
|
91
|
+
var formatter = (open, close, replace = open) => (input) => {
|
|
92
|
+
let string = "" + input, index = string.indexOf(close, open.length);
|
|
93
|
+
return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
|
|
94
|
+
};
|
|
95
|
+
var replaceClose = (string, close, replace, index) => {
|
|
96
|
+
let result = "", cursor = 0;
|
|
97
|
+
do {
|
|
98
|
+
result += string.substring(cursor, index) + replace;
|
|
99
|
+
cursor = index + close.length;
|
|
100
|
+
index = string.indexOf(close, cursor);
|
|
101
|
+
} while (~index);
|
|
102
|
+
return result + string.substring(cursor);
|
|
103
|
+
};
|
|
104
|
+
var createColors = (enabled = isColorSupported) => {
|
|
105
|
+
let f = enabled ? formatter : () => String;
|
|
106
|
+
return {
|
|
107
|
+
isColorSupported: enabled,
|
|
108
|
+
reset: f("\x1B[0m", "\x1B[0m"),
|
|
109
|
+
bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
|
|
110
|
+
dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
|
|
111
|
+
italic: f("\x1B[3m", "\x1B[23m"),
|
|
112
|
+
underline: f("\x1B[4m", "\x1B[24m"),
|
|
113
|
+
inverse: f("\x1B[7m", "\x1B[27m"),
|
|
114
|
+
hidden: f("\x1B[8m", "\x1B[28m"),
|
|
115
|
+
strikethrough: f("\x1B[9m", "\x1B[29m"),
|
|
116
|
+
black: f("\x1B[30m", "\x1B[39m"),
|
|
117
|
+
red: f("\x1B[31m", "\x1B[39m"),
|
|
118
|
+
green: f("\x1B[32m", "\x1B[39m"),
|
|
119
|
+
yellow: f("\x1B[33m", "\x1B[39m"),
|
|
120
|
+
blue: f("\x1B[34m", "\x1B[39m"),
|
|
121
|
+
magenta: f("\x1B[35m", "\x1B[39m"),
|
|
122
|
+
cyan: f("\x1B[36m", "\x1B[39m"),
|
|
123
|
+
white: f("\x1B[37m", "\x1B[39m"),
|
|
124
|
+
gray: f("\x1B[90m", "\x1B[39m"),
|
|
125
|
+
bgBlack: f("\x1B[40m", "\x1B[49m"),
|
|
126
|
+
bgRed: f("\x1B[41m", "\x1B[49m"),
|
|
127
|
+
bgGreen: f("\x1B[42m", "\x1B[49m"),
|
|
128
|
+
bgYellow: f("\x1B[43m", "\x1B[49m"),
|
|
129
|
+
bgBlue: f("\x1B[44m", "\x1B[49m"),
|
|
130
|
+
bgMagenta: f("\x1B[45m", "\x1B[49m"),
|
|
131
|
+
bgCyan: f("\x1B[46m", "\x1B[49m"),
|
|
132
|
+
bgWhite: f("\x1B[47m", "\x1B[49m"),
|
|
133
|
+
blackBright: f("\x1B[90m", "\x1B[39m"),
|
|
134
|
+
redBright: f("\x1B[91m", "\x1B[39m"),
|
|
135
|
+
greenBright: f("\x1B[92m", "\x1B[39m"),
|
|
136
|
+
yellowBright: f("\x1B[93m", "\x1B[39m"),
|
|
137
|
+
blueBright: f("\x1B[94m", "\x1B[39m"),
|
|
138
|
+
magentaBright: f("\x1B[95m", "\x1B[39m"),
|
|
139
|
+
cyanBright: f("\x1B[96m", "\x1B[39m"),
|
|
140
|
+
whiteBright: f("\x1B[97m", "\x1B[39m"),
|
|
141
|
+
bgBlackBright: f("\x1B[100m", "\x1B[49m"),
|
|
142
|
+
bgRedBright: f("\x1B[101m", "\x1B[49m"),
|
|
143
|
+
bgGreenBright: f("\x1B[102m", "\x1B[49m"),
|
|
144
|
+
bgYellowBright: f("\x1B[103m", "\x1B[49m"),
|
|
145
|
+
bgBlueBright: f("\x1B[104m", "\x1B[49m"),
|
|
146
|
+
bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
|
|
147
|
+
bgCyanBright: f("\x1B[106m", "\x1B[49m"),
|
|
148
|
+
bgWhiteBright: f("\x1B[107m", "\x1B[49m")
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
module.exports = createColors();
|
|
152
|
+
module.exports.createColors = createColors;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// src/telemetry.ts
|
|
157
|
+
var TELEMETRY_URL = "https://add-skill.vercel.sh/t";
|
|
158
|
+
var AUDIT_URL = "https://add-skill.vercel.sh/audit";
|
|
159
|
+
var cliVersion = null;
|
|
160
|
+
function isCI() {
|
|
161
|
+
return !!(process.env.CI || process.env.GITHUB_ACTIONS || process.env.GITLAB_CI || process.env.CIRCLECI || process.env.TRAVIS || process.env.BUILDKITE || process.env.JENKINS_URL || process.env.TEAMCITY_VERSION);
|
|
162
|
+
}
|
|
163
|
+
function isEnabled() {
|
|
164
|
+
return !process.env.DISABLE_TELEMETRY && !process.env.DO_NOT_TRACK;
|
|
165
|
+
}
|
|
166
|
+
function setVersion(version2) {
|
|
167
|
+
cliVersion = version2;
|
|
168
|
+
}
|
|
169
|
+
async function fetchAuditData(source, skillSlugs, timeoutMs = 3e3) {
|
|
170
|
+
if (skillSlugs.length === 0) return null;
|
|
171
|
+
try {
|
|
172
|
+
const params = new URLSearchParams({
|
|
173
|
+
source,
|
|
174
|
+
skills: skillSlugs.join(",")
|
|
175
|
+
});
|
|
176
|
+
const controller = new AbortController();
|
|
177
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
178
|
+
const response = await fetch(`${AUDIT_URL}?${params.toString()}`, {
|
|
179
|
+
signal: controller.signal
|
|
180
|
+
});
|
|
181
|
+
clearTimeout(timeout);
|
|
182
|
+
if (!response.ok) return null;
|
|
183
|
+
return await response.json();
|
|
184
|
+
} catch {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function track(data) {
|
|
189
|
+
if (!isEnabled()) return;
|
|
190
|
+
try {
|
|
191
|
+
const params = new URLSearchParams();
|
|
192
|
+
if (cliVersion) {
|
|
193
|
+
params.set("v", cliVersion);
|
|
194
|
+
}
|
|
195
|
+
if (isCI()) {
|
|
196
|
+
params.set("ci", "1");
|
|
197
|
+
}
|
|
198
|
+
for (const [key, value] of Object.entries(data)) {
|
|
199
|
+
if (value !== void 0 && value !== null) {
|
|
200
|
+
params.set(key, String(value));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
fetch(`${TELEMETRY_URL}?${params.toString()}`).catch(() => {
|
|
204
|
+
});
|
|
205
|
+
} catch {
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// src/skill-lock.ts
|
|
210
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
211
|
+
import { join, dirname } from "path";
|
|
212
|
+
import { homedir } from "os";
|
|
213
|
+
import { execSync } from "child_process";
|
|
214
|
+
var AGENTS_DIR = ".agents";
|
|
215
|
+
var LOCK_FILE = ".skill-lock.json";
|
|
216
|
+
var CURRENT_VERSION = 3;
|
|
217
|
+
function getSkillLockPath() {
|
|
218
|
+
const xdgStateHome = process.env.XDG_STATE_HOME;
|
|
219
|
+
if (xdgStateHome) {
|
|
220
|
+
return join(xdgStateHome, "skills", LOCK_FILE);
|
|
221
|
+
}
|
|
222
|
+
return join(homedir(), AGENTS_DIR, LOCK_FILE);
|
|
223
|
+
}
|
|
224
|
+
async function readSkillLock() {
|
|
225
|
+
const lockPath = getSkillLockPath();
|
|
226
|
+
try {
|
|
227
|
+
const content = await readFile(lockPath, "utf-8");
|
|
228
|
+
const parsed = JSON.parse(content);
|
|
229
|
+
if (typeof parsed.version !== "number" || !parsed.skills) {
|
|
230
|
+
return createEmptyLockFile();
|
|
231
|
+
}
|
|
232
|
+
if (parsed.version < CURRENT_VERSION) {
|
|
233
|
+
return createEmptyLockFile();
|
|
234
|
+
}
|
|
235
|
+
return parsed;
|
|
236
|
+
} catch (error) {
|
|
237
|
+
return createEmptyLockFile();
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
async function writeSkillLock(lock) {
|
|
241
|
+
const lockPath = getSkillLockPath();
|
|
242
|
+
await mkdir(dirname(lockPath), { recursive: true });
|
|
243
|
+
const content = JSON.stringify(lock, null, 2);
|
|
244
|
+
await writeFile(lockPath, content, "utf-8");
|
|
245
|
+
}
|
|
246
|
+
function getGitHubToken() {
|
|
247
|
+
if (process.env.GITHUB_TOKEN) {
|
|
248
|
+
return process.env.GITHUB_TOKEN;
|
|
249
|
+
}
|
|
250
|
+
if (process.env.GH_TOKEN) {
|
|
251
|
+
return process.env.GH_TOKEN;
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
const token = execSync("gh auth token", {
|
|
255
|
+
encoding: "utf-8",
|
|
256
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
257
|
+
}).trim();
|
|
258
|
+
if (token) {
|
|
259
|
+
return token;
|
|
260
|
+
}
|
|
261
|
+
} catch {
|
|
262
|
+
}
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
async function fetchSkillFolderHash(ownerRepo, skillPath, token) {
|
|
266
|
+
let folderPath = skillPath.replace(/\\/g, "/");
|
|
267
|
+
if (folderPath.endsWith("/SKILL.md")) {
|
|
268
|
+
folderPath = folderPath.slice(0, -9);
|
|
269
|
+
} else if (folderPath.endsWith("SKILL.md")) {
|
|
270
|
+
folderPath = folderPath.slice(0, -8);
|
|
271
|
+
}
|
|
272
|
+
if (folderPath.endsWith("/")) {
|
|
273
|
+
folderPath = folderPath.slice(0, -1);
|
|
274
|
+
}
|
|
275
|
+
const branches = ["main", "master"];
|
|
276
|
+
for (const branch of branches) {
|
|
277
|
+
try {
|
|
278
|
+
const url = `https://api.github.com/repos/${ownerRepo}/git/trees/${branch}?recursive=1`;
|
|
279
|
+
const headers = {
|
|
280
|
+
Accept: "application/vnd.github.v3+json",
|
|
281
|
+
"User-Agent": "skills-cli"
|
|
282
|
+
};
|
|
283
|
+
if (token) {
|
|
284
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
285
|
+
}
|
|
286
|
+
const response = await fetch(url, { headers });
|
|
287
|
+
if (!response.ok) continue;
|
|
288
|
+
const data = await response.json();
|
|
289
|
+
if (!folderPath) {
|
|
290
|
+
return data.sha;
|
|
291
|
+
}
|
|
292
|
+
const folderEntry = data.tree.find(
|
|
293
|
+
(entry) => entry.type === "tree" && entry.path === folderPath
|
|
294
|
+
);
|
|
295
|
+
if (folderEntry) {
|
|
296
|
+
return folderEntry.sha;
|
|
297
|
+
}
|
|
298
|
+
} catch {
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
async function addSkillToLock(skillName, entry) {
|
|
305
|
+
const lock = await readSkillLock();
|
|
306
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
307
|
+
const existingEntry = lock.skills[skillName];
|
|
308
|
+
lock.skills[skillName] = {
|
|
309
|
+
...entry,
|
|
310
|
+
installedAt: existingEntry?.installedAt ?? now,
|
|
311
|
+
updatedAt: now
|
|
312
|
+
};
|
|
313
|
+
await writeSkillLock(lock);
|
|
314
|
+
}
|
|
315
|
+
async function removeSkillFromLock(skillName) {
|
|
316
|
+
const lock = await readSkillLock();
|
|
317
|
+
if (!(skillName in lock.skills)) {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
delete lock.skills[skillName];
|
|
321
|
+
await writeSkillLock(lock);
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
async function getSkillFromLock(skillName) {
|
|
325
|
+
const lock = await readSkillLock();
|
|
326
|
+
return lock.skills[skillName] ?? null;
|
|
327
|
+
}
|
|
328
|
+
async function getAllLockedSkills() {
|
|
329
|
+
const lock = await readSkillLock();
|
|
330
|
+
return lock.skills;
|
|
331
|
+
}
|
|
332
|
+
function createEmptyLockFile() {
|
|
333
|
+
return {
|
|
334
|
+
version: CURRENT_VERSION,
|
|
335
|
+
skills: {},
|
|
336
|
+
dismissed: {}
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
async function isPromptDismissed(promptKey) {
|
|
340
|
+
const lock = await readSkillLock();
|
|
341
|
+
return lock.dismissed?.[promptKey] === true;
|
|
342
|
+
}
|
|
343
|
+
async function dismissPrompt(promptKey) {
|
|
344
|
+
const lock = await readSkillLock();
|
|
345
|
+
if (!lock.dismissed) {
|
|
346
|
+
lock.dismissed = {};
|
|
347
|
+
}
|
|
348
|
+
lock.dismissed[promptKey] = true;
|
|
349
|
+
await writeSkillLock(lock);
|
|
350
|
+
}
|
|
351
|
+
async function getLastSelectedAgents() {
|
|
352
|
+
const lock = await readSkillLock();
|
|
353
|
+
return lock.lastSelectedAgents;
|
|
354
|
+
}
|
|
355
|
+
async function saveSelectedAgents(agents2) {
|
|
356
|
+
const lock = await readSkillLock();
|
|
357
|
+
lock.lastSelectedAgents = agents2;
|
|
358
|
+
await writeSkillLock(lock);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// src/local-lock.ts
|
|
362
|
+
import { readFile as readFile2, writeFile as writeFile2, readdir } from "fs/promises";
|
|
363
|
+
import { join as join2, relative } from "path";
|
|
364
|
+
import { createHash } from "crypto";
|
|
365
|
+
var LOCAL_LOCK_FILE = "skills-lock.json";
|
|
366
|
+
var CURRENT_VERSION2 = 1;
|
|
367
|
+
function getLocalLockPath(cwd) {
|
|
368
|
+
return join2(cwd || process.cwd(), LOCAL_LOCK_FILE);
|
|
369
|
+
}
|
|
370
|
+
async function readLocalLock(cwd) {
|
|
371
|
+
const lockPath = getLocalLockPath(cwd);
|
|
372
|
+
try {
|
|
373
|
+
const content = await readFile2(lockPath, "utf-8");
|
|
374
|
+
const parsed = JSON.parse(content);
|
|
375
|
+
if (typeof parsed.version !== "number" || !parsed.skills) {
|
|
376
|
+
return createEmptyLocalLock();
|
|
377
|
+
}
|
|
378
|
+
if (parsed.version < CURRENT_VERSION2) {
|
|
379
|
+
return createEmptyLocalLock();
|
|
380
|
+
}
|
|
381
|
+
return parsed;
|
|
382
|
+
} catch {
|
|
383
|
+
return createEmptyLocalLock();
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
async function writeLocalLock(lock, cwd) {
|
|
387
|
+
const lockPath = getLocalLockPath(cwd);
|
|
388
|
+
const sortedSkills = {};
|
|
389
|
+
for (const key of Object.keys(lock.skills).sort()) {
|
|
390
|
+
sortedSkills[key] = lock.skills[key];
|
|
391
|
+
}
|
|
392
|
+
const sorted = { version: lock.version, skills: sortedSkills };
|
|
393
|
+
const content = JSON.stringify(sorted, null, 2) + "\n";
|
|
394
|
+
await writeFile2(lockPath, content, "utf-8");
|
|
395
|
+
}
|
|
396
|
+
async function computeSkillFolderHash(skillDir) {
|
|
397
|
+
const files = [];
|
|
398
|
+
await collectFiles(skillDir, skillDir, files);
|
|
399
|
+
files.sort((a, b3) => a.relativePath.localeCompare(b3.relativePath));
|
|
400
|
+
const hash = createHash("sha256");
|
|
401
|
+
for (const file of files) {
|
|
402
|
+
hash.update(file.relativePath);
|
|
403
|
+
hash.update(file.content);
|
|
404
|
+
}
|
|
405
|
+
return hash.digest("hex");
|
|
406
|
+
}
|
|
407
|
+
async function collectFiles(baseDir, currentDir, results) {
|
|
408
|
+
const entries = await readdir(currentDir, { withFileTypes: true });
|
|
409
|
+
await Promise.all(
|
|
410
|
+
entries.map(async (entry) => {
|
|
411
|
+
const fullPath = join2(currentDir, entry.name);
|
|
412
|
+
if (entry.isDirectory()) {
|
|
413
|
+
if (entry.name === ".git" || entry.name === "node_modules") return;
|
|
414
|
+
await collectFiles(baseDir, fullPath, results);
|
|
415
|
+
} else if (entry.isFile()) {
|
|
416
|
+
const content = await readFile2(fullPath);
|
|
417
|
+
const relativePath = relative(baseDir, fullPath).split("\\").join("/");
|
|
418
|
+
results.push({ relativePath, content });
|
|
419
|
+
}
|
|
420
|
+
})
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
async function addSkillToLocalLock(skillName, entry, cwd) {
|
|
424
|
+
const lock = await readLocalLock(cwd);
|
|
425
|
+
lock.skills[skillName] = entry;
|
|
426
|
+
await writeLocalLock(lock, cwd);
|
|
427
|
+
}
|
|
428
|
+
async function removeSkillFromLocalLock(skillName, cwd) {
|
|
429
|
+
const lock = await readLocalLock(cwd);
|
|
430
|
+
if (!(skillName in lock.skills)) {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
delete lock.skills[skillName];
|
|
434
|
+
await writeLocalLock(lock, cwd);
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
function createEmptyLocalLock() {
|
|
438
|
+
return {
|
|
439
|
+
version: CURRENT_VERSION2,
|
|
440
|
+
skills: {}
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// ../../node_modules/.pnpm/@clack+prompts@0.11.0/node_modules/@clack/prompts/dist/index.mjs
|
|
445
|
+
import { stripVTControlCharacters as S2 } from "util";
|
|
446
|
+
|
|
447
|
+
// ../../node_modules/.pnpm/@clack+core@0.5.0/node_modules/@clack/core/dist/index.mjs
|
|
448
|
+
var import_sisteransi = __toESM(require_src(), 1);
|
|
449
|
+
import { stdin as j, stdout as M } from "process";
|
|
450
|
+
import * as g from "readline";
|
|
451
|
+
import O from "readline";
|
|
452
|
+
import { Writable as X } from "stream";
|
|
453
|
+
function DD({ onlyFirst: e2 = false } = {}) {
|
|
454
|
+
const t = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|");
|
|
455
|
+
return new RegExp(t, e2 ? void 0 : "g");
|
|
456
|
+
}
|
|
457
|
+
var uD = DD();
|
|
458
|
+
function P(e2) {
|
|
459
|
+
if (typeof e2 != "string") throw new TypeError(`Expected a \`string\`, got \`${typeof e2}\``);
|
|
460
|
+
return e2.replace(uD, "");
|
|
461
|
+
}
|
|
462
|
+
function L(e2) {
|
|
463
|
+
return e2 && e2.__esModule && Object.prototype.hasOwnProperty.call(e2, "default") ? e2.default : e2;
|
|
464
|
+
}
|
|
465
|
+
var W = { exports: {} };
|
|
466
|
+
(function(e2) {
|
|
467
|
+
var u2 = {};
|
|
468
|
+
e2.exports = u2, u2.eastAsianWidth = function(F2) {
|
|
469
|
+
var s = F2.charCodeAt(0), i = F2.length == 2 ? F2.charCodeAt(1) : 0, D2 = s;
|
|
470
|
+
return 55296 <= s && s <= 56319 && 56320 <= i && i <= 57343 && (s &= 1023, i &= 1023, D2 = s << 10 | i, D2 += 65536), D2 == 12288 || 65281 <= D2 && D2 <= 65376 || 65504 <= D2 && D2 <= 65510 ? "F" : D2 == 8361 || 65377 <= D2 && D2 <= 65470 || 65474 <= D2 && D2 <= 65479 || 65482 <= D2 && D2 <= 65487 || 65490 <= D2 && D2 <= 65495 || 65498 <= D2 && D2 <= 65500 || 65512 <= D2 && D2 <= 65518 ? "H" : 4352 <= D2 && D2 <= 4447 || 4515 <= D2 && D2 <= 4519 || 4602 <= D2 && D2 <= 4607 || 9001 <= D2 && D2 <= 9002 || 11904 <= D2 && D2 <= 11929 || 11931 <= D2 && D2 <= 12019 || 12032 <= D2 && D2 <= 12245 || 12272 <= D2 && D2 <= 12283 || 12289 <= D2 && D2 <= 12350 || 12353 <= D2 && D2 <= 12438 || 12441 <= D2 && D2 <= 12543 || 12549 <= D2 && D2 <= 12589 || 12593 <= D2 && D2 <= 12686 || 12688 <= D2 && D2 <= 12730 || 12736 <= D2 && D2 <= 12771 || 12784 <= D2 && D2 <= 12830 || 12832 <= D2 && D2 <= 12871 || 12880 <= D2 && D2 <= 13054 || 13056 <= D2 && D2 <= 19903 || 19968 <= D2 && D2 <= 42124 || 42128 <= D2 && D2 <= 42182 || 43360 <= D2 && D2 <= 43388 || 44032 <= D2 && D2 <= 55203 || 55216 <= D2 && D2 <= 55238 || 55243 <= D2 && D2 <= 55291 || 63744 <= D2 && D2 <= 64255 || 65040 <= D2 && D2 <= 65049 || 65072 <= D2 && D2 <= 65106 || 65108 <= D2 && D2 <= 65126 || 65128 <= D2 && D2 <= 65131 || 110592 <= D2 && D2 <= 110593 || 127488 <= D2 && D2 <= 127490 || 127504 <= D2 && D2 <= 127546 || 127552 <= D2 && D2 <= 127560 || 127568 <= D2 && D2 <= 127569 || 131072 <= D2 && D2 <= 194367 || 177984 <= D2 && D2 <= 196605 || 196608 <= D2 && D2 <= 262141 ? "W" : 32 <= D2 && D2 <= 126 || 162 <= D2 && D2 <= 163 || 165 <= D2 && D2 <= 166 || D2 == 172 || D2 == 175 || 10214 <= D2 && D2 <= 10221 || 10629 <= D2 && D2 <= 10630 ? "Na" : D2 == 161 || D2 == 164 || 167 <= D2 && D2 <= 168 || D2 == 170 || 173 <= D2 && D2 <= 174 || 176 <= D2 && D2 <= 180 || 182 <= D2 && D2 <= 186 || 188 <= D2 && D2 <= 191 || D2 == 198 || D2 == 208 || 215 <= D2 && D2 <= 216 || 222 <= D2 && D2 <= 225 || D2 == 230 || 232 <= D2 && D2 <= 234 || 236 <= D2 && D2 <= 237 || D2 == 240 || 242 <= D2 && D2 <= 243 || 247 <= D2 && D2 <= 250 || D2 == 252 || D2 == 254 || D2 == 257 || D2 == 273 || D2 == 275 || D2 == 283 || 294 <= D2 && D2 <= 295 || D2 == 299 || 305 <= D2 && D2 <= 307 || D2 == 312 || 319 <= D2 && D2 <= 322 || D2 == 324 || 328 <= D2 && D2 <= 331 || D2 == 333 || 338 <= D2 && D2 <= 339 || 358 <= D2 && D2 <= 359 || D2 == 363 || D2 == 462 || D2 == 464 || D2 == 466 || D2 == 468 || D2 == 470 || D2 == 472 || D2 == 474 || D2 == 476 || D2 == 593 || D2 == 609 || D2 == 708 || D2 == 711 || 713 <= D2 && D2 <= 715 || D2 == 717 || D2 == 720 || 728 <= D2 && D2 <= 731 || D2 == 733 || D2 == 735 || 768 <= D2 && D2 <= 879 || 913 <= D2 && D2 <= 929 || 931 <= D2 && D2 <= 937 || 945 <= D2 && D2 <= 961 || 963 <= D2 && D2 <= 969 || D2 == 1025 || 1040 <= D2 && D2 <= 1103 || D2 == 1105 || D2 == 8208 || 8211 <= D2 && D2 <= 8214 || 8216 <= D2 && D2 <= 8217 || 8220 <= D2 && D2 <= 8221 || 8224 <= D2 && D2 <= 8226 || 8228 <= D2 && D2 <= 8231 || D2 == 8240 || 8242 <= D2 && D2 <= 8243 || D2 == 8245 || D2 == 8251 || D2 == 8254 || D2 == 8308 || D2 == 8319 || 8321 <= D2 && D2 <= 8324 || D2 == 8364 || D2 == 8451 || D2 == 8453 || D2 == 8457 || D2 == 8467 || D2 == 8470 || 8481 <= D2 && D2 <= 8482 || D2 == 8486 || D2 == 8491 || 8531 <= D2 && D2 <= 8532 || 8539 <= D2 && D2 <= 8542 || 8544 <= D2 && D2 <= 8555 || 8560 <= D2 && D2 <= 8569 || D2 == 8585 || 8592 <= D2 && D2 <= 8601 || 8632 <= D2 && D2 <= 8633 || D2 == 8658 || D2 == 8660 || D2 == 8679 || D2 == 8704 || 8706 <= D2 && D2 <= 8707 || 8711 <= D2 && D2 <= 8712 || D2 == 8715 || D2 == 8719 || D2 == 8721 || D2 == 8725 || D2 == 8730 || 8733 <= D2 && D2 <= 8736 || D2 == 8739 || D2 == 8741 || 8743 <= D2 && D2 <= 8748 || D2 == 8750 || 8756 <= D2 && D2 <= 8759 || 8764 <= D2 && D2 <= 8765 || D2 == 8776 || D2 == 8780 || D2 == 8786 || 8800 <= D2 && D2 <= 8801 || 8804 <= D2 && D2 <= 8807 || 8810 <= D2 && D2 <= 8811 || 8814 <= D2 && D2 <= 8815 || 8834 <= D2 && D2 <= 8835 || 8838 <= D2 && D2 <= 8839 || D2 == 8853 || D2 == 8857 || D2 == 8869 || D2 == 8895 || D2 == 8978 || 9312 <= D2 && D2 <= 9449 || 9451 <= D2 && D2 <= 9547 || 9552 <= D2 && D2 <= 9587 || 9600 <= D2 && D2 <= 9615 || 9618 <= D2 && D2 <= 9621 || 9632 <= D2 && D2 <= 9633 || 9635 <= D2 && D2 <= 9641 || 9650 <= D2 && D2 <= 9651 || 9654 <= D2 && D2 <= 9655 || 9660 <= D2 && D2 <= 9661 || 9664 <= D2 && D2 <= 9665 || 9670 <= D2 && D2 <= 9672 || D2 == 9675 || 9678 <= D2 && D2 <= 9681 || 9698 <= D2 && D2 <= 9701 || D2 == 9711 || 9733 <= D2 && D2 <= 9734 || D2 == 9737 || 9742 <= D2 && D2 <= 9743 || 9748 <= D2 && D2 <= 9749 || D2 == 9756 || D2 == 9758 || D2 == 9792 || D2 == 9794 || 9824 <= D2 && D2 <= 9825 || 9827 <= D2 && D2 <= 9829 || 9831 <= D2 && D2 <= 9834 || 9836 <= D2 && D2 <= 9837 || D2 == 9839 || 9886 <= D2 && D2 <= 9887 || 9918 <= D2 && D2 <= 9919 || 9924 <= D2 && D2 <= 9933 || 9935 <= D2 && D2 <= 9953 || D2 == 9955 || 9960 <= D2 && D2 <= 9983 || D2 == 10045 || D2 == 10071 || 10102 <= D2 && D2 <= 10111 || 11093 <= D2 && D2 <= 11097 || 12872 <= D2 && D2 <= 12879 || 57344 <= D2 && D2 <= 63743 || 65024 <= D2 && D2 <= 65039 || D2 == 65533 || 127232 <= D2 && D2 <= 127242 || 127248 <= D2 && D2 <= 127277 || 127280 <= D2 && D2 <= 127337 || 127344 <= D2 && D2 <= 127386 || 917760 <= D2 && D2 <= 917999 || 983040 <= D2 && D2 <= 1048573 || 1048576 <= D2 && D2 <= 1114109 ? "A" : "N";
|
|
471
|
+
}, u2.characterLength = function(F2) {
|
|
472
|
+
var s = this.eastAsianWidth(F2);
|
|
473
|
+
return s == "F" || s == "W" || s == "A" ? 2 : 1;
|
|
474
|
+
};
|
|
475
|
+
function t(F2) {
|
|
476
|
+
return F2.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[^\uD800-\uDFFF]/g) || [];
|
|
477
|
+
}
|
|
478
|
+
u2.length = function(F2) {
|
|
479
|
+
for (var s = t(F2), i = 0, D2 = 0; D2 < s.length; D2++) i = i + this.characterLength(s[D2]);
|
|
480
|
+
return i;
|
|
481
|
+
}, u2.slice = function(F2, s, i) {
|
|
482
|
+
textLen = u2.length(F2), s = s || 0, i = i || 1, s < 0 && (s = textLen + s), i < 0 && (i = textLen + i);
|
|
483
|
+
for (var D2 = "", C2 = 0, n = t(F2), E = 0; E < n.length; E++) {
|
|
484
|
+
var a = n[E], o2 = u2.length(a);
|
|
485
|
+
if (C2 >= s - (o2 == 2 ? 1 : 0)) if (C2 + o2 <= i) D2 += a;
|
|
486
|
+
else break;
|
|
487
|
+
C2 += o2;
|
|
488
|
+
}
|
|
489
|
+
return D2;
|
|
490
|
+
};
|
|
491
|
+
})(W);
|
|
492
|
+
var tD = W.exports;
|
|
493
|
+
var eD = L(tD);
|
|
494
|
+
var FD = function() {
|
|
495
|
+
return /\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|(?:\uD83E\uDDD1\uD83C\uDFFF\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFC-\uDFFF])|\uD83D\uDC68(?:\uD83C\uDFFB(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])\uFE0F|\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC)?|(?:\uD83D\uDC69(?:\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC69(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83E\uDDD1(?:\u200D(?:\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F\u200D\u26A7|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\uD83C\uDFF4\u200D\u2620|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u2600-\u2604\u260E\u2611\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26B0\u26B1\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0\u26F1\u26F4\u26F7\u26F8\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u3030\u303D\u3297\u3299]|\uD83C[\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3])\uFE0F|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDE35\u200D\uD83D\uDCAB|\uD83D\uDE2E\u200D\uD83D\uDCA8|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83E\uDDD1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC69(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83D\uDC08\u200D\u2B1B|\u2764\uFE0F\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uD83D\uDC41\uFE0F|\uD83C\uDFF3\uFE0F|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#\*0-9]\uFE0F\u20E3|\u2764\uFE0F|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|\uD83C\uDFF4|(?:[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270C\u270D]|\uD83D[\uDD74\uDD90])(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC08\uDC15\uDC3B\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE2E\uDE35\uDE36\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5]|\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD]|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF]|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0D\uDD0E\uDD10-\uDD17\uDD1D\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78\uDD7A-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCB\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6]|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26A7\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5-\uDED7\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDD77\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g;
|
|
496
|
+
};
|
|
497
|
+
var sD = L(FD);
|
|
498
|
+
function p(e2, u2 = {}) {
|
|
499
|
+
if (typeof e2 != "string" || e2.length === 0 || (u2 = { ambiguousIsNarrow: true, ...u2 }, e2 = P(e2), e2.length === 0)) return 0;
|
|
500
|
+
e2 = e2.replace(sD(), " ");
|
|
501
|
+
const t = u2.ambiguousIsNarrow ? 1 : 2;
|
|
502
|
+
let F2 = 0;
|
|
503
|
+
for (const s of e2) {
|
|
504
|
+
const i = s.codePointAt(0);
|
|
505
|
+
if (i <= 31 || i >= 127 && i <= 159 || i >= 768 && i <= 879) continue;
|
|
506
|
+
switch (eD.eastAsianWidth(s)) {
|
|
507
|
+
case "F":
|
|
508
|
+
case "W":
|
|
509
|
+
F2 += 2;
|
|
510
|
+
break;
|
|
511
|
+
case "A":
|
|
512
|
+
F2 += t;
|
|
513
|
+
break;
|
|
514
|
+
default:
|
|
515
|
+
F2 += 1;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return F2;
|
|
519
|
+
}
|
|
520
|
+
var w = 10;
|
|
521
|
+
var N = (e2 = 0) => (u2) => `\x1B[${u2 + e2}m`;
|
|
522
|
+
var I = (e2 = 0) => (u2) => `\x1B[${38 + e2};5;${u2}m`;
|
|
523
|
+
var R = (e2 = 0) => (u2, t, F2) => `\x1B[${38 + e2};2;${u2};${t};${F2}m`;
|
|
524
|
+
var r = { modifier: { reset: [0, 0], bold: [1, 22], dim: [2, 22], italic: [3, 23], underline: [4, 24], overline: [53, 55], inverse: [7, 27], hidden: [8, 28], strikethrough: [9, 29] }, color: { black: [30, 39], red: [31, 39], green: [32, 39], yellow: [33, 39], blue: [34, 39], magenta: [35, 39], cyan: [36, 39], white: [37, 39], blackBright: [90, 39], gray: [90, 39], grey: [90, 39], redBright: [91, 39], greenBright: [92, 39], yellowBright: [93, 39], blueBright: [94, 39], magentaBright: [95, 39], cyanBright: [96, 39], whiteBright: [97, 39] }, bgColor: { bgBlack: [40, 49], bgRed: [41, 49], bgGreen: [42, 49], bgYellow: [43, 49], bgBlue: [44, 49], bgMagenta: [45, 49], bgCyan: [46, 49], bgWhite: [47, 49], bgBlackBright: [100, 49], bgGray: [100, 49], bgGrey: [100, 49], bgRedBright: [101, 49], bgGreenBright: [102, 49], bgYellowBright: [103, 49], bgBlueBright: [104, 49], bgMagentaBright: [105, 49], bgCyanBright: [106, 49], bgWhiteBright: [107, 49] } };
|
|
525
|
+
Object.keys(r.modifier);
|
|
526
|
+
var iD = Object.keys(r.color);
|
|
527
|
+
var CD = Object.keys(r.bgColor);
|
|
528
|
+
[...iD, ...CD];
|
|
529
|
+
function rD() {
|
|
530
|
+
const e2 = /* @__PURE__ */ new Map();
|
|
531
|
+
for (const [u2, t] of Object.entries(r)) {
|
|
532
|
+
for (const [F2, s] of Object.entries(t)) r[F2] = { open: `\x1B[${s[0]}m`, close: `\x1B[${s[1]}m` }, t[F2] = r[F2], e2.set(s[0], s[1]);
|
|
533
|
+
Object.defineProperty(r, u2, { value: t, enumerable: false });
|
|
534
|
+
}
|
|
535
|
+
return Object.defineProperty(r, "codes", { value: e2, enumerable: false }), r.color.close = "\x1B[39m", r.bgColor.close = "\x1B[49m", r.color.ansi = N(), r.color.ansi256 = I(), r.color.ansi16m = R(), r.bgColor.ansi = N(w), r.bgColor.ansi256 = I(w), r.bgColor.ansi16m = R(w), Object.defineProperties(r, { rgbToAnsi256: { value: (u2, t, F2) => u2 === t && t === F2 ? u2 < 8 ? 16 : u2 > 248 ? 231 : Math.round((u2 - 8) / 247 * 24) + 232 : 16 + 36 * Math.round(u2 / 255 * 5) + 6 * Math.round(t / 255 * 5) + Math.round(F2 / 255 * 5), enumerable: false }, hexToRgb: { value: (u2) => {
|
|
536
|
+
const t = /[a-f\d]{6}|[a-f\d]{3}/i.exec(u2.toString(16));
|
|
537
|
+
if (!t) return [0, 0, 0];
|
|
538
|
+
let [F2] = t;
|
|
539
|
+
F2.length === 3 && (F2 = [...F2].map((i) => i + i).join(""));
|
|
540
|
+
const s = Number.parseInt(F2, 16);
|
|
541
|
+
return [s >> 16 & 255, s >> 8 & 255, s & 255];
|
|
542
|
+
}, enumerable: false }, hexToAnsi256: { value: (u2) => r.rgbToAnsi256(...r.hexToRgb(u2)), enumerable: false }, ansi256ToAnsi: { value: (u2) => {
|
|
543
|
+
if (u2 < 8) return 30 + u2;
|
|
544
|
+
if (u2 < 16) return 90 + (u2 - 8);
|
|
545
|
+
let t, F2, s;
|
|
546
|
+
if (u2 >= 232) t = ((u2 - 232) * 10 + 8) / 255, F2 = t, s = t;
|
|
547
|
+
else {
|
|
548
|
+
u2 -= 16;
|
|
549
|
+
const C2 = u2 % 36;
|
|
550
|
+
t = Math.floor(u2 / 36) / 5, F2 = Math.floor(C2 / 6) / 5, s = C2 % 6 / 5;
|
|
551
|
+
}
|
|
552
|
+
const i = Math.max(t, F2, s) * 2;
|
|
553
|
+
if (i === 0) return 30;
|
|
554
|
+
let D2 = 30 + (Math.round(s) << 2 | Math.round(F2) << 1 | Math.round(t));
|
|
555
|
+
return i === 2 && (D2 += 60), D2;
|
|
556
|
+
}, enumerable: false }, rgbToAnsi: { value: (u2, t, F2) => r.ansi256ToAnsi(r.rgbToAnsi256(u2, t, F2)), enumerable: false }, hexToAnsi: { value: (u2) => r.ansi256ToAnsi(r.hexToAnsi256(u2)), enumerable: false } }), r;
|
|
557
|
+
}
|
|
558
|
+
var ED = rD();
|
|
559
|
+
var d = /* @__PURE__ */ new Set(["\x1B", "\x9B"]);
|
|
560
|
+
var oD = 39;
|
|
561
|
+
var y = "\x07";
|
|
562
|
+
var V = "[";
|
|
563
|
+
var nD = "]";
|
|
564
|
+
var G = "m";
|
|
565
|
+
var _ = `${nD}8;;`;
|
|
566
|
+
var z = (e2) => `${d.values().next().value}${V}${e2}${G}`;
|
|
567
|
+
var K = (e2) => `${d.values().next().value}${_}${e2}${y}`;
|
|
568
|
+
var aD = (e2) => e2.split(" ").map((u2) => p(u2));
|
|
569
|
+
var k = (e2, u2, t) => {
|
|
570
|
+
const F2 = [...u2];
|
|
571
|
+
let s = false, i = false, D2 = p(P(e2[e2.length - 1]));
|
|
572
|
+
for (const [C2, n] of F2.entries()) {
|
|
573
|
+
const E = p(n);
|
|
574
|
+
if (D2 + E <= t ? e2[e2.length - 1] += n : (e2.push(n), D2 = 0), d.has(n) && (s = true, i = F2.slice(C2 + 1).join("").startsWith(_)), s) {
|
|
575
|
+
i ? n === y && (s = false, i = false) : n === G && (s = false);
|
|
576
|
+
continue;
|
|
577
|
+
}
|
|
578
|
+
D2 += E, D2 === t && C2 < F2.length - 1 && (e2.push(""), D2 = 0);
|
|
579
|
+
}
|
|
580
|
+
!D2 && e2[e2.length - 1].length > 0 && e2.length > 1 && (e2[e2.length - 2] += e2.pop());
|
|
581
|
+
};
|
|
582
|
+
var hD = (e2) => {
|
|
583
|
+
const u2 = e2.split(" ");
|
|
584
|
+
let t = u2.length;
|
|
585
|
+
for (; t > 0 && !(p(u2[t - 1]) > 0); ) t--;
|
|
586
|
+
return t === u2.length ? e2 : u2.slice(0, t).join(" ") + u2.slice(t).join("");
|
|
587
|
+
};
|
|
588
|
+
var lD = (e2, u2, t = {}) => {
|
|
589
|
+
if (t.trim !== false && e2.trim() === "") return "";
|
|
590
|
+
let F2 = "", s, i;
|
|
591
|
+
const D2 = aD(e2);
|
|
592
|
+
let C2 = [""];
|
|
593
|
+
for (const [E, a] of e2.split(" ").entries()) {
|
|
594
|
+
t.trim !== false && (C2[C2.length - 1] = C2[C2.length - 1].trimStart());
|
|
595
|
+
let o2 = p(C2[C2.length - 1]);
|
|
596
|
+
if (E !== 0 && (o2 >= u2 && (t.wordWrap === false || t.trim === false) && (C2.push(""), o2 = 0), (o2 > 0 || t.trim === false) && (C2[C2.length - 1] += " ", o2++)), t.hard && D2[E] > u2) {
|
|
597
|
+
const c = u2 - o2, f = 1 + Math.floor((D2[E] - c - 1) / u2);
|
|
598
|
+
Math.floor((D2[E] - 1) / u2) < f && C2.push(""), k(C2, a, u2);
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
if (o2 + D2[E] > u2 && o2 > 0 && D2[E] > 0) {
|
|
602
|
+
if (t.wordWrap === false && o2 < u2) {
|
|
603
|
+
k(C2, a, u2);
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
C2.push("");
|
|
607
|
+
}
|
|
608
|
+
if (o2 + D2[E] > u2 && t.wordWrap === false) {
|
|
609
|
+
k(C2, a, u2);
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
612
|
+
C2[C2.length - 1] += a;
|
|
613
|
+
}
|
|
614
|
+
t.trim !== false && (C2 = C2.map((E) => hD(E)));
|
|
615
|
+
const n = [...C2.join(`
|
|
616
|
+
`)];
|
|
617
|
+
for (const [E, a] of n.entries()) {
|
|
618
|
+
if (F2 += a, d.has(a)) {
|
|
619
|
+
const { groups: c } = new RegExp(`(?:\\${V}(?<code>\\d+)m|\\${_}(?<uri>.*)${y})`).exec(n.slice(E).join("")) || { groups: {} };
|
|
620
|
+
if (c.code !== void 0) {
|
|
621
|
+
const f = Number.parseFloat(c.code);
|
|
622
|
+
s = f === oD ? void 0 : f;
|
|
623
|
+
} else c.uri !== void 0 && (i = c.uri.length === 0 ? void 0 : c.uri);
|
|
624
|
+
}
|
|
625
|
+
const o2 = ED.codes.get(Number(s));
|
|
626
|
+
n[E + 1] === `
|
|
627
|
+
` ? (i && (F2 += K("")), s && o2 && (F2 += z(o2))) : a === `
|
|
628
|
+
` && (s && o2 && (F2 += z(s)), i && (F2 += K(i)));
|
|
629
|
+
}
|
|
630
|
+
return F2;
|
|
631
|
+
};
|
|
632
|
+
function Y(e2, u2, t) {
|
|
633
|
+
return String(e2).normalize().replace(/\r\n/g, `
|
|
634
|
+
`).split(`
|
|
635
|
+
`).map((F2) => lD(F2, u2, t)).join(`
|
|
636
|
+
`);
|
|
637
|
+
}
|
|
638
|
+
var xD = ["up", "down", "left", "right", "space", "enter", "cancel"];
|
|
639
|
+
var B = { actions: new Set(xD), aliases: /* @__PURE__ */ new Map([["k", "up"], ["j", "down"], ["h", "left"], ["l", "right"], ["", "cancel"], ["escape", "cancel"]]) };
|
|
640
|
+
function $(e2, u2) {
|
|
641
|
+
if (typeof e2 == "string") return B.aliases.get(e2) === u2;
|
|
642
|
+
for (const t of e2) if (t !== void 0 && $(t, u2)) return true;
|
|
643
|
+
return false;
|
|
644
|
+
}
|
|
645
|
+
function BD(e2, u2) {
|
|
646
|
+
if (e2 === u2) return;
|
|
647
|
+
const t = e2.split(`
|
|
648
|
+
`), F2 = u2.split(`
|
|
649
|
+
`), s = [];
|
|
650
|
+
for (let i = 0; i < Math.max(t.length, F2.length); i++) t[i] !== F2[i] && s.push(i);
|
|
651
|
+
return s;
|
|
652
|
+
}
|
|
653
|
+
var AD = globalThis.process.platform.startsWith("win");
|
|
654
|
+
var S = /* @__PURE__ */ Symbol("clack:cancel");
|
|
655
|
+
function pD(e2) {
|
|
656
|
+
return e2 === S;
|
|
657
|
+
}
|
|
658
|
+
function m(e2, u2) {
|
|
659
|
+
const t = e2;
|
|
660
|
+
t.isTTY && t.setRawMode(u2);
|
|
661
|
+
}
|
|
662
|
+
function fD({ input: e2 = j, output: u2 = M, overwrite: t = true, hideCursor: F2 = true } = {}) {
|
|
663
|
+
const s = g.createInterface({ input: e2, output: u2, prompt: "", tabSize: 1 });
|
|
664
|
+
g.emitKeypressEvents(e2, s), e2.isTTY && e2.setRawMode(true);
|
|
665
|
+
const i = (D2, { name: C2, sequence: n }) => {
|
|
666
|
+
const E = String(D2);
|
|
667
|
+
if ($([E, C2, n], "cancel")) {
|
|
668
|
+
F2 && u2.write(import_sisteransi.cursor.show), process.exit(0);
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
if (!t) return;
|
|
672
|
+
const a = C2 === "return" ? 0 : -1, o2 = C2 === "return" ? -1 : 0;
|
|
673
|
+
g.moveCursor(u2, a, o2, () => {
|
|
674
|
+
g.clearLine(u2, 1, () => {
|
|
675
|
+
e2.once("keypress", i);
|
|
676
|
+
});
|
|
677
|
+
});
|
|
678
|
+
};
|
|
679
|
+
return F2 && u2.write(import_sisteransi.cursor.hide), e2.once("keypress", i), () => {
|
|
680
|
+
e2.off("keypress", i), F2 && u2.write(import_sisteransi.cursor.show), e2.isTTY && !AD && e2.setRawMode(false), s.terminal = false, s.close();
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
var gD = Object.defineProperty;
|
|
684
|
+
var vD = (e2, u2, t) => u2 in e2 ? gD(e2, u2, { enumerable: true, configurable: true, writable: true, value: t }) : e2[u2] = t;
|
|
685
|
+
var h = (e2, u2, t) => (vD(e2, typeof u2 != "symbol" ? u2 + "" : u2, t), t);
|
|
686
|
+
var x = class {
|
|
687
|
+
constructor(u2, t = true) {
|
|
688
|
+
h(this, "input"), h(this, "output"), h(this, "_abortSignal"), h(this, "rl"), h(this, "opts"), h(this, "_render"), h(this, "_track", false), h(this, "_prevFrame", ""), h(this, "_subscribers", /* @__PURE__ */ new Map()), h(this, "_cursor", 0), h(this, "state", "initial"), h(this, "error", ""), h(this, "value");
|
|
689
|
+
const { input: F2 = j, output: s = M, render: i, signal: D2, ...C2 } = u2;
|
|
690
|
+
this.opts = C2, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = i.bind(this), this._track = t, this._abortSignal = D2, this.input = F2, this.output = s;
|
|
691
|
+
}
|
|
692
|
+
unsubscribe() {
|
|
693
|
+
this._subscribers.clear();
|
|
694
|
+
}
|
|
695
|
+
setSubscriber(u2, t) {
|
|
696
|
+
const F2 = this._subscribers.get(u2) ?? [];
|
|
697
|
+
F2.push(t), this._subscribers.set(u2, F2);
|
|
698
|
+
}
|
|
699
|
+
on(u2, t) {
|
|
700
|
+
this.setSubscriber(u2, { cb: t });
|
|
701
|
+
}
|
|
702
|
+
once(u2, t) {
|
|
703
|
+
this.setSubscriber(u2, { cb: t, once: true });
|
|
704
|
+
}
|
|
705
|
+
emit(u2, ...t) {
|
|
706
|
+
const F2 = this._subscribers.get(u2) ?? [], s = [];
|
|
707
|
+
for (const i of F2) i.cb(...t), i.once && s.push(() => F2.splice(F2.indexOf(i), 1));
|
|
708
|
+
for (const i of s) i();
|
|
709
|
+
}
|
|
710
|
+
prompt() {
|
|
711
|
+
return new Promise((u2, t) => {
|
|
712
|
+
if (this._abortSignal) {
|
|
713
|
+
if (this._abortSignal.aborted) return this.state = "cancel", this.close(), u2(S);
|
|
714
|
+
this._abortSignal.addEventListener("abort", () => {
|
|
715
|
+
this.state = "cancel", this.close();
|
|
716
|
+
}, { once: true });
|
|
717
|
+
}
|
|
718
|
+
const F2 = new X();
|
|
719
|
+
F2._write = (s, i, D2) => {
|
|
720
|
+
this._track && (this.value = this.rl?.line.replace(/\t/g, ""), this._cursor = this.rl?.cursor ?? 0, this.emit("value", this.value)), D2();
|
|
721
|
+
}, this.input.pipe(F2), this.rl = O.createInterface({ input: this.input, output: F2, tabSize: 2, prompt: "", escapeCodeTimeout: 50, terminal: true }), O.emitKeypressEvents(this.input, this.rl), this.rl.prompt(), this.opts.initialValue !== void 0 && this._track && this.rl.write(this.opts.initialValue), this.input.on("keypress", this.onKeypress), m(this.input, true), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
|
|
722
|
+
this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), m(this.input, false), u2(this.value);
|
|
723
|
+
}), this.once("cancel", () => {
|
|
724
|
+
this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), m(this.input, false), u2(S);
|
|
725
|
+
});
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
onKeypress(u2, t) {
|
|
729
|
+
if (this.state === "error" && (this.state = "active"), t?.name && (!this._track && B.aliases.has(t.name) && this.emit("cursor", B.aliases.get(t.name)), B.actions.has(t.name) && this.emit("cursor", t.name)), u2 && (u2.toLowerCase() === "y" || u2.toLowerCase() === "n") && this.emit("confirm", u2.toLowerCase() === "y"), u2 === " " && this.opts.placeholder && (this.value || (this.rl?.write(this.opts.placeholder), this.emit("value", this.opts.placeholder))), u2 && this.emit("key", u2.toLowerCase()), t?.name === "return") {
|
|
730
|
+
if (this.opts.validate) {
|
|
731
|
+
const F2 = this.opts.validate(this.value);
|
|
732
|
+
F2 && (this.error = F2 instanceof Error ? F2.message : F2, this.state = "error", this.rl?.write(this.value));
|
|
733
|
+
}
|
|
734
|
+
this.state !== "error" && (this.state = "submit");
|
|
735
|
+
}
|
|
736
|
+
$([u2, t?.name, t?.sequence], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
|
|
737
|
+
}
|
|
738
|
+
close() {
|
|
739
|
+
this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
|
|
740
|
+
`), m(this.input, false), this.rl?.close(), this.rl = void 0, this.emit(`${this.state}`, this.value), this.unsubscribe();
|
|
741
|
+
}
|
|
742
|
+
restoreCursor() {
|
|
743
|
+
const u2 = Y(this._prevFrame, process.stdout.columns, { hard: true }).split(`
|
|
744
|
+
`).length - 1;
|
|
745
|
+
this.output.write(import_sisteransi.cursor.move(-999, u2 * -1));
|
|
746
|
+
}
|
|
747
|
+
render() {
|
|
748
|
+
const u2 = Y(this._render(this) ?? "", process.stdout.columns, { hard: true });
|
|
749
|
+
if (u2 !== this._prevFrame) {
|
|
750
|
+
if (this.state === "initial") this.output.write(import_sisteransi.cursor.hide);
|
|
751
|
+
else {
|
|
752
|
+
const t = BD(this._prevFrame, u2);
|
|
753
|
+
if (this.restoreCursor(), t && t?.length === 1) {
|
|
754
|
+
const F2 = t[0];
|
|
755
|
+
this.output.write(import_sisteransi.cursor.move(0, F2)), this.output.write(import_sisteransi.erase.lines(1));
|
|
756
|
+
const s = u2.split(`
|
|
757
|
+
`);
|
|
758
|
+
this.output.write(s[F2]), this._prevFrame = u2, this.output.write(import_sisteransi.cursor.move(0, s.length - F2 - 1));
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
if (t && t?.length > 1) {
|
|
762
|
+
const F2 = t[0];
|
|
763
|
+
this.output.write(import_sisteransi.cursor.move(0, F2)), this.output.write(import_sisteransi.erase.down());
|
|
764
|
+
const s = u2.split(`
|
|
765
|
+
`).slice(F2);
|
|
766
|
+
this.output.write(s.join(`
|
|
767
|
+
`)), this._prevFrame = u2;
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
this.output.write(import_sisteransi.erase.down());
|
|
771
|
+
}
|
|
772
|
+
this.output.write(u2), this.state === "initial" && (this.state = "active"), this._prevFrame = u2;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
};
|
|
776
|
+
var dD = class extends x {
|
|
777
|
+
get cursor() {
|
|
778
|
+
return this.value ? 0 : 1;
|
|
779
|
+
}
|
|
780
|
+
get _value() {
|
|
781
|
+
return this.cursor === 0;
|
|
782
|
+
}
|
|
783
|
+
constructor(u2) {
|
|
784
|
+
super(u2, false), this.value = !!u2.initialValue, this.on("value", () => {
|
|
785
|
+
this.value = this._value;
|
|
786
|
+
}), this.on("confirm", (t) => {
|
|
787
|
+
this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = t, this.state = "submit", this.close();
|
|
788
|
+
}), this.on("cursor", () => {
|
|
789
|
+
this.value = !this.value;
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
var mD = Object.defineProperty;
|
|
794
|
+
var bD = (e2, u2, t) => u2 in e2 ? mD(e2, u2, { enumerable: true, configurable: true, writable: true, value: t }) : e2[u2] = t;
|
|
795
|
+
var Z = (e2, u2, t) => (bD(e2, typeof u2 != "symbol" ? u2 + "" : u2, t), t);
|
|
796
|
+
var q = (e2, u2, t) => {
|
|
797
|
+
if (!u2.has(e2)) throw TypeError("Cannot " + t);
|
|
798
|
+
};
|
|
799
|
+
var T = (e2, u2, t) => (q(e2, u2, "read from private field"), t ? t.call(e2) : u2.get(e2));
|
|
800
|
+
var wD = (e2, u2, t) => {
|
|
801
|
+
if (u2.has(e2)) throw TypeError("Cannot add the same private member more than once");
|
|
802
|
+
u2 instanceof WeakSet ? u2.add(e2) : u2.set(e2, t);
|
|
803
|
+
};
|
|
804
|
+
var yD = (e2, u2, t, F2) => (q(e2, u2, "write to private field"), F2 ? F2.call(e2, t) : u2.set(e2, t), t);
|
|
805
|
+
var A;
|
|
806
|
+
var _D = class extends x {
|
|
807
|
+
constructor(u2) {
|
|
808
|
+
super(u2, false), Z(this, "options"), Z(this, "cursor", 0), wD(this, A, void 0);
|
|
809
|
+
const { options: t } = u2;
|
|
810
|
+
yD(this, A, u2.selectableGroups !== false), this.options = Object.entries(t).flatMap(([F2, s]) => [{ value: F2, group: true, label: F2 }, ...s.map((i) => ({ ...i, group: F2 }))]), this.value = [...u2.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: F2 }) => F2 === u2.cursorAt), T(this, A) ? 0 : 1), this.on("cursor", (F2) => {
|
|
811
|
+
switch (F2) {
|
|
812
|
+
case "left":
|
|
813
|
+
case "up": {
|
|
814
|
+
this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
|
|
815
|
+
const s = this.options[this.cursor]?.group === true;
|
|
816
|
+
!T(this, A) && s && (this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1);
|
|
817
|
+
break;
|
|
818
|
+
}
|
|
819
|
+
case "down":
|
|
820
|
+
case "right": {
|
|
821
|
+
this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
|
|
822
|
+
const s = this.options[this.cursor]?.group === true;
|
|
823
|
+
!T(this, A) && s && (this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1);
|
|
824
|
+
break;
|
|
825
|
+
}
|
|
826
|
+
case "space":
|
|
827
|
+
this.toggleValue();
|
|
828
|
+
break;
|
|
829
|
+
}
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
getGroupItems(u2) {
|
|
833
|
+
return this.options.filter((t) => t.group === u2);
|
|
834
|
+
}
|
|
835
|
+
isGroupSelected(u2) {
|
|
836
|
+
return this.getGroupItems(u2).every((t) => this.value.includes(t.value));
|
|
837
|
+
}
|
|
838
|
+
toggleValue() {
|
|
839
|
+
const u2 = this.options[this.cursor];
|
|
840
|
+
if (u2.group === true) {
|
|
841
|
+
const t = u2.value, F2 = this.getGroupItems(t);
|
|
842
|
+
this.isGroupSelected(t) ? this.value = this.value.filter((s) => F2.findIndex((i) => i.value === s) === -1) : this.value = [...this.value, ...F2.map((s) => s.value)], this.value = Array.from(new Set(this.value));
|
|
843
|
+
} else {
|
|
844
|
+
const t = this.value.includes(u2.value);
|
|
845
|
+
this.value = t ? this.value.filter((F2) => F2 !== u2.value) : [...this.value, u2.value];
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
};
|
|
849
|
+
A = /* @__PURE__ */ new WeakMap();
|
|
850
|
+
var kD = Object.defineProperty;
|
|
851
|
+
var $D = (e2, u2, t) => u2 in e2 ? kD(e2, u2, { enumerable: true, configurable: true, writable: true, value: t }) : e2[u2] = t;
|
|
852
|
+
var H = (e2, u2, t) => ($D(e2, typeof u2 != "symbol" ? u2 + "" : u2, t), t);
|
|
853
|
+
var SD = class extends x {
|
|
854
|
+
constructor(u2) {
|
|
855
|
+
super(u2, false), H(this, "options"), H(this, "cursor", 0), this.options = u2.options, this.value = [...u2.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: t }) => t === u2.cursorAt), 0), this.on("key", (t) => {
|
|
856
|
+
t === "a" && this.toggleAll();
|
|
857
|
+
}), this.on("cursor", (t) => {
|
|
858
|
+
switch (t) {
|
|
859
|
+
case "left":
|
|
860
|
+
case "up":
|
|
861
|
+
this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
|
|
862
|
+
break;
|
|
863
|
+
case "down":
|
|
864
|
+
case "right":
|
|
865
|
+
this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
|
|
866
|
+
break;
|
|
867
|
+
case "space":
|
|
868
|
+
this.toggleValue();
|
|
869
|
+
break;
|
|
870
|
+
}
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
get _value() {
|
|
874
|
+
return this.options[this.cursor].value;
|
|
875
|
+
}
|
|
876
|
+
toggleAll() {
|
|
877
|
+
const u2 = this.value.length === this.options.length;
|
|
878
|
+
this.value = u2 ? [] : this.options.map((t) => t.value);
|
|
879
|
+
}
|
|
880
|
+
toggleValue() {
|
|
881
|
+
const u2 = this.value.includes(this._value);
|
|
882
|
+
this.value = u2 ? this.value.filter((t) => t !== this._value) : [...this.value, this._value];
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
var OD = Object.defineProperty;
|
|
886
|
+
var PD = (e2, u2, t) => u2 in e2 ? OD(e2, u2, { enumerable: true, configurable: true, writable: true, value: t }) : e2[u2] = t;
|
|
887
|
+
var J = (e2, u2, t) => (PD(e2, typeof u2 != "symbol" ? u2 + "" : u2, t), t);
|
|
888
|
+
var LD = class extends x {
|
|
889
|
+
constructor(u2) {
|
|
890
|
+
super(u2, false), J(this, "options"), J(this, "cursor", 0), this.options = u2.options, this.cursor = this.options.findIndex(({ value: t }) => t === u2.initialValue), this.cursor === -1 && (this.cursor = 0), this.changeValue(), this.on("cursor", (t) => {
|
|
891
|
+
switch (t) {
|
|
892
|
+
case "left":
|
|
893
|
+
case "up":
|
|
894
|
+
this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
|
|
895
|
+
break;
|
|
896
|
+
case "down":
|
|
897
|
+
case "right":
|
|
898
|
+
this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
|
|
899
|
+
break;
|
|
900
|
+
}
|
|
901
|
+
this.changeValue();
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
get _value() {
|
|
905
|
+
return this.options[this.cursor];
|
|
906
|
+
}
|
|
907
|
+
changeValue() {
|
|
908
|
+
this.value = this._value.value;
|
|
909
|
+
}
|
|
910
|
+
};
|
|
911
|
+
|
|
912
|
+
// ../../node_modules/.pnpm/@clack+prompts@0.11.0/node_modules/@clack/prompts/dist/index.mjs
|
|
913
|
+
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
914
|
+
var import_sisteransi2 = __toESM(require_src(), 1);
|
|
915
|
+
import y2 from "process";
|
|
916
|
+
function ce() {
|
|
917
|
+
return y2.platform !== "win32" ? y2.env.TERM !== "linux" : !!y2.env.CI || !!y2.env.WT_SESSION || !!y2.env.TERMINUS_SUBLIME || y2.env.ConEmuTask === "{cmd::Cmder}" || y2.env.TERM_PROGRAM === "Terminus-Sublime" || y2.env.TERM_PROGRAM === "vscode" || y2.env.TERM === "xterm-256color" || y2.env.TERM === "alacritty" || y2.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
918
|
+
}
|
|
919
|
+
var V2 = ce();
|
|
920
|
+
var u = (t, n) => V2 ? t : n;
|
|
921
|
+
var le = u("\u25C6", "*");
|
|
922
|
+
var L2 = u("\u25A0", "x");
|
|
923
|
+
var W2 = u("\u25B2", "x");
|
|
924
|
+
var C = u("\u25C7", "o");
|
|
925
|
+
var ue = u("\u250C", "T");
|
|
926
|
+
var o = u("\u2502", "|");
|
|
927
|
+
var d2 = u("\u2514", "\u2014");
|
|
928
|
+
var k2 = u("\u25CF", ">");
|
|
929
|
+
var P2 = u("\u25CB", " ");
|
|
930
|
+
var A2 = u("\u25FB", "[\u2022]");
|
|
931
|
+
var T2 = u("\u25FC", "[+]");
|
|
932
|
+
var F = u("\u25FB", "[ ]");
|
|
933
|
+
var $e = u("\u25AA", "\u2022");
|
|
934
|
+
var _2 = u("\u2500", "-");
|
|
935
|
+
var me = u("\u256E", "+");
|
|
936
|
+
var de = u("\u251C", "+");
|
|
937
|
+
var pe = u("\u256F", "+");
|
|
938
|
+
var q2 = u("\u25CF", "\u2022");
|
|
939
|
+
var D = u("\u25C6", "*");
|
|
940
|
+
var U = u("\u25B2", "!");
|
|
941
|
+
var K2 = u("\u25A0", "x");
|
|
942
|
+
var b2 = (t) => {
|
|
943
|
+
switch (t) {
|
|
944
|
+
case "initial":
|
|
945
|
+
case "active":
|
|
946
|
+
return import_picocolors.default.cyan(le);
|
|
947
|
+
case "cancel":
|
|
948
|
+
return import_picocolors.default.red(L2);
|
|
949
|
+
case "error":
|
|
950
|
+
return import_picocolors.default.yellow(W2);
|
|
951
|
+
case "submit":
|
|
952
|
+
return import_picocolors.default.green(C);
|
|
953
|
+
}
|
|
954
|
+
};
|
|
955
|
+
var G2 = (t) => {
|
|
956
|
+
const { cursor: n, options: r2, style: i } = t, s = t.maxItems ?? Number.POSITIVE_INFINITY, c = Math.max(process.stdout.rows - 4, 0), a = Math.min(c, Math.max(s, 5));
|
|
957
|
+
let l2 = 0;
|
|
958
|
+
n >= l2 + a - 3 ? l2 = Math.max(Math.min(n - a + 3, r2.length - a), 0) : n < l2 + 2 && (l2 = Math.max(n - 2, 0));
|
|
959
|
+
const $2 = a < r2.length && l2 > 0, g2 = a < r2.length && l2 + a < r2.length;
|
|
960
|
+
return r2.slice(l2, l2 + a).map((p2, v, f) => {
|
|
961
|
+
const j2 = v === 0 && $2, E = v === f.length - 1 && g2;
|
|
962
|
+
return j2 || E ? import_picocolors.default.dim("...") : i(p2, v + l2 === n);
|
|
963
|
+
});
|
|
964
|
+
};
|
|
965
|
+
var ye = (t) => {
|
|
966
|
+
const n = t.active ?? "Yes", r2 = t.inactive ?? "No";
|
|
967
|
+
return new dD({ active: n, inactive: r2, initialValue: t.initialValue ?? true, render() {
|
|
968
|
+
const i = `${import_picocolors.default.gray(o)}
|
|
969
|
+
${b2(this.state)} ${t.message}
|
|
970
|
+
`, s = this.value ? n : r2;
|
|
971
|
+
switch (this.state) {
|
|
972
|
+
case "submit":
|
|
973
|
+
return `${i}${import_picocolors.default.gray(o)} ${import_picocolors.default.dim(s)}`;
|
|
974
|
+
case "cancel":
|
|
975
|
+
return `${i}${import_picocolors.default.gray(o)} ${import_picocolors.default.strikethrough(import_picocolors.default.dim(s))}
|
|
976
|
+
${import_picocolors.default.gray(o)}`;
|
|
977
|
+
default:
|
|
978
|
+
return `${i}${import_picocolors.default.cyan(o)} ${this.value ? `${import_picocolors.default.green(k2)} ${n}` : `${import_picocolors.default.dim(P2)} ${import_picocolors.default.dim(n)}`} ${import_picocolors.default.dim("/")} ${this.value ? `${import_picocolors.default.dim(P2)} ${import_picocolors.default.dim(r2)}` : `${import_picocolors.default.green(k2)} ${r2}`}
|
|
979
|
+
${import_picocolors.default.cyan(d2)}
|
|
980
|
+
`;
|
|
981
|
+
}
|
|
982
|
+
} }).prompt();
|
|
983
|
+
};
|
|
984
|
+
var ve = (t) => {
|
|
985
|
+
const n = (r2, i) => {
|
|
986
|
+
const s = r2.label ?? String(r2.value);
|
|
987
|
+
switch (i) {
|
|
988
|
+
case "selected":
|
|
989
|
+
return `${import_picocolors.default.dim(s)}`;
|
|
990
|
+
case "active":
|
|
991
|
+
return `${import_picocolors.default.green(k2)} ${s} ${r2.hint ? import_picocolors.default.dim(`(${r2.hint})`) : ""}`;
|
|
992
|
+
case "cancelled":
|
|
993
|
+
return `${import_picocolors.default.strikethrough(import_picocolors.default.dim(s))}`;
|
|
994
|
+
default:
|
|
995
|
+
return `${import_picocolors.default.dim(P2)} ${import_picocolors.default.dim(s)}`;
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
return new LD({ options: t.options, initialValue: t.initialValue, render() {
|
|
999
|
+
const r2 = `${import_picocolors.default.gray(o)}
|
|
1000
|
+
${b2(this.state)} ${t.message}
|
|
1001
|
+
`;
|
|
1002
|
+
switch (this.state) {
|
|
1003
|
+
case "submit":
|
|
1004
|
+
return `${r2}${import_picocolors.default.gray(o)} ${n(this.options[this.cursor], "selected")}`;
|
|
1005
|
+
case "cancel":
|
|
1006
|
+
return `${r2}${import_picocolors.default.gray(o)} ${n(this.options[this.cursor], "cancelled")}
|
|
1007
|
+
${import_picocolors.default.gray(o)}`;
|
|
1008
|
+
default:
|
|
1009
|
+
return `${r2}${import_picocolors.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i, s) => n(i, s ? "active" : "inactive") }).join(`
|
|
1010
|
+
${import_picocolors.default.cyan(o)} `)}
|
|
1011
|
+
${import_picocolors.default.cyan(d2)}
|
|
1012
|
+
`;
|
|
1013
|
+
}
|
|
1014
|
+
} }).prompt();
|
|
1015
|
+
};
|
|
1016
|
+
var fe = (t) => {
|
|
1017
|
+
const n = (r2, i) => {
|
|
1018
|
+
const s = r2.label ?? String(r2.value);
|
|
1019
|
+
return i === "active" ? `${import_picocolors.default.cyan(A2)} ${s} ${r2.hint ? import_picocolors.default.dim(`(${r2.hint})`) : ""}` : i === "selected" ? `${import_picocolors.default.green(T2)} ${import_picocolors.default.dim(s)} ${r2.hint ? import_picocolors.default.dim(`(${r2.hint})`) : ""}` : i === "cancelled" ? `${import_picocolors.default.strikethrough(import_picocolors.default.dim(s))}` : i === "active-selected" ? `${import_picocolors.default.green(T2)} ${s} ${r2.hint ? import_picocolors.default.dim(`(${r2.hint})`) : ""}` : i === "submitted" ? `${import_picocolors.default.dim(s)}` : `${import_picocolors.default.dim(F)} ${import_picocolors.default.dim(s)}`;
|
|
1020
|
+
};
|
|
1021
|
+
return new SD({ options: t.options, initialValues: t.initialValues, required: t.required ?? true, cursorAt: t.cursorAt, validate(r2) {
|
|
1022
|
+
if (this.required && r2.length === 0) return `Please select at least one option.
|
|
1023
|
+
${import_picocolors.default.reset(import_picocolors.default.dim(`Press ${import_picocolors.default.gray(import_picocolors.default.bgWhite(import_picocolors.default.inverse(" space ")))} to select, ${import_picocolors.default.gray(import_picocolors.default.bgWhite(import_picocolors.default.inverse(" enter ")))} to submit`))}`;
|
|
1024
|
+
}, render() {
|
|
1025
|
+
const r2 = `${import_picocolors.default.gray(o)}
|
|
1026
|
+
${b2(this.state)} ${t.message}
|
|
1027
|
+
`, i = (s, c) => {
|
|
1028
|
+
const a = this.value.includes(s.value);
|
|
1029
|
+
return c && a ? n(s, "active-selected") : a ? n(s, "selected") : n(s, c ? "active" : "inactive");
|
|
1030
|
+
};
|
|
1031
|
+
switch (this.state) {
|
|
1032
|
+
case "submit":
|
|
1033
|
+
return `${r2}${import_picocolors.default.gray(o)} ${this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "submitted")).join(import_picocolors.default.dim(", ")) || import_picocolors.default.dim("none")}`;
|
|
1034
|
+
case "cancel": {
|
|
1035
|
+
const s = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => n(c, "cancelled")).join(import_picocolors.default.dim(", "));
|
|
1036
|
+
return `${r2}${import_picocolors.default.gray(o)} ${s.trim() ? `${s}
|
|
1037
|
+
${import_picocolors.default.gray(o)}` : ""}`;
|
|
1038
|
+
}
|
|
1039
|
+
case "error": {
|
|
1040
|
+
const s = this.error.split(`
|
|
1041
|
+
`).map((c, a) => a === 0 ? `${import_picocolors.default.yellow(d2)} ${import_picocolors.default.yellow(c)}` : ` ${c}`).join(`
|
|
1042
|
+
`);
|
|
1043
|
+
return `${r2 + import_picocolors.default.yellow(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
|
|
1044
|
+
${import_picocolors.default.yellow(o)} `)}
|
|
1045
|
+
${s}
|
|
1046
|
+
`;
|
|
1047
|
+
}
|
|
1048
|
+
default:
|
|
1049
|
+
return `${r2}${import_picocolors.default.cyan(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
|
|
1050
|
+
${import_picocolors.default.cyan(o)} `)}
|
|
1051
|
+
${import_picocolors.default.cyan(d2)}
|
|
1052
|
+
`;
|
|
1053
|
+
}
|
|
1054
|
+
} }).prompt();
|
|
1055
|
+
};
|
|
1056
|
+
var be = (t) => {
|
|
1057
|
+
const { selectableGroups: n = true } = t, r2 = (i, s, c = []) => {
|
|
1058
|
+
const a = i.label ?? String(i.value), l2 = typeof i.group == "string", $2 = l2 && (c[c.indexOf(i) + 1] ?? { group: true }), g2 = l2 && $2.group === true, p2 = l2 ? n ? `${g2 ? d2 : o} ` : " " : "";
|
|
1059
|
+
if (s === "active") return `${import_picocolors.default.dim(p2)}${import_picocolors.default.cyan(A2)} ${a} ${i.hint ? import_picocolors.default.dim(`(${i.hint})`) : ""}`;
|
|
1060
|
+
if (s === "group-active") return `${p2}${import_picocolors.default.cyan(A2)} ${import_picocolors.default.dim(a)}`;
|
|
1061
|
+
if (s === "group-active-selected") return `${p2}${import_picocolors.default.green(T2)} ${import_picocolors.default.dim(a)}`;
|
|
1062
|
+
if (s === "selected") {
|
|
1063
|
+
const f = l2 || n ? import_picocolors.default.green(T2) : "";
|
|
1064
|
+
return `${import_picocolors.default.dim(p2)}${f} ${import_picocolors.default.dim(a)} ${i.hint ? import_picocolors.default.dim(`(${i.hint})`) : ""}`;
|
|
1065
|
+
}
|
|
1066
|
+
if (s === "cancelled") return `${import_picocolors.default.strikethrough(import_picocolors.default.dim(a))}`;
|
|
1067
|
+
if (s === "active-selected") return `${import_picocolors.default.dim(p2)}${import_picocolors.default.green(T2)} ${a} ${i.hint ? import_picocolors.default.dim(`(${i.hint})`) : ""}`;
|
|
1068
|
+
if (s === "submitted") return `${import_picocolors.default.dim(a)}`;
|
|
1069
|
+
const v = l2 || n ? import_picocolors.default.dim(F) : "";
|
|
1070
|
+
return `${import_picocolors.default.dim(p2)}${v} ${import_picocolors.default.dim(a)}`;
|
|
1071
|
+
};
|
|
1072
|
+
return new _D({ options: t.options, initialValues: t.initialValues, required: t.required ?? true, cursorAt: t.cursorAt, selectableGroups: n, validate(i) {
|
|
1073
|
+
if (this.required && i.length === 0) return `Please select at least one option.
|
|
1074
|
+
${import_picocolors.default.reset(import_picocolors.default.dim(`Press ${import_picocolors.default.gray(import_picocolors.default.bgWhite(import_picocolors.default.inverse(" space ")))} to select, ${import_picocolors.default.gray(import_picocolors.default.bgWhite(import_picocolors.default.inverse(" enter ")))} to submit`))}`;
|
|
1075
|
+
}, render() {
|
|
1076
|
+
const i = `${import_picocolors.default.gray(o)}
|
|
1077
|
+
${b2(this.state)} ${t.message}
|
|
1078
|
+
`;
|
|
1079
|
+
switch (this.state) {
|
|
1080
|
+
case "submit":
|
|
1081
|
+
return `${i}${import_picocolors.default.gray(o)} ${this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => r2(s, "submitted")).join(import_picocolors.default.dim(", "))}`;
|
|
1082
|
+
case "cancel": {
|
|
1083
|
+
const s = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => r2(c, "cancelled")).join(import_picocolors.default.dim(", "));
|
|
1084
|
+
return `${i}${import_picocolors.default.gray(o)} ${s.trim() ? `${s}
|
|
1085
|
+
${import_picocolors.default.gray(o)}` : ""}`;
|
|
1086
|
+
}
|
|
1087
|
+
case "error": {
|
|
1088
|
+
const s = this.error.split(`
|
|
1089
|
+
`).map((c, a) => a === 0 ? `${import_picocolors.default.yellow(d2)} ${import_picocolors.default.yellow(c)}` : ` ${c}`).join(`
|
|
1090
|
+
`);
|
|
1091
|
+
return `${i}${import_picocolors.default.yellow(o)} ${this.options.map((c, a, l2) => {
|
|
1092
|
+
const $2 = this.value.includes(c.value) || c.group === true && this.isGroupSelected(`${c.value}`), g2 = a === this.cursor;
|
|
1093
|
+
return !g2 && typeof c.group == "string" && this.options[this.cursor].value === c.group ? r2(c, $2 ? "group-active-selected" : "group-active", l2) : g2 && $2 ? r2(c, "active-selected", l2) : $2 ? r2(c, "selected", l2) : r2(c, g2 ? "active" : "inactive", l2);
|
|
1094
|
+
}).join(`
|
|
1095
|
+
${import_picocolors.default.yellow(o)} `)}
|
|
1096
|
+
${s}
|
|
1097
|
+
`;
|
|
1098
|
+
}
|
|
1099
|
+
default:
|
|
1100
|
+
return `${i}${import_picocolors.default.cyan(o)} ${this.options.map((s, c, a) => {
|
|
1101
|
+
const l2 = this.value.includes(s.value) || s.group === true && this.isGroupSelected(`${s.value}`), $2 = c === this.cursor;
|
|
1102
|
+
return !$2 && typeof s.group == "string" && this.options[this.cursor].value === s.group ? r2(s, l2 ? "group-active-selected" : "group-active", a) : $2 && l2 ? r2(s, "active-selected", a) : l2 ? r2(s, "selected", a) : r2(s, $2 ? "active" : "inactive", a);
|
|
1103
|
+
}).join(`
|
|
1104
|
+
${import_picocolors.default.cyan(o)} `)}
|
|
1105
|
+
${import_picocolors.default.cyan(d2)}
|
|
1106
|
+
`;
|
|
1107
|
+
}
|
|
1108
|
+
} }).prompt();
|
|
1109
|
+
};
|
|
1110
|
+
var Me = (t = "", n = "") => {
|
|
1111
|
+
const r2 = `
|
|
1112
|
+
${t}
|
|
1113
|
+
`.split(`
|
|
1114
|
+
`), i = S2(n).length, s = Math.max(r2.reduce((a, l2) => {
|
|
1115
|
+
const $2 = S2(l2);
|
|
1116
|
+
return $2.length > a ? $2.length : a;
|
|
1117
|
+
}, 0), i) + 2, c = r2.map((a) => `${import_picocolors.default.gray(o)} ${import_picocolors.default.dim(a)}${" ".repeat(s - S2(a).length)}${import_picocolors.default.gray(o)}`).join(`
|
|
1118
|
+
`);
|
|
1119
|
+
process.stdout.write(`${import_picocolors.default.gray(o)}
|
|
1120
|
+
${import_picocolors.default.green(C)} ${import_picocolors.default.reset(n)} ${import_picocolors.default.gray(_2.repeat(Math.max(s - i - 1, 1)) + me)}
|
|
1121
|
+
${c}
|
|
1122
|
+
${import_picocolors.default.gray(de + _2.repeat(s + 2) + pe)}
|
|
1123
|
+
`);
|
|
1124
|
+
};
|
|
1125
|
+
var xe = (t = "") => {
|
|
1126
|
+
process.stdout.write(`${import_picocolors.default.gray(d2)} ${import_picocolors.default.red(t)}
|
|
1127
|
+
|
|
1128
|
+
`);
|
|
1129
|
+
};
|
|
1130
|
+
var Ie = (t = "") => {
|
|
1131
|
+
process.stdout.write(`${import_picocolors.default.gray(ue)} ${t}
|
|
1132
|
+
`);
|
|
1133
|
+
};
|
|
1134
|
+
var Se = (t = "") => {
|
|
1135
|
+
process.stdout.write(`${import_picocolors.default.gray(o)}
|
|
1136
|
+
${import_picocolors.default.gray(d2)} ${t}
|
|
1137
|
+
|
|
1138
|
+
`);
|
|
1139
|
+
};
|
|
1140
|
+
var M2 = { message: (t = "", { symbol: n = import_picocolors.default.gray(o) } = {}) => {
|
|
1141
|
+
const r2 = [`${import_picocolors.default.gray(o)}`];
|
|
1142
|
+
if (t) {
|
|
1143
|
+
const [i, ...s] = t.split(`
|
|
1144
|
+
`);
|
|
1145
|
+
r2.push(`${n} ${i}`, ...s.map((c) => `${import_picocolors.default.gray(o)} ${c}`));
|
|
1146
|
+
}
|
|
1147
|
+
process.stdout.write(`${r2.join(`
|
|
1148
|
+
`)}
|
|
1149
|
+
`);
|
|
1150
|
+
}, info: (t) => {
|
|
1151
|
+
M2.message(t, { symbol: import_picocolors.default.blue(q2) });
|
|
1152
|
+
}, success: (t) => {
|
|
1153
|
+
M2.message(t, { symbol: import_picocolors.default.green(D) });
|
|
1154
|
+
}, step: (t) => {
|
|
1155
|
+
M2.message(t, { symbol: import_picocolors.default.green(C) });
|
|
1156
|
+
}, warn: (t) => {
|
|
1157
|
+
M2.message(t, { symbol: import_picocolors.default.yellow(U) });
|
|
1158
|
+
}, warning: (t) => {
|
|
1159
|
+
M2.warn(t);
|
|
1160
|
+
}, error: (t) => {
|
|
1161
|
+
M2.message(t, { symbol: import_picocolors.default.red(K2) });
|
|
1162
|
+
} };
|
|
1163
|
+
var J2 = `${import_picocolors.default.gray(o)} `;
|
|
1164
|
+
var Y2 = ({ indicator: t = "dots" } = {}) => {
|
|
1165
|
+
const n = V2 ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"], r2 = V2 ? 80 : 120, i = process.env.CI === "true";
|
|
1166
|
+
let s, c, a = false, l2 = "", $2, g2 = performance.now();
|
|
1167
|
+
const p2 = (m2) => {
|
|
1168
|
+
const h2 = m2 > 1 ? "Something went wrong" : "Canceled";
|
|
1169
|
+
a && N2(h2, m2);
|
|
1170
|
+
}, v = () => p2(2), f = () => p2(1), j2 = () => {
|
|
1171
|
+
process.on("uncaughtExceptionMonitor", v), process.on("unhandledRejection", v), process.on("SIGINT", f), process.on("SIGTERM", f), process.on("exit", p2);
|
|
1172
|
+
}, E = () => {
|
|
1173
|
+
process.removeListener("uncaughtExceptionMonitor", v), process.removeListener("unhandledRejection", v), process.removeListener("SIGINT", f), process.removeListener("SIGTERM", f), process.removeListener("exit", p2);
|
|
1174
|
+
}, B2 = () => {
|
|
1175
|
+
if ($2 === void 0) return;
|
|
1176
|
+
i && process.stdout.write(`
|
|
1177
|
+
`);
|
|
1178
|
+
const m2 = $2.split(`
|
|
1179
|
+
`);
|
|
1180
|
+
process.stdout.write(import_sisteransi2.cursor.move(-999, m2.length - 1)), process.stdout.write(import_sisteransi2.erase.down(m2.length));
|
|
1181
|
+
}, R2 = (m2) => m2.replace(/\.+$/, ""), O2 = (m2) => {
|
|
1182
|
+
const h2 = (performance.now() - m2) / 1e3, w2 = Math.floor(h2 / 60), I2 = Math.floor(h2 % 60);
|
|
1183
|
+
return w2 > 0 ? `[${w2}m ${I2}s]` : `[${I2}s]`;
|
|
1184
|
+
}, H2 = (m2 = "") => {
|
|
1185
|
+
a = true, s = fD(), l2 = R2(m2), g2 = performance.now(), process.stdout.write(`${import_picocolors.default.gray(o)}
|
|
1186
|
+
`);
|
|
1187
|
+
let h2 = 0, w2 = 0;
|
|
1188
|
+
j2(), c = setInterval(() => {
|
|
1189
|
+
if (i && l2 === $2) return;
|
|
1190
|
+
B2(), $2 = l2;
|
|
1191
|
+
const I2 = import_picocolors.default.magenta(n[h2]);
|
|
1192
|
+
if (i) process.stdout.write(`${I2} ${l2}...`);
|
|
1193
|
+
else if (t === "timer") process.stdout.write(`${I2} ${l2} ${O2(g2)}`);
|
|
1194
|
+
else {
|
|
1195
|
+
const z2 = ".".repeat(Math.floor(w2)).slice(0, 3);
|
|
1196
|
+
process.stdout.write(`${I2} ${l2}${z2}`);
|
|
1197
|
+
}
|
|
1198
|
+
h2 = h2 + 1 < n.length ? h2 + 1 : 0, w2 = w2 < n.length ? w2 + 0.125 : 0;
|
|
1199
|
+
}, r2);
|
|
1200
|
+
}, N2 = (m2 = "", h2 = 0) => {
|
|
1201
|
+
a = false, clearInterval(c), B2();
|
|
1202
|
+
const w2 = h2 === 0 ? import_picocolors.default.green(C) : h2 === 1 ? import_picocolors.default.red(L2) : import_picocolors.default.red(W2);
|
|
1203
|
+
l2 = R2(m2 ?? l2), t === "timer" ? process.stdout.write(`${w2} ${l2} ${O2(g2)}
|
|
1204
|
+
`) : process.stdout.write(`${w2} ${l2}
|
|
1205
|
+
`), E(), s();
|
|
1206
|
+
};
|
|
1207
|
+
return { start: H2, stop: N2, message: (m2 = "") => {
|
|
1208
|
+
l2 = R2(m2 ?? l2);
|
|
1209
|
+
} };
|
|
1210
|
+
};
|
|
1211
|
+
|
|
1212
|
+
// src/add.ts
|
|
1213
|
+
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
1214
|
+
import { existsSync as existsSync2 } from "fs";
|
|
1215
|
+
import { homedir as homedir4 } from "os";
|
|
1216
|
+
import { sep as sep5 } from "path";
|
|
1217
|
+
|
|
1218
|
+
// src/source-parser.ts
|
|
1219
|
+
import { isAbsolute, resolve } from "path";
|
|
1220
|
+
function getOwnerRepo(parsed) {
|
|
1221
|
+
if (parsed.type === "local") {
|
|
1222
|
+
return null;
|
|
1223
|
+
}
|
|
1224
|
+
const sshMatch = parsed.url.match(/^git@[^:]+:(.+)$/);
|
|
1225
|
+
if (sshMatch) {
|
|
1226
|
+
let path2 = sshMatch[1];
|
|
1227
|
+
path2 = path2.replace(/\.git$/, "");
|
|
1228
|
+
if (path2.includes("/")) {
|
|
1229
|
+
return path2;
|
|
1230
|
+
}
|
|
1231
|
+
return null;
|
|
1232
|
+
}
|
|
1233
|
+
if (!parsed.url.startsWith("http://") && !parsed.url.startsWith("https://")) {
|
|
1234
|
+
return null;
|
|
1235
|
+
}
|
|
1236
|
+
try {
|
|
1237
|
+
const url = new URL(parsed.url);
|
|
1238
|
+
let path2 = url.pathname.slice(1);
|
|
1239
|
+
path2 = path2.replace(/\.git$/, "");
|
|
1240
|
+
if (path2.includes("/")) {
|
|
1241
|
+
return path2;
|
|
1242
|
+
}
|
|
1243
|
+
} catch {
|
|
1244
|
+
}
|
|
1245
|
+
return null;
|
|
1246
|
+
}
|
|
1247
|
+
function parseOwnerRepo(ownerRepo) {
|
|
1248
|
+
const match = ownerRepo.match(/^([^/]+)\/([^/]+)$/);
|
|
1249
|
+
if (match) {
|
|
1250
|
+
return { owner: match[1], repo: match[2] };
|
|
1251
|
+
}
|
|
1252
|
+
return null;
|
|
1253
|
+
}
|
|
1254
|
+
async function isRepoPrivate(owner, repo) {
|
|
1255
|
+
try {
|
|
1256
|
+
const res = await fetch(`https://api.github.com/repos/${owner}/${repo}`);
|
|
1257
|
+
if (!res.ok) {
|
|
1258
|
+
return null;
|
|
1259
|
+
}
|
|
1260
|
+
const data = await res.json();
|
|
1261
|
+
return data.private === true;
|
|
1262
|
+
} catch {
|
|
1263
|
+
return null;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
function sanitizeSubpath(subpath) {
|
|
1267
|
+
const normalized = subpath.replace(/\\/g, "/");
|
|
1268
|
+
const segments = normalized.split("/");
|
|
1269
|
+
for (const segment of segments) {
|
|
1270
|
+
if (segment === "..") {
|
|
1271
|
+
throw new Error(
|
|
1272
|
+
`Unsafe subpath: "${subpath}" contains path traversal segments. Subpaths must not contain ".." components.`
|
|
1273
|
+
);
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
return subpath;
|
|
1277
|
+
}
|
|
1278
|
+
function isLocalPath(input) {
|
|
1279
|
+
return isAbsolute(input) || input.startsWith("./") || input.startsWith("../") || input === "." || input === ".." || // Windows absolute paths like C:\ or D:\
|
|
1280
|
+
/^[a-zA-Z]:[/\\]/.test(input);
|
|
1281
|
+
}
|
|
1282
|
+
var SOURCE_ALIASES = {
|
|
1283
|
+
"coinbase/agentWallet": "coinbase/agentic-wallet-skills"
|
|
1284
|
+
};
|
|
1285
|
+
function parseSource(input) {
|
|
1286
|
+
const alias = SOURCE_ALIASES[input];
|
|
1287
|
+
if (alias) {
|
|
1288
|
+
input = alias;
|
|
1289
|
+
}
|
|
1290
|
+
const githubPrefixMatch = input.match(/^github:(.+)$/);
|
|
1291
|
+
if (githubPrefixMatch) {
|
|
1292
|
+
return parseSource(githubPrefixMatch[1]);
|
|
1293
|
+
}
|
|
1294
|
+
const gitlabPrefixMatch = input.match(/^gitlab:(.+)$/);
|
|
1295
|
+
if (gitlabPrefixMatch) {
|
|
1296
|
+
return parseSource(`https://gitlab.com/${gitlabPrefixMatch[1]}`);
|
|
1297
|
+
}
|
|
1298
|
+
if (isLocalPath(input)) {
|
|
1299
|
+
const resolvedPath = resolve(input);
|
|
1300
|
+
return {
|
|
1301
|
+
type: "local",
|
|
1302
|
+
url: resolvedPath,
|
|
1303
|
+
// Store resolved path in url for consistency
|
|
1304
|
+
localPath: resolvedPath
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
const githubTreeWithPathMatch = input.match(/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+)/);
|
|
1308
|
+
if (githubTreeWithPathMatch) {
|
|
1309
|
+
const [, owner, repo, ref, subpath] = githubTreeWithPathMatch;
|
|
1310
|
+
return {
|
|
1311
|
+
type: "github",
|
|
1312
|
+
url: `https://github.com/${owner}/${repo}.git`,
|
|
1313
|
+
ref,
|
|
1314
|
+
subpath: subpath ? sanitizeSubpath(subpath) : subpath
|
|
1315
|
+
};
|
|
1316
|
+
}
|
|
1317
|
+
const githubTreeMatch = input.match(/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)$/);
|
|
1318
|
+
if (githubTreeMatch) {
|
|
1319
|
+
const [, owner, repo, ref] = githubTreeMatch;
|
|
1320
|
+
return {
|
|
1321
|
+
type: "github",
|
|
1322
|
+
url: `https://github.com/${owner}/${repo}.git`,
|
|
1323
|
+
ref
|
|
1324
|
+
};
|
|
1325
|
+
}
|
|
1326
|
+
const githubRepoMatch = input.match(/github\.com\/([^/]+)\/([^/]+)/);
|
|
1327
|
+
if (githubRepoMatch) {
|
|
1328
|
+
const [, owner, repo] = githubRepoMatch;
|
|
1329
|
+
const cleanRepo = repo.replace(/\.git$/, "");
|
|
1330
|
+
return {
|
|
1331
|
+
type: "github",
|
|
1332
|
+
url: `https://github.com/${owner}/${cleanRepo}.git`
|
|
1333
|
+
};
|
|
1334
|
+
}
|
|
1335
|
+
const gitlabTreeWithPathMatch = input.match(
|
|
1336
|
+
/^(https?):\/\/([^/]+)\/(.+?)\/-\/tree\/([^/]+)\/(.+)/
|
|
1337
|
+
);
|
|
1338
|
+
if (gitlabTreeWithPathMatch) {
|
|
1339
|
+
const [, protocol, hostname, repoPath, ref, subpath] = gitlabTreeWithPathMatch;
|
|
1340
|
+
if (hostname !== "github.com" && repoPath) {
|
|
1341
|
+
return {
|
|
1342
|
+
type: "gitlab",
|
|
1343
|
+
url: `${protocol}://${hostname}/${repoPath.replace(/\.git$/, "")}.git`,
|
|
1344
|
+
ref,
|
|
1345
|
+
subpath: subpath ? sanitizeSubpath(subpath) : subpath
|
|
1346
|
+
};
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
const gitlabTreeMatch = input.match(/^(https?):\/\/([^/]+)\/(.+?)\/-\/tree\/([^/]+)$/);
|
|
1350
|
+
if (gitlabTreeMatch) {
|
|
1351
|
+
const [, protocol, hostname, repoPath, ref] = gitlabTreeMatch;
|
|
1352
|
+
if (hostname !== "github.com" && repoPath) {
|
|
1353
|
+
return {
|
|
1354
|
+
type: "gitlab",
|
|
1355
|
+
url: `${protocol}://${hostname}/${repoPath.replace(/\.git$/, "")}.git`,
|
|
1356
|
+
ref
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
const gitlabRepoMatch = input.match(/gitlab\.com\/(.+?)(?:\.git)?\/?$/);
|
|
1361
|
+
if (gitlabRepoMatch) {
|
|
1362
|
+
const repoPath = gitlabRepoMatch[1];
|
|
1363
|
+
if (repoPath.includes("/")) {
|
|
1364
|
+
return {
|
|
1365
|
+
type: "gitlab",
|
|
1366
|
+
url: `https://gitlab.com/${repoPath}.git`
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
const atSkillMatch = input.match(/^([^/]+)\/([^/@]+)@(.+)$/);
|
|
1371
|
+
if (atSkillMatch && !input.includes(":") && !input.startsWith(".") && !input.startsWith("/")) {
|
|
1372
|
+
const [, owner, repo, skillFilter] = atSkillMatch;
|
|
1373
|
+
return {
|
|
1374
|
+
type: "github",
|
|
1375
|
+
url: `https://github.com/${owner}/${repo}.git`,
|
|
1376
|
+
skillFilter
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1379
|
+
const shorthandMatch = input.match(/^([^/]+)\/([^/]+)(?:\/(.+))?$/);
|
|
1380
|
+
if (shorthandMatch && !input.includes(":") && !input.startsWith(".") && !input.startsWith("/")) {
|
|
1381
|
+
const [, owner, repo, subpath] = shorthandMatch;
|
|
1382
|
+
return {
|
|
1383
|
+
type: "github",
|
|
1384
|
+
url: `https://github.com/${owner}/${repo}.git`,
|
|
1385
|
+
subpath: subpath ? sanitizeSubpath(subpath) : subpath
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
if (isWellKnownUrl(input)) {
|
|
1389
|
+
return {
|
|
1390
|
+
type: "well-known",
|
|
1391
|
+
url: input
|
|
1392
|
+
};
|
|
1393
|
+
}
|
|
1394
|
+
return {
|
|
1395
|
+
type: "git",
|
|
1396
|
+
url: input
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
function isWellKnownUrl(input) {
|
|
1400
|
+
if (!input.startsWith("http://") && !input.startsWith("https://")) {
|
|
1401
|
+
return false;
|
|
1402
|
+
}
|
|
1403
|
+
try {
|
|
1404
|
+
const parsed = new URL(input);
|
|
1405
|
+
const excludedHosts = ["github.com", "gitlab.com", "raw.githubusercontent.com"];
|
|
1406
|
+
if (excludedHosts.includes(parsed.hostname)) {
|
|
1407
|
+
return false;
|
|
1408
|
+
}
|
|
1409
|
+
if (input.endsWith(".git")) {
|
|
1410
|
+
return false;
|
|
1411
|
+
}
|
|
1412
|
+
return true;
|
|
1413
|
+
} catch {
|
|
1414
|
+
return false;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
// src/prompts/search-multiselect.ts
|
|
1419
|
+
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
1420
|
+
import * as readline from "readline";
|
|
1421
|
+
import { Writable } from "stream";
|
|
1422
|
+
var silentOutput = new Writable({
|
|
1423
|
+
write(_chunk, _encoding, callback) {
|
|
1424
|
+
callback();
|
|
1425
|
+
}
|
|
1426
|
+
});
|
|
1427
|
+
var S_STEP_ACTIVE = import_picocolors2.default.green("\u25C6");
|
|
1428
|
+
var S_STEP_CANCEL = import_picocolors2.default.red("\u25A0");
|
|
1429
|
+
var S_STEP_SUBMIT = import_picocolors2.default.green("\u25C7");
|
|
1430
|
+
var S_RADIO_ACTIVE = import_picocolors2.default.green("\u25CF");
|
|
1431
|
+
var S_RADIO_INACTIVE = import_picocolors2.default.dim("\u25CB");
|
|
1432
|
+
var S_CHECKBOX_LOCKED = import_picocolors2.default.green("\u2713");
|
|
1433
|
+
var S_BULLET = import_picocolors2.default.green("\u2022");
|
|
1434
|
+
var S_BAR = import_picocolors2.default.dim("\u2502");
|
|
1435
|
+
var S_BAR_H = import_picocolors2.default.dim("\u2500");
|
|
1436
|
+
var cancelSymbol = /* @__PURE__ */ Symbol("cancel");
|
|
1437
|
+
async function searchMultiselect(options) {
|
|
1438
|
+
const {
|
|
1439
|
+
message,
|
|
1440
|
+
items,
|
|
1441
|
+
maxVisible = 8,
|
|
1442
|
+
initialSelected = [],
|
|
1443
|
+
required = false,
|
|
1444
|
+
lockedSection
|
|
1445
|
+
} = options;
|
|
1446
|
+
return new Promise((resolve6) => {
|
|
1447
|
+
const rl = readline.createInterface({
|
|
1448
|
+
input: process.stdin,
|
|
1449
|
+
output: silentOutput,
|
|
1450
|
+
terminal: false
|
|
1451
|
+
});
|
|
1452
|
+
if (process.stdin.isTTY) {
|
|
1453
|
+
process.stdin.setRawMode(true);
|
|
1454
|
+
}
|
|
1455
|
+
readline.emitKeypressEvents(process.stdin, rl);
|
|
1456
|
+
let query = "";
|
|
1457
|
+
let cursor = 0;
|
|
1458
|
+
const selected = new Set(initialSelected);
|
|
1459
|
+
let lastRenderHeight = 0;
|
|
1460
|
+
const lockedValues = lockedSection ? lockedSection.items.map((i) => i.value) : [];
|
|
1461
|
+
const filter = (item, q3) => {
|
|
1462
|
+
if (!q3) return true;
|
|
1463
|
+
const lowerQ = q3.toLowerCase();
|
|
1464
|
+
return item.label.toLowerCase().includes(lowerQ) || String(item.value).toLowerCase().includes(lowerQ);
|
|
1465
|
+
};
|
|
1466
|
+
const getFiltered = () => {
|
|
1467
|
+
return items.filter((item) => filter(item, query));
|
|
1468
|
+
};
|
|
1469
|
+
const clearRender = () => {
|
|
1470
|
+
if (lastRenderHeight > 0) {
|
|
1471
|
+
process.stdout.write(`\x1B[${lastRenderHeight}A`);
|
|
1472
|
+
for (let i = 0; i < lastRenderHeight; i++) {
|
|
1473
|
+
process.stdout.write("\x1B[2K\x1B[1B");
|
|
1474
|
+
}
|
|
1475
|
+
process.stdout.write(`\x1B[${lastRenderHeight}A`);
|
|
1476
|
+
}
|
|
1477
|
+
};
|
|
1478
|
+
const render = (state = "active") => {
|
|
1479
|
+
clearRender();
|
|
1480
|
+
const lines = [];
|
|
1481
|
+
const filtered = getFiltered();
|
|
1482
|
+
const icon = state === "active" ? S_STEP_ACTIVE : state === "cancel" ? S_STEP_CANCEL : S_STEP_SUBMIT;
|
|
1483
|
+
lines.push(`${icon} ${import_picocolors2.default.bold(message)}`);
|
|
1484
|
+
if (state === "active") {
|
|
1485
|
+
if (lockedSection && lockedSection.items.length > 0) {
|
|
1486
|
+
lines.push(`${S_BAR}`);
|
|
1487
|
+
const lockedTitle = `${import_picocolors2.default.bold(lockedSection.title)} ${import_picocolors2.default.dim("\u2500\u2500 always included")}`;
|
|
1488
|
+
lines.push(`${S_BAR} ${S_BAR_H}${S_BAR_H} ${lockedTitle} ${S_BAR_H.repeat(12)}`);
|
|
1489
|
+
for (const item of lockedSection.items) {
|
|
1490
|
+
lines.push(`${S_BAR} ${S_BULLET} ${import_picocolors2.default.bold(item.label)}`);
|
|
1491
|
+
}
|
|
1492
|
+
lines.push(`${S_BAR}`);
|
|
1493
|
+
lines.push(
|
|
1494
|
+
`${S_BAR} ${S_BAR_H}${S_BAR_H} ${import_picocolors2.default.bold("Additional agents")} ${S_BAR_H.repeat(29)}`
|
|
1495
|
+
);
|
|
1496
|
+
}
|
|
1497
|
+
const searchLine = `${S_BAR} ${import_picocolors2.default.dim("Search:")} ${query}${import_picocolors2.default.inverse(" ")}`;
|
|
1498
|
+
lines.push(searchLine);
|
|
1499
|
+
lines.push(`${S_BAR} ${import_picocolors2.default.dim("\u2191\u2193 move, space select, enter confirm")}`);
|
|
1500
|
+
lines.push(`${S_BAR}`);
|
|
1501
|
+
const visibleStart = Math.max(
|
|
1502
|
+
0,
|
|
1503
|
+
Math.min(cursor - Math.floor(maxVisible / 2), filtered.length - maxVisible)
|
|
1504
|
+
);
|
|
1505
|
+
const visibleEnd = Math.min(filtered.length, visibleStart + maxVisible);
|
|
1506
|
+
const visibleItems = filtered.slice(visibleStart, visibleEnd);
|
|
1507
|
+
if (filtered.length === 0) {
|
|
1508
|
+
lines.push(`${S_BAR} ${import_picocolors2.default.dim("No matches found")}`);
|
|
1509
|
+
} else {
|
|
1510
|
+
for (let i = 0; i < visibleItems.length; i++) {
|
|
1511
|
+
const item = visibleItems[i];
|
|
1512
|
+
const actualIndex = visibleStart + i;
|
|
1513
|
+
const isSelected = selected.has(item.value);
|
|
1514
|
+
const isCursor = actualIndex === cursor;
|
|
1515
|
+
const radio = isSelected ? S_RADIO_ACTIVE : S_RADIO_INACTIVE;
|
|
1516
|
+
const label = isCursor ? import_picocolors2.default.underline(item.label) : item.label;
|
|
1517
|
+
const hint = item.hint ? import_picocolors2.default.dim(` (${item.hint})`) : "";
|
|
1518
|
+
const prefix = isCursor ? import_picocolors2.default.cyan("\u276F") : " ";
|
|
1519
|
+
lines.push(`${S_BAR} ${prefix} ${radio} ${label}${hint}`);
|
|
1520
|
+
}
|
|
1521
|
+
const hiddenBefore = visibleStart;
|
|
1522
|
+
const hiddenAfter = filtered.length - visibleEnd;
|
|
1523
|
+
if (hiddenBefore > 0 || hiddenAfter > 0) {
|
|
1524
|
+
const parts = [];
|
|
1525
|
+
if (hiddenBefore > 0) parts.push(`\u2191 ${hiddenBefore} more`);
|
|
1526
|
+
if (hiddenAfter > 0) parts.push(`\u2193 ${hiddenAfter} more`);
|
|
1527
|
+
lines.push(`${S_BAR} ${import_picocolors2.default.dim(parts.join(" "))}`);
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
lines.push(`${S_BAR}`);
|
|
1531
|
+
const allSelectedLabels = [
|
|
1532
|
+
...lockedSection ? lockedSection.items.map((i) => i.label) : [],
|
|
1533
|
+
...items.filter((item) => selected.has(item.value)).map((item) => item.label)
|
|
1534
|
+
];
|
|
1535
|
+
if (allSelectedLabels.length === 0) {
|
|
1536
|
+
lines.push(`${S_BAR} ${import_picocolors2.default.dim("Selected: (none)")}`);
|
|
1537
|
+
} else {
|
|
1538
|
+
const summary = allSelectedLabels.length <= 3 ? allSelectedLabels.join(", ") : `${allSelectedLabels.slice(0, 3).join(", ")} +${allSelectedLabels.length - 3} more`;
|
|
1539
|
+
lines.push(`${S_BAR} ${import_picocolors2.default.green("Selected:")} ${summary}`);
|
|
1540
|
+
}
|
|
1541
|
+
lines.push(`${import_picocolors2.default.dim("\u2514")}`);
|
|
1542
|
+
} else if (state === "submit") {
|
|
1543
|
+
const allSelectedLabels = [
|
|
1544
|
+
...lockedSection ? lockedSection.items.map((i) => i.label) : [],
|
|
1545
|
+
...items.filter((item) => selected.has(item.value)).map((item) => item.label)
|
|
1546
|
+
];
|
|
1547
|
+
lines.push(`${S_BAR} ${import_picocolors2.default.dim(allSelectedLabels.join(", "))}`);
|
|
1548
|
+
} else if (state === "cancel") {
|
|
1549
|
+
lines.push(`${S_BAR} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim("Cancelled"))}`);
|
|
1550
|
+
}
|
|
1551
|
+
process.stdout.write(lines.join("\n") + "\n");
|
|
1552
|
+
lastRenderHeight = lines.length;
|
|
1553
|
+
};
|
|
1554
|
+
const cleanup2 = () => {
|
|
1555
|
+
process.stdin.removeListener("keypress", keypressHandler);
|
|
1556
|
+
if (process.stdin.isTTY) {
|
|
1557
|
+
process.stdin.setRawMode(false);
|
|
1558
|
+
}
|
|
1559
|
+
rl.close();
|
|
1560
|
+
};
|
|
1561
|
+
const submit = () => {
|
|
1562
|
+
if (required && selected.size === 0 && lockedValues.length === 0) {
|
|
1563
|
+
return;
|
|
1564
|
+
}
|
|
1565
|
+
render("submit");
|
|
1566
|
+
cleanup2();
|
|
1567
|
+
resolve6([...lockedValues, ...Array.from(selected)]);
|
|
1568
|
+
};
|
|
1569
|
+
const cancel = () => {
|
|
1570
|
+
render("cancel");
|
|
1571
|
+
cleanup2();
|
|
1572
|
+
resolve6(cancelSymbol);
|
|
1573
|
+
};
|
|
1574
|
+
const keypressHandler = (_str, key) => {
|
|
1575
|
+
if (!key) return;
|
|
1576
|
+
const filtered = getFiltered();
|
|
1577
|
+
if (key.name === "return") {
|
|
1578
|
+
submit();
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1581
|
+
if (key.name === "escape" || key.ctrl && key.name === "c") {
|
|
1582
|
+
cancel();
|
|
1583
|
+
return;
|
|
1584
|
+
}
|
|
1585
|
+
if (key.name === "up") {
|
|
1586
|
+
cursor = Math.max(0, cursor - 1);
|
|
1587
|
+
render();
|
|
1588
|
+
return;
|
|
1589
|
+
}
|
|
1590
|
+
if (key.name === "down") {
|
|
1591
|
+
cursor = Math.min(filtered.length - 1, cursor + 1);
|
|
1592
|
+
render();
|
|
1593
|
+
return;
|
|
1594
|
+
}
|
|
1595
|
+
if (key.name === "space") {
|
|
1596
|
+
const item = filtered[cursor];
|
|
1597
|
+
if (item) {
|
|
1598
|
+
if (selected.has(item.value)) {
|
|
1599
|
+
selected.delete(item.value);
|
|
1600
|
+
} else {
|
|
1601
|
+
selected.add(item.value);
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
render();
|
|
1605
|
+
return;
|
|
1606
|
+
}
|
|
1607
|
+
if (key.name === "backspace") {
|
|
1608
|
+
query = query.slice(0, -1);
|
|
1609
|
+
cursor = 0;
|
|
1610
|
+
render();
|
|
1611
|
+
return;
|
|
1612
|
+
}
|
|
1613
|
+
if (key.sequence && !key.ctrl && !key.meta && key.sequence.length === 1) {
|
|
1614
|
+
query += key.sequence;
|
|
1615
|
+
cursor = 0;
|
|
1616
|
+
render();
|
|
1617
|
+
return;
|
|
1618
|
+
}
|
|
1619
|
+
};
|
|
1620
|
+
process.stdin.on("keypress", keypressHandler);
|
|
1621
|
+
render();
|
|
1622
|
+
});
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
// src/git.ts
|
|
1626
|
+
import simpleGit from "simple-git";
|
|
1627
|
+
import { join as join3, normalize, resolve as resolve2, sep } from "path";
|
|
1628
|
+
import { mkdtemp, rm } from "fs/promises";
|
|
1629
|
+
import { tmpdir } from "os";
|
|
1630
|
+
var CLONE_TIMEOUT_MS = 6e4;
|
|
1631
|
+
var GitCloneError = class extends Error {
|
|
1632
|
+
url;
|
|
1633
|
+
isTimeout;
|
|
1634
|
+
isAuthError;
|
|
1635
|
+
constructor(message, url, isTimeout = false, isAuthError = false) {
|
|
1636
|
+
super(message);
|
|
1637
|
+
this.name = "GitCloneError";
|
|
1638
|
+
this.url = url;
|
|
1639
|
+
this.isTimeout = isTimeout;
|
|
1640
|
+
this.isAuthError = isAuthError;
|
|
1641
|
+
}
|
|
1642
|
+
};
|
|
1643
|
+
async function cloneRepo(url, ref) {
|
|
1644
|
+
const tempDir = await mkdtemp(join3(tmpdir(), "skills-"));
|
|
1645
|
+
const git = simpleGit({
|
|
1646
|
+
timeout: { block: CLONE_TIMEOUT_MS },
|
|
1647
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
|
|
1648
|
+
});
|
|
1649
|
+
const cloneOptions = ref ? ["--depth", "1", "--branch", ref] : ["--depth", "1"];
|
|
1650
|
+
try {
|
|
1651
|
+
await git.clone(url, tempDir, cloneOptions);
|
|
1652
|
+
return tempDir;
|
|
1653
|
+
} catch (error) {
|
|
1654
|
+
await rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
1655
|
+
});
|
|
1656
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1657
|
+
const isTimeout = errorMessage.includes("block timeout") || errorMessage.includes("timed out");
|
|
1658
|
+
const isAuthError = errorMessage.includes("Authentication failed") || errorMessage.includes("could not read Username") || errorMessage.includes("Permission denied") || errorMessage.includes("Repository not found");
|
|
1659
|
+
if (isTimeout) {
|
|
1660
|
+
throw new GitCloneError(
|
|
1661
|
+
`Clone timed out after 60s. This often happens with private repos that require authentication.
|
|
1662
|
+
Ensure you have access and your SSH keys or credentials are configured:
|
|
1663
|
+
- For SSH: ssh-add -l (to check loaded keys)
|
|
1664
|
+
- For HTTPS: gh auth status (if using GitHub CLI)`,
|
|
1665
|
+
url,
|
|
1666
|
+
true,
|
|
1667
|
+
false
|
|
1668
|
+
);
|
|
1669
|
+
}
|
|
1670
|
+
if (isAuthError) {
|
|
1671
|
+
throw new GitCloneError(
|
|
1672
|
+
`Authentication failed for ${url}.
|
|
1673
|
+
- For private repos, ensure you have access
|
|
1674
|
+
- For SSH: Check your keys with 'ssh -T git@github.com'
|
|
1675
|
+
- For HTTPS: Run 'gh auth login' or configure git credentials`,
|
|
1676
|
+
url,
|
|
1677
|
+
false,
|
|
1678
|
+
true
|
|
1679
|
+
);
|
|
1680
|
+
}
|
|
1681
|
+
throw new GitCloneError(`Failed to clone ${url}: ${errorMessage}`, url, false, false);
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
async function cleanupTempDir(dir) {
|
|
1685
|
+
const normalizedDir = normalize(resolve2(dir));
|
|
1686
|
+
const normalizedTmpDir = normalize(resolve2(tmpdir()));
|
|
1687
|
+
if (!normalizedDir.startsWith(normalizedTmpDir + sep) && normalizedDir !== normalizedTmpDir) {
|
|
1688
|
+
throw new Error("Attempted to clean up directory outside of temp directory");
|
|
1689
|
+
}
|
|
1690
|
+
await rm(dir, { recursive: true, force: true });
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
// src/skills.ts
|
|
1694
|
+
import { readdir as readdir2, readFile as readFile4, stat as stat2 } from "fs/promises";
|
|
1695
|
+
import { join as join5, basename, dirname as dirname3, resolve as resolve4, normalize as normalize3, sep as sep3 } from "path";
|
|
1696
|
+
import matter from "gray-matter";
|
|
1697
|
+
|
|
1698
|
+
// src/plugin-manifest.ts
|
|
1699
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
1700
|
+
import { join as join4, dirname as dirname2, resolve as resolve3, normalize as normalize2, sep as sep2 } from "path";
|
|
1701
|
+
function isContainedIn(targetPath, basePath) {
|
|
1702
|
+
const normalizedBase = normalize2(resolve3(basePath));
|
|
1703
|
+
const normalizedTarget = normalize2(resolve3(targetPath));
|
|
1704
|
+
return normalizedTarget.startsWith(normalizedBase + sep2) || normalizedTarget === normalizedBase;
|
|
1705
|
+
}
|
|
1706
|
+
function isValidRelativePath(path2) {
|
|
1707
|
+
return path2.startsWith("./");
|
|
1708
|
+
}
|
|
1709
|
+
async function getPluginSkillPaths(basePath) {
|
|
1710
|
+
const searchDirs = [];
|
|
1711
|
+
const addPluginSkillPaths = (pluginBase, skills) => {
|
|
1712
|
+
if (!isContainedIn(pluginBase, basePath)) return;
|
|
1713
|
+
if (skills && skills.length > 0) {
|
|
1714
|
+
for (const skillPath of skills) {
|
|
1715
|
+
if (!isValidRelativePath(skillPath)) continue;
|
|
1716
|
+
const skillDir = dirname2(join4(pluginBase, skillPath));
|
|
1717
|
+
if (isContainedIn(skillDir, basePath)) {
|
|
1718
|
+
searchDirs.push(skillDir);
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
searchDirs.push(join4(pluginBase, "skills"));
|
|
1723
|
+
};
|
|
1724
|
+
try {
|
|
1725
|
+
const content = await readFile3(join4(basePath, ".claude-plugin/marketplace.json"), "utf-8");
|
|
1726
|
+
const manifest = JSON.parse(content);
|
|
1727
|
+
const pluginRoot = manifest.metadata?.pluginRoot;
|
|
1728
|
+
const validPluginRoot = pluginRoot === void 0 || isValidRelativePath(pluginRoot);
|
|
1729
|
+
if (validPluginRoot) {
|
|
1730
|
+
for (const plugin of manifest.plugins ?? []) {
|
|
1731
|
+
if (typeof plugin.source !== "string" && plugin.source !== void 0) continue;
|
|
1732
|
+
if (plugin.source !== void 0 && !isValidRelativePath(plugin.source)) continue;
|
|
1733
|
+
const pluginBase = join4(basePath, pluginRoot ?? "", plugin.source ?? "");
|
|
1734
|
+
addPluginSkillPaths(pluginBase, plugin.skills);
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
} catch {
|
|
1738
|
+
}
|
|
1739
|
+
try {
|
|
1740
|
+
const content = await readFile3(join4(basePath, ".claude-plugin/plugin.json"), "utf-8");
|
|
1741
|
+
const manifest = JSON.parse(content);
|
|
1742
|
+
addPluginSkillPaths(basePath, manifest.skills);
|
|
1743
|
+
} catch {
|
|
1744
|
+
}
|
|
1745
|
+
return searchDirs;
|
|
1746
|
+
}
|
|
1747
|
+
async function getPluginGroupings(basePath) {
|
|
1748
|
+
const groupings = /* @__PURE__ */ new Map();
|
|
1749
|
+
try {
|
|
1750
|
+
const content = await readFile3(join4(basePath, ".claude-plugin/marketplace.json"), "utf-8");
|
|
1751
|
+
const manifest = JSON.parse(content);
|
|
1752
|
+
const pluginRoot = manifest.metadata?.pluginRoot;
|
|
1753
|
+
const validPluginRoot = pluginRoot === void 0 || isValidRelativePath(pluginRoot);
|
|
1754
|
+
if (validPluginRoot) {
|
|
1755
|
+
for (const plugin of manifest.plugins ?? []) {
|
|
1756
|
+
if (!plugin.name) continue;
|
|
1757
|
+
if (typeof plugin.source !== "string" && plugin.source !== void 0) continue;
|
|
1758
|
+
if (plugin.source !== void 0 && !isValidRelativePath(plugin.source)) continue;
|
|
1759
|
+
const pluginBase = join4(basePath, pluginRoot ?? "", plugin.source ?? "");
|
|
1760
|
+
if (!isContainedIn(pluginBase, basePath)) continue;
|
|
1761
|
+
if (plugin.skills && plugin.skills.length > 0) {
|
|
1762
|
+
for (const skillPath of plugin.skills) {
|
|
1763
|
+
if (!isValidRelativePath(skillPath)) continue;
|
|
1764
|
+
const skillDir = join4(pluginBase, skillPath);
|
|
1765
|
+
if (isContainedIn(skillDir, basePath)) {
|
|
1766
|
+
groupings.set(resolve3(skillDir), plugin.name);
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
} catch {
|
|
1773
|
+
}
|
|
1774
|
+
try {
|
|
1775
|
+
const content = await readFile3(join4(basePath, ".claude-plugin/plugin.json"), "utf-8");
|
|
1776
|
+
const manifest = JSON.parse(content);
|
|
1777
|
+
if (manifest.name && manifest.skills && manifest.skills.length > 0) {
|
|
1778
|
+
for (const skillPath of manifest.skills) {
|
|
1779
|
+
if (!isValidRelativePath(skillPath)) continue;
|
|
1780
|
+
const skillDir = join4(basePath, skillPath);
|
|
1781
|
+
if (isContainedIn(skillDir, basePath)) {
|
|
1782
|
+
groupings.set(resolve3(skillDir), manifest.name);
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
} catch {
|
|
1787
|
+
}
|
|
1788
|
+
return groupings;
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
// src/skills.ts
|
|
1792
|
+
var SKIP_DIRS = ["node_modules", ".git", "dist", "build", "__pycache__"];
|
|
1793
|
+
function shouldInstallInternalSkills() {
|
|
1794
|
+
const envValue = process.env.INSTALL_INTERNAL_SKILLS;
|
|
1795
|
+
return envValue === "1" || envValue === "true";
|
|
1796
|
+
}
|
|
1797
|
+
async function hasSkillMd(dir) {
|
|
1798
|
+
try {
|
|
1799
|
+
const skillPath = join5(dir, "SKILL.md");
|
|
1800
|
+
const stats = await stat2(skillPath);
|
|
1801
|
+
return stats.isFile();
|
|
1802
|
+
} catch {
|
|
1803
|
+
return false;
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
async function parseSkillMd(skillMdPath, options) {
|
|
1807
|
+
try {
|
|
1808
|
+
const content = await readFile4(skillMdPath, "utf-8");
|
|
1809
|
+
const { data } = matter(content);
|
|
1810
|
+
if (!data.name || !data.description) {
|
|
1811
|
+
return null;
|
|
1812
|
+
}
|
|
1813
|
+
if (typeof data.name !== "string" || typeof data.description !== "string") {
|
|
1814
|
+
return null;
|
|
1815
|
+
}
|
|
1816
|
+
const isInternal = data.metadata?.internal === true;
|
|
1817
|
+
if (isInternal && !shouldInstallInternalSkills() && !options?.includeInternal) {
|
|
1818
|
+
return null;
|
|
1819
|
+
}
|
|
1820
|
+
return {
|
|
1821
|
+
name: data.name,
|
|
1822
|
+
description: data.description,
|
|
1823
|
+
path: dirname3(skillMdPath),
|
|
1824
|
+
rawContent: content,
|
|
1825
|
+
metadata: data.metadata
|
|
1826
|
+
};
|
|
1827
|
+
} catch {
|
|
1828
|
+
return null;
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
async function findSkillDirs(dir, depth = 0, maxDepth = 5) {
|
|
1832
|
+
if (depth > maxDepth) return [];
|
|
1833
|
+
try {
|
|
1834
|
+
const [hasSkill, entries] = await Promise.all([
|
|
1835
|
+
hasSkillMd(dir),
|
|
1836
|
+
readdir2(dir, { withFileTypes: true }).catch(() => [])
|
|
1837
|
+
]);
|
|
1838
|
+
const currentDir = hasSkill ? [dir] : [];
|
|
1839
|
+
const subDirResults = await Promise.all(
|
|
1840
|
+
entries.filter((entry) => entry.isDirectory() && !SKIP_DIRS.includes(entry.name)).map((entry) => findSkillDirs(join5(dir, entry.name), depth + 1, maxDepth))
|
|
1841
|
+
);
|
|
1842
|
+
return [...currentDir, ...subDirResults.flat()];
|
|
1843
|
+
} catch {
|
|
1844
|
+
return [];
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
function isSubpathSafe(basePath, subpath) {
|
|
1848
|
+
const normalizedBase = normalize3(resolve4(basePath));
|
|
1849
|
+
const normalizedTarget = normalize3(resolve4(join5(basePath, subpath)));
|
|
1850
|
+
return normalizedTarget.startsWith(normalizedBase + sep3) || normalizedTarget === normalizedBase;
|
|
1851
|
+
}
|
|
1852
|
+
async function discoverSkills(basePath, subpath, options) {
|
|
1853
|
+
const skills = [];
|
|
1854
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
1855
|
+
if (subpath && !isSubpathSafe(basePath, subpath)) {
|
|
1856
|
+
throw new Error(
|
|
1857
|
+
`Invalid subpath: "${subpath}" resolves outside the repository directory. Subpath must not contain ".." segments that escape the base path.`
|
|
1858
|
+
);
|
|
1859
|
+
}
|
|
1860
|
+
const searchPath = subpath ? join5(basePath, subpath) : basePath;
|
|
1861
|
+
const pluginGroupings = await getPluginGroupings(searchPath);
|
|
1862
|
+
const enhanceSkill = (skill) => {
|
|
1863
|
+
const resolvedPath = resolve4(skill.path);
|
|
1864
|
+
if (pluginGroupings.has(resolvedPath)) {
|
|
1865
|
+
skill.pluginName = pluginGroupings.get(resolvedPath);
|
|
1866
|
+
}
|
|
1867
|
+
return skill;
|
|
1868
|
+
};
|
|
1869
|
+
if (await hasSkillMd(searchPath)) {
|
|
1870
|
+
let skill = await parseSkillMd(join5(searchPath, "SKILL.md"), options);
|
|
1871
|
+
if (skill) {
|
|
1872
|
+
skill = enhanceSkill(skill);
|
|
1873
|
+
skills.push(skill);
|
|
1874
|
+
seenNames.add(skill.name);
|
|
1875
|
+
if (!options?.fullDepth) {
|
|
1876
|
+
return skills;
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
const prioritySearchDirs = [
|
|
1881
|
+
searchPath,
|
|
1882
|
+
join5(searchPath, "skills"),
|
|
1883
|
+
join5(searchPath, "skills/.curated"),
|
|
1884
|
+
join5(searchPath, "skills/.experimental"),
|
|
1885
|
+
join5(searchPath, "skills/.system"),
|
|
1886
|
+
join5(searchPath, ".agent/skills"),
|
|
1887
|
+
join5(searchPath, ".agents/skills"),
|
|
1888
|
+
join5(searchPath, ".claude/skills"),
|
|
1889
|
+
join5(searchPath, ".cline/skills"),
|
|
1890
|
+
join5(searchPath, ".codebuddy/skills"),
|
|
1891
|
+
join5(searchPath, ".codex/skills"),
|
|
1892
|
+
join5(searchPath, ".commandcode/skills"),
|
|
1893
|
+
join5(searchPath, ".continue/skills"),
|
|
1894
|
+
join5(searchPath, ".github/skills"),
|
|
1895
|
+
join5(searchPath, ".goose/skills"),
|
|
1896
|
+
join5(searchPath, ".iflow/skills"),
|
|
1897
|
+
join5(searchPath, ".junie/skills"),
|
|
1898
|
+
join5(searchPath, ".kilocode/skills"),
|
|
1899
|
+
join5(searchPath, ".kiro/skills"),
|
|
1900
|
+
join5(searchPath, ".mux/skills"),
|
|
1901
|
+
join5(searchPath, ".neovate/skills"),
|
|
1902
|
+
join5(searchPath, ".opencode/skills"),
|
|
1903
|
+
join5(searchPath, ".openhands/skills"),
|
|
1904
|
+
join5(searchPath, ".pi/skills"),
|
|
1905
|
+
join5(searchPath, ".qoder/skills"),
|
|
1906
|
+
join5(searchPath, ".roo/skills"),
|
|
1907
|
+
join5(searchPath, ".trae/skills"),
|
|
1908
|
+
join5(searchPath, ".windsurf/skills"),
|
|
1909
|
+
join5(searchPath, ".zencoder/skills")
|
|
1910
|
+
];
|
|
1911
|
+
prioritySearchDirs.push(...await getPluginSkillPaths(searchPath));
|
|
1912
|
+
for (const dir of prioritySearchDirs) {
|
|
1913
|
+
try {
|
|
1914
|
+
const entries = await readdir2(dir, { withFileTypes: true });
|
|
1915
|
+
for (const entry of entries) {
|
|
1916
|
+
if (entry.isDirectory()) {
|
|
1917
|
+
const skillDir = join5(dir, entry.name);
|
|
1918
|
+
if (await hasSkillMd(skillDir)) {
|
|
1919
|
+
let skill = await parseSkillMd(join5(skillDir, "SKILL.md"), options);
|
|
1920
|
+
if (skill && !seenNames.has(skill.name)) {
|
|
1921
|
+
skill = enhanceSkill(skill);
|
|
1922
|
+
skills.push(skill);
|
|
1923
|
+
seenNames.add(skill.name);
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1928
|
+
} catch {
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
if (skills.length === 0 || options?.fullDepth) {
|
|
1932
|
+
const allSkillDirs = await findSkillDirs(searchPath);
|
|
1933
|
+
for (const skillDir of allSkillDirs) {
|
|
1934
|
+
let skill = await parseSkillMd(join5(skillDir, "SKILL.md"), options);
|
|
1935
|
+
if (skill && !seenNames.has(skill.name)) {
|
|
1936
|
+
skill = enhanceSkill(skill);
|
|
1937
|
+
skills.push(skill);
|
|
1938
|
+
seenNames.add(skill.name);
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
return skills;
|
|
1943
|
+
}
|
|
1944
|
+
function getSkillDisplayName(skill) {
|
|
1945
|
+
return skill.name || basename(skill.path);
|
|
1946
|
+
}
|
|
1947
|
+
function filterSkills(skills, inputNames) {
|
|
1948
|
+
const normalizedInputs = inputNames.map((n) => n.toLowerCase());
|
|
1949
|
+
return skills.filter((skill) => {
|
|
1950
|
+
const name = skill.name.toLowerCase();
|
|
1951
|
+
const displayName = getSkillDisplayName(skill).toLowerCase();
|
|
1952
|
+
return normalizedInputs.some((input) => input === name || input === displayName);
|
|
1953
|
+
});
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
// src/installer.ts
|
|
1957
|
+
import {
|
|
1958
|
+
mkdir as mkdir2,
|
|
1959
|
+
cp,
|
|
1960
|
+
access,
|
|
1961
|
+
readdir as readdir3,
|
|
1962
|
+
symlink,
|
|
1963
|
+
lstat,
|
|
1964
|
+
rm as rm2,
|
|
1965
|
+
readlink,
|
|
1966
|
+
writeFile as writeFile3,
|
|
1967
|
+
stat as stat3,
|
|
1968
|
+
realpath
|
|
1969
|
+
} from "fs/promises";
|
|
1970
|
+
import { join as join7, basename as basename2, normalize as normalize4, resolve as resolve5, sep as sep4, relative as relative2, dirname as dirname4 } from "path";
|
|
1971
|
+
import { homedir as homedir3, platform } from "os";
|
|
1972
|
+
|
|
1973
|
+
// src/agents.ts
|
|
1974
|
+
import { homedir as homedir2 } from "os";
|
|
1975
|
+
import { join as join6 } from "path";
|
|
1976
|
+
import { existsSync } from "fs";
|
|
1977
|
+
|
|
1978
|
+
// ../../node_modules/.pnpm/xdg-basedir@5.1.0/node_modules/xdg-basedir/index.js
|
|
1979
|
+
import os from "os";
|
|
1980
|
+
import path from "path";
|
|
1981
|
+
var homeDirectory = os.homedir();
|
|
1982
|
+
var { env } = process;
|
|
1983
|
+
var xdgData = env.XDG_DATA_HOME || (homeDirectory ? path.join(homeDirectory, ".local", "share") : void 0);
|
|
1984
|
+
var xdgConfig = env.XDG_CONFIG_HOME || (homeDirectory ? path.join(homeDirectory, ".config") : void 0);
|
|
1985
|
+
var xdgState = env.XDG_STATE_HOME || (homeDirectory ? path.join(homeDirectory, ".local", "state") : void 0);
|
|
1986
|
+
var xdgCache = env.XDG_CACHE_HOME || (homeDirectory ? path.join(homeDirectory, ".cache") : void 0);
|
|
1987
|
+
var xdgRuntime = env.XDG_RUNTIME_DIR || void 0;
|
|
1988
|
+
var xdgDataDirectories = (env.XDG_DATA_DIRS || "/usr/local/share/:/usr/share/").split(":");
|
|
1989
|
+
if (xdgData) {
|
|
1990
|
+
xdgDataDirectories.unshift(xdgData);
|
|
1991
|
+
}
|
|
1992
|
+
var xdgConfigDirectories = (env.XDG_CONFIG_DIRS || "/etc/xdg").split(":");
|
|
1993
|
+
if (xdgConfig) {
|
|
1994
|
+
xdgConfigDirectories.unshift(xdgConfig);
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
// src/agents.ts
|
|
1998
|
+
var home = homedir2();
|
|
1999
|
+
var configHome = xdgConfig ?? join6(home, ".config");
|
|
2000
|
+
var codexHome = process.env.CODEX_HOME?.trim() || join6(home, ".codex");
|
|
2001
|
+
var claudeHome = process.env.CLAUDE_CONFIG_DIR?.trim() || join6(home, ".claude");
|
|
2002
|
+
function getOpenClawGlobalSkillsDir(homeDir = home, pathExists = existsSync) {
|
|
2003
|
+
if (pathExists(join6(homeDir, ".openclaw"))) {
|
|
2004
|
+
return join6(homeDir, ".openclaw/skills");
|
|
2005
|
+
}
|
|
2006
|
+
if (pathExists(join6(homeDir, ".clawdbot"))) {
|
|
2007
|
+
return join6(homeDir, ".clawdbot/skills");
|
|
2008
|
+
}
|
|
2009
|
+
if (pathExists(join6(homeDir, ".moltbot"))) {
|
|
2010
|
+
return join6(homeDir, ".moltbot/skills");
|
|
2011
|
+
}
|
|
2012
|
+
return join6(homeDir, ".openclaw/skills");
|
|
2013
|
+
}
|
|
2014
|
+
var agents = {
|
|
2015
|
+
amp: {
|
|
2016
|
+
name: "amp",
|
|
2017
|
+
displayName: "Amp",
|
|
2018
|
+
skillsDir: ".agents/skills",
|
|
2019
|
+
globalSkillsDir: join6(configHome, "agents/skills"),
|
|
2020
|
+
detectInstalled: async () => {
|
|
2021
|
+
return existsSync(join6(configHome, "amp"));
|
|
2022
|
+
}
|
|
2023
|
+
},
|
|
2024
|
+
antigravity: {
|
|
2025
|
+
name: "antigravity",
|
|
2026
|
+
displayName: "Antigravity",
|
|
2027
|
+
skillsDir: ".agent/skills",
|
|
2028
|
+
globalSkillsDir: join6(home, ".gemini/antigravity/skills"),
|
|
2029
|
+
detectInstalled: async () => {
|
|
2030
|
+
return existsSync(join6(home, ".gemini/antigravity"));
|
|
2031
|
+
}
|
|
2032
|
+
},
|
|
2033
|
+
augment: {
|
|
2034
|
+
name: "augment",
|
|
2035
|
+
displayName: "Augment",
|
|
2036
|
+
skillsDir: ".augment/skills",
|
|
2037
|
+
globalSkillsDir: join6(home, ".augment/skills"),
|
|
2038
|
+
detectInstalled: async () => {
|
|
2039
|
+
return existsSync(join6(home, ".augment"));
|
|
2040
|
+
}
|
|
2041
|
+
},
|
|
2042
|
+
"claude-code": {
|
|
2043
|
+
name: "claude-code",
|
|
2044
|
+
displayName: "Claude Code",
|
|
2045
|
+
skillsDir: ".claude/skills",
|
|
2046
|
+
globalSkillsDir: join6(claudeHome, "skills"),
|
|
2047
|
+
detectInstalled: async () => {
|
|
2048
|
+
return existsSync(claudeHome);
|
|
2049
|
+
}
|
|
2050
|
+
},
|
|
2051
|
+
openclaw: {
|
|
2052
|
+
name: "openclaw",
|
|
2053
|
+
displayName: "OpenClaw",
|
|
2054
|
+
skillsDir: "skills",
|
|
2055
|
+
globalSkillsDir: getOpenClawGlobalSkillsDir(),
|
|
2056
|
+
detectInstalled: async () => {
|
|
2057
|
+
return existsSync(join6(home, ".openclaw")) || existsSync(join6(home, ".clawdbot")) || existsSync(join6(home, ".moltbot"));
|
|
2058
|
+
}
|
|
2059
|
+
},
|
|
2060
|
+
cline: {
|
|
2061
|
+
name: "cline",
|
|
2062
|
+
displayName: "Cline",
|
|
2063
|
+
skillsDir: ".agents/skills",
|
|
2064
|
+
globalSkillsDir: join6(home, ".agents", "skills"),
|
|
2065
|
+
detectInstalled: async () => {
|
|
2066
|
+
return existsSync(join6(home, ".cline"));
|
|
2067
|
+
}
|
|
2068
|
+
},
|
|
2069
|
+
codebuddy: {
|
|
2070
|
+
name: "codebuddy",
|
|
2071
|
+
displayName: "CodeBuddy",
|
|
2072
|
+
skillsDir: ".codebuddy/skills",
|
|
2073
|
+
globalSkillsDir: join6(home, ".codebuddy/skills"),
|
|
2074
|
+
detectInstalled: async () => {
|
|
2075
|
+
return existsSync(join6(process.cwd(), ".codebuddy")) || existsSync(join6(home, ".codebuddy"));
|
|
2076
|
+
}
|
|
2077
|
+
},
|
|
2078
|
+
codex: {
|
|
2079
|
+
name: "codex",
|
|
2080
|
+
displayName: "Codex",
|
|
2081
|
+
skillsDir: ".agents/skills",
|
|
2082
|
+
globalSkillsDir: join6(codexHome, "skills"),
|
|
2083
|
+
detectInstalled: async () => {
|
|
2084
|
+
return existsSync(codexHome) || existsSync("/etc/codex");
|
|
2085
|
+
}
|
|
2086
|
+
},
|
|
2087
|
+
"command-code": {
|
|
2088
|
+
name: "command-code",
|
|
2089
|
+
displayName: "Command Code",
|
|
2090
|
+
skillsDir: ".commandcode/skills",
|
|
2091
|
+
globalSkillsDir: join6(home, ".commandcode/skills"),
|
|
2092
|
+
detectInstalled: async () => {
|
|
2093
|
+
return existsSync(join6(home, ".commandcode"));
|
|
2094
|
+
}
|
|
2095
|
+
},
|
|
2096
|
+
continue: {
|
|
2097
|
+
name: "continue",
|
|
2098
|
+
displayName: "Continue",
|
|
2099
|
+
skillsDir: ".continue/skills",
|
|
2100
|
+
globalSkillsDir: join6(home, ".continue/skills"),
|
|
2101
|
+
detectInstalled: async () => {
|
|
2102
|
+
return existsSync(join6(process.cwd(), ".continue")) || existsSync(join6(home, ".continue"));
|
|
2103
|
+
}
|
|
2104
|
+
},
|
|
2105
|
+
cortex: {
|
|
2106
|
+
name: "cortex",
|
|
2107
|
+
displayName: "Cortex Code",
|
|
2108
|
+
skillsDir: ".cortex/skills",
|
|
2109
|
+
globalSkillsDir: join6(home, ".snowflake/cortex/skills"),
|
|
2110
|
+
detectInstalled: async () => {
|
|
2111
|
+
return existsSync(join6(home, ".snowflake/cortex"));
|
|
2112
|
+
}
|
|
2113
|
+
},
|
|
2114
|
+
crush: {
|
|
2115
|
+
name: "crush",
|
|
2116
|
+
displayName: "Crush",
|
|
2117
|
+
skillsDir: ".crush/skills",
|
|
2118
|
+
globalSkillsDir: join6(home, ".config/crush/skills"),
|
|
2119
|
+
detectInstalled: async () => {
|
|
2120
|
+
return existsSync(join6(home, ".config/crush"));
|
|
2121
|
+
}
|
|
2122
|
+
},
|
|
2123
|
+
cursor: {
|
|
2124
|
+
name: "cursor",
|
|
2125
|
+
displayName: "Cursor",
|
|
2126
|
+
skillsDir: ".agents/skills",
|
|
2127
|
+
globalSkillsDir: join6(home, ".cursor/skills"),
|
|
2128
|
+
detectInstalled: async () => {
|
|
2129
|
+
return existsSync(join6(home, ".cursor"));
|
|
2130
|
+
}
|
|
2131
|
+
},
|
|
2132
|
+
droid: {
|
|
2133
|
+
name: "droid",
|
|
2134
|
+
displayName: "Droid",
|
|
2135
|
+
skillsDir: ".factory/skills",
|
|
2136
|
+
globalSkillsDir: join6(home, ".factory/skills"),
|
|
2137
|
+
detectInstalled: async () => {
|
|
2138
|
+
return existsSync(join6(home, ".factory"));
|
|
2139
|
+
}
|
|
2140
|
+
},
|
|
2141
|
+
"gemini-cli": {
|
|
2142
|
+
name: "gemini-cli",
|
|
2143
|
+
displayName: "Gemini CLI",
|
|
2144
|
+
skillsDir: ".agents/skills",
|
|
2145
|
+
globalSkillsDir: join6(home, ".gemini/skills"),
|
|
2146
|
+
detectInstalled: async () => {
|
|
2147
|
+
return existsSync(join6(home, ".gemini"));
|
|
2148
|
+
}
|
|
2149
|
+
},
|
|
2150
|
+
"github-copilot": {
|
|
2151
|
+
name: "github-copilot",
|
|
2152
|
+
displayName: "GitHub Copilot",
|
|
2153
|
+
skillsDir: ".agents/skills",
|
|
2154
|
+
globalSkillsDir: join6(home, ".copilot/skills"),
|
|
2155
|
+
detectInstalled: async () => {
|
|
2156
|
+
return existsSync(join6(home, ".copilot"));
|
|
2157
|
+
}
|
|
2158
|
+
},
|
|
2159
|
+
goose: {
|
|
2160
|
+
name: "goose",
|
|
2161
|
+
displayName: "Goose",
|
|
2162
|
+
skillsDir: ".goose/skills",
|
|
2163
|
+
globalSkillsDir: join6(configHome, "goose/skills"),
|
|
2164
|
+
detectInstalled: async () => {
|
|
2165
|
+
return existsSync(join6(configHome, "goose"));
|
|
2166
|
+
}
|
|
2167
|
+
},
|
|
2168
|
+
junie: {
|
|
2169
|
+
name: "junie",
|
|
2170
|
+
displayName: "Junie",
|
|
2171
|
+
skillsDir: ".junie/skills",
|
|
2172
|
+
globalSkillsDir: join6(home, ".junie/skills"),
|
|
2173
|
+
detectInstalled: async () => {
|
|
2174
|
+
return existsSync(join6(home, ".junie"));
|
|
2175
|
+
}
|
|
2176
|
+
},
|
|
2177
|
+
"iflow-cli": {
|
|
2178
|
+
name: "iflow-cli",
|
|
2179
|
+
displayName: "iFlow CLI",
|
|
2180
|
+
skillsDir: ".iflow/skills",
|
|
2181
|
+
globalSkillsDir: join6(home, ".iflow/skills"),
|
|
2182
|
+
detectInstalled: async () => {
|
|
2183
|
+
return existsSync(join6(home, ".iflow"));
|
|
2184
|
+
}
|
|
2185
|
+
},
|
|
2186
|
+
kilo: {
|
|
2187
|
+
name: "kilo",
|
|
2188
|
+
displayName: "Kilo Code",
|
|
2189
|
+
skillsDir: ".kilocode/skills",
|
|
2190
|
+
globalSkillsDir: join6(home, ".kilocode/skills"),
|
|
2191
|
+
detectInstalled: async () => {
|
|
2192
|
+
return existsSync(join6(home, ".kilocode"));
|
|
2193
|
+
}
|
|
2194
|
+
},
|
|
2195
|
+
"kimi-cli": {
|
|
2196
|
+
name: "kimi-cli",
|
|
2197
|
+
displayName: "Kimi Code CLI",
|
|
2198
|
+
skillsDir: ".agents/skills",
|
|
2199
|
+
globalSkillsDir: join6(home, ".config/agents/skills"),
|
|
2200
|
+
detectInstalled: async () => {
|
|
2201
|
+
return existsSync(join6(home, ".kimi"));
|
|
2202
|
+
}
|
|
2203
|
+
},
|
|
2204
|
+
"kiro-cli": {
|
|
2205
|
+
name: "kiro-cli",
|
|
2206
|
+
displayName: "Kiro CLI",
|
|
2207
|
+
skillsDir: ".kiro/skills",
|
|
2208
|
+
globalSkillsDir: join6(home, ".kiro/skills"),
|
|
2209
|
+
detectInstalled: async () => {
|
|
2210
|
+
return existsSync(join6(home, ".kiro"));
|
|
2211
|
+
}
|
|
2212
|
+
},
|
|
2213
|
+
kode: {
|
|
2214
|
+
name: "kode",
|
|
2215
|
+
displayName: "Kode",
|
|
2216
|
+
skillsDir: ".kode/skills",
|
|
2217
|
+
globalSkillsDir: join6(home, ".kode/skills"),
|
|
2218
|
+
detectInstalled: async () => {
|
|
2219
|
+
return existsSync(join6(home, ".kode"));
|
|
2220
|
+
}
|
|
2221
|
+
},
|
|
2222
|
+
mcpjam: {
|
|
2223
|
+
name: "mcpjam",
|
|
2224
|
+
displayName: "MCPJam",
|
|
2225
|
+
skillsDir: ".mcpjam/skills",
|
|
2226
|
+
globalSkillsDir: join6(home, ".mcpjam/skills"),
|
|
2227
|
+
detectInstalled: async () => {
|
|
2228
|
+
return existsSync(join6(home, ".mcpjam"));
|
|
2229
|
+
}
|
|
2230
|
+
},
|
|
2231
|
+
"mistral-vibe": {
|
|
2232
|
+
name: "mistral-vibe",
|
|
2233
|
+
displayName: "Mistral Vibe",
|
|
2234
|
+
skillsDir: ".vibe/skills",
|
|
2235
|
+
globalSkillsDir: join6(home, ".vibe/skills"),
|
|
2236
|
+
detectInstalled: async () => {
|
|
2237
|
+
return existsSync(join6(home, ".vibe"));
|
|
2238
|
+
}
|
|
2239
|
+
},
|
|
2240
|
+
mux: {
|
|
2241
|
+
name: "mux",
|
|
2242
|
+
displayName: "Mux",
|
|
2243
|
+
skillsDir: ".mux/skills",
|
|
2244
|
+
globalSkillsDir: join6(home, ".mux/skills"),
|
|
2245
|
+
detectInstalled: async () => {
|
|
2246
|
+
return existsSync(join6(home, ".mux"));
|
|
2247
|
+
}
|
|
2248
|
+
},
|
|
2249
|
+
opencode: {
|
|
2250
|
+
name: "opencode",
|
|
2251
|
+
displayName: "OpenCode",
|
|
2252
|
+
skillsDir: ".agents/skills",
|
|
2253
|
+
globalSkillsDir: join6(configHome, "opencode/skills"),
|
|
2254
|
+
detectInstalled: async () => {
|
|
2255
|
+
return existsSync(join6(configHome, "opencode"));
|
|
2256
|
+
}
|
|
2257
|
+
},
|
|
2258
|
+
openhands: {
|
|
2259
|
+
name: "openhands",
|
|
2260
|
+
displayName: "OpenHands",
|
|
2261
|
+
skillsDir: ".openhands/skills",
|
|
2262
|
+
globalSkillsDir: join6(home, ".openhands/skills"),
|
|
2263
|
+
detectInstalled: async () => {
|
|
2264
|
+
return existsSync(join6(home, ".openhands"));
|
|
2265
|
+
}
|
|
2266
|
+
},
|
|
2267
|
+
pi: {
|
|
2268
|
+
name: "pi",
|
|
2269
|
+
displayName: "Pi",
|
|
2270
|
+
skillsDir: ".pi/skills",
|
|
2271
|
+
globalSkillsDir: join6(home, ".pi/agent/skills"),
|
|
2272
|
+
detectInstalled: async () => {
|
|
2273
|
+
return existsSync(join6(home, ".pi/agent"));
|
|
2274
|
+
}
|
|
2275
|
+
},
|
|
2276
|
+
qoder: {
|
|
2277
|
+
name: "qoder",
|
|
2278
|
+
displayName: "Qoder",
|
|
2279
|
+
skillsDir: ".qoder/skills",
|
|
2280
|
+
globalSkillsDir: join6(home, ".qoder/skills"),
|
|
2281
|
+
detectInstalled: async () => {
|
|
2282
|
+
return existsSync(join6(home, ".qoder"));
|
|
2283
|
+
}
|
|
2284
|
+
},
|
|
2285
|
+
"qwen-code": {
|
|
2286
|
+
name: "qwen-code",
|
|
2287
|
+
displayName: "Qwen Code",
|
|
2288
|
+
skillsDir: ".qwen/skills",
|
|
2289
|
+
globalSkillsDir: join6(home, ".qwen/skills"),
|
|
2290
|
+
detectInstalled: async () => {
|
|
2291
|
+
return existsSync(join6(home, ".qwen"));
|
|
2292
|
+
}
|
|
2293
|
+
},
|
|
2294
|
+
replit: {
|
|
2295
|
+
name: "replit",
|
|
2296
|
+
displayName: "Replit",
|
|
2297
|
+
skillsDir: ".agents/skills",
|
|
2298
|
+
globalSkillsDir: join6(configHome, "agents/skills"),
|
|
2299
|
+
showInUniversalList: false,
|
|
2300
|
+
detectInstalled: async () => {
|
|
2301
|
+
return existsSync(join6(process.cwd(), ".replit"));
|
|
2302
|
+
}
|
|
2303
|
+
},
|
|
2304
|
+
roo: {
|
|
2305
|
+
name: "roo",
|
|
2306
|
+
displayName: "Roo Code",
|
|
2307
|
+
skillsDir: ".roo/skills",
|
|
2308
|
+
globalSkillsDir: join6(home, ".roo/skills"),
|
|
2309
|
+
detectInstalled: async () => {
|
|
2310
|
+
return existsSync(join6(home, ".roo"));
|
|
2311
|
+
}
|
|
2312
|
+
},
|
|
2313
|
+
trae: {
|
|
2314
|
+
name: "trae",
|
|
2315
|
+
displayName: "Trae",
|
|
2316
|
+
skillsDir: ".trae/skills",
|
|
2317
|
+
globalSkillsDir: join6(home, ".trae/skills"),
|
|
2318
|
+
detectInstalled: async () => {
|
|
2319
|
+
return existsSync(join6(home, ".trae"));
|
|
2320
|
+
}
|
|
2321
|
+
},
|
|
2322
|
+
"trae-cn": {
|
|
2323
|
+
name: "trae-cn",
|
|
2324
|
+
displayName: "Trae CN",
|
|
2325
|
+
skillsDir: ".trae/skills",
|
|
2326
|
+
globalSkillsDir: join6(home, ".trae-cn/skills"),
|
|
2327
|
+
detectInstalled: async () => {
|
|
2328
|
+
return existsSync(join6(home, ".trae-cn"));
|
|
2329
|
+
}
|
|
2330
|
+
},
|
|
2331
|
+
warp: {
|
|
2332
|
+
name: "warp",
|
|
2333
|
+
displayName: "Warp",
|
|
2334
|
+
skillsDir: ".agents/skills",
|
|
2335
|
+
globalSkillsDir: join6(home, ".agents/skills"),
|
|
2336
|
+
detectInstalled: async () => {
|
|
2337
|
+
return existsSync(join6(home, ".warp"));
|
|
2338
|
+
}
|
|
2339
|
+
},
|
|
2340
|
+
windsurf: {
|
|
2341
|
+
name: "windsurf",
|
|
2342
|
+
displayName: "Windsurf",
|
|
2343
|
+
skillsDir: ".windsurf/skills",
|
|
2344
|
+
globalSkillsDir: join6(home, ".codeium/windsurf/skills"),
|
|
2345
|
+
detectInstalled: async () => {
|
|
2346
|
+
return existsSync(join6(home, ".codeium/windsurf"));
|
|
2347
|
+
}
|
|
2348
|
+
},
|
|
2349
|
+
zencoder: {
|
|
2350
|
+
name: "zencoder",
|
|
2351
|
+
displayName: "Zencoder",
|
|
2352
|
+
skillsDir: ".zencoder/skills",
|
|
2353
|
+
globalSkillsDir: join6(home, ".zencoder/skills"),
|
|
2354
|
+
detectInstalled: async () => {
|
|
2355
|
+
return existsSync(join6(home, ".zencoder"));
|
|
2356
|
+
}
|
|
2357
|
+
},
|
|
2358
|
+
neovate: {
|
|
2359
|
+
name: "neovate",
|
|
2360
|
+
displayName: "Neovate",
|
|
2361
|
+
skillsDir: ".neovate/skills",
|
|
2362
|
+
globalSkillsDir: join6(home, ".neovate/skills"),
|
|
2363
|
+
detectInstalled: async () => {
|
|
2364
|
+
return existsSync(join6(home, ".neovate"));
|
|
2365
|
+
}
|
|
2366
|
+
},
|
|
2367
|
+
pochi: {
|
|
2368
|
+
name: "pochi",
|
|
2369
|
+
displayName: "Pochi",
|
|
2370
|
+
skillsDir: ".pochi/skills",
|
|
2371
|
+
globalSkillsDir: join6(home, ".pochi/skills"),
|
|
2372
|
+
detectInstalled: async () => {
|
|
2373
|
+
return existsSync(join6(home, ".pochi"));
|
|
2374
|
+
}
|
|
2375
|
+
},
|
|
2376
|
+
adal: {
|
|
2377
|
+
name: "adal",
|
|
2378
|
+
displayName: "AdaL",
|
|
2379
|
+
skillsDir: ".adal/skills",
|
|
2380
|
+
globalSkillsDir: join6(home, ".adal/skills"),
|
|
2381
|
+
detectInstalled: async () => {
|
|
2382
|
+
return existsSync(join6(home, ".adal"));
|
|
2383
|
+
}
|
|
2384
|
+
},
|
|
2385
|
+
universal: {
|
|
2386
|
+
name: "universal",
|
|
2387
|
+
displayName: "Universal",
|
|
2388
|
+
skillsDir: ".agents/skills",
|
|
2389
|
+
globalSkillsDir: join6(configHome, "agents/skills"),
|
|
2390
|
+
showInUniversalList: false,
|
|
2391
|
+
detectInstalled: async () => false
|
|
2392
|
+
}
|
|
2393
|
+
};
|
|
2394
|
+
async function detectInstalledAgents() {
|
|
2395
|
+
const results = await Promise.all(
|
|
2396
|
+
Object.entries(agents).map(async ([type, config]) => ({
|
|
2397
|
+
type,
|
|
2398
|
+
installed: await config.detectInstalled()
|
|
2399
|
+
}))
|
|
2400
|
+
);
|
|
2401
|
+
return results.filter((r2) => r2.installed).map((r2) => r2.type);
|
|
2402
|
+
}
|
|
2403
|
+
function getUniversalAgents() {
|
|
2404
|
+
return Object.entries(agents).filter(
|
|
2405
|
+
([_3, config]) => config.skillsDir === ".agents/skills" && config.showInUniversalList !== false
|
|
2406
|
+
).map(([type]) => type);
|
|
2407
|
+
}
|
|
2408
|
+
function getNonUniversalAgents() {
|
|
2409
|
+
return Object.entries(agents).filter(([_3, config]) => config.skillsDir !== ".agents/skills").map(([type]) => type);
|
|
2410
|
+
}
|
|
2411
|
+
function isUniversalAgent(type) {
|
|
2412
|
+
return agents[type].skillsDir === ".agents/skills";
|
|
2413
|
+
}
|
|
2414
|
+
|
|
2415
|
+
// src/constants.ts
|
|
2416
|
+
var AGENTS_DIR2 = ".agents";
|
|
2417
|
+
var SKILLS_SUBDIR = "skills";
|
|
2418
|
+
|
|
2419
|
+
// src/installer.ts
|
|
2420
|
+
function sanitizeName(name) {
|
|
2421
|
+
const sanitized = name.toLowerCase().replace(/[^a-z0-9._]+/g, "-").replace(/^[.\-]+|[.\-]+$/g, "");
|
|
2422
|
+
return sanitized.substring(0, 255) || "unnamed-skill";
|
|
2423
|
+
}
|
|
2424
|
+
function isPathSafe(basePath, targetPath) {
|
|
2425
|
+
const normalizedBase = normalize4(resolve5(basePath));
|
|
2426
|
+
const normalizedTarget = normalize4(resolve5(targetPath));
|
|
2427
|
+
return normalizedTarget.startsWith(normalizedBase + sep4) || normalizedTarget === normalizedBase;
|
|
2428
|
+
}
|
|
2429
|
+
function getCanonicalSkillsDir(global, cwd) {
|
|
2430
|
+
const baseDir = global ? homedir3() : cwd || process.cwd();
|
|
2431
|
+
return join7(baseDir, AGENTS_DIR2, SKILLS_SUBDIR);
|
|
2432
|
+
}
|
|
2433
|
+
function getMCPCanonicalSkillsDir(global, cwd) {
|
|
2434
|
+
const baseDir = global ? homedir3() : cwd || process.cwd();
|
|
2435
|
+
return join7(baseDir, ".agentskills", "skills");
|
|
2436
|
+
}
|
|
2437
|
+
function getAgentBaseDir(agentType, global, cwd) {
|
|
2438
|
+
if (isUniversalAgent(agentType)) {
|
|
2439
|
+
return getCanonicalSkillsDir(global, cwd);
|
|
2440
|
+
}
|
|
2441
|
+
const agent = agents[agentType];
|
|
2442
|
+
const baseDir = global ? homedir3() : cwd || process.cwd();
|
|
2443
|
+
if (global) {
|
|
2444
|
+
if (agent.globalSkillsDir === void 0) {
|
|
2445
|
+
return join7(baseDir, agent.skillsDir);
|
|
2446
|
+
}
|
|
2447
|
+
return agent.globalSkillsDir;
|
|
2448
|
+
}
|
|
2449
|
+
return join7(baseDir, agent.skillsDir);
|
|
2450
|
+
}
|
|
2451
|
+
function resolveSymlinkTarget(linkPath, linkTarget) {
|
|
2452
|
+
return resolve5(dirname4(linkPath), linkTarget);
|
|
2453
|
+
}
|
|
2454
|
+
async function cleanAndCreateDirectory(path2) {
|
|
2455
|
+
try {
|
|
2456
|
+
await rm2(path2, { recursive: true, force: true });
|
|
2457
|
+
} catch {
|
|
2458
|
+
}
|
|
2459
|
+
await mkdir2(path2, { recursive: true });
|
|
2460
|
+
}
|
|
2461
|
+
async function resolveParentSymlinks(path2) {
|
|
2462
|
+
const resolved = resolve5(path2);
|
|
2463
|
+
const dir = dirname4(resolved);
|
|
2464
|
+
const base = basename2(resolved);
|
|
2465
|
+
try {
|
|
2466
|
+
const realDir = await realpath(dir);
|
|
2467
|
+
return join7(realDir, base);
|
|
2468
|
+
} catch {
|
|
2469
|
+
return resolved;
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
async function createSymlink(target, linkPath) {
|
|
2473
|
+
try {
|
|
2474
|
+
const resolvedTarget = resolve5(target);
|
|
2475
|
+
const resolvedLinkPath = resolve5(linkPath);
|
|
2476
|
+
const [realTarget, realLinkPath] = await Promise.all([
|
|
2477
|
+
realpath(resolvedTarget).catch(() => resolvedTarget),
|
|
2478
|
+
realpath(resolvedLinkPath).catch(() => resolvedLinkPath)
|
|
2479
|
+
]);
|
|
2480
|
+
if (realTarget === realLinkPath) {
|
|
2481
|
+
return true;
|
|
2482
|
+
}
|
|
2483
|
+
const realTargetWithParents = await resolveParentSymlinks(target);
|
|
2484
|
+
const realLinkPathWithParents = await resolveParentSymlinks(linkPath);
|
|
2485
|
+
if (realTargetWithParents === realLinkPathWithParents) {
|
|
2486
|
+
return true;
|
|
2487
|
+
}
|
|
2488
|
+
try {
|
|
2489
|
+
const stats = await lstat(linkPath);
|
|
2490
|
+
if (stats.isSymbolicLink()) {
|
|
2491
|
+
const existingTarget = await readlink(linkPath);
|
|
2492
|
+
if (resolveSymlinkTarget(linkPath, existingTarget) === resolvedTarget) {
|
|
2493
|
+
return true;
|
|
2494
|
+
}
|
|
2495
|
+
await rm2(linkPath);
|
|
2496
|
+
} else {
|
|
2497
|
+
await rm2(linkPath, { recursive: true });
|
|
2498
|
+
}
|
|
2499
|
+
} catch (err) {
|
|
2500
|
+
if (err && typeof err === "object" && "code" in err && err.code === "ELOOP") {
|
|
2501
|
+
try {
|
|
2502
|
+
await rm2(linkPath, { force: true });
|
|
2503
|
+
} catch {
|
|
2504
|
+
}
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
const linkDir = dirname4(linkPath);
|
|
2508
|
+
await mkdir2(linkDir, { recursive: true });
|
|
2509
|
+
const realLinkDir = await resolveParentSymlinks(linkDir);
|
|
2510
|
+
const relativePath = relative2(realLinkDir, target);
|
|
2511
|
+
const symlinkType = platform() === "win32" ? "junction" : void 0;
|
|
2512
|
+
await symlink(relativePath, linkPath, symlinkType);
|
|
2513
|
+
return true;
|
|
2514
|
+
} catch {
|
|
2515
|
+
return false;
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
async function installSkillForAgent(skill, agentType, options = {}) {
|
|
2519
|
+
const agent = agents[agentType];
|
|
2520
|
+
const isGlobal = options.global ?? false;
|
|
2521
|
+
const cwd = options.cwd || process.cwd();
|
|
2522
|
+
if (isGlobal && agent.globalSkillsDir === void 0) {
|
|
2523
|
+
return {
|
|
2524
|
+
success: false,
|
|
2525
|
+
path: "",
|
|
2526
|
+
mode: options.mode ?? "symlink",
|
|
2527
|
+
error: `${agent.displayName} does not support global skill installation`
|
|
2528
|
+
};
|
|
2529
|
+
}
|
|
2530
|
+
const rawSkillName = skill.name || basename2(skill.path);
|
|
2531
|
+
const skillName = sanitizeName(rawSkillName);
|
|
2532
|
+
const installMode = options.mode ?? "symlink";
|
|
2533
|
+
const canonicalBase = installMode === "mcp-server" ? getMCPCanonicalSkillsDir(isGlobal, cwd) : getCanonicalSkillsDir(isGlobal, cwd);
|
|
2534
|
+
const canonicalDir = join7(canonicalBase, skillName);
|
|
2535
|
+
const agentBase = getAgentBaseDir(agentType, isGlobal, cwd);
|
|
2536
|
+
const agentDir = join7(agentBase, skillName);
|
|
2537
|
+
if (!isPathSafe(canonicalBase, canonicalDir)) {
|
|
2538
|
+
return {
|
|
2539
|
+
success: false,
|
|
2540
|
+
path: agentDir,
|
|
2541
|
+
mode: installMode,
|
|
2542
|
+
error: "Invalid skill name: potential path traversal detected"
|
|
2543
|
+
};
|
|
2544
|
+
}
|
|
2545
|
+
if (!isPathSafe(agentBase, agentDir)) {
|
|
2546
|
+
return {
|
|
2547
|
+
success: false,
|
|
2548
|
+
path: agentDir,
|
|
2549
|
+
mode: installMode,
|
|
2550
|
+
error: "Invalid skill name: potential path traversal detected"
|
|
2551
|
+
};
|
|
2552
|
+
}
|
|
2553
|
+
try {
|
|
2554
|
+
if (installMode === "mcp-server") {
|
|
2555
|
+
await cleanAndCreateDirectory(canonicalDir);
|
|
2556
|
+
await copyDirectory(skill.path, canonicalDir);
|
|
2557
|
+
return {
|
|
2558
|
+
success: true,
|
|
2559
|
+
path: canonicalDir,
|
|
2560
|
+
canonicalPath: canonicalDir,
|
|
2561
|
+
mode: "mcp-server"
|
|
2562
|
+
};
|
|
2563
|
+
}
|
|
2564
|
+
if (installMode === "copy") {
|
|
2565
|
+
await cleanAndCreateDirectory(agentDir);
|
|
2566
|
+
await copyDirectory(skill.path, agentDir);
|
|
2567
|
+
return {
|
|
2568
|
+
success: true,
|
|
2569
|
+
path: agentDir,
|
|
2570
|
+
mode: "copy"
|
|
2571
|
+
};
|
|
2572
|
+
}
|
|
2573
|
+
await cleanAndCreateDirectory(canonicalDir);
|
|
2574
|
+
await copyDirectory(skill.path, canonicalDir);
|
|
2575
|
+
if (isGlobal && isUniversalAgent(agentType)) {
|
|
2576
|
+
return {
|
|
2577
|
+
success: true,
|
|
2578
|
+
path: canonicalDir,
|
|
2579
|
+
canonicalPath: canonicalDir,
|
|
2580
|
+
mode: "symlink"
|
|
2581
|
+
};
|
|
2582
|
+
}
|
|
2583
|
+
const symlinkCreated = await createSymlink(canonicalDir, agentDir);
|
|
2584
|
+
if (!symlinkCreated) {
|
|
2585
|
+
await cleanAndCreateDirectory(agentDir);
|
|
2586
|
+
await copyDirectory(skill.path, agentDir);
|
|
2587
|
+
return {
|
|
2588
|
+
success: true,
|
|
2589
|
+
path: agentDir,
|
|
2590
|
+
canonicalPath: canonicalDir,
|
|
2591
|
+
mode: "symlink",
|
|
2592
|
+
symlinkFailed: true
|
|
2593
|
+
};
|
|
2594
|
+
}
|
|
2595
|
+
return {
|
|
2596
|
+
success: true,
|
|
2597
|
+
path: agentDir,
|
|
2598
|
+
canonicalPath: canonicalDir,
|
|
2599
|
+
mode: "symlink"
|
|
2600
|
+
};
|
|
2601
|
+
} catch (error) {
|
|
2602
|
+
return {
|
|
2603
|
+
success: false,
|
|
2604
|
+
path: agentDir,
|
|
2605
|
+
mode: installMode,
|
|
2606
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
2607
|
+
};
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
var EXCLUDE_FILES = /* @__PURE__ */ new Set(["metadata.json"]);
|
|
2611
|
+
var EXCLUDE_DIRS = /* @__PURE__ */ new Set([".git", "__pycache__", "__pypackages__"]);
|
|
2612
|
+
var isExcluded = (name, isDirectory = false) => {
|
|
2613
|
+
if (EXCLUDE_FILES.has(name)) return true;
|
|
2614
|
+
if (name.startsWith(".")) return true;
|
|
2615
|
+
if (isDirectory && EXCLUDE_DIRS.has(name)) return true;
|
|
2616
|
+
return false;
|
|
2617
|
+
};
|
|
2618
|
+
async function copyDirectory(src, dest) {
|
|
2619
|
+
await mkdir2(dest, { recursive: true });
|
|
2620
|
+
const entries = await readdir3(src, { withFileTypes: true });
|
|
2621
|
+
await Promise.all(
|
|
2622
|
+
entries.filter((entry) => !isExcluded(entry.name, entry.isDirectory())).map(async (entry) => {
|
|
2623
|
+
const srcPath = join7(src, entry.name);
|
|
2624
|
+
const destPath = join7(dest, entry.name);
|
|
2625
|
+
if (entry.isDirectory()) {
|
|
2626
|
+
await copyDirectory(srcPath, destPath);
|
|
2627
|
+
} else {
|
|
2628
|
+
try {
|
|
2629
|
+
await cp(srcPath, destPath, {
|
|
2630
|
+
// If the file is a symlink to elsewhere in a remote skill, it may not
|
|
2631
|
+
// resolve correctly once it has been copied to the local location.
|
|
2632
|
+
// `dereference: true` tells Node to copy the file instead of copying
|
|
2633
|
+
// the symlink. `recursive: true` handles symlinks pointing to directories.
|
|
2634
|
+
dereference: true,
|
|
2635
|
+
recursive: true
|
|
2636
|
+
});
|
|
2637
|
+
} catch (err) {
|
|
2638
|
+
if (err instanceof Error && "code" in err && err.code === "ENOENT" && entry.isSymbolicLink()) {
|
|
2639
|
+
console.warn(`Skipping broken symlink: ${srcPath}`);
|
|
2640
|
+
} else {
|
|
2641
|
+
throw err;
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
})
|
|
2646
|
+
);
|
|
2647
|
+
}
|
|
2648
|
+
async function isSkillInstalled(skillName, agentType, options = {}) {
|
|
2649
|
+
const agent = agents[agentType];
|
|
2650
|
+
const sanitized = sanitizeName(skillName);
|
|
2651
|
+
if (options.global && agent.globalSkillsDir === void 0) {
|
|
2652
|
+
return false;
|
|
2653
|
+
}
|
|
2654
|
+
const targetBase = options.global ? agent.globalSkillsDir : join7(options.cwd || process.cwd(), agent.skillsDir);
|
|
2655
|
+
const skillDir = join7(targetBase, sanitized);
|
|
2656
|
+
if (!isPathSafe(targetBase, skillDir)) {
|
|
2657
|
+
return false;
|
|
2658
|
+
}
|
|
2659
|
+
try {
|
|
2660
|
+
await access(skillDir);
|
|
2661
|
+
return true;
|
|
2662
|
+
} catch {
|
|
2663
|
+
return false;
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
function getInstallPath(skillName, agentType, options = {}) {
|
|
2667
|
+
const agent = agents[agentType];
|
|
2668
|
+
const cwd = options.cwd || process.cwd();
|
|
2669
|
+
const sanitized = sanitizeName(skillName);
|
|
2670
|
+
const targetBase = getAgentBaseDir(agentType, options.global ?? false, options.cwd);
|
|
2671
|
+
const installPath = join7(targetBase, sanitized);
|
|
2672
|
+
if (!isPathSafe(targetBase, installPath)) {
|
|
2673
|
+
throw new Error("Invalid skill name: potential path traversal detected");
|
|
2674
|
+
}
|
|
2675
|
+
return installPath;
|
|
2676
|
+
}
|
|
2677
|
+
function getCanonicalPath(skillName, options = {}) {
|
|
2678
|
+
const sanitized = sanitizeName(skillName);
|
|
2679
|
+
const canonicalBase = getCanonicalSkillsDir(options.global ?? false, options.cwd);
|
|
2680
|
+
const canonicalPath = join7(canonicalBase, sanitized);
|
|
2681
|
+
if (!isPathSafe(canonicalBase, canonicalPath)) {
|
|
2682
|
+
throw new Error("Invalid skill name: potential path traversal detected");
|
|
2683
|
+
}
|
|
2684
|
+
return canonicalPath;
|
|
2685
|
+
}
|
|
2686
|
+
async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
|
|
2687
|
+
const agent = agents[agentType];
|
|
2688
|
+
const isGlobal = options.global ?? false;
|
|
2689
|
+
const cwd = options.cwd || process.cwd();
|
|
2690
|
+
const installMode = options.mode ?? "symlink";
|
|
2691
|
+
if (isGlobal && agent.globalSkillsDir === void 0) {
|
|
2692
|
+
return {
|
|
2693
|
+
success: false,
|
|
2694
|
+
path: "",
|
|
2695
|
+
mode: installMode,
|
|
2696
|
+
error: `${agent.displayName} does not support global skill installation`
|
|
2697
|
+
};
|
|
2698
|
+
}
|
|
2699
|
+
const skillName = sanitizeName(skill.installName);
|
|
2700
|
+
const canonicalBase = installMode === "mcp-server" ? getMCPCanonicalSkillsDir(isGlobal, cwd) : getCanonicalSkillsDir(isGlobal, cwd);
|
|
2701
|
+
const canonicalDir = join7(canonicalBase, skillName);
|
|
2702
|
+
const agentBase = getAgentBaseDir(agentType, isGlobal, cwd);
|
|
2703
|
+
const agentDir = join7(agentBase, skillName);
|
|
2704
|
+
if (!isPathSafe(canonicalBase, canonicalDir)) {
|
|
2705
|
+
return {
|
|
2706
|
+
success: false,
|
|
2707
|
+
path: agentDir,
|
|
2708
|
+
mode: installMode,
|
|
2709
|
+
error: "Invalid skill name: potential path traversal detected"
|
|
2710
|
+
};
|
|
2711
|
+
}
|
|
2712
|
+
if (!isPathSafe(agentBase, agentDir)) {
|
|
2713
|
+
return {
|
|
2714
|
+
success: false,
|
|
2715
|
+
path: agentDir,
|
|
2716
|
+
mode: installMode,
|
|
2717
|
+
error: "Invalid skill name: potential path traversal detected"
|
|
2718
|
+
};
|
|
2719
|
+
}
|
|
2720
|
+
async function writeSkillFiles(targetDir) {
|
|
2721
|
+
for (const [filePath, content] of skill.files) {
|
|
2722
|
+
const fullPath = join7(targetDir, filePath);
|
|
2723
|
+
if (!isPathSafe(targetDir, fullPath)) {
|
|
2724
|
+
continue;
|
|
2725
|
+
}
|
|
2726
|
+
const parentDir = dirname4(fullPath);
|
|
2727
|
+
if (parentDir !== targetDir) {
|
|
2728
|
+
await mkdir2(parentDir, { recursive: true });
|
|
2729
|
+
}
|
|
2730
|
+
await writeFile3(fullPath, content, "utf-8");
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2733
|
+
try {
|
|
2734
|
+
if (installMode === "mcp-server") {
|
|
2735
|
+
await cleanAndCreateDirectory(canonicalDir);
|
|
2736
|
+
await writeSkillFiles(canonicalDir);
|
|
2737
|
+
return {
|
|
2738
|
+
success: true,
|
|
2739
|
+
path: canonicalDir,
|
|
2740
|
+
canonicalPath: canonicalDir,
|
|
2741
|
+
mode: "mcp-server"
|
|
2742
|
+
};
|
|
2743
|
+
}
|
|
2744
|
+
if (installMode === "copy") {
|
|
2745
|
+
await cleanAndCreateDirectory(agentDir);
|
|
2746
|
+
await writeSkillFiles(agentDir);
|
|
2747
|
+
return {
|
|
2748
|
+
success: true,
|
|
2749
|
+
path: agentDir,
|
|
2750
|
+
mode: "copy"
|
|
2751
|
+
};
|
|
2752
|
+
}
|
|
2753
|
+
await cleanAndCreateDirectory(canonicalDir);
|
|
2754
|
+
await writeSkillFiles(canonicalDir);
|
|
2755
|
+
if (isGlobal && isUniversalAgent(agentType)) {
|
|
2756
|
+
return {
|
|
2757
|
+
success: true,
|
|
2758
|
+
path: canonicalDir,
|
|
2759
|
+
canonicalPath: canonicalDir,
|
|
2760
|
+
mode: "symlink"
|
|
2761
|
+
};
|
|
2762
|
+
}
|
|
2763
|
+
const symlinkCreated = await createSymlink(canonicalDir, agentDir);
|
|
2764
|
+
if (!symlinkCreated) {
|
|
2765
|
+
await cleanAndCreateDirectory(agentDir);
|
|
2766
|
+
await writeSkillFiles(agentDir);
|
|
2767
|
+
return {
|
|
2768
|
+
success: true,
|
|
2769
|
+
path: agentDir,
|
|
2770
|
+
canonicalPath: canonicalDir,
|
|
2771
|
+
mode: "symlink",
|
|
2772
|
+
symlinkFailed: true
|
|
2773
|
+
};
|
|
2774
|
+
}
|
|
2775
|
+
return {
|
|
2776
|
+
success: true,
|
|
2777
|
+
path: agentDir,
|
|
2778
|
+
canonicalPath: canonicalDir,
|
|
2779
|
+
mode: "symlink"
|
|
2780
|
+
};
|
|
2781
|
+
} catch (error) {
|
|
2782
|
+
return {
|
|
2783
|
+
success: false,
|
|
2784
|
+
path: agentDir,
|
|
2785
|
+
mode: installMode,
|
|
2786
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
2787
|
+
};
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2790
|
+
async function listInstalledSkills(options = {}) {
|
|
2791
|
+
const cwd = options.cwd || process.cwd();
|
|
2792
|
+
const skillsMap = /* @__PURE__ */ new Map();
|
|
2793
|
+
const scopes = [];
|
|
2794
|
+
const detectedAgents = await detectInstalledAgents();
|
|
2795
|
+
const agentFilter = options.agentFilter;
|
|
2796
|
+
const agentsToCheck = agentFilter ? detectedAgents.filter((a) => agentFilter.includes(a)) : detectedAgents;
|
|
2797
|
+
const scopeTypes = [];
|
|
2798
|
+
if (options.global === void 0) {
|
|
2799
|
+
scopeTypes.push({ global: false }, { global: true });
|
|
2800
|
+
} else {
|
|
2801
|
+
scopeTypes.push({ global: options.global });
|
|
2802
|
+
}
|
|
2803
|
+
for (const { global: isGlobal } of scopeTypes) {
|
|
2804
|
+
scopes.push({ global: isGlobal, path: getCanonicalSkillsDir(isGlobal, cwd) });
|
|
2805
|
+
for (const agentType of agentsToCheck) {
|
|
2806
|
+
const agent = agents[agentType];
|
|
2807
|
+
if (isGlobal && agent.globalSkillsDir === void 0) {
|
|
2808
|
+
continue;
|
|
2809
|
+
}
|
|
2810
|
+
const agentDir = isGlobal ? agent.globalSkillsDir : join7(cwd, agent.skillsDir);
|
|
2811
|
+
if (!scopes.some((s) => s.path === agentDir && s.global === isGlobal)) {
|
|
2812
|
+
scopes.push({ global: isGlobal, path: agentDir, agentType });
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
for (const scope of scopes) {
|
|
2817
|
+
try {
|
|
2818
|
+
const entries = await readdir3(scope.path, { withFileTypes: true });
|
|
2819
|
+
for (const entry of entries) {
|
|
2820
|
+
if (!entry.isDirectory()) {
|
|
2821
|
+
continue;
|
|
2822
|
+
}
|
|
2823
|
+
const skillDir = join7(scope.path, entry.name);
|
|
2824
|
+
const skillMdPath = join7(skillDir, "SKILL.md");
|
|
2825
|
+
try {
|
|
2826
|
+
await stat3(skillMdPath);
|
|
2827
|
+
} catch {
|
|
2828
|
+
continue;
|
|
2829
|
+
}
|
|
2830
|
+
const skill = await parseSkillMd(skillMdPath);
|
|
2831
|
+
if (!skill) {
|
|
2832
|
+
continue;
|
|
2833
|
+
}
|
|
2834
|
+
const scopeKey = scope.global ? "global" : "project";
|
|
2835
|
+
const skillKey = `${scopeKey}:${skill.name}`;
|
|
2836
|
+
if (scope.agentType) {
|
|
2837
|
+
if (skillsMap.has(skillKey)) {
|
|
2838
|
+
const existing = skillsMap.get(skillKey);
|
|
2839
|
+
if (!existing.agents.includes(scope.agentType)) {
|
|
2840
|
+
existing.agents.push(scope.agentType);
|
|
2841
|
+
}
|
|
2842
|
+
} else {
|
|
2843
|
+
skillsMap.set(skillKey, {
|
|
2844
|
+
name: skill.name,
|
|
2845
|
+
description: skill.description,
|
|
2846
|
+
path: skillDir,
|
|
2847
|
+
canonicalPath: skillDir,
|
|
2848
|
+
scope: scopeKey,
|
|
2849
|
+
agents: [scope.agentType]
|
|
2850
|
+
});
|
|
2851
|
+
}
|
|
2852
|
+
continue;
|
|
2853
|
+
}
|
|
2854
|
+
const sanitizedSkillName = sanitizeName(skill.name);
|
|
2855
|
+
const installedAgents = [];
|
|
2856
|
+
for (const agentType of agentsToCheck) {
|
|
2857
|
+
const agent = agents[agentType];
|
|
2858
|
+
if (scope.global && agent.globalSkillsDir === void 0) {
|
|
2859
|
+
continue;
|
|
2860
|
+
}
|
|
2861
|
+
const agentBase = scope.global ? agent.globalSkillsDir : join7(cwd, agent.skillsDir);
|
|
2862
|
+
let found = false;
|
|
2863
|
+
const possibleNames = Array.from(
|
|
2864
|
+
/* @__PURE__ */ new Set([
|
|
2865
|
+
entry.name,
|
|
2866
|
+
sanitizedSkillName,
|
|
2867
|
+
skill.name.toLowerCase().replace(/\s+/g, "-").replace(/[\/\\:\0]/g, "")
|
|
2868
|
+
])
|
|
2869
|
+
);
|
|
2870
|
+
for (const possibleName of possibleNames) {
|
|
2871
|
+
const agentSkillDir = join7(agentBase, possibleName);
|
|
2872
|
+
if (!isPathSafe(agentBase, agentSkillDir)) continue;
|
|
2873
|
+
try {
|
|
2874
|
+
await access(agentSkillDir);
|
|
2875
|
+
found = true;
|
|
2876
|
+
break;
|
|
2877
|
+
} catch {
|
|
2878
|
+
}
|
|
2879
|
+
}
|
|
2880
|
+
if (!found) {
|
|
2881
|
+
try {
|
|
2882
|
+
const agentEntries = await readdir3(agentBase, { withFileTypes: true });
|
|
2883
|
+
for (const agentEntry of agentEntries) {
|
|
2884
|
+
if (!agentEntry.isDirectory()) continue;
|
|
2885
|
+
const candidateDir = join7(agentBase, agentEntry.name);
|
|
2886
|
+
if (!isPathSafe(agentBase, candidateDir)) continue;
|
|
2887
|
+
try {
|
|
2888
|
+
const candidateSkillMd = join7(candidateDir, "SKILL.md");
|
|
2889
|
+
await stat3(candidateSkillMd);
|
|
2890
|
+
const candidateSkill = await parseSkillMd(candidateSkillMd);
|
|
2891
|
+
if (candidateSkill && candidateSkill.name === skill.name) {
|
|
2892
|
+
found = true;
|
|
2893
|
+
break;
|
|
2894
|
+
}
|
|
2895
|
+
} catch {
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
} catch {
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
if (found) {
|
|
2902
|
+
installedAgents.push(agentType);
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
if (skillsMap.has(skillKey)) {
|
|
2906
|
+
const existing = skillsMap.get(skillKey);
|
|
2907
|
+
for (const agent of installedAgents) {
|
|
2908
|
+
if (!existing.agents.includes(agent)) {
|
|
2909
|
+
existing.agents.push(agent);
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
} else {
|
|
2913
|
+
skillsMap.set(skillKey, {
|
|
2914
|
+
name: skill.name,
|
|
2915
|
+
description: skill.description,
|
|
2916
|
+
path: skillDir,
|
|
2917
|
+
canonicalPath: skillDir,
|
|
2918
|
+
scope: scopeKey,
|
|
2919
|
+
agents: installedAgents
|
|
2920
|
+
});
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2923
|
+
} catch {
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
return Array.from(skillsMap.values());
|
|
2927
|
+
}
|
|
2928
|
+
|
|
2929
|
+
// src/providers/registry.ts
|
|
2930
|
+
var ProviderRegistryImpl = class {
|
|
2931
|
+
providers = [];
|
|
2932
|
+
register(provider) {
|
|
2933
|
+
if (this.providers.some((p2) => p2.id === provider.id)) {
|
|
2934
|
+
throw new Error(`Provider with id "${provider.id}" already registered`);
|
|
2935
|
+
}
|
|
2936
|
+
this.providers.push(provider);
|
|
2937
|
+
}
|
|
2938
|
+
findProvider(url) {
|
|
2939
|
+
for (const provider of this.providers) {
|
|
2940
|
+
const match = provider.match(url);
|
|
2941
|
+
if (match.matches) {
|
|
2942
|
+
return provider;
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
return null;
|
|
2946
|
+
}
|
|
2947
|
+
getProviders() {
|
|
2948
|
+
return [...this.providers];
|
|
2949
|
+
}
|
|
2950
|
+
};
|
|
2951
|
+
var registry = new ProviderRegistryImpl();
|
|
2952
|
+
|
|
2953
|
+
// src/providers/wellknown.ts
|
|
2954
|
+
import matter2 from "gray-matter";
|
|
2955
|
+
var WellKnownProvider = class {
|
|
2956
|
+
id = "well-known";
|
|
2957
|
+
displayName = "Well-Known Skills";
|
|
2958
|
+
WELL_KNOWN_PATH = ".well-known/skills";
|
|
2959
|
+
INDEX_FILE = "index.json";
|
|
2960
|
+
/**
|
|
2961
|
+
* Check if a URL could be a well-known skills endpoint.
|
|
2962
|
+
* This is a fallback provider - it matches any HTTP(S) URL that is not
|
|
2963
|
+
* a recognized pattern (GitHub, GitLab, owner/repo shorthand, etc.)
|
|
2964
|
+
*/
|
|
2965
|
+
match(url) {
|
|
2966
|
+
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
|
2967
|
+
return { matches: false };
|
|
2968
|
+
}
|
|
2969
|
+
try {
|
|
2970
|
+
const parsed = new URL(url);
|
|
2971
|
+
const excludedHosts = ["github.com", "gitlab.com", "huggingface.co"];
|
|
2972
|
+
if (excludedHosts.includes(parsed.hostname)) {
|
|
2973
|
+
return { matches: false };
|
|
2974
|
+
}
|
|
2975
|
+
return {
|
|
2976
|
+
matches: true,
|
|
2977
|
+
sourceIdentifier: `wellknown/${parsed.hostname}`
|
|
2978
|
+
};
|
|
2979
|
+
} catch {
|
|
2980
|
+
return { matches: false };
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
/**
|
|
2984
|
+
* Fetch the skills index from a well-known endpoint.
|
|
2985
|
+
* Tries both the path-relative .well-known and the root .well-known.
|
|
2986
|
+
*/
|
|
2987
|
+
async fetchIndex(baseUrl) {
|
|
2988
|
+
try {
|
|
2989
|
+
const parsed = new URL(baseUrl);
|
|
2990
|
+
const basePath = parsed.pathname.replace(/\/$/, "");
|
|
2991
|
+
const urlsToTry = [
|
|
2992
|
+
// Path-relative: https://example.com/docs/.well-known/skills/index.json
|
|
2993
|
+
{
|
|
2994
|
+
indexUrl: `${parsed.protocol}//${parsed.host}${basePath}/${this.WELL_KNOWN_PATH}/${this.INDEX_FILE}`,
|
|
2995
|
+
baseUrl: `${parsed.protocol}//${parsed.host}${basePath}`
|
|
2996
|
+
}
|
|
2997
|
+
];
|
|
2998
|
+
if (basePath && basePath !== "") {
|
|
2999
|
+
urlsToTry.push({
|
|
3000
|
+
indexUrl: `${parsed.protocol}//${parsed.host}/${this.WELL_KNOWN_PATH}/${this.INDEX_FILE}`,
|
|
3001
|
+
baseUrl: `${parsed.protocol}//${parsed.host}`
|
|
3002
|
+
});
|
|
3003
|
+
}
|
|
3004
|
+
for (const { indexUrl, baseUrl: resolvedBase } of urlsToTry) {
|
|
3005
|
+
try {
|
|
3006
|
+
const response = await fetch(indexUrl);
|
|
3007
|
+
if (!response.ok) {
|
|
3008
|
+
continue;
|
|
3009
|
+
}
|
|
3010
|
+
const index = await response.json();
|
|
3011
|
+
if (!index.skills || !Array.isArray(index.skills)) {
|
|
3012
|
+
continue;
|
|
3013
|
+
}
|
|
3014
|
+
let allValid = true;
|
|
3015
|
+
for (const entry of index.skills) {
|
|
3016
|
+
if (!this.isValidSkillEntry(entry)) {
|
|
3017
|
+
allValid = false;
|
|
3018
|
+
break;
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
if (allValid) {
|
|
3022
|
+
return { index, resolvedBaseUrl: resolvedBase };
|
|
3023
|
+
}
|
|
3024
|
+
} catch {
|
|
3025
|
+
continue;
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
return null;
|
|
3029
|
+
} catch {
|
|
3030
|
+
return null;
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
/**
|
|
3034
|
+
* Validate a skill entry from the index.
|
|
3035
|
+
*/
|
|
3036
|
+
isValidSkillEntry(entry) {
|
|
3037
|
+
if (!entry || typeof entry !== "object") return false;
|
|
3038
|
+
const e2 = entry;
|
|
3039
|
+
if (typeof e2.name !== "string" || !e2.name) return false;
|
|
3040
|
+
if (typeof e2.description !== "string" || !e2.description) return false;
|
|
3041
|
+
if (!Array.isArray(e2.files) || e2.files.length === 0) return false;
|
|
3042
|
+
const nameRegex = /^[a-z0-9]([a-z0-9-]{0,62}[a-z0-9])?$/;
|
|
3043
|
+
if (!nameRegex.test(e2.name) && e2.name.length > 1) {
|
|
3044
|
+
if (e2.name.length === 1 && !/^[a-z0-9]$/.test(e2.name)) {
|
|
3045
|
+
return false;
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
for (const file of e2.files) {
|
|
3049
|
+
if (typeof file !== "string") return false;
|
|
3050
|
+
if (file.startsWith("/") || file.startsWith("\\") || file.includes("..")) return false;
|
|
3051
|
+
}
|
|
3052
|
+
const hasSkillMd2 = e2.files.some((f) => typeof f === "string" && f.toLowerCase() === "skill.md");
|
|
3053
|
+
if (!hasSkillMd2) return false;
|
|
3054
|
+
return true;
|
|
3055
|
+
}
|
|
3056
|
+
/**
|
|
3057
|
+
* Fetch a single skill and all its files from a well-known endpoint.
|
|
3058
|
+
*/
|
|
3059
|
+
async fetchSkill(url) {
|
|
3060
|
+
try {
|
|
3061
|
+
const parsed = new URL(url);
|
|
3062
|
+
const result = await this.fetchIndex(url);
|
|
3063
|
+
if (!result) {
|
|
3064
|
+
return null;
|
|
3065
|
+
}
|
|
3066
|
+
const { index, resolvedBaseUrl } = result;
|
|
3067
|
+
let skillName = null;
|
|
3068
|
+
const pathMatch = parsed.pathname.match(/\/.well-known\/skills\/([^/]+)\/?$/);
|
|
3069
|
+
if (pathMatch && pathMatch[1] && pathMatch[1] !== "index.json") {
|
|
3070
|
+
skillName = pathMatch[1];
|
|
3071
|
+
} else if (index.skills.length === 1) {
|
|
3072
|
+
skillName = index.skills[0].name;
|
|
3073
|
+
}
|
|
3074
|
+
if (!skillName) {
|
|
3075
|
+
return null;
|
|
3076
|
+
}
|
|
3077
|
+
const skillEntry = index.skills.find((s) => s.name === skillName);
|
|
3078
|
+
if (!skillEntry) {
|
|
3079
|
+
return null;
|
|
3080
|
+
}
|
|
3081
|
+
return this.fetchSkillByEntry(resolvedBaseUrl, skillEntry);
|
|
3082
|
+
} catch {
|
|
3083
|
+
return null;
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
/**
|
|
3087
|
+
* Fetch a skill by its index entry.
|
|
3088
|
+
* @param baseUrl - The base URL (e.g., https://example.com or https://example.com/docs)
|
|
3089
|
+
* @param entry - The skill entry from index.json
|
|
3090
|
+
*/
|
|
3091
|
+
async fetchSkillByEntry(baseUrl, entry) {
|
|
3092
|
+
try {
|
|
3093
|
+
const skillBaseUrl = `${baseUrl.replace(/\/$/, "")}/${this.WELL_KNOWN_PATH}/${entry.name}`;
|
|
3094
|
+
const skillMdUrl = `${skillBaseUrl}/SKILL.md`;
|
|
3095
|
+
const response = await fetch(skillMdUrl);
|
|
3096
|
+
if (!response.ok) {
|
|
3097
|
+
return null;
|
|
3098
|
+
}
|
|
3099
|
+
const content = await response.text();
|
|
3100
|
+
const { data } = matter2(content);
|
|
3101
|
+
if (!data.name || !data.description) {
|
|
3102
|
+
return null;
|
|
3103
|
+
}
|
|
3104
|
+
const files = /* @__PURE__ */ new Map();
|
|
3105
|
+
files.set("SKILL.md", content);
|
|
3106
|
+
const otherFiles = entry.files.filter((f) => f.toLowerCase() !== "skill.md");
|
|
3107
|
+
const filePromises = otherFiles.map(async (filePath) => {
|
|
3108
|
+
try {
|
|
3109
|
+
const fileUrl = `${skillBaseUrl}/${filePath}`;
|
|
3110
|
+
const fileResponse = await fetch(fileUrl);
|
|
3111
|
+
if (fileResponse.ok) {
|
|
3112
|
+
const fileContent = await fileResponse.text();
|
|
3113
|
+
return { path: filePath, content: fileContent };
|
|
3114
|
+
}
|
|
3115
|
+
} catch {
|
|
3116
|
+
}
|
|
3117
|
+
return null;
|
|
3118
|
+
});
|
|
3119
|
+
const fileResults = await Promise.all(filePromises);
|
|
3120
|
+
for (const result of fileResults) {
|
|
3121
|
+
if (result) {
|
|
3122
|
+
files.set(result.path, result.content);
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
return {
|
|
3126
|
+
name: data.name,
|
|
3127
|
+
description: data.description,
|
|
3128
|
+
content,
|
|
3129
|
+
installName: entry.name,
|
|
3130
|
+
sourceUrl: skillMdUrl,
|
|
3131
|
+
metadata: data.metadata,
|
|
3132
|
+
files,
|
|
3133
|
+
indexEntry: entry
|
|
3134
|
+
};
|
|
3135
|
+
} catch {
|
|
3136
|
+
return null;
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
3139
|
+
/**
|
|
3140
|
+
* Fetch all skills from a well-known endpoint.
|
|
3141
|
+
*/
|
|
3142
|
+
async fetchAllSkills(url) {
|
|
3143
|
+
try {
|
|
3144
|
+
const result = await this.fetchIndex(url);
|
|
3145
|
+
if (!result) {
|
|
3146
|
+
return [];
|
|
3147
|
+
}
|
|
3148
|
+
const { index, resolvedBaseUrl } = result;
|
|
3149
|
+
const skillPromises = index.skills.map(
|
|
3150
|
+
(entry) => this.fetchSkillByEntry(resolvedBaseUrl, entry)
|
|
3151
|
+
);
|
|
3152
|
+
const results = await Promise.all(skillPromises);
|
|
3153
|
+
return results.filter((s) => s !== null);
|
|
3154
|
+
} catch {
|
|
3155
|
+
return [];
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
/**
|
|
3159
|
+
* Convert a user-facing URL to a skill URL.
|
|
3160
|
+
* For well-known, this extracts the base domain and constructs the proper path.
|
|
3161
|
+
*/
|
|
3162
|
+
toRawUrl(url) {
|
|
3163
|
+
try {
|
|
3164
|
+
const parsed = new URL(url);
|
|
3165
|
+
if (url.toLowerCase().endsWith("/skill.md")) {
|
|
3166
|
+
return url;
|
|
3167
|
+
}
|
|
3168
|
+
const pathMatch = parsed.pathname.match(/\/.well-known\/skills\/([^/]+)\/?$/);
|
|
3169
|
+
if (pathMatch && pathMatch[1]) {
|
|
3170
|
+
const basePath2 = parsed.pathname.replace(/\/.well-known\/skills\/.*$/, "");
|
|
3171
|
+
return `${parsed.protocol}//${parsed.host}${basePath2}/${this.WELL_KNOWN_PATH}/${pathMatch[1]}/SKILL.md`;
|
|
3172
|
+
}
|
|
3173
|
+
const basePath = parsed.pathname.replace(/\/$/, "");
|
|
3174
|
+
return `${parsed.protocol}//${parsed.host}${basePath}/${this.WELL_KNOWN_PATH}/${this.INDEX_FILE}`;
|
|
3175
|
+
} catch {
|
|
3176
|
+
return url;
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
3179
|
+
/**
|
|
3180
|
+
* Get the source identifier for telemetry/storage.
|
|
3181
|
+
* Returns the full hostname with www. stripped.
|
|
3182
|
+
* e.g., "https://mintlify.com/docs" → "mintlify.com"
|
|
3183
|
+
* "https://mppx-discovery-skills.vercel.app" → "mppx-discovery-skills.vercel.app"
|
|
3184
|
+
* "https://www.example.com" → "example.com"
|
|
3185
|
+
* "https://docs.lovable.dev" → "docs.lovable.dev"
|
|
3186
|
+
*/
|
|
3187
|
+
getSourceIdentifier(url) {
|
|
3188
|
+
try {
|
|
3189
|
+
const parsed = new URL(url);
|
|
3190
|
+
return parsed.hostname.replace(/^www\./, "");
|
|
3191
|
+
} catch {
|
|
3192
|
+
return "unknown";
|
|
3193
|
+
}
|
|
3194
|
+
}
|
|
3195
|
+
/**
|
|
3196
|
+
* Check if a URL has a well-known skills index.
|
|
3197
|
+
*/
|
|
3198
|
+
async hasSkillsIndex(url) {
|
|
3199
|
+
const result = await this.fetchIndex(url);
|
|
3200
|
+
return result !== null;
|
|
3201
|
+
}
|
|
3202
|
+
};
|
|
3203
|
+
var wellKnownProvider = new WellKnownProvider();
|
|
3204
|
+
|
|
3205
|
+
// package.json
|
|
3206
|
+
var package_default = {
|
|
3207
|
+
name: "@codemcp/skills",
|
|
3208
|
+
version: "2.1.1",
|
|
3209
|
+
description: "Command-line interface for Agent Skills management",
|
|
3210
|
+
type: "module",
|
|
3211
|
+
publishConfig: {
|
|
3212
|
+
access: "public"
|
|
3213
|
+
},
|
|
3214
|
+
bin: {
|
|
3215
|
+
"ade-skills": "./dist/cli.js"
|
|
3216
|
+
},
|
|
3217
|
+
exports: {
|
|
3218
|
+
"./api": "./dist/api.js"
|
|
3219
|
+
},
|
|
3220
|
+
files: [
|
|
3221
|
+
"dist",
|
|
3222
|
+
"README.md",
|
|
3223
|
+
"ThirdPartyNoticeText.txt"
|
|
3224
|
+
],
|
|
3225
|
+
scripts: {
|
|
3226
|
+
build: "tsup",
|
|
3227
|
+
"build:obuild": "obuild",
|
|
3228
|
+
"generate-licenses": "node --loader tsx scripts/generate-licenses.ts",
|
|
3229
|
+
dev: "node --loader tsx src/cli.ts",
|
|
3230
|
+
"exec:test": "node --loader tsx scripts/execute-tests.ts",
|
|
3231
|
+
prepublishOnly: "npm run build",
|
|
3232
|
+
format: "prettier --write 'src/**/*.ts' 'scripts/**/*.ts'",
|
|
3233
|
+
"format:check": "prettier --check 'src/**/*.ts' 'scripts/**/*.ts'",
|
|
3234
|
+
prepare: "husky",
|
|
3235
|
+
test: "vitest",
|
|
3236
|
+
"type-check": "tsc --noEmit"
|
|
3237
|
+
},
|
|
3238
|
+
"lint-staged": {
|
|
3239
|
+
"src/**/*.ts": "prettier --write",
|
|
3240
|
+
"scripts/**/*.ts": "prettier --write",
|
|
3241
|
+
"tests/**/*.ts": "prettier --write"
|
|
3242
|
+
},
|
|
3243
|
+
dependencies: {
|
|
3244
|
+
ajv: "^8.17.1",
|
|
3245
|
+
"gray-matter": "^4.0.3",
|
|
3246
|
+
"js-yaml": "^4.1.0",
|
|
3247
|
+
pacote: "21.3.1",
|
|
3248
|
+
"simple-git": "^3.27.0"
|
|
3249
|
+
},
|
|
3250
|
+
devDependencies: {
|
|
3251
|
+
"@clack/prompts": "^0.11.0",
|
|
3252
|
+
"@codemcp/skills-core": "workspace:*",
|
|
3253
|
+
"@types/node": "^22.10.0",
|
|
3254
|
+
husky: "^9.1.7",
|
|
3255
|
+
"lint-staged": "^16.2.7",
|
|
3256
|
+
obuild: "^0.4.22",
|
|
3257
|
+
picocolors: "^1.1.1",
|
|
3258
|
+
prettier: "^3.8.1",
|
|
3259
|
+
tsup: "^8.0.0",
|
|
3260
|
+
typescript: "^5.9.3",
|
|
3261
|
+
vitest: "^4.0.17",
|
|
3262
|
+
"xdg-basedir": "^5.1.0"
|
|
3263
|
+
},
|
|
3264
|
+
keywords: [
|
|
3265
|
+
"agentskills",
|
|
3266
|
+
"cli",
|
|
3267
|
+
"skills-management"
|
|
3268
|
+
],
|
|
3269
|
+
author: "Oliver J\xE4gle <github@beimir.net>",
|
|
3270
|
+
license: "MIT",
|
|
3271
|
+
engines: {
|
|
3272
|
+
node: ">=18"
|
|
3273
|
+
}
|
|
3274
|
+
};
|
|
3275
|
+
|
|
3276
|
+
// src/add.ts
|
|
3277
|
+
var isCancelled = (value) => typeof value === "symbol";
|
|
3278
|
+
async function isSourcePrivate(source) {
|
|
3279
|
+
const ownerRepo = parseOwnerRepo(source);
|
|
3280
|
+
if (!ownerRepo) {
|
|
3281
|
+
return false;
|
|
3282
|
+
}
|
|
3283
|
+
return isRepoPrivate(ownerRepo.owner, ownerRepo.repo);
|
|
3284
|
+
}
|
|
3285
|
+
function initTelemetry(version2) {
|
|
3286
|
+
setVersion(version2);
|
|
3287
|
+
}
|
|
3288
|
+
function riskLabel(risk) {
|
|
3289
|
+
switch (risk) {
|
|
3290
|
+
case "critical":
|
|
3291
|
+
return import_picocolors3.default.red(import_picocolors3.default.bold("Critical Risk"));
|
|
3292
|
+
case "high":
|
|
3293
|
+
return import_picocolors3.default.red("High Risk");
|
|
3294
|
+
case "medium":
|
|
3295
|
+
return import_picocolors3.default.yellow("Med Risk");
|
|
3296
|
+
case "low":
|
|
3297
|
+
return import_picocolors3.default.green("Low Risk");
|
|
3298
|
+
case "safe":
|
|
3299
|
+
return import_picocolors3.default.green("Safe");
|
|
3300
|
+
default:
|
|
3301
|
+
return import_picocolors3.default.dim("--");
|
|
3302
|
+
}
|
|
3303
|
+
}
|
|
3304
|
+
function socketLabel(audit) {
|
|
3305
|
+
if (!audit) return import_picocolors3.default.dim("--");
|
|
3306
|
+
const count = audit.alerts ?? 0;
|
|
3307
|
+
return count > 0 ? import_picocolors3.default.red(`${count} alert${count !== 1 ? "s" : ""}`) : import_picocolors3.default.green("0 alerts");
|
|
3308
|
+
}
|
|
3309
|
+
function padEnd(str, width) {
|
|
3310
|
+
const visible = str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
3311
|
+
const pad = Math.max(0, width - visible.length);
|
|
3312
|
+
return str + " ".repeat(pad);
|
|
3313
|
+
}
|
|
3314
|
+
function buildSecurityLines(auditData, skills, source) {
|
|
3315
|
+
if (!auditData) return [];
|
|
3316
|
+
const hasAny = skills.some((s) => {
|
|
3317
|
+
const data = auditData[s.slug];
|
|
3318
|
+
return data && Object.keys(data).length > 0;
|
|
3319
|
+
});
|
|
3320
|
+
if (!hasAny) return [];
|
|
3321
|
+
const nameWidth = Math.min(Math.max(...skills.map((s) => s.displayName.length)), 36);
|
|
3322
|
+
const lines = [];
|
|
3323
|
+
const header = padEnd("", nameWidth + 2) + padEnd(import_picocolors3.default.dim("Gen"), 18) + padEnd(import_picocolors3.default.dim("Socket"), 18) + import_picocolors3.default.dim("Snyk");
|
|
3324
|
+
lines.push(header);
|
|
3325
|
+
for (const skill of skills) {
|
|
3326
|
+
const data = auditData[skill.slug];
|
|
3327
|
+
const name = skill.displayName.length > nameWidth ? skill.displayName.slice(0, nameWidth - 1) + "\u2026" : skill.displayName;
|
|
3328
|
+
const ath = data?.ath ? riskLabel(data.ath.risk) : import_picocolors3.default.dim("--");
|
|
3329
|
+
const socket = data?.socket ? socketLabel(data.socket) : import_picocolors3.default.dim("--");
|
|
3330
|
+
const snyk = data?.snyk ? riskLabel(data.snyk.risk) : import_picocolors3.default.dim("--");
|
|
3331
|
+
lines.push(padEnd(import_picocolors3.default.cyan(name), nameWidth + 2) + padEnd(ath, 18) + padEnd(socket, 18) + snyk);
|
|
3332
|
+
}
|
|
3333
|
+
lines.push("");
|
|
3334
|
+
lines.push(`${import_picocolors3.default.dim("Details:")} ${import_picocolors3.default.dim(`https://skills.sh/${source}`)}`);
|
|
3335
|
+
return lines;
|
|
3336
|
+
}
|
|
3337
|
+
function shortenPath(fullPath, cwd) {
|
|
3338
|
+
const home2 = homedir4();
|
|
3339
|
+
if (fullPath === home2 || fullPath.startsWith(home2 + sep5)) {
|
|
3340
|
+
return "~" + fullPath.slice(home2.length);
|
|
3341
|
+
}
|
|
3342
|
+
if (fullPath === cwd || fullPath.startsWith(cwd + sep5)) {
|
|
3343
|
+
return "." + fullPath.slice(cwd.length);
|
|
3344
|
+
}
|
|
3345
|
+
return fullPath;
|
|
3346
|
+
}
|
|
3347
|
+
function formatList(items, maxShow = 5) {
|
|
3348
|
+
if (items.length <= maxShow) {
|
|
3349
|
+
return items.join(", ");
|
|
3350
|
+
}
|
|
3351
|
+
const shown = items.slice(0, maxShow);
|
|
3352
|
+
const remaining = items.length - maxShow;
|
|
3353
|
+
return `${shown.join(", ")} +${remaining} more`;
|
|
3354
|
+
}
|
|
3355
|
+
function splitAgentsByType(agentTypes) {
|
|
3356
|
+
const universal = [];
|
|
3357
|
+
const symlinked = [];
|
|
3358
|
+
for (const a of agentTypes) {
|
|
3359
|
+
if (isUniversalAgent(a)) {
|
|
3360
|
+
universal.push(agents[a].displayName);
|
|
3361
|
+
} else {
|
|
3362
|
+
symlinked.push(agents[a].displayName);
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
return { universal, symlinked };
|
|
3366
|
+
}
|
|
3367
|
+
function buildAgentSummaryLines(targetAgents, installMode) {
|
|
3368
|
+
const lines = [];
|
|
3369
|
+
const { universal, symlinked } = splitAgentsByType(targetAgents);
|
|
3370
|
+
if (installMode === "mcp-server") {
|
|
3371
|
+
lines.push(` ${import_picocolors3.default.dim("mcp-server \u2192")} @codemcp/skills-server`);
|
|
3372
|
+
} else if (installMode === "symlink") {
|
|
3373
|
+
if (universal.length > 0) {
|
|
3374
|
+
lines.push(` ${import_picocolors3.default.green("universal:")} ${formatList(universal)}`);
|
|
3375
|
+
}
|
|
3376
|
+
if (symlinked.length > 0) {
|
|
3377
|
+
lines.push(` ${import_picocolors3.default.dim("symlink \u2192")} ${formatList(symlinked)}`);
|
|
3378
|
+
}
|
|
3379
|
+
} else {
|
|
3380
|
+
const allNames = targetAgents.map((a) => agents[a].displayName);
|
|
3381
|
+
lines.push(` ${import_picocolors3.default.dim("copy \u2192")} ${formatList(allNames)}`);
|
|
3382
|
+
}
|
|
3383
|
+
return lines;
|
|
3384
|
+
}
|
|
3385
|
+
function ensureUniversalAgents(targetAgents) {
|
|
3386
|
+
const universalAgents = getUniversalAgents();
|
|
3387
|
+
const result = [...targetAgents];
|
|
3388
|
+
for (const ua of universalAgents) {
|
|
3389
|
+
if (!result.includes(ua)) {
|
|
3390
|
+
result.push(ua);
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
return result;
|
|
3394
|
+
}
|
|
3395
|
+
function buildResultLines(results, targetAgents) {
|
|
3396
|
+
const lines = [];
|
|
3397
|
+
const isMcpMode = results.length > 0 && results[0].mode === "mcp-server";
|
|
3398
|
+
if (isMcpMode) {
|
|
3399
|
+
lines.push(` ${import_picocolors3.default.dim("Important:")} Make sure your agent has configured`);
|
|
3400
|
+
lines.push(` ${import_picocolors3.default.cyan("@codemcp/skills-server")} as MCP server.`);
|
|
3401
|
+
lines.push(` Then, the skill will automatically be picked up`);
|
|
3402
|
+
} else {
|
|
3403
|
+
const { universal, symlinked: symlinkAgents } = splitAgentsByType(targetAgents);
|
|
3404
|
+
const successfulSymlinks = results.filter((r2) => !r2.symlinkFailed && !universal.includes(r2.agent)).map((r2) => r2.agent);
|
|
3405
|
+
const failedSymlinks = results.filter((r2) => r2.symlinkFailed).map((r2) => r2.agent);
|
|
3406
|
+
if (universal.length > 0) {
|
|
3407
|
+
lines.push(` ${import_picocolors3.default.green("universal:")} ${formatList(universal)}`);
|
|
3408
|
+
}
|
|
3409
|
+
if (successfulSymlinks.length > 0) {
|
|
3410
|
+
lines.push(` ${import_picocolors3.default.dim("symlinked:")} ${formatList(successfulSymlinks)}`);
|
|
3411
|
+
}
|
|
3412
|
+
if (failedSymlinks.length > 0) {
|
|
3413
|
+
lines.push(` ${import_picocolors3.default.yellow("copied:")} ${formatList(failedSymlinks)}`);
|
|
3414
|
+
}
|
|
3415
|
+
}
|
|
3416
|
+
return lines;
|
|
3417
|
+
}
|
|
3418
|
+
function multiselect(opts) {
|
|
3419
|
+
return fe({
|
|
3420
|
+
...opts,
|
|
3421
|
+
// Cast is safe: our options always have labels, which satisfies p.Option requirements
|
|
3422
|
+
options: opts.options,
|
|
3423
|
+
message: `${opts.message} ${import_picocolors3.default.dim("(space to toggle)")}`
|
|
3424
|
+
});
|
|
3425
|
+
}
|
|
3426
|
+
async function promptForAgents(message, choices) {
|
|
3427
|
+
let lastSelected;
|
|
3428
|
+
try {
|
|
3429
|
+
lastSelected = await getLastSelectedAgents();
|
|
3430
|
+
} catch {
|
|
3431
|
+
}
|
|
3432
|
+
const validAgents = choices.map((c) => c.value);
|
|
3433
|
+
const defaultAgents = ["claude-code", "opencode", "codex"];
|
|
3434
|
+
const defaultValues = defaultAgents.filter((a) => validAgents.includes(a));
|
|
3435
|
+
let initialValues = [];
|
|
3436
|
+
if (lastSelected && lastSelected.length > 0) {
|
|
3437
|
+
initialValues = lastSelected.filter((a) => validAgents.includes(a));
|
|
3438
|
+
}
|
|
3439
|
+
if (initialValues.length === 0) {
|
|
3440
|
+
initialValues = defaultValues;
|
|
3441
|
+
}
|
|
3442
|
+
const selected = await searchMultiselect({
|
|
3443
|
+
message,
|
|
3444
|
+
items: choices,
|
|
3445
|
+
initialSelected: initialValues,
|
|
3446
|
+
required: true
|
|
3447
|
+
});
|
|
3448
|
+
if (!isCancelled(selected)) {
|
|
3449
|
+
try {
|
|
3450
|
+
await saveSelectedAgents(selected);
|
|
3451
|
+
} catch {
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3454
|
+
return selected;
|
|
3455
|
+
}
|
|
3456
|
+
async function selectAgentsInteractive(options) {
|
|
3457
|
+
const supportsGlobalFilter = (a) => !options.global || agents[a].globalSkillsDir;
|
|
3458
|
+
const universalAgents = getUniversalAgents().filter(supportsGlobalFilter);
|
|
3459
|
+
const otherAgents = getNonUniversalAgents().filter(supportsGlobalFilter);
|
|
3460
|
+
const universalSection = {
|
|
3461
|
+
title: "Universal (.agentskills/skills)",
|
|
3462
|
+
items: universalAgents.map((a) => ({
|
|
3463
|
+
value: a,
|
|
3464
|
+
label: agents[a].displayName
|
|
3465
|
+
}))
|
|
3466
|
+
};
|
|
3467
|
+
const otherChoices = otherAgents.map((a) => ({
|
|
3468
|
+
value: a,
|
|
3469
|
+
label: agents[a].displayName,
|
|
3470
|
+
hint: options.global ? agents[a].globalSkillsDir : agents[a].skillsDir
|
|
3471
|
+
}));
|
|
3472
|
+
let lastSelected;
|
|
3473
|
+
try {
|
|
3474
|
+
lastSelected = await getLastSelectedAgents();
|
|
3475
|
+
} catch {
|
|
3476
|
+
}
|
|
3477
|
+
const initialSelected = lastSelected ? lastSelected.filter(
|
|
3478
|
+
(a) => otherAgents.includes(a) && !universalAgents.includes(a)
|
|
3479
|
+
) : [];
|
|
3480
|
+
const selected = await searchMultiselect({
|
|
3481
|
+
message: "Which agents do you want to install to?",
|
|
3482
|
+
items: otherChoices,
|
|
3483
|
+
initialSelected,
|
|
3484
|
+
lockedSection: universalSection
|
|
3485
|
+
});
|
|
3486
|
+
if (!isCancelled(selected)) {
|
|
3487
|
+
try {
|
|
3488
|
+
await saveSelectedAgents(selected);
|
|
3489
|
+
} catch {
|
|
3490
|
+
}
|
|
3491
|
+
}
|
|
3492
|
+
return selected;
|
|
3493
|
+
}
|
|
3494
|
+
var version = package_default.version;
|
|
3495
|
+
setVersion(version);
|
|
3496
|
+
async function handleWellKnownSkills(source, url, options, spinner) {
|
|
3497
|
+
spinner.start("Discovering skills from well-known endpoint...");
|
|
3498
|
+
const skills = await wellKnownProvider.fetchAllSkills(url);
|
|
3499
|
+
if (skills.length === 0) {
|
|
3500
|
+
spinner.stop(import_picocolors3.default.red("No skills found"));
|
|
3501
|
+
Se(
|
|
3502
|
+
import_picocolors3.default.red(
|
|
3503
|
+
"No skills found at this URL. Make sure the server has a /.well-known/skills/index.json file."
|
|
3504
|
+
)
|
|
3505
|
+
);
|
|
3506
|
+
process.exit(1);
|
|
3507
|
+
}
|
|
3508
|
+
spinner.stop(`Found ${import_picocolors3.default.green(skills.length)} skill${skills.length > 1 ? "s" : ""}`);
|
|
3509
|
+
for (const skill of skills) {
|
|
3510
|
+
M2.info(`Skill: ${import_picocolors3.default.cyan(skill.installName)}`);
|
|
3511
|
+
M2.message(import_picocolors3.default.dim(skill.description));
|
|
3512
|
+
if (skill.files.size > 1) {
|
|
3513
|
+
M2.message(import_picocolors3.default.dim(` Files: ${Array.from(skill.files.keys()).join(", ")}`));
|
|
3514
|
+
}
|
|
3515
|
+
}
|
|
3516
|
+
if (options.list) {
|
|
3517
|
+
console.log();
|
|
3518
|
+
M2.step(import_picocolors3.default.bold("Available Skills"));
|
|
3519
|
+
for (const skill of skills) {
|
|
3520
|
+
M2.message(` ${import_picocolors3.default.cyan(skill.installName)}`);
|
|
3521
|
+
M2.message(` ${import_picocolors3.default.dim(skill.description)}`);
|
|
3522
|
+
if (skill.files.size > 1) {
|
|
3523
|
+
M2.message(` ${import_picocolors3.default.dim(`Files: ${skill.files.size}`)}`);
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
console.log();
|
|
3527
|
+
Se("Run without --list to install");
|
|
3528
|
+
process.exit(0);
|
|
3529
|
+
}
|
|
3530
|
+
let selectedSkills;
|
|
3531
|
+
if (options.skill?.includes("*")) {
|
|
3532
|
+
selectedSkills = skills;
|
|
3533
|
+
M2.info(`Installing all ${skills.length} skills`);
|
|
3534
|
+
} else if (options.skill && options.skill.length > 0) {
|
|
3535
|
+
selectedSkills = skills.filter(
|
|
3536
|
+
(s) => options.skill.some(
|
|
3537
|
+
(name) => s.installName.toLowerCase() === name.toLowerCase() || s.name.toLowerCase() === name.toLowerCase()
|
|
3538
|
+
)
|
|
3539
|
+
);
|
|
3540
|
+
if (selectedSkills.length === 0) {
|
|
3541
|
+
M2.error(`No matching skills found for: ${options.skill.join(", ")}`);
|
|
3542
|
+
M2.info("Available skills:");
|
|
3543
|
+
for (const s of skills) {
|
|
3544
|
+
M2.message(` - ${s.installName}`);
|
|
3545
|
+
}
|
|
3546
|
+
process.exit(1);
|
|
3547
|
+
}
|
|
3548
|
+
} else if (skills.length === 1) {
|
|
3549
|
+
selectedSkills = skills;
|
|
3550
|
+
const firstSkill = skills[0];
|
|
3551
|
+
M2.info(`Skill: ${import_picocolors3.default.cyan(firstSkill.installName)}`);
|
|
3552
|
+
} else if (options.yes) {
|
|
3553
|
+
selectedSkills = skills;
|
|
3554
|
+
M2.info(`Installing all ${skills.length} skills`);
|
|
3555
|
+
} else {
|
|
3556
|
+
const skillChoices = skills.map((s) => ({
|
|
3557
|
+
value: s,
|
|
3558
|
+
label: s.installName,
|
|
3559
|
+
hint: s.description.length > 60 ? s.description.slice(0, 57) + "..." : s.description
|
|
3560
|
+
}));
|
|
3561
|
+
const selected = await multiselect({
|
|
3562
|
+
message: "Select skills to install",
|
|
3563
|
+
options: skillChoices,
|
|
3564
|
+
required: true
|
|
3565
|
+
});
|
|
3566
|
+
if (pD(selected)) {
|
|
3567
|
+
xe("Installation cancelled");
|
|
3568
|
+
process.exit(0);
|
|
3569
|
+
}
|
|
3570
|
+
selectedSkills = selected;
|
|
3571
|
+
}
|
|
3572
|
+
let targetAgents;
|
|
3573
|
+
const validAgents = Object.keys(agents);
|
|
3574
|
+
if (options.agent?.includes("*")) {
|
|
3575
|
+
targetAgents = validAgents;
|
|
3576
|
+
M2.info(`Installing to all ${targetAgents.length} agents`);
|
|
3577
|
+
} else if (options.agent && options.agent.length > 0) {
|
|
3578
|
+
const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
|
|
3579
|
+
if (invalidAgents.length > 0) {
|
|
3580
|
+
M2.error(`Invalid agents: ${invalidAgents.join(", ")}`);
|
|
3581
|
+
M2.info(`Valid agents: ${validAgents.join(", ")}`);
|
|
3582
|
+
process.exit(1);
|
|
3583
|
+
}
|
|
3584
|
+
targetAgents = options.agent;
|
|
3585
|
+
} else {
|
|
3586
|
+
spinner.start("Loading agents...");
|
|
3587
|
+
const installedAgents = await detectInstalledAgents();
|
|
3588
|
+
const totalAgents = Object.keys(agents).length;
|
|
3589
|
+
spinner.stop(`${totalAgents} agents`);
|
|
3590
|
+
if (installedAgents.length === 0) {
|
|
3591
|
+
if (options.yes) {
|
|
3592
|
+
targetAgents = validAgents;
|
|
3593
|
+
M2.info("Installing to all agents");
|
|
3594
|
+
} else {
|
|
3595
|
+
M2.info("Select agents to install skills to");
|
|
3596
|
+
const allAgentChoices = Object.entries(agents).map(([key, config]) => ({
|
|
3597
|
+
value: key,
|
|
3598
|
+
label: config.displayName
|
|
3599
|
+
}));
|
|
3600
|
+
const selected = await promptForAgents(
|
|
3601
|
+
"Which agents do you want to install to?",
|
|
3602
|
+
allAgentChoices
|
|
3603
|
+
);
|
|
3604
|
+
if (pD(selected)) {
|
|
3605
|
+
xe("Installation cancelled");
|
|
3606
|
+
process.exit(0);
|
|
3607
|
+
}
|
|
3608
|
+
targetAgents = selected;
|
|
3609
|
+
}
|
|
3610
|
+
} else if (installedAgents.length === 1 || options.yes) {
|
|
3611
|
+
targetAgents = ensureUniversalAgents(installedAgents);
|
|
3612
|
+
if (installedAgents.length === 1) {
|
|
3613
|
+
const firstAgent = installedAgents[0];
|
|
3614
|
+
M2.info(`Installing to: ${import_picocolors3.default.cyan(agents[firstAgent].displayName)}`);
|
|
3615
|
+
} else {
|
|
3616
|
+
M2.info(
|
|
3617
|
+
`Installing to: ${installedAgents.map((a) => import_picocolors3.default.cyan(agents[a].displayName)).join(", ")}`
|
|
3618
|
+
);
|
|
3619
|
+
}
|
|
3620
|
+
} else {
|
|
3621
|
+
const selected = await selectAgentsInteractive({ global: options.global });
|
|
3622
|
+
if (pD(selected)) {
|
|
3623
|
+
xe("Installation cancelled");
|
|
3624
|
+
process.exit(0);
|
|
3625
|
+
}
|
|
3626
|
+
targetAgents = selected;
|
|
3627
|
+
}
|
|
3628
|
+
}
|
|
3629
|
+
let installGlobally = options.global ?? false;
|
|
3630
|
+
const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== void 0);
|
|
3631
|
+
if (options.global === void 0 && !options.yes && supportsGlobal) {
|
|
3632
|
+
const scope = await ve({
|
|
3633
|
+
message: "Installation scope",
|
|
3634
|
+
options: [
|
|
3635
|
+
{
|
|
3636
|
+
value: false,
|
|
3637
|
+
label: "Project",
|
|
3638
|
+
hint: "Install in current directory (committed with your project)"
|
|
3639
|
+
},
|
|
3640
|
+
{
|
|
3641
|
+
value: true,
|
|
3642
|
+
label: "Global",
|
|
3643
|
+
hint: "Install in home directory (available across all projects)"
|
|
3644
|
+
}
|
|
3645
|
+
]
|
|
3646
|
+
});
|
|
3647
|
+
if (pD(scope)) {
|
|
3648
|
+
xe("Installation cancelled");
|
|
3649
|
+
process.exit(0);
|
|
3650
|
+
}
|
|
3651
|
+
installGlobally = scope;
|
|
3652
|
+
}
|
|
3653
|
+
const installMode = "mcp-server";
|
|
3654
|
+
const cwd = process.cwd();
|
|
3655
|
+
const summaryLines = [];
|
|
3656
|
+
const agentNames = targetAgents.map((a) => agents[a].displayName);
|
|
3657
|
+
const overwriteChecks = await Promise.all(
|
|
3658
|
+
selectedSkills.flatMap(
|
|
3659
|
+
(skill) => targetAgents.map(async (agent) => ({
|
|
3660
|
+
skillName: skill.installName,
|
|
3661
|
+
agent,
|
|
3662
|
+
installed: await isSkillInstalled(skill.installName, agent, { global: installGlobally })
|
|
3663
|
+
}))
|
|
3664
|
+
)
|
|
3665
|
+
);
|
|
3666
|
+
const overwriteStatus = /* @__PURE__ */ new Map();
|
|
3667
|
+
for (const { skillName, agent, installed } of overwriteChecks) {
|
|
3668
|
+
if (!overwriteStatus.has(skillName)) {
|
|
3669
|
+
overwriteStatus.set(skillName, /* @__PURE__ */ new Map());
|
|
3670
|
+
}
|
|
3671
|
+
overwriteStatus.get(skillName).set(agent, installed);
|
|
3672
|
+
}
|
|
3673
|
+
for (const skill of selectedSkills) {
|
|
3674
|
+
if (summaryLines.length > 0) summaryLines.push("");
|
|
3675
|
+
const canonicalPath = getCanonicalPath(skill.installName, { global: installGlobally });
|
|
3676
|
+
const shortCanonical = shortenPath(canonicalPath, cwd);
|
|
3677
|
+
summaryLines.push(`${import_picocolors3.default.cyan(shortCanonical)}`);
|
|
3678
|
+
summaryLines.push(...buildAgentSummaryLines(targetAgents, installMode));
|
|
3679
|
+
if (skill.files.size > 1) {
|
|
3680
|
+
summaryLines.push(` ${import_picocolors3.default.dim("files:")} ${skill.files.size}`);
|
|
3681
|
+
}
|
|
3682
|
+
const skillOverwrites = overwriteStatus.get(skill.installName);
|
|
3683
|
+
const overwriteAgents = targetAgents.filter((a) => skillOverwrites?.get(a)).map((a) => agents[a].displayName);
|
|
3684
|
+
if (overwriteAgents.length > 0) {
|
|
3685
|
+
summaryLines.push(` ${import_picocolors3.default.yellow("overwrites:")} ${formatList(overwriteAgents)}`);
|
|
3686
|
+
}
|
|
3687
|
+
}
|
|
3688
|
+
console.log();
|
|
3689
|
+
Me(summaryLines.join("\n"), "Installation Summary");
|
|
3690
|
+
if (!options.yes) {
|
|
3691
|
+
const confirmed = await ye({ message: "Proceed with installation?" });
|
|
3692
|
+
if (pD(confirmed) || !confirmed) {
|
|
3693
|
+
xe("Installation cancelled");
|
|
3694
|
+
process.exit(0);
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3697
|
+
spinner.start("Installing skills...");
|
|
3698
|
+
const results = [];
|
|
3699
|
+
for (const skill of selectedSkills) {
|
|
3700
|
+
for (const agent of targetAgents) {
|
|
3701
|
+
const result = await installWellKnownSkillForAgent(skill, agent, {
|
|
3702
|
+
global: installGlobally,
|
|
3703
|
+
mode: installMode
|
|
3704
|
+
});
|
|
3705
|
+
results.push({
|
|
3706
|
+
skill: skill.installName,
|
|
3707
|
+
agent: agents[agent].displayName,
|
|
3708
|
+
...result
|
|
3709
|
+
});
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
spinner.stop("Installation complete");
|
|
3713
|
+
console.log();
|
|
3714
|
+
const successful = results.filter((r2) => r2.success);
|
|
3715
|
+
const failed = results.filter((r2) => !r2.success);
|
|
3716
|
+
const sourceIdentifier = wellKnownProvider.getSourceIdentifier(url);
|
|
3717
|
+
const skillFiles = {};
|
|
3718
|
+
for (const skill of selectedSkills) {
|
|
3719
|
+
skillFiles[skill.installName] = skill.sourceUrl;
|
|
3720
|
+
}
|
|
3721
|
+
const isPrivate = await isSourcePrivate(sourceIdentifier);
|
|
3722
|
+
if (isPrivate !== true) {
|
|
3723
|
+
track({
|
|
3724
|
+
event: "install",
|
|
3725
|
+
source: sourceIdentifier,
|
|
3726
|
+
skills: selectedSkills.map((s) => s.installName).join(","),
|
|
3727
|
+
agents: targetAgents.join(","),
|
|
3728
|
+
...installGlobally && { global: "1" },
|
|
3729
|
+
skillFiles: JSON.stringify(skillFiles),
|
|
3730
|
+
sourceType: "well-known"
|
|
3731
|
+
});
|
|
3732
|
+
}
|
|
3733
|
+
if (successful.length > 0 && installGlobally) {
|
|
3734
|
+
const successfulSkillNames = new Set(successful.map((r2) => r2.skill));
|
|
3735
|
+
for (const skill of selectedSkills) {
|
|
3736
|
+
if (successfulSkillNames.has(skill.installName)) {
|
|
3737
|
+
try {
|
|
3738
|
+
await addSkillToLock(skill.installName, {
|
|
3739
|
+
source: sourceIdentifier,
|
|
3740
|
+
sourceType: "well-known",
|
|
3741
|
+
sourceUrl: skill.sourceUrl,
|
|
3742
|
+
skillFolderHash: ""
|
|
3743
|
+
// Well-known skills don't have a folder hash
|
|
3744
|
+
});
|
|
3745
|
+
} catch {
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3748
|
+
}
|
|
3749
|
+
}
|
|
3750
|
+
if (successful.length > 0 && !installGlobally) {
|
|
3751
|
+
const successfulSkillNames = new Set(successful.map((r2) => r2.skill));
|
|
3752
|
+
for (const skill of selectedSkills) {
|
|
3753
|
+
if (successfulSkillNames.has(skill.installName)) {
|
|
3754
|
+
try {
|
|
3755
|
+
const matchingResult = successful.find((r2) => r2.skill === skill.installName);
|
|
3756
|
+
const installDir = matchingResult?.canonicalPath || matchingResult?.path;
|
|
3757
|
+
if (installDir) {
|
|
3758
|
+
const computedHash = await computeSkillFolderHash(installDir);
|
|
3759
|
+
await addSkillToLocalLock(
|
|
3760
|
+
skill.installName,
|
|
3761
|
+
{
|
|
3762
|
+
source: sourceIdentifier,
|
|
3763
|
+
sourceType: "well-known",
|
|
3764
|
+
computedHash
|
|
3765
|
+
},
|
|
3766
|
+
cwd
|
|
3767
|
+
);
|
|
3768
|
+
}
|
|
3769
|
+
} catch {
|
|
3770
|
+
}
|
|
3771
|
+
}
|
|
3772
|
+
}
|
|
3773
|
+
}
|
|
3774
|
+
if (successful.length > 0) {
|
|
3775
|
+
const bySkill = /* @__PURE__ */ new Map();
|
|
3776
|
+
for (const r2 of successful) {
|
|
3777
|
+
const skillResults = bySkill.get(r2.skill) || [];
|
|
3778
|
+
skillResults.push(r2);
|
|
3779
|
+
bySkill.set(r2.skill, skillResults);
|
|
3780
|
+
}
|
|
3781
|
+
const skillCount = bySkill.size;
|
|
3782
|
+
const symlinkFailures = successful.filter((r2) => r2.mode === "symlink" && r2.symlinkFailed);
|
|
3783
|
+
const copiedAgents = symlinkFailures.map((r2) => r2.agent);
|
|
3784
|
+
const resultLines = [];
|
|
3785
|
+
for (const [skillName, skillResults] of bySkill) {
|
|
3786
|
+
const firstResult = skillResults[0];
|
|
3787
|
+
if (firstResult.mode === "copy") {
|
|
3788
|
+
resultLines.push(`${import_picocolors3.default.green("\u2713")} ${skillName} ${import_picocolors3.default.dim("(copied)")}`);
|
|
3789
|
+
for (const r2 of skillResults) {
|
|
3790
|
+
const shortPath = shortenPath(r2.path, cwd);
|
|
3791
|
+
resultLines.push(` ${import_picocolors3.default.dim("\u2192")} ${shortPath}`);
|
|
3792
|
+
}
|
|
3793
|
+
} else {
|
|
3794
|
+
if (firstResult.canonicalPath) {
|
|
3795
|
+
const shortPath = shortenPath(firstResult.canonicalPath, cwd);
|
|
3796
|
+
resultLines.push(`${import_picocolors3.default.green("\u2713")} ${shortPath}`);
|
|
3797
|
+
} else {
|
|
3798
|
+
resultLines.push(`${import_picocolors3.default.green("\u2713")} ${skillName}`);
|
|
3799
|
+
}
|
|
3800
|
+
resultLines.push(...buildResultLines(skillResults, targetAgents));
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
const title = import_picocolors3.default.green(`Installed ${skillCount} skill${skillCount !== 1 ? "s" : ""}`);
|
|
3804
|
+
Me(resultLines.join("\n"), title);
|
|
3805
|
+
if (symlinkFailures.length > 0) {
|
|
3806
|
+
M2.warn(import_picocolors3.default.yellow(`Symlinks failed for: ${formatList(copiedAgents)}`));
|
|
3807
|
+
M2.message(
|
|
3808
|
+
import_picocolors3.default.dim(
|
|
3809
|
+
" Files were copied instead. On Windows, enable Developer Mode for symlink support."
|
|
3810
|
+
)
|
|
3811
|
+
);
|
|
3812
|
+
}
|
|
3813
|
+
}
|
|
3814
|
+
if (failed.length > 0) {
|
|
3815
|
+
console.log();
|
|
3816
|
+
M2.error(import_picocolors3.default.red(`Failed to install ${failed.length}`));
|
|
3817
|
+
for (const r2 of failed) {
|
|
3818
|
+
M2.message(` ${import_picocolors3.default.red("\u2717")} ${r2.skill} \u2192 ${r2.agent}: ${import_picocolors3.default.dim(r2.error)}`);
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
console.log();
|
|
3822
|
+
Se(
|
|
3823
|
+
import_picocolors3.default.green("Done!") + import_picocolors3.default.dim(" Review skills before use; they run with full agent permissions.")
|
|
3824
|
+
);
|
|
3825
|
+
await promptForFindSkills(options, targetAgents);
|
|
3826
|
+
}
|
|
3827
|
+
async function runAdd(args, options = {}) {
|
|
3828
|
+
const source = args[0];
|
|
3829
|
+
let installTipShown = false;
|
|
3830
|
+
const showInstallTip = () => {
|
|
3831
|
+
if (installTipShown) return;
|
|
3832
|
+
M2.message(
|
|
3833
|
+
import_picocolors3.default.dim("Tip: use the --yes (-y) and --global (-g) flags to install without prompts.")
|
|
3834
|
+
);
|
|
3835
|
+
installTipShown = true;
|
|
3836
|
+
};
|
|
3837
|
+
if (!source) {
|
|
3838
|
+
console.log();
|
|
3839
|
+
console.log(
|
|
3840
|
+
import_picocolors3.default.bgRed(import_picocolors3.default.white(import_picocolors3.default.bold(" ERROR "))) + " " + import_picocolors3.default.red("Missing required argument: source")
|
|
3841
|
+
);
|
|
3842
|
+
console.log();
|
|
3843
|
+
console.log(import_picocolors3.default.dim(" Usage:"));
|
|
3844
|
+
console.log(
|
|
3845
|
+
` ${import_picocolors3.default.cyan("npx @codemcp/skills add")} ${import_picocolors3.default.yellow("<source>")} ${import_picocolors3.default.dim("[options]")}`
|
|
3846
|
+
);
|
|
3847
|
+
console.log();
|
|
3848
|
+
console.log(import_picocolors3.default.dim(" Example:"));
|
|
3849
|
+
console.log(
|
|
3850
|
+
` ${import_picocolors3.default.cyan("npx @codemcp/skills add")} ${import_picocolors3.default.yellow("vercel-labs/agent-skills")}`
|
|
3851
|
+
);
|
|
3852
|
+
console.log();
|
|
3853
|
+
process.exit(1);
|
|
3854
|
+
}
|
|
3855
|
+
if (options.all) {
|
|
3856
|
+
options.skill = ["*"];
|
|
3857
|
+
options.agent = ["*"];
|
|
3858
|
+
options.yes = true;
|
|
3859
|
+
}
|
|
3860
|
+
console.log();
|
|
3861
|
+
Ie(import_picocolors3.default.bgCyan(import_picocolors3.default.black(" skills ")));
|
|
3862
|
+
if (!process.stdin.isTTY) {
|
|
3863
|
+
showInstallTip();
|
|
3864
|
+
}
|
|
3865
|
+
let tempDir = null;
|
|
3866
|
+
try {
|
|
3867
|
+
const spinner = Y2();
|
|
3868
|
+
spinner.start("Parsing source...");
|
|
3869
|
+
const parsed = parseSource(source);
|
|
3870
|
+
spinner.stop(
|
|
3871
|
+
`Source: ${parsed.type === "local" ? parsed.localPath : parsed.url}${parsed.ref ? ` @ ${import_picocolors3.default.yellow(parsed.ref)}` : ""}${parsed.subpath ? ` (${parsed.subpath})` : ""}${parsed.skillFilter ? ` ${import_picocolors3.default.dim("@")}${import_picocolors3.default.cyan(parsed.skillFilter)}` : ""}`
|
|
3872
|
+
);
|
|
3873
|
+
if (parsed.type === "well-known") {
|
|
3874
|
+
await handleWellKnownSkills(source, parsed.url, options, spinner);
|
|
3875
|
+
return;
|
|
3876
|
+
}
|
|
3877
|
+
let skillsDir;
|
|
3878
|
+
if (parsed.type === "local") {
|
|
3879
|
+
spinner.start("Validating local path...");
|
|
3880
|
+
if (!existsSync2(parsed.localPath)) {
|
|
3881
|
+
spinner.stop(import_picocolors3.default.red("Path not found"));
|
|
3882
|
+
Se(import_picocolors3.default.red(`Local path does not exist: ${parsed.localPath}`));
|
|
3883
|
+
process.exit(1);
|
|
3884
|
+
}
|
|
3885
|
+
skillsDir = parsed.localPath;
|
|
3886
|
+
spinner.stop("Local path validated");
|
|
3887
|
+
} else {
|
|
3888
|
+
spinner.start("Cloning repository...");
|
|
3889
|
+
tempDir = await cloneRepo(parsed.url, parsed.ref);
|
|
3890
|
+
skillsDir = tempDir;
|
|
3891
|
+
spinner.stop("Repository cloned");
|
|
3892
|
+
}
|
|
3893
|
+
if (parsed.skillFilter) {
|
|
3894
|
+
options.skill = options.skill || [];
|
|
3895
|
+
if (!options.skill.includes(parsed.skillFilter)) {
|
|
3896
|
+
options.skill.push(parsed.skillFilter);
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3899
|
+
const includeInternal = !!(options.skill && options.skill.length > 0);
|
|
3900
|
+
spinner.start("Discovering skills...");
|
|
3901
|
+
const skills = await discoverSkills(skillsDir, parsed.subpath, {
|
|
3902
|
+
includeInternal,
|
|
3903
|
+
fullDepth: options.fullDepth
|
|
3904
|
+
});
|
|
3905
|
+
if (skills.length === 0) {
|
|
3906
|
+
spinner.stop(import_picocolors3.default.red("No skills found"));
|
|
3907
|
+
Se(
|
|
3908
|
+
import_picocolors3.default.red("No valid skills found. Skills require a SKILL.md with name and description.")
|
|
3909
|
+
);
|
|
3910
|
+
await cleanup(tempDir);
|
|
3911
|
+
process.exit(1);
|
|
3912
|
+
}
|
|
3913
|
+
spinner.stop(`Found ${import_picocolors3.default.green(skills.length)} skill${skills.length > 1 ? "s" : ""}`);
|
|
3914
|
+
if (options.list) {
|
|
3915
|
+
console.log();
|
|
3916
|
+
M2.step(import_picocolors3.default.bold("Available Skills"));
|
|
3917
|
+
const groupedSkills = {};
|
|
3918
|
+
const ungroupedSkills = [];
|
|
3919
|
+
for (const skill of skills) {
|
|
3920
|
+
if (skill.pluginName) {
|
|
3921
|
+
const group = skill.pluginName;
|
|
3922
|
+
if (!groupedSkills[group]) groupedSkills[group] = [];
|
|
3923
|
+
groupedSkills[group].push(skill);
|
|
3924
|
+
} else {
|
|
3925
|
+
ungroupedSkills.push(skill);
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3928
|
+
const sortedGroups2 = Object.keys(groupedSkills).sort();
|
|
3929
|
+
for (const group of sortedGroups2) {
|
|
3930
|
+
const title = group.split("-").map((w2) => w2.charAt(0).toUpperCase() + w2.slice(1)).join(" ");
|
|
3931
|
+
console.log(import_picocolors3.default.bold(title));
|
|
3932
|
+
for (const skill of groupedSkills[group]) {
|
|
3933
|
+
M2.message(` ${import_picocolors3.default.cyan(getSkillDisplayName(skill))}`);
|
|
3934
|
+
M2.message(` ${import_picocolors3.default.dim(skill.description)}`);
|
|
3935
|
+
}
|
|
3936
|
+
console.log();
|
|
3937
|
+
}
|
|
3938
|
+
if (ungroupedSkills.length > 0) {
|
|
3939
|
+
if (sortedGroups2.length > 0) console.log(import_picocolors3.default.bold("General"));
|
|
3940
|
+
for (const skill of ungroupedSkills) {
|
|
3941
|
+
M2.message(` ${import_picocolors3.default.cyan(getSkillDisplayName(skill))}`);
|
|
3942
|
+
M2.message(` ${import_picocolors3.default.dim(skill.description)}`);
|
|
3943
|
+
}
|
|
3944
|
+
}
|
|
3945
|
+
console.log();
|
|
3946
|
+
Se("Use --skill <name> to install specific skills");
|
|
3947
|
+
await cleanup(tempDir);
|
|
3948
|
+
process.exit(0);
|
|
3949
|
+
}
|
|
3950
|
+
let selectedSkills;
|
|
3951
|
+
if (options.skill?.includes("*")) {
|
|
3952
|
+
selectedSkills = skills;
|
|
3953
|
+
M2.info(`Installing all ${skills.length} skills`);
|
|
3954
|
+
} else if (options.skill && options.skill.length > 0) {
|
|
3955
|
+
selectedSkills = filterSkills(skills, options.skill);
|
|
3956
|
+
if (selectedSkills.length === 0) {
|
|
3957
|
+
M2.error(`No matching skills found for: ${options.skill.join(", ")}`);
|
|
3958
|
+
M2.info("Available skills:");
|
|
3959
|
+
for (const s of skills) {
|
|
3960
|
+
M2.message(` - ${getSkillDisplayName(s)}`);
|
|
3961
|
+
}
|
|
3962
|
+
await cleanup(tempDir);
|
|
3963
|
+
process.exit(1);
|
|
3964
|
+
}
|
|
3965
|
+
M2.info(
|
|
3966
|
+
`Selected ${selectedSkills.length} skill${selectedSkills.length !== 1 ? "s" : ""}: ${selectedSkills.map((s) => import_picocolors3.default.cyan(getSkillDisplayName(s))).join(", ")}`
|
|
3967
|
+
);
|
|
3968
|
+
} else if (skills.length === 1) {
|
|
3969
|
+
selectedSkills = skills;
|
|
3970
|
+
const firstSkill = skills[0];
|
|
3971
|
+
M2.info(`Skill: ${import_picocolors3.default.cyan(getSkillDisplayName(firstSkill))}`);
|
|
3972
|
+
M2.message(import_picocolors3.default.dim(firstSkill.description));
|
|
3973
|
+
} else if (options.yes) {
|
|
3974
|
+
selectedSkills = skills;
|
|
3975
|
+
M2.info(`Installing all ${skills.length} skills`);
|
|
3976
|
+
} else {
|
|
3977
|
+
const sortedSkills = [...skills].sort((a, b3) => {
|
|
3978
|
+
if (a.pluginName && !b3.pluginName) return -1;
|
|
3979
|
+
if (!a.pluginName && b3.pluginName) return 1;
|
|
3980
|
+
if (a.pluginName && b3.pluginName && a.pluginName !== b3.pluginName) {
|
|
3981
|
+
return a.pluginName.localeCompare(b3.pluginName);
|
|
3982
|
+
}
|
|
3983
|
+
return getSkillDisplayName(a).localeCompare(getSkillDisplayName(b3));
|
|
3984
|
+
});
|
|
3985
|
+
const hasGroups = sortedSkills.some((s) => s.pluginName);
|
|
3986
|
+
let selected;
|
|
3987
|
+
if (hasGroups) {
|
|
3988
|
+
const kebabToTitle = (s) => s.split("-").map((w2) => w2.charAt(0).toUpperCase() + w2.slice(1)).join(" ");
|
|
3989
|
+
const grouped = {};
|
|
3990
|
+
for (const s of sortedSkills) {
|
|
3991
|
+
const groupName = s.pluginName ? kebabToTitle(s.pluginName) : "Other";
|
|
3992
|
+
if (!grouped[groupName]) grouped[groupName] = [];
|
|
3993
|
+
grouped[groupName].push({
|
|
3994
|
+
value: s,
|
|
3995
|
+
label: getSkillDisplayName(s),
|
|
3996
|
+
hint: s.description.length > 60 ? s.description.slice(0, 57) + "..." : s.description
|
|
3997
|
+
});
|
|
3998
|
+
}
|
|
3999
|
+
selected = await be({
|
|
4000
|
+
message: `Select skills to install ${import_picocolors3.default.dim("(space to toggle)")}`,
|
|
4001
|
+
options: grouped,
|
|
4002
|
+
required: true
|
|
4003
|
+
});
|
|
4004
|
+
} else {
|
|
4005
|
+
const skillChoices = sortedSkills.map((s) => ({
|
|
4006
|
+
value: s,
|
|
4007
|
+
label: getSkillDisplayName(s),
|
|
4008
|
+
hint: s.description.length > 60 ? s.description.slice(0, 57) + "..." : s.description
|
|
4009
|
+
}));
|
|
4010
|
+
selected = await multiselect({
|
|
4011
|
+
message: "Select skills to install",
|
|
4012
|
+
options: skillChoices,
|
|
4013
|
+
required: true
|
|
4014
|
+
});
|
|
4015
|
+
}
|
|
4016
|
+
if (pD(selected)) {
|
|
4017
|
+
xe("Installation cancelled");
|
|
4018
|
+
await cleanup(tempDir);
|
|
4019
|
+
process.exit(0);
|
|
4020
|
+
}
|
|
4021
|
+
selectedSkills = selected;
|
|
4022
|
+
}
|
|
4023
|
+
const ownerRepoForAudit = getOwnerRepo(parsed);
|
|
4024
|
+
const auditPromise = ownerRepoForAudit ? fetchAuditData(
|
|
4025
|
+
ownerRepoForAudit,
|
|
4026
|
+
selectedSkills.map((s) => getSkillDisplayName(s))
|
|
4027
|
+
) : Promise.resolve(null);
|
|
4028
|
+
const targetAgents = getUniversalAgents();
|
|
4029
|
+
let installGlobally = options.global ?? false;
|
|
4030
|
+
const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== void 0);
|
|
4031
|
+
if (options.global === void 0 && !options.yes && supportsGlobal) {
|
|
4032
|
+
const scope = await ve({
|
|
4033
|
+
message: "Installation scope",
|
|
4034
|
+
options: [
|
|
4035
|
+
{
|
|
4036
|
+
value: false,
|
|
4037
|
+
label: "Project",
|
|
4038
|
+
hint: "Install in current directory (committed with your project)"
|
|
4039
|
+
},
|
|
4040
|
+
{
|
|
4041
|
+
value: true,
|
|
4042
|
+
label: "Global",
|
|
4043
|
+
hint: "Install in home directory (available across all projects)"
|
|
4044
|
+
}
|
|
4045
|
+
]
|
|
4046
|
+
});
|
|
4047
|
+
if (pD(scope)) {
|
|
4048
|
+
xe("Installation cancelled");
|
|
4049
|
+
await cleanup(tempDir);
|
|
4050
|
+
process.exit(0);
|
|
4051
|
+
}
|
|
4052
|
+
installGlobally = scope;
|
|
4053
|
+
}
|
|
4054
|
+
const installMode = "mcp-server";
|
|
4055
|
+
const cwd = process.cwd();
|
|
4056
|
+
const summaryLines = [];
|
|
4057
|
+
const agentNames = targetAgents.map((a) => agents[a].displayName);
|
|
4058
|
+
const overwriteChecks = await Promise.all(
|
|
4059
|
+
selectedSkills.flatMap(
|
|
4060
|
+
(skill) => targetAgents.map(async (agent) => ({
|
|
4061
|
+
skillName: skill.name,
|
|
4062
|
+
agent,
|
|
4063
|
+
installed: await isSkillInstalled(skill.name, agent, { global: installGlobally })
|
|
4064
|
+
}))
|
|
4065
|
+
)
|
|
4066
|
+
);
|
|
4067
|
+
const overwriteStatus = /* @__PURE__ */ new Map();
|
|
4068
|
+
for (const { skillName, agent, installed } of overwriteChecks) {
|
|
4069
|
+
if (!overwriteStatus.has(skillName)) {
|
|
4070
|
+
overwriteStatus.set(skillName, /* @__PURE__ */ new Map());
|
|
4071
|
+
}
|
|
4072
|
+
overwriteStatus.get(skillName).set(agent, installed);
|
|
4073
|
+
}
|
|
4074
|
+
const groupedSummary = {};
|
|
4075
|
+
const ungroupedSummary = [];
|
|
4076
|
+
for (const skill of selectedSkills) {
|
|
4077
|
+
if (skill.pluginName) {
|
|
4078
|
+
const group = skill.pluginName;
|
|
4079
|
+
if (!groupedSummary[group]) groupedSummary[group] = [];
|
|
4080
|
+
groupedSummary[group].push(skill);
|
|
4081
|
+
} else {
|
|
4082
|
+
ungroupedSummary.push(skill);
|
|
4083
|
+
}
|
|
4084
|
+
}
|
|
4085
|
+
const printSkillSummary = (skills2) => {
|
|
4086
|
+
for (const skill of skills2) {
|
|
4087
|
+
if (summaryLines.length > 0) summaryLines.push("");
|
|
4088
|
+
const canonicalPath = getCanonicalPath(skill.name, { global: installGlobally });
|
|
4089
|
+
const shortCanonical = shortenPath(canonicalPath, cwd);
|
|
4090
|
+
summaryLines.push(`${import_picocolors3.default.cyan(shortCanonical)}`);
|
|
4091
|
+
summaryLines.push(...buildAgentSummaryLines(targetAgents, installMode));
|
|
4092
|
+
const skillOverwrites = overwriteStatus.get(skill.name);
|
|
4093
|
+
const overwriteAgents = targetAgents.filter((a) => skillOverwrites?.get(a)).map((a) => agents[a].displayName);
|
|
4094
|
+
if (overwriteAgents.length > 0) {
|
|
4095
|
+
summaryLines.push(` ${import_picocolors3.default.yellow("overwrites:")} ${formatList(overwriteAgents)}`);
|
|
4096
|
+
}
|
|
4097
|
+
}
|
|
4098
|
+
};
|
|
4099
|
+
const sortedGroups = Object.keys(groupedSummary).sort();
|
|
4100
|
+
for (const group of sortedGroups) {
|
|
4101
|
+
const title = group.split("-").map((w2) => w2.charAt(0).toUpperCase() + w2.slice(1)).join(" ");
|
|
4102
|
+
summaryLines.push("");
|
|
4103
|
+
summaryLines.push(import_picocolors3.default.bold(title));
|
|
4104
|
+
printSkillSummary(groupedSummary[group]);
|
|
4105
|
+
}
|
|
4106
|
+
if (ungroupedSummary.length > 0) {
|
|
4107
|
+
if (sortedGroups.length > 0) {
|
|
4108
|
+
summaryLines.push("");
|
|
4109
|
+
summaryLines.push(import_picocolors3.default.bold("General"));
|
|
4110
|
+
}
|
|
4111
|
+
printSkillSummary(ungroupedSummary);
|
|
4112
|
+
}
|
|
4113
|
+
console.log();
|
|
4114
|
+
Me(summaryLines.join("\n"), "Installation Summary");
|
|
4115
|
+
try {
|
|
4116
|
+
const auditData = await auditPromise;
|
|
4117
|
+
if (auditData && ownerRepoForAudit) {
|
|
4118
|
+
const securityLines = buildSecurityLines(
|
|
4119
|
+
auditData,
|
|
4120
|
+
selectedSkills.map((s) => ({
|
|
4121
|
+
slug: getSkillDisplayName(s),
|
|
4122
|
+
displayName: getSkillDisplayName(s)
|
|
4123
|
+
})),
|
|
4124
|
+
ownerRepoForAudit
|
|
4125
|
+
);
|
|
4126
|
+
if (securityLines.length > 0) {
|
|
4127
|
+
Me(securityLines.join("\n"), "Security Risk Assessments");
|
|
4128
|
+
}
|
|
4129
|
+
}
|
|
4130
|
+
} catch {
|
|
4131
|
+
}
|
|
4132
|
+
if (!options.yes) {
|
|
4133
|
+
const confirmed = await ye({ message: "Proceed with installation?" });
|
|
4134
|
+
if (pD(confirmed) || !confirmed) {
|
|
4135
|
+
xe("Installation cancelled");
|
|
4136
|
+
await cleanup(tempDir);
|
|
4137
|
+
process.exit(0);
|
|
4138
|
+
}
|
|
4139
|
+
}
|
|
4140
|
+
spinner.start("Installing skills...");
|
|
4141
|
+
const results = [];
|
|
4142
|
+
for (const skill of selectedSkills) {
|
|
4143
|
+
for (const agent of targetAgents) {
|
|
4144
|
+
const result = await installSkillForAgent(skill, agent, {
|
|
4145
|
+
global: installGlobally,
|
|
4146
|
+
mode: installMode
|
|
4147
|
+
});
|
|
4148
|
+
results.push({
|
|
4149
|
+
skill: getSkillDisplayName(skill),
|
|
4150
|
+
agent: agents[agent].displayName,
|
|
4151
|
+
pluginName: skill.pluginName,
|
|
4152
|
+
...result
|
|
4153
|
+
});
|
|
4154
|
+
}
|
|
4155
|
+
}
|
|
4156
|
+
spinner.stop("Installation complete");
|
|
4157
|
+
console.log();
|
|
4158
|
+
const successful = results.filter((r2) => r2.success);
|
|
4159
|
+
const failed = results.filter((r2) => !r2.success);
|
|
4160
|
+
const skillFiles = {};
|
|
4161
|
+
for (const skill of selectedSkills) {
|
|
4162
|
+
let relativePath;
|
|
4163
|
+
if (tempDir && skill.path === tempDir) {
|
|
4164
|
+
relativePath = "SKILL.md";
|
|
4165
|
+
} else if (tempDir && skill.path.startsWith(tempDir + sep5)) {
|
|
4166
|
+
relativePath = skill.path.slice(tempDir.length + 1).split(sep5).join("/") + "/SKILL.md";
|
|
4167
|
+
} else {
|
|
4168
|
+
continue;
|
|
4169
|
+
}
|
|
4170
|
+
skillFiles[skill.name] = relativePath;
|
|
4171
|
+
}
|
|
4172
|
+
const normalizedSource = getOwnerRepo(parsed);
|
|
4173
|
+
const isSSH = parsed.url.startsWith("git@");
|
|
4174
|
+
const lockSource = isSSH ? parsed.url : normalizedSource;
|
|
4175
|
+
if (normalizedSource) {
|
|
4176
|
+
const ownerRepo = parseOwnerRepo(normalizedSource);
|
|
4177
|
+
if (ownerRepo) {
|
|
4178
|
+
const isPrivate = await isRepoPrivate(ownerRepo.owner, ownerRepo.repo);
|
|
4179
|
+
if (isPrivate === false) {
|
|
4180
|
+
track({
|
|
4181
|
+
event: "install",
|
|
4182
|
+
source: normalizedSource,
|
|
4183
|
+
skills: selectedSkills.map((s) => s.name).join(","),
|
|
4184
|
+
agents: targetAgents.join(","),
|
|
4185
|
+
...installGlobally && { global: "1" },
|
|
4186
|
+
skillFiles: JSON.stringify(skillFiles)
|
|
4187
|
+
});
|
|
4188
|
+
}
|
|
4189
|
+
} else {
|
|
4190
|
+
track({
|
|
4191
|
+
event: "install",
|
|
4192
|
+
source: normalizedSource,
|
|
4193
|
+
skills: selectedSkills.map((s) => s.name).join(","),
|
|
4194
|
+
agents: targetAgents.join(","),
|
|
4195
|
+
...installGlobally && { global: "1" },
|
|
4196
|
+
skillFiles: JSON.stringify(skillFiles)
|
|
4197
|
+
});
|
|
4198
|
+
}
|
|
4199
|
+
}
|
|
4200
|
+
if (successful.length > 0 && installGlobally && normalizedSource) {
|
|
4201
|
+
const successfulSkillNames = new Set(successful.map((r2) => r2.skill));
|
|
4202
|
+
for (const skill of selectedSkills) {
|
|
4203
|
+
const skillDisplayName = getSkillDisplayName(skill);
|
|
4204
|
+
if (successfulSkillNames.has(skillDisplayName)) {
|
|
4205
|
+
try {
|
|
4206
|
+
let skillFolderHash = "";
|
|
4207
|
+
const skillPathValue = skillFiles[skill.name];
|
|
4208
|
+
if (parsed.type === "github" && skillPathValue) {
|
|
4209
|
+
const token = getGitHubToken();
|
|
4210
|
+
const hash = await fetchSkillFolderHash(normalizedSource, skillPathValue, token);
|
|
4211
|
+
if (hash) skillFolderHash = hash;
|
|
4212
|
+
}
|
|
4213
|
+
await addSkillToLock(skill.name, {
|
|
4214
|
+
source: lockSource || normalizedSource,
|
|
4215
|
+
sourceType: parsed.type,
|
|
4216
|
+
sourceUrl: parsed.url,
|
|
4217
|
+
skillPath: skillPathValue,
|
|
4218
|
+
skillFolderHash,
|
|
4219
|
+
pluginName: skill.pluginName
|
|
4220
|
+
});
|
|
4221
|
+
} catch {
|
|
4222
|
+
}
|
|
4223
|
+
}
|
|
4224
|
+
}
|
|
4225
|
+
}
|
|
4226
|
+
if (successful.length > 0 && !installGlobally) {
|
|
4227
|
+
const successfulSkillNames = new Set(successful.map((r2) => r2.skill));
|
|
4228
|
+
for (const skill of selectedSkills) {
|
|
4229
|
+
const skillDisplayName = getSkillDisplayName(skill);
|
|
4230
|
+
if (successfulSkillNames.has(skillDisplayName)) {
|
|
4231
|
+
try {
|
|
4232
|
+
const computedHash = await computeSkillFolderHash(skill.path);
|
|
4233
|
+
await addSkillToLocalLock(
|
|
4234
|
+
skill.name,
|
|
4235
|
+
{
|
|
4236
|
+
source: lockSource || parsed.url,
|
|
4237
|
+
sourceType: parsed.type,
|
|
4238
|
+
computedHash
|
|
4239
|
+
},
|
|
4240
|
+
cwd
|
|
4241
|
+
);
|
|
4242
|
+
} catch {
|
|
4243
|
+
}
|
|
4244
|
+
}
|
|
4245
|
+
}
|
|
4246
|
+
}
|
|
4247
|
+
if (successful.length > 0) {
|
|
4248
|
+
const bySkill = /* @__PURE__ */ new Map();
|
|
4249
|
+
const groupedResults = {};
|
|
4250
|
+
const ungroupedResults = [];
|
|
4251
|
+
for (const r2 of successful) {
|
|
4252
|
+
const skillResults = bySkill.get(r2.skill) || [];
|
|
4253
|
+
skillResults.push(r2);
|
|
4254
|
+
bySkill.set(r2.skill, skillResults);
|
|
4255
|
+
if (skillResults.length === 1) {
|
|
4256
|
+
if (r2.pluginName) {
|
|
4257
|
+
const group = r2.pluginName;
|
|
4258
|
+
if (!groupedResults[group]) groupedResults[group] = [];
|
|
4259
|
+
groupedResults[group].push(r2);
|
|
4260
|
+
} else {
|
|
4261
|
+
ungroupedResults.push(r2);
|
|
4262
|
+
}
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
4265
|
+
const skillCount = bySkill.size;
|
|
4266
|
+
const symlinkFailures = successful.filter((r2) => r2.mode === "symlink" && r2.symlinkFailed);
|
|
4267
|
+
const copiedAgents = symlinkFailures.map((r2) => r2.agent);
|
|
4268
|
+
const resultLines = [];
|
|
4269
|
+
const printSkillResults = (entries) => {
|
|
4270
|
+
for (const entry of entries) {
|
|
4271
|
+
const skillResults = bySkill.get(entry.skill) || [];
|
|
4272
|
+
const firstResult = skillResults[0];
|
|
4273
|
+
if (firstResult.mode === "copy") {
|
|
4274
|
+
resultLines.push(`${import_picocolors3.default.green("\u2713")} ${entry.skill} ${import_picocolors3.default.dim("(copied)")}`);
|
|
4275
|
+
for (const r2 of skillResults) {
|
|
4276
|
+
const shortPath = shortenPath(r2.path, cwd);
|
|
4277
|
+
resultLines.push(` ${import_picocolors3.default.dim("\u2192")} ${shortPath}`);
|
|
4278
|
+
}
|
|
4279
|
+
} else {
|
|
4280
|
+
if (firstResult.canonicalPath) {
|
|
4281
|
+
const shortPath = shortenPath(firstResult.canonicalPath, cwd);
|
|
4282
|
+
resultLines.push(`${import_picocolors3.default.green("\u2713")} ${shortPath}`);
|
|
4283
|
+
} else {
|
|
4284
|
+
resultLines.push(`${import_picocolors3.default.green("\u2713")} ${entry.skill}`);
|
|
4285
|
+
}
|
|
4286
|
+
resultLines.push(...buildResultLines(skillResults, targetAgents));
|
|
4287
|
+
}
|
|
4288
|
+
}
|
|
4289
|
+
};
|
|
4290
|
+
const sortedResultGroups = Object.keys(groupedResults).sort();
|
|
4291
|
+
for (const group of sortedResultGroups) {
|
|
4292
|
+
const title2 = group.split("-").map((w2) => w2.charAt(0).toUpperCase() + w2.slice(1)).join(" ");
|
|
4293
|
+
resultLines.push("");
|
|
4294
|
+
resultLines.push(import_picocolors3.default.bold(title2));
|
|
4295
|
+
printSkillResults(groupedResults[group]);
|
|
4296
|
+
}
|
|
4297
|
+
if (ungroupedResults.length > 0) {
|
|
4298
|
+
if (sortedResultGroups.length > 0) {
|
|
4299
|
+
resultLines.push("");
|
|
4300
|
+
resultLines.push(import_picocolors3.default.bold("General"));
|
|
4301
|
+
}
|
|
4302
|
+
printSkillResults(ungroupedResults);
|
|
4303
|
+
}
|
|
4304
|
+
const title = import_picocolors3.default.green(`Installed ${skillCount} skill${skillCount !== 1 ? "s" : ""}`);
|
|
4305
|
+
Me(resultLines.join("\n"), title);
|
|
4306
|
+
if (symlinkFailures.length > 0) {
|
|
4307
|
+
M2.warn(import_picocolors3.default.yellow(`Symlinks failed for: ${formatList(copiedAgents)}`));
|
|
4308
|
+
M2.message(
|
|
4309
|
+
import_picocolors3.default.dim(
|
|
4310
|
+
" Files were copied instead. On Windows, enable Developer Mode for symlink support."
|
|
4311
|
+
)
|
|
4312
|
+
);
|
|
4313
|
+
}
|
|
4314
|
+
}
|
|
4315
|
+
if (failed.length > 0) {
|
|
4316
|
+
console.log();
|
|
4317
|
+
M2.error(import_picocolors3.default.red(`Failed to install ${failed.length}`));
|
|
4318
|
+
for (const r2 of failed) {
|
|
4319
|
+
M2.message(` ${import_picocolors3.default.red("\u2717")} ${r2.skill} \u2192 ${r2.agent}: ${import_picocolors3.default.dim(r2.error)}`);
|
|
4320
|
+
}
|
|
4321
|
+
}
|
|
4322
|
+
console.log();
|
|
4323
|
+
Se(
|
|
4324
|
+
import_picocolors3.default.green("Done!") + import_picocolors3.default.dim(" Review skills before use; they run with full agent permissions.")
|
|
4325
|
+
);
|
|
4326
|
+
await promptForFindSkills(options, targetAgents);
|
|
4327
|
+
} catch (error) {
|
|
4328
|
+
if (error instanceof GitCloneError) {
|
|
4329
|
+
M2.error(import_picocolors3.default.red("Failed to clone repository"));
|
|
4330
|
+
for (const line of error.message.split("\n")) {
|
|
4331
|
+
M2.message(import_picocolors3.default.dim(line));
|
|
4332
|
+
}
|
|
4333
|
+
} else {
|
|
4334
|
+
M2.error(error instanceof Error ? error.message : "Unknown error occurred");
|
|
4335
|
+
}
|
|
4336
|
+
showInstallTip();
|
|
4337
|
+
Se(import_picocolors3.default.red("Installation failed"));
|
|
4338
|
+
process.exit(1);
|
|
4339
|
+
} finally {
|
|
4340
|
+
await cleanup(tempDir);
|
|
4341
|
+
}
|
|
4342
|
+
}
|
|
4343
|
+
async function cleanup(tempDir) {
|
|
4344
|
+
if (tempDir) {
|
|
4345
|
+
try {
|
|
4346
|
+
await cleanupTempDir(tempDir);
|
|
4347
|
+
} catch {
|
|
4348
|
+
}
|
|
4349
|
+
}
|
|
4350
|
+
}
|
|
4351
|
+
async function promptForFindSkills(options, targetAgents) {
|
|
4352
|
+
if (!process.stdin.isTTY) return;
|
|
4353
|
+
if (options?.yes) return;
|
|
4354
|
+
try {
|
|
4355
|
+
const dismissed = await isPromptDismissed("findSkillsPrompt");
|
|
4356
|
+
if (dismissed) return;
|
|
4357
|
+
const findSkillsInstalled = await isSkillInstalled("find-skills", "claude-code", {
|
|
4358
|
+
global: true
|
|
4359
|
+
});
|
|
4360
|
+
if (findSkillsInstalled) {
|
|
4361
|
+
await dismissPrompt("findSkillsPrompt");
|
|
4362
|
+
return;
|
|
4363
|
+
}
|
|
4364
|
+
console.log();
|
|
4365
|
+
M2.message(import_picocolors3.default.dim("One-time prompt - you won't be asked again if you dismiss."));
|
|
4366
|
+
const install = await ye({
|
|
4367
|
+
message: `Install the ${import_picocolors3.default.cyan("find-skills")} skill? It helps your agent discover and suggest skills.`
|
|
4368
|
+
});
|
|
4369
|
+
if (pD(install)) {
|
|
4370
|
+
await dismissPrompt("findSkillsPrompt");
|
|
4371
|
+
return;
|
|
4372
|
+
}
|
|
4373
|
+
if (install) {
|
|
4374
|
+
await dismissPrompt("findSkillsPrompt");
|
|
4375
|
+
const findSkillsAgents = targetAgents?.filter((a) => a !== "replit");
|
|
4376
|
+
if (!findSkillsAgents || findSkillsAgents.length === 0) {
|
|
4377
|
+
return;
|
|
4378
|
+
}
|
|
4379
|
+
console.log();
|
|
4380
|
+
M2.step("Installing find-skills skill...");
|
|
4381
|
+
try {
|
|
4382
|
+
await runAdd(["vercel-labs/skills"], {
|
|
4383
|
+
skill: ["find-skills"],
|
|
4384
|
+
global: true,
|
|
4385
|
+
yes: true,
|
|
4386
|
+
agent: findSkillsAgents
|
|
4387
|
+
});
|
|
4388
|
+
} catch {
|
|
4389
|
+
M2.warn("Failed to install find-skills. You can try again with:");
|
|
4390
|
+
M2.message(
|
|
4391
|
+
import_picocolors3.default.dim(" npx @codemcp/skills add vercel-labs/skills@find-skills -g -y --all")
|
|
4392
|
+
);
|
|
4393
|
+
}
|
|
4394
|
+
} else {
|
|
4395
|
+
await dismissPrompt("findSkillsPrompt");
|
|
4396
|
+
M2.message(
|
|
4397
|
+
import_picocolors3.default.dim(
|
|
4398
|
+
"You can install it later with: npx @codemcp/skills add vercel-labs/skills@find-skills"
|
|
4399
|
+
)
|
|
4400
|
+
);
|
|
4401
|
+
}
|
|
4402
|
+
} catch {
|
|
4403
|
+
}
|
|
4404
|
+
}
|
|
4405
|
+
function parseAddOptions(args) {
|
|
4406
|
+
const options = {};
|
|
4407
|
+
const source = [];
|
|
4408
|
+
for (let i = 0; i < args.length; i++) {
|
|
4409
|
+
const arg = args[i];
|
|
4410
|
+
if (arg === "-g" || arg === "--global") {
|
|
4411
|
+
options.global = true;
|
|
4412
|
+
} else if (arg === "-y" || arg === "--yes") {
|
|
4413
|
+
options.yes = true;
|
|
4414
|
+
} else if (arg === "-l" || arg === "--list") {
|
|
4415
|
+
options.list = true;
|
|
4416
|
+
} else if (arg === "--all") {
|
|
4417
|
+
options.all = true;
|
|
4418
|
+
} else if (arg === "-a" || arg === "--agent") {
|
|
4419
|
+
options.agent = options.agent || [];
|
|
4420
|
+
i++;
|
|
4421
|
+
let nextArg = args[i];
|
|
4422
|
+
while (i < args.length && nextArg && !nextArg.startsWith("-")) {
|
|
4423
|
+
options.agent.push(nextArg);
|
|
4424
|
+
i++;
|
|
4425
|
+
nextArg = args[i];
|
|
4426
|
+
}
|
|
4427
|
+
i--;
|
|
4428
|
+
} else if (arg === "-s" || arg === "--skill") {
|
|
4429
|
+
options.skill = options.skill || [];
|
|
4430
|
+
i++;
|
|
4431
|
+
let nextArg = args[i];
|
|
4432
|
+
while (i < args.length && nextArg && !nextArg.startsWith("-")) {
|
|
4433
|
+
options.skill.push(nextArg);
|
|
4434
|
+
i++;
|
|
4435
|
+
nextArg = args[i];
|
|
4436
|
+
}
|
|
4437
|
+
i--;
|
|
4438
|
+
} else if (arg === "--full-depth") {
|
|
4439
|
+
options.fullDepth = true;
|
|
4440
|
+
} else if (arg === "--copy") {
|
|
4441
|
+
options.copy = true;
|
|
4442
|
+
} else if (arg && !arg.startsWith("-")) {
|
|
4443
|
+
source.push(arg);
|
|
4444
|
+
}
|
|
4445
|
+
}
|
|
4446
|
+
return { source, options };
|
|
4447
|
+
}
|
|
4448
|
+
|
|
4449
|
+
// src/sync.ts
|
|
4450
|
+
var import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
4451
|
+
import { readdir as readdir4, stat as stat4 } from "fs/promises";
|
|
4452
|
+
import { join as join8, sep as sep6 } from "path";
|
|
4453
|
+
import { homedir as homedir5 } from "os";
|
|
4454
|
+
var isCancelled2 = (value) => typeof value === "symbol";
|
|
4455
|
+
function shortenPath2(fullPath, cwd) {
|
|
4456
|
+
const home2 = homedir5();
|
|
4457
|
+
if (fullPath === home2 || fullPath.startsWith(home2 + sep6)) {
|
|
4458
|
+
return "~" + fullPath.slice(home2.length);
|
|
4459
|
+
}
|
|
4460
|
+
if (fullPath === cwd || fullPath.startsWith(cwd + sep6)) {
|
|
4461
|
+
return "." + fullPath.slice(cwd.length);
|
|
4462
|
+
}
|
|
4463
|
+
return fullPath;
|
|
4464
|
+
}
|
|
4465
|
+
async function discoverNodeModuleSkills(cwd) {
|
|
4466
|
+
const nodeModulesDir = join8(cwd, "node_modules");
|
|
4467
|
+
const skills = [];
|
|
4468
|
+
let topNames;
|
|
4469
|
+
try {
|
|
4470
|
+
topNames = await readdir4(nodeModulesDir);
|
|
4471
|
+
} catch {
|
|
4472
|
+
return skills;
|
|
4473
|
+
}
|
|
4474
|
+
const processPackageDir = async (pkgDir, packageName) => {
|
|
4475
|
+
const rootSkill = await parseSkillMd(join8(pkgDir, "SKILL.md"));
|
|
4476
|
+
if (rootSkill) {
|
|
4477
|
+
skills.push({ ...rootSkill, packageName });
|
|
4478
|
+
return;
|
|
4479
|
+
}
|
|
4480
|
+
const searchDirs = [pkgDir, join8(pkgDir, "skills"), join8(pkgDir, ".agents", "skills")];
|
|
4481
|
+
for (const searchDir of searchDirs) {
|
|
4482
|
+
try {
|
|
4483
|
+
const entries = await readdir4(searchDir);
|
|
4484
|
+
for (const name of entries) {
|
|
4485
|
+
const skillDir = join8(searchDir, name);
|
|
4486
|
+
try {
|
|
4487
|
+
const s = await stat4(skillDir);
|
|
4488
|
+
if (!s.isDirectory()) continue;
|
|
4489
|
+
} catch {
|
|
4490
|
+
continue;
|
|
4491
|
+
}
|
|
4492
|
+
const skill = await parseSkillMd(join8(skillDir, "SKILL.md"));
|
|
4493
|
+
if (skill) {
|
|
4494
|
+
skills.push({ ...skill, packageName });
|
|
4495
|
+
}
|
|
4496
|
+
}
|
|
4497
|
+
} catch {
|
|
4498
|
+
}
|
|
4499
|
+
}
|
|
4500
|
+
};
|
|
4501
|
+
await Promise.all(
|
|
4502
|
+
topNames.map(async (name) => {
|
|
4503
|
+
if (name.startsWith(".")) return;
|
|
4504
|
+
const fullPath = join8(nodeModulesDir, name);
|
|
4505
|
+
try {
|
|
4506
|
+
const s = await stat4(fullPath);
|
|
4507
|
+
if (!s.isDirectory()) return;
|
|
4508
|
+
} catch {
|
|
4509
|
+
return;
|
|
4510
|
+
}
|
|
4511
|
+
if (name.startsWith("@")) {
|
|
4512
|
+
try {
|
|
4513
|
+
const scopeNames = await readdir4(fullPath);
|
|
4514
|
+
await Promise.all(
|
|
4515
|
+
scopeNames.map(async (scopedName) => {
|
|
4516
|
+
const scopedPath = join8(fullPath, scopedName);
|
|
4517
|
+
try {
|
|
4518
|
+
const s = await stat4(scopedPath);
|
|
4519
|
+
if (!s.isDirectory()) return;
|
|
4520
|
+
} catch {
|
|
4521
|
+
return;
|
|
4522
|
+
}
|
|
4523
|
+
await processPackageDir(scopedPath, `${name}/${scopedName}`);
|
|
4524
|
+
})
|
|
4525
|
+
);
|
|
4526
|
+
} catch {
|
|
4527
|
+
}
|
|
4528
|
+
} else {
|
|
4529
|
+
await processPackageDir(fullPath, name);
|
|
4530
|
+
}
|
|
4531
|
+
})
|
|
4532
|
+
);
|
|
4533
|
+
return skills;
|
|
4534
|
+
}
|
|
4535
|
+
async function runSync(args, options = {}) {
|
|
4536
|
+
const cwd = process.cwd();
|
|
4537
|
+
console.log();
|
|
4538
|
+
Ie(import_picocolors4.default.bgCyan(import_picocolors4.default.black(" skills experimental_sync ")));
|
|
4539
|
+
const spinner = Y2();
|
|
4540
|
+
spinner.start("Scanning node_modules for skills...");
|
|
4541
|
+
const discoveredSkills = await discoverNodeModuleSkills(cwd);
|
|
4542
|
+
if (discoveredSkills.length === 0) {
|
|
4543
|
+
spinner.stop(import_picocolors4.default.yellow("No skills found"));
|
|
4544
|
+
Se(import_picocolors4.default.dim("No SKILL.md files found in node_modules."));
|
|
4545
|
+
return;
|
|
4546
|
+
}
|
|
4547
|
+
spinner.stop(
|
|
4548
|
+
`Found ${import_picocolors4.default.green(String(discoveredSkills.length))} skill${discoveredSkills.length > 1 ? "s" : ""} in node_modules`
|
|
4549
|
+
);
|
|
4550
|
+
for (const skill of discoveredSkills) {
|
|
4551
|
+
M2.info(`${import_picocolors4.default.cyan(skill.name)} ${import_picocolors4.default.dim(`from ${skill.packageName}`)}`);
|
|
4552
|
+
if (skill.description) {
|
|
4553
|
+
M2.message(import_picocolors4.default.dim(` ${skill.description}`));
|
|
4554
|
+
}
|
|
4555
|
+
}
|
|
4556
|
+
const localLock = await readLocalLock(cwd);
|
|
4557
|
+
const toInstall = [];
|
|
4558
|
+
const upToDate = [];
|
|
4559
|
+
if (options.force) {
|
|
4560
|
+
toInstall.push(...discoveredSkills);
|
|
4561
|
+
M2.info(import_picocolors4.default.dim("Force mode: reinstalling all skills"));
|
|
4562
|
+
} else {
|
|
4563
|
+
for (const skill of discoveredSkills) {
|
|
4564
|
+
const existingEntry = localLock.skills[skill.name];
|
|
4565
|
+
if (existingEntry) {
|
|
4566
|
+
const currentHash = await computeSkillFolderHash(skill.path);
|
|
4567
|
+
if (currentHash === existingEntry.computedHash) {
|
|
4568
|
+
upToDate.push(skill.name);
|
|
4569
|
+
continue;
|
|
4570
|
+
}
|
|
4571
|
+
}
|
|
4572
|
+
toInstall.push(skill);
|
|
4573
|
+
}
|
|
4574
|
+
if (upToDate.length > 0) {
|
|
4575
|
+
M2.info(
|
|
4576
|
+
import_picocolors4.default.dim(`${upToDate.length} skill${upToDate.length !== 1 ? "s" : ""} already up to date`)
|
|
4577
|
+
);
|
|
4578
|
+
}
|
|
4579
|
+
if (toInstall.length === 0) {
|
|
4580
|
+
console.log();
|
|
4581
|
+
Se(import_picocolors4.default.green("All skills are up to date."));
|
|
4582
|
+
return;
|
|
4583
|
+
}
|
|
4584
|
+
}
|
|
4585
|
+
M2.info(`${toInstall.length} skill${toInstall.length !== 1 ? "s" : ""} to install/update`);
|
|
4586
|
+
let targetAgents;
|
|
4587
|
+
const validAgents = Object.keys(agents);
|
|
4588
|
+
const universalAgents = getUniversalAgents();
|
|
4589
|
+
if (options.agent?.includes("*")) {
|
|
4590
|
+
targetAgents = validAgents;
|
|
4591
|
+
M2.info(`Installing to all ${targetAgents.length} agents`);
|
|
4592
|
+
} else if (options.agent && options.agent.length > 0) {
|
|
4593
|
+
const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
|
|
4594
|
+
if (invalidAgents.length > 0) {
|
|
4595
|
+
M2.error(`Invalid agents: ${invalidAgents.join(", ")}`);
|
|
4596
|
+
M2.info(`Valid agents: ${validAgents.join(", ")}`);
|
|
4597
|
+
process.exit(1);
|
|
4598
|
+
}
|
|
4599
|
+
targetAgents = options.agent;
|
|
4600
|
+
} else {
|
|
4601
|
+
spinner.start("Loading agents...");
|
|
4602
|
+
const installedAgents = await detectInstalledAgents();
|
|
4603
|
+
const totalAgents = Object.keys(agents).length;
|
|
4604
|
+
spinner.stop(`${totalAgents} agents`);
|
|
4605
|
+
if (installedAgents.length === 0) {
|
|
4606
|
+
if (options.yes) {
|
|
4607
|
+
targetAgents = universalAgents;
|
|
4608
|
+
M2.info("Installing to universal agents");
|
|
4609
|
+
} else {
|
|
4610
|
+
const otherAgents = getNonUniversalAgents();
|
|
4611
|
+
const otherChoices = otherAgents.map((a) => ({
|
|
4612
|
+
value: a,
|
|
4613
|
+
label: agents[a].displayName,
|
|
4614
|
+
hint: agents[a].skillsDir
|
|
4615
|
+
}));
|
|
4616
|
+
const selected = await searchMultiselect({
|
|
4617
|
+
message: "Which agents do you want to install to?",
|
|
4618
|
+
items: otherChoices,
|
|
4619
|
+
initialSelected: [],
|
|
4620
|
+
lockedSection: {
|
|
4621
|
+
title: "Universal (.agents/skills)",
|
|
4622
|
+
items: universalAgents.map((a) => ({
|
|
4623
|
+
value: a,
|
|
4624
|
+
label: agents[a].displayName
|
|
4625
|
+
}))
|
|
4626
|
+
}
|
|
4627
|
+
});
|
|
4628
|
+
if (isCancelled2(selected)) {
|
|
4629
|
+
xe("Sync cancelled");
|
|
4630
|
+
process.exit(0);
|
|
4631
|
+
}
|
|
4632
|
+
targetAgents = selected;
|
|
4633
|
+
}
|
|
4634
|
+
} else if (installedAgents.length === 1 || options.yes) {
|
|
4635
|
+
targetAgents = [...installedAgents];
|
|
4636
|
+
for (const ua of universalAgents) {
|
|
4637
|
+
if (!targetAgents.includes(ua)) {
|
|
4638
|
+
targetAgents.push(ua);
|
|
4639
|
+
}
|
|
4640
|
+
}
|
|
4641
|
+
} else {
|
|
4642
|
+
const otherAgents = getNonUniversalAgents().filter((a) => installedAgents.includes(a));
|
|
4643
|
+
const otherChoices = otherAgents.map((a) => ({
|
|
4644
|
+
value: a,
|
|
4645
|
+
label: agents[a].displayName,
|
|
4646
|
+
hint: agents[a].skillsDir
|
|
4647
|
+
}));
|
|
4648
|
+
const selected = await searchMultiselect({
|
|
4649
|
+
message: "Which agents do you want to install to?",
|
|
4650
|
+
items: otherChoices,
|
|
4651
|
+
initialSelected: installedAgents.filter((a) => !universalAgents.includes(a)),
|
|
4652
|
+
lockedSection: {
|
|
4653
|
+
title: "Universal (.agents/skills)",
|
|
4654
|
+
items: universalAgents.map((a) => ({
|
|
4655
|
+
value: a,
|
|
4656
|
+
label: agents[a].displayName
|
|
4657
|
+
}))
|
|
4658
|
+
}
|
|
4659
|
+
});
|
|
4660
|
+
if (isCancelled2(selected)) {
|
|
4661
|
+
xe("Sync cancelled");
|
|
4662
|
+
process.exit(0);
|
|
4663
|
+
}
|
|
4664
|
+
targetAgents = selected;
|
|
4665
|
+
}
|
|
4666
|
+
}
|
|
4667
|
+
const summaryLines = [];
|
|
4668
|
+
for (const skill of toInstall) {
|
|
4669
|
+
const canonicalPath = getCanonicalPath(skill.name, { global: false });
|
|
4670
|
+
const shortCanonical = shortenPath2(canonicalPath, cwd);
|
|
4671
|
+
summaryLines.push(`${import_picocolors4.default.cyan(skill.name)} ${import_picocolors4.default.dim(`\u2190 ${skill.packageName}`)}`);
|
|
4672
|
+
summaryLines.push(` ${import_picocolors4.default.dim(shortCanonical)}`);
|
|
4673
|
+
}
|
|
4674
|
+
console.log();
|
|
4675
|
+
Me(summaryLines.join("\n"), "Sync Summary");
|
|
4676
|
+
if (!options.yes) {
|
|
4677
|
+
const confirmed = await ye({ message: "Proceed with sync?" });
|
|
4678
|
+
if (pD(confirmed) || !confirmed) {
|
|
4679
|
+
xe("Sync cancelled");
|
|
4680
|
+
process.exit(0);
|
|
4681
|
+
}
|
|
4682
|
+
}
|
|
4683
|
+
spinner.start("Syncing skills...");
|
|
4684
|
+
const results = [];
|
|
4685
|
+
for (const skill of toInstall) {
|
|
4686
|
+
for (const agent of targetAgents) {
|
|
4687
|
+
const result = await installSkillForAgent(skill, agent, {
|
|
4688
|
+
global: false,
|
|
4689
|
+
cwd,
|
|
4690
|
+
mode: "symlink"
|
|
4691
|
+
});
|
|
4692
|
+
results.push({
|
|
4693
|
+
skill: skill.name,
|
|
4694
|
+
packageName: skill.packageName,
|
|
4695
|
+
agent: agents[agent].displayName,
|
|
4696
|
+
success: result.success,
|
|
4697
|
+
path: result.path,
|
|
4698
|
+
canonicalPath: result.canonicalPath,
|
|
4699
|
+
error: result.error
|
|
4700
|
+
});
|
|
4701
|
+
}
|
|
4702
|
+
}
|
|
4703
|
+
spinner.stop("Sync complete");
|
|
4704
|
+
const successful = results.filter((r2) => r2.success);
|
|
4705
|
+
const failed = results.filter((r2) => !r2.success);
|
|
4706
|
+
const successfulSkillNames = new Set(successful.map((r2) => r2.skill));
|
|
4707
|
+
for (const skill of toInstall) {
|
|
4708
|
+
if (successfulSkillNames.has(skill.name)) {
|
|
4709
|
+
try {
|
|
4710
|
+
const computedHash = await computeSkillFolderHash(skill.path);
|
|
4711
|
+
await addSkillToLocalLock(
|
|
4712
|
+
skill.name,
|
|
4713
|
+
{
|
|
4714
|
+
source: skill.packageName,
|
|
4715
|
+
sourceType: "node_modules",
|
|
4716
|
+
computedHash
|
|
4717
|
+
},
|
|
4718
|
+
cwd
|
|
4719
|
+
);
|
|
4720
|
+
} catch {
|
|
4721
|
+
}
|
|
4722
|
+
}
|
|
4723
|
+
}
|
|
4724
|
+
console.log();
|
|
4725
|
+
if (successful.length > 0) {
|
|
4726
|
+
const bySkill = /* @__PURE__ */ new Map();
|
|
4727
|
+
for (const r2 of successful) {
|
|
4728
|
+
const skillResults = bySkill.get(r2.skill) || [];
|
|
4729
|
+
skillResults.push(r2);
|
|
4730
|
+
bySkill.set(r2.skill, skillResults);
|
|
4731
|
+
}
|
|
4732
|
+
const resultLines = [];
|
|
4733
|
+
for (const [skillName, skillResults] of bySkill) {
|
|
4734
|
+
const firstResult = skillResults[0];
|
|
4735
|
+
const pkg = toInstall.find((s) => s.name === skillName)?.packageName;
|
|
4736
|
+
if (firstResult.canonicalPath) {
|
|
4737
|
+
const shortPath = shortenPath2(firstResult.canonicalPath, cwd);
|
|
4738
|
+
resultLines.push(`${import_picocolors4.default.green("\u2713")} ${skillName} ${import_picocolors4.default.dim(`\u2190 ${pkg}`)}`);
|
|
4739
|
+
resultLines.push(` ${import_picocolors4.default.dim(shortPath)}`);
|
|
4740
|
+
} else {
|
|
4741
|
+
resultLines.push(`${import_picocolors4.default.green("\u2713")} ${skillName} ${import_picocolors4.default.dim(`\u2190 ${pkg}`)}`);
|
|
4742
|
+
}
|
|
4743
|
+
}
|
|
4744
|
+
const skillCount = bySkill.size;
|
|
4745
|
+
const title = import_picocolors4.default.green(`Synced ${skillCount} skill${skillCount !== 1 ? "s" : ""}`);
|
|
4746
|
+
Me(resultLines.join("\n"), title);
|
|
4747
|
+
}
|
|
4748
|
+
if (failed.length > 0) {
|
|
4749
|
+
console.log();
|
|
4750
|
+
M2.error(import_picocolors4.default.red(`Failed to install ${failed.length}`));
|
|
4751
|
+
for (const r2 of failed) {
|
|
4752
|
+
M2.message(` ${import_picocolors4.default.red("\u2717")} ${r2.skill} \u2192 ${r2.agent}: ${import_picocolors4.default.dim(r2.error)}`);
|
|
4753
|
+
}
|
|
4754
|
+
}
|
|
4755
|
+
track({
|
|
4756
|
+
event: "experimental_sync",
|
|
4757
|
+
skillCount: String(toInstall.length),
|
|
4758
|
+
successCount: String(successfulSkillNames.size),
|
|
4759
|
+
agents: targetAgents.join(",")
|
|
4760
|
+
});
|
|
4761
|
+
console.log();
|
|
4762
|
+
Se(
|
|
4763
|
+
import_picocolors4.default.green("Done!") + import_picocolors4.default.dim(" Review skills before use; they run with full agent permissions.")
|
|
4764
|
+
);
|
|
4765
|
+
}
|
|
4766
|
+
function parseSyncOptions(args) {
|
|
4767
|
+
const options = {};
|
|
4768
|
+
for (let i = 0; i < args.length; i++) {
|
|
4769
|
+
const arg = args[i];
|
|
4770
|
+
if (arg === "-y" || arg === "--yes") {
|
|
4771
|
+
options.yes = true;
|
|
4772
|
+
} else if (arg === "-f" || arg === "--force") {
|
|
4773
|
+
options.force = true;
|
|
4774
|
+
} else if (arg === "-a" || arg === "--agent") {
|
|
4775
|
+
options.agent = options.agent || [];
|
|
4776
|
+
i++;
|
|
4777
|
+
let nextArg = args[i];
|
|
4778
|
+
while (i < args.length && nextArg && !nextArg.startsWith("-")) {
|
|
4779
|
+
options.agent.push(nextArg);
|
|
4780
|
+
i++;
|
|
4781
|
+
nextArg = args[i];
|
|
4782
|
+
}
|
|
4783
|
+
i--;
|
|
4784
|
+
}
|
|
4785
|
+
}
|
|
4786
|
+
return { options };
|
|
4787
|
+
}
|
|
4788
|
+
|
|
4789
|
+
// src/install.ts
|
|
4790
|
+
var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
4791
|
+
async function runInstallFromLock(args) {
|
|
4792
|
+
const cwd = process.cwd();
|
|
4793
|
+
const lock = await readLocalLock(cwd);
|
|
4794
|
+
const skillEntries = Object.entries(lock.skills);
|
|
4795
|
+
if (skillEntries.length === 0) {
|
|
4796
|
+
M2.warn("No project skills found in skills-lock.json");
|
|
4797
|
+
M2.info(
|
|
4798
|
+
`Add project-level skills with ${import_picocolors5.default.cyan("npx @codemcp/skills add <package>")} (without ${import_picocolors5.default.cyan("-g")})`
|
|
4799
|
+
);
|
|
4800
|
+
return;
|
|
4801
|
+
}
|
|
4802
|
+
const universalAgentNames = getUniversalAgents();
|
|
4803
|
+
const nodeModuleSkills = [];
|
|
4804
|
+
const bySource = /* @__PURE__ */ new Map();
|
|
4805
|
+
for (const [skillName, entry] of skillEntries) {
|
|
4806
|
+
if (entry.sourceType === "node_modules") {
|
|
4807
|
+
nodeModuleSkills.push(skillName);
|
|
4808
|
+
continue;
|
|
4809
|
+
}
|
|
4810
|
+
const existing = bySource.get(entry.source);
|
|
4811
|
+
if (existing) {
|
|
4812
|
+
existing.skills.push(skillName);
|
|
4813
|
+
} else {
|
|
4814
|
+
bySource.set(entry.source, {
|
|
4815
|
+
sourceType: entry.sourceType,
|
|
4816
|
+
skills: [skillName]
|
|
4817
|
+
});
|
|
4818
|
+
}
|
|
4819
|
+
}
|
|
4820
|
+
const remoteCount = skillEntries.length - nodeModuleSkills.length;
|
|
4821
|
+
if (remoteCount > 0) {
|
|
4822
|
+
M2.info(
|
|
4823
|
+
`Restoring ${import_picocolors5.default.cyan(String(remoteCount))} skill${remoteCount !== 1 ? "s" : ""} from skills-lock.json into ${import_picocolors5.default.dim(".agents/skills/")}`
|
|
4824
|
+
);
|
|
4825
|
+
}
|
|
4826
|
+
for (const [source, { skills }] of bySource) {
|
|
4827
|
+
try {
|
|
4828
|
+
await runAdd([source], {
|
|
4829
|
+
skill: skills,
|
|
4830
|
+
agent: universalAgentNames,
|
|
4831
|
+
yes: true
|
|
4832
|
+
});
|
|
4833
|
+
} catch (error) {
|
|
4834
|
+
M2.error(
|
|
4835
|
+
`Failed to install from ${import_picocolors5.default.cyan(source)}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
4836
|
+
);
|
|
4837
|
+
}
|
|
4838
|
+
}
|
|
4839
|
+
if (nodeModuleSkills.length > 0) {
|
|
4840
|
+
M2.info(
|
|
4841
|
+
`${import_picocolors5.default.cyan(String(nodeModuleSkills.length))} skill${nodeModuleSkills.length !== 1 ? "s" : ""} from node_modules`
|
|
4842
|
+
);
|
|
4843
|
+
try {
|
|
4844
|
+
const { options: syncOptions } = parseSyncOptions(args);
|
|
4845
|
+
await runSync(args, { ...syncOptions, yes: true, agent: universalAgentNames });
|
|
4846
|
+
} catch (error) {
|
|
4847
|
+
M2.error(
|
|
4848
|
+
`Failed to sync node_modules skills: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
4849
|
+
);
|
|
4850
|
+
}
|
|
4851
|
+
}
|
|
4852
|
+
}
|
|
4853
|
+
|
|
4854
|
+
export {
|
|
4855
|
+
__toESM,
|
|
4856
|
+
require_picocolors,
|
|
4857
|
+
pD,
|
|
4858
|
+
ye,
|
|
4859
|
+
fe,
|
|
4860
|
+
xe,
|
|
4861
|
+
Se,
|
|
4862
|
+
M2 as M,
|
|
4863
|
+
Y2 as Y,
|
|
4864
|
+
isRepoPrivate,
|
|
4865
|
+
agents,
|
|
4866
|
+
detectInstalledAgents,
|
|
4867
|
+
sanitizeName,
|
|
4868
|
+
getCanonicalSkillsDir,
|
|
4869
|
+
getInstallPath,
|
|
4870
|
+
getCanonicalPath,
|
|
4871
|
+
listInstalledSkills,
|
|
4872
|
+
track,
|
|
4873
|
+
getGitHubToken,
|
|
4874
|
+
fetchSkillFolderHash,
|
|
4875
|
+
removeSkillFromLock,
|
|
4876
|
+
getSkillFromLock,
|
|
4877
|
+
getAllLockedSkills,
|
|
4878
|
+
getLocalLockPath,
|
|
4879
|
+
readLocalLock,
|
|
4880
|
+
writeLocalLock,
|
|
4881
|
+
computeSkillFolderHash,
|
|
4882
|
+
addSkillToLocalLock,
|
|
4883
|
+
removeSkillFromLocalLock,
|
|
4884
|
+
initTelemetry,
|
|
4885
|
+
runAdd,
|
|
4886
|
+
parseAddOptions,
|
|
4887
|
+
runSync,
|
|
4888
|
+
parseSyncOptions,
|
|
4889
|
+
runInstallFromLock
|
|
4890
|
+
};
|