skills 1.4.2 → 1.4.3
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/cli.mjs +4 -632
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -49,15 +49,6 @@ async function isRepoPrivate(owner, repo) {
|
|
|
49
49
|
function isLocalPath(input) {
|
|
50
50
|
return isAbsolute(input) || input.startsWith("./") || input.startsWith("../") || input === "." || input === ".." || /^[a-zA-Z]:[/\\]/.test(input);
|
|
51
51
|
}
|
|
52
|
-
function isDirectSkillUrl(input) {
|
|
53
|
-
if (!input.startsWith("http://") && !input.startsWith("https://")) return false;
|
|
54
|
-
if (!input.toLowerCase().endsWith("/skill.md")) return false;
|
|
55
|
-
if (input.includes("github.com/") && !input.includes("raw.githubusercontent.com")) {
|
|
56
|
-
if (!input.includes("/blob/") && !input.includes("/raw/")) return false;
|
|
57
|
-
}
|
|
58
|
-
if (input.includes("gitlab.com/") && !input.includes("/-/raw/")) return false;
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
52
|
const SOURCE_ALIASES = { "coinbase/agentWallet": "coinbase/agentic-wallet-skills" };
|
|
62
53
|
function parseSource(input) {
|
|
63
54
|
const alias = SOURCE_ALIASES[input];
|
|
@@ -70,10 +61,6 @@ function parseSource(input) {
|
|
|
70
61
|
localPath: resolvedPath
|
|
71
62
|
};
|
|
72
63
|
}
|
|
73
|
-
if (isDirectSkillUrl(input)) return {
|
|
74
|
-
type: "direct-url",
|
|
75
|
-
url: input
|
|
76
|
-
};
|
|
77
64
|
const githubTreeWithPathMatch = input.match(/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+)/);
|
|
78
65
|
if (githubTreeWithPathMatch) {
|
|
79
66
|
const [, owner, repo, ref, subpath] = githubTreeWithPathMatch;
|
|
@@ -162,10 +149,8 @@ function isWellKnownUrl(input) {
|
|
|
162
149
|
if ([
|
|
163
150
|
"github.com",
|
|
164
151
|
"gitlab.com",
|
|
165
|
-
"huggingface.co",
|
|
166
152
|
"raw.githubusercontent.com"
|
|
167
153
|
].includes(parsed.hostname)) return false;
|
|
168
|
-
if (input.toLowerCase().endsWith("/skill.md")) return false;
|
|
169
154
|
if (input.endsWith(".git")) return false;
|
|
170
155
|
return true;
|
|
171
156
|
} catch {
|
|
@@ -1179,78 +1164,6 @@ function getCanonicalPath(skillName, options = {}) {
|
|
|
1179
1164
|
if (!isPathSafe(canonicalBase, canonicalPath)) throw new Error("Invalid skill name: potential path traversal detected");
|
|
1180
1165
|
return canonicalPath;
|
|
1181
1166
|
}
|
|
1182
|
-
async function installRemoteSkillForAgent(skill, agentType, options = {}) {
|
|
1183
|
-
const agent = agents[agentType];
|
|
1184
|
-
const isGlobal = options.global ?? false;
|
|
1185
|
-
const cwd = options.cwd || process.cwd();
|
|
1186
|
-
const installMode = options.mode ?? "symlink";
|
|
1187
|
-
if (isGlobal && agent.globalSkillsDir === void 0) return {
|
|
1188
|
-
success: false,
|
|
1189
|
-
path: "",
|
|
1190
|
-
mode: installMode,
|
|
1191
|
-
error: `${agent.displayName} does not support global skill installation`
|
|
1192
|
-
};
|
|
1193
|
-
const skillName = sanitizeName(skill.installName);
|
|
1194
|
-
const canonicalBase = getCanonicalSkillsDir(isGlobal, cwd);
|
|
1195
|
-
const canonicalDir = join(canonicalBase, skillName);
|
|
1196
|
-
const agentBase = getAgentBaseDir(agentType, isGlobal, cwd);
|
|
1197
|
-
const agentDir = join(agentBase, skillName);
|
|
1198
|
-
if (!isPathSafe(canonicalBase, canonicalDir)) return {
|
|
1199
|
-
success: false,
|
|
1200
|
-
path: agentDir,
|
|
1201
|
-
mode: installMode,
|
|
1202
|
-
error: "Invalid skill name: potential path traversal detected"
|
|
1203
|
-
};
|
|
1204
|
-
if (!isPathSafe(agentBase, agentDir)) return {
|
|
1205
|
-
success: false,
|
|
1206
|
-
path: agentDir,
|
|
1207
|
-
mode: installMode,
|
|
1208
|
-
error: "Invalid skill name: potential path traversal detected"
|
|
1209
|
-
};
|
|
1210
|
-
try {
|
|
1211
|
-
if (installMode === "copy") {
|
|
1212
|
-
await cleanAndCreateDirectory(agentDir);
|
|
1213
|
-
await writeFile(join(agentDir, "SKILL.md"), skill.content, "utf-8");
|
|
1214
|
-
return {
|
|
1215
|
-
success: true,
|
|
1216
|
-
path: agentDir,
|
|
1217
|
-
mode: "copy"
|
|
1218
|
-
};
|
|
1219
|
-
}
|
|
1220
|
-
await cleanAndCreateDirectory(canonicalDir);
|
|
1221
|
-
await writeFile(join(canonicalDir, "SKILL.md"), skill.content, "utf-8");
|
|
1222
|
-
if (isGlobal && isUniversalAgent(agentType)) return {
|
|
1223
|
-
success: true,
|
|
1224
|
-
path: canonicalDir,
|
|
1225
|
-
canonicalPath: canonicalDir,
|
|
1226
|
-
mode: "symlink"
|
|
1227
|
-
};
|
|
1228
|
-
if (!await createSymlink(canonicalDir, agentDir)) {
|
|
1229
|
-
await cleanAndCreateDirectory(agentDir);
|
|
1230
|
-
await writeFile(join(agentDir, "SKILL.md"), skill.content, "utf-8");
|
|
1231
|
-
return {
|
|
1232
|
-
success: true,
|
|
1233
|
-
path: agentDir,
|
|
1234
|
-
canonicalPath: canonicalDir,
|
|
1235
|
-
mode: "symlink",
|
|
1236
|
-
symlinkFailed: true
|
|
1237
|
-
};
|
|
1238
|
-
}
|
|
1239
|
-
return {
|
|
1240
|
-
success: true,
|
|
1241
|
-
path: agentDir,
|
|
1242
|
-
canonicalPath: canonicalDir,
|
|
1243
|
-
mode: "symlink"
|
|
1244
|
-
};
|
|
1245
|
-
} catch (error) {
|
|
1246
|
-
return {
|
|
1247
|
-
success: false,
|
|
1248
|
-
path: agentDir,
|
|
1249
|
-
mode: installMode,
|
|
1250
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
1251
|
-
};
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
1167
|
async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
|
|
1255
1168
|
const agent = agents[agentType];
|
|
1256
1169
|
const isGlobal = options.global ?? false;
|
|
@@ -1495,108 +1408,7 @@ var ProviderRegistryImpl = class {
|
|
|
1495
1408
|
return [...this.providers];
|
|
1496
1409
|
}
|
|
1497
1410
|
};
|
|
1498
|
-
|
|
1499
|
-
function registerProvider(provider) {
|
|
1500
|
-
registry.register(provider);
|
|
1501
|
-
}
|
|
1502
|
-
function findProvider(url) {
|
|
1503
|
-
return registry.findProvider(url);
|
|
1504
|
-
}
|
|
1505
|
-
var MintlifyProvider = class {
|
|
1506
|
-
id = "mintlify";
|
|
1507
|
-
displayName = "Mintlify";
|
|
1508
|
-
match(url) {
|
|
1509
|
-
if (!url.startsWith("http://") && !url.startsWith("https://")) return { matches: false };
|
|
1510
|
-
if (!url.toLowerCase().endsWith("/skill.md")) return { matches: false };
|
|
1511
|
-
if (url.includes("github.com") || url.includes("gitlab.com")) return { matches: false };
|
|
1512
|
-
if (url.includes("huggingface.co")) return { matches: false };
|
|
1513
|
-
return { matches: true };
|
|
1514
|
-
}
|
|
1515
|
-
async fetchSkill(url) {
|
|
1516
|
-
try {
|
|
1517
|
-
const response = await fetch(url, { signal: AbortSignal.timeout(3e4) });
|
|
1518
|
-
if (!response.ok) return null;
|
|
1519
|
-
const content = await response.text();
|
|
1520
|
-
const { data } = (0, import_gray_matter.default)(content);
|
|
1521
|
-
const mintlifySite = data.metadata?.["mintlify-proj"];
|
|
1522
|
-
if (!mintlifySite) return null;
|
|
1523
|
-
if (!data.name || !data.description) return null;
|
|
1524
|
-
return {
|
|
1525
|
-
name: data.name,
|
|
1526
|
-
description: data.description,
|
|
1527
|
-
content,
|
|
1528
|
-
installName: mintlifySite,
|
|
1529
|
-
sourceUrl: url,
|
|
1530
|
-
metadata: data.metadata
|
|
1531
|
-
};
|
|
1532
|
-
} catch {
|
|
1533
|
-
return null;
|
|
1534
|
-
}
|
|
1535
|
-
}
|
|
1536
|
-
toRawUrl(url) {
|
|
1537
|
-
return url;
|
|
1538
|
-
}
|
|
1539
|
-
getSourceIdentifier(url) {
|
|
1540
|
-
return "mintlify/com";
|
|
1541
|
-
}
|
|
1542
|
-
};
|
|
1543
|
-
const mintlifyProvider = new MintlifyProvider();
|
|
1544
|
-
var HuggingFaceProvider = class {
|
|
1545
|
-
id = "huggingface";
|
|
1546
|
-
displayName = "HuggingFace";
|
|
1547
|
-
HOST = "huggingface.co";
|
|
1548
|
-
match(url) {
|
|
1549
|
-
if (!url.startsWith("http://") && !url.startsWith("https://")) return { matches: false };
|
|
1550
|
-
try {
|
|
1551
|
-
if (new URL(url).hostname !== this.HOST) return { matches: false };
|
|
1552
|
-
} catch {
|
|
1553
|
-
return { matches: false };
|
|
1554
|
-
}
|
|
1555
|
-
if (!url.toLowerCase().endsWith("/skill.md")) return { matches: false };
|
|
1556
|
-
if (!url.includes("/spaces/")) return { matches: false };
|
|
1557
|
-
return { matches: true };
|
|
1558
|
-
}
|
|
1559
|
-
async fetchSkill(url) {
|
|
1560
|
-
try {
|
|
1561
|
-
const rawUrl = this.toRawUrl(url);
|
|
1562
|
-
const response = await fetch(rawUrl, { signal: AbortSignal.timeout(3e4) });
|
|
1563
|
-
if (!response.ok) return null;
|
|
1564
|
-
const content = await response.text();
|
|
1565
|
-
const { data } = (0, import_gray_matter.default)(content);
|
|
1566
|
-
if (!data.name || !data.description) return null;
|
|
1567
|
-
const parsed = this.parseUrl(url);
|
|
1568
|
-
if (!parsed) return null;
|
|
1569
|
-
const installName = data.metadata?.["install-name"] || parsed.repo;
|
|
1570
|
-
return {
|
|
1571
|
-
name: data.name,
|
|
1572
|
-
description: data.description,
|
|
1573
|
-
content,
|
|
1574
|
-
installName,
|
|
1575
|
-
sourceUrl: url,
|
|
1576
|
-
metadata: data.metadata
|
|
1577
|
-
};
|
|
1578
|
-
} catch {
|
|
1579
|
-
return null;
|
|
1580
|
-
}
|
|
1581
|
-
}
|
|
1582
|
-
toRawUrl(url) {
|
|
1583
|
-
return url.replace("/blob/", "/raw/");
|
|
1584
|
-
}
|
|
1585
|
-
getSourceIdentifier(url) {
|
|
1586
|
-
const parsed = this.parseUrl(url);
|
|
1587
|
-
if (!parsed) return "huggingface/unknown";
|
|
1588
|
-
return `huggingface/${parsed.owner}/${parsed.repo}`;
|
|
1589
|
-
}
|
|
1590
|
-
parseUrl(url) {
|
|
1591
|
-
const match = url.match(/\/spaces\/([^/]+)\/([^/]+)/);
|
|
1592
|
-
if (!match || !match[1] || !match[2]) return null;
|
|
1593
|
-
return {
|
|
1594
|
-
owner: match[1],
|
|
1595
|
-
repo: match[2]
|
|
1596
|
-
};
|
|
1597
|
-
}
|
|
1598
|
-
};
|
|
1599
|
-
const huggingFaceProvider = new HuggingFaceProvider();
|
|
1411
|
+
new ProviderRegistryImpl();
|
|
1600
1412
|
var WellKnownProvider = class {
|
|
1601
1413
|
id = "well-known";
|
|
1602
1414
|
displayName = "Well-Known Skills";
|
|
@@ -1753,15 +1565,9 @@ var WellKnownProvider = class {
|
|
|
1753
1565
|
}
|
|
1754
1566
|
getSourceIdentifier(url) {
|
|
1755
1567
|
try {
|
|
1756
|
-
|
|
1757
|
-
const hostParts = parsed.hostname.split(".");
|
|
1758
|
-
if (hostParts.length >= 2) {
|
|
1759
|
-
const tld = hostParts[hostParts.length - 1];
|
|
1760
|
-
return `${hostParts[hostParts.length - 2]}/${tld}`;
|
|
1761
|
-
}
|
|
1762
|
-
return parsed.hostname.replace(".", "/");
|
|
1568
|
+
return new URL(url).hostname.replace(/^www\./, "");
|
|
1763
1569
|
} catch {
|
|
1764
|
-
return "unknown
|
|
1570
|
+
return "unknown";
|
|
1765
1571
|
}
|
|
1766
1572
|
}
|
|
1767
1573
|
async hasSkillsIndex(url) {
|
|
@@ -1769,28 +1575,6 @@ var WellKnownProvider = class {
|
|
|
1769
1575
|
}
|
|
1770
1576
|
};
|
|
1771
1577
|
const wellKnownProvider = new WellKnownProvider();
|
|
1772
|
-
registerProvider(mintlifyProvider);
|
|
1773
|
-
registerProvider(huggingFaceProvider);
|
|
1774
|
-
async function fetchMintlifySkill(url) {
|
|
1775
|
-
try {
|
|
1776
|
-
const response = await fetch(url, { signal: AbortSignal.timeout(3e4) });
|
|
1777
|
-
if (!response.ok) return null;
|
|
1778
|
-
const content = await response.text();
|
|
1779
|
-
const { data } = (0, import_gray_matter.default)(content);
|
|
1780
|
-
const mintlifySite = data.metadata?.["mintlify-proj"];
|
|
1781
|
-
if (!mintlifySite) return null;
|
|
1782
|
-
if (!data.name || !data.description) return null;
|
|
1783
|
-
return {
|
|
1784
|
-
name: data.name,
|
|
1785
|
-
description: data.description,
|
|
1786
|
-
content,
|
|
1787
|
-
mintlifySite,
|
|
1788
|
-
sourceUrl: url
|
|
1789
|
-
};
|
|
1790
|
-
} catch {
|
|
1791
|
-
return null;
|
|
1792
|
-
}
|
|
1793
|
-
}
|
|
1794
1578
|
const AGENTS_DIR$1 = ".agents";
|
|
1795
1579
|
const LOCK_FILE$1 = ".skill-lock.json";
|
|
1796
1580
|
const CURRENT_VERSION$1 = 3;
|
|
@@ -1967,7 +1751,7 @@ function createEmptyLocalLock() {
|
|
|
1967
1751
|
skills: {}
|
|
1968
1752
|
};
|
|
1969
1753
|
}
|
|
1970
|
-
var version$1 = "1.4.
|
|
1754
|
+
var version$1 = "1.4.3";
|
|
1971
1755
|
const isCancelled$1 = (value) => typeof value === "symbol";
|
|
1972
1756
|
async function isSourcePrivate(source) {
|
|
1973
1757
|
const ownerRepo = parseOwnerRepo(source);
|
|
@@ -2133,232 +1917,6 @@ async function selectAgentsInteractive(options) {
|
|
|
2133
1917
|
return selected;
|
|
2134
1918
|
}
|
|
2135
1919
|
setVersion(version$1);
|
|
2136
|
-
async function handleRemoteSkill(source, url, options, spinner) {
|
|
2137
|
-
const provider = findProvider(url);
|
|
2138
|
-
if (!provider) {
|
|
2139
|
-
await handleDirectUrlSkillLegacy(source, url, options, spinner);
|
|
2140
|
-
return;
|
|
2141
|
-
}
|
|
2142
|
-
spinner.start(`Fetching skill.md from ${provider.displayName}...`);
|
|
2143
|
-
const providerSkill = await provider.fetchSkill(url);
|
|
2144
|
-
if (!providerSkill) {
|
|
2145
|
-
spinner.stop(import_picocolors.default.red("Invalid skill"));
|
|
2146
|
-
Se(import_picocolors.default.red("Could not fetch skill.md or missing required frontmatter (name, description)."));
|
|
2147
|
-
process.exit(1);
|
|
2148
|
-
}
|
|
2149
|
-
const remoteSkill = {
|
|
2150
|
-
name: providerSkill.name,
|
|
2151
|
-
description: providerSkill.description,
|
|
2152
|
-
content: providerSkill.content,
|
|
2153
|
-
installName: providerSkill.installName,
|
|
2154
|
-
sourceUrl: providerSkill.sourceUrl,
|
|
2155
|
-
providerId: provider.id,
|
|
2156
|
-
sourceIdentifier: provider.getSourceIdentifier(url),
|
|
2157
|
-
metadata: providerSkill.metadata
|
|
2158
|
-
};
|
|
2159
|
-
spinner.stop(`Found skill: ${import_picocolors.default.cyan(remoteSkill.installName)}`);
|
|
2160
|
-
M.info(`Skill: ${import_picocolors.default.cyan(remoteSkill.name)}`);
|
|
2161
|
-
M.message(import_picocolors.default.dim(remoteSkill.description));
|
|
2162
|
-
M.message(import_picocolors.default.dim(`Source: ${remoteSkill.sourceIdentifier}`));
|
|
2163
|
-
if (options.list) {
|
|
2164
|
-
console.log();
|
|
2165
|
-
M.step(import_picocolors.default.bold("Skill Details"));
|
|
2166
|
-
M.message(` ${import_picocolors.default.cyan("Name:")} ${remoteSkill.name}`);
|
|
2167
|
-
M.message(` ${import_picocolors.default.cyan("Install as:")} ${remoteSkill.installName}`);
|
|
2168
|
-
M.message(` ${import_picocolors.default.cyan("Provider:")} ${provider.displayName}`);
|
|
2169
|
-
M.message(` ${import_picocolors.default.cyan("Description:")} ${remoteSkill.description}`);
|
|
2170
|
-
console.log();
|
|
2171
|
-
Se("Run without --list to install");
|
|
2172
|
-
process.exit(0);
|
|
2173
|
-
}
|
|
2174
|
-
let targetAgents;
|
|
2175
|
-
const validAgents = Object.keys(agents);
|
|
2176
|
-
const universalAgents = getUniversalAgents();
|
|
2177
|
-
if (options.agent?.includes("*")) {
|
|
2178
|
-
targetAgents = validAgents;
|
|
2179
|
-
M.info(`Installing to all ${targetAgents.length} agents`);
|
|
2180
|
-
} else if (options.agent && options.agent.length > 0) {
|
|
2181
|
-
const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
|
|
2182
|
-
if (invalidAgents.length > 0) {
|
|
2183
|
-
M.error(`Invalid agents: ${invalidAgents.join(", ")}`);
|
|
2184
|
-
M.info(`Valid agents: ${validAgents.join(", ")}`);
|
|
2185
|
-
process.exit(1);
|
|
2186
|
-
}
|
|
2187
|
-
targetAgents = options.agent;
|
|
2188
|
-
} else {
|
|
2189
|
-
spinner.start("Loading agents...");
|
|
2190
|
-
const installedAgents = await detectInstalledAgents();
|
|
2191
|
-
const totalAgents = Object.keys(agents).length;
|
|
2192
|
-
spinner.stop(`${totalAgents} agents`);
|
|
2193
|
-
if (installedAgents.length === 0) if (options.yes) {
|
|
2194
|
-
targetAgents = universalAgents;
|
|
2195
|
-
M.info(`Installing to universal agents`);
|
|
2196
|
-
} else {
|
|
2197
|
-
const selected = await selectAgentsInteractive({ global: options.global });
|
|
2198
|
-
if (pD(selected)) {
|
|
2199
|
-
xe("Installation cancelled");
|
|
2200
|
-
process.exit(0);
|
|
2201
|
-
}
|
|
2202
|
-
targetAgents = selected;
|
|
2203
|
-
}
|
|
2204
|
-
else if (installedAgents.length === 1 || options.yes) {
|
|
2205
|
-
targetAgents = ensureUniversalAgents(installedAgents);
|
|
2206
|
-
const { universal, symlinked } = splitAgentsByType(targetAgents);
|
|
2207
|
-
if (symlinked.length > 0) M.info(`Installing to: ${import_picocolors.default.green("universal")} + ${symlinked.map((a) => import_picocolors.default.cyan(a)).join(", ")}`);
|
|
2208
|
-
else M.info(`Installing to: ${import_picocolors.default.green("universal agents")}`);
|
|
2209
|
-
} else {
|
|
2210
|
-
const selected = await selectAgentsInteractive({ global: options.global });
|
|
2211
|
-
if (pD(selected)) {
|
|
2212
|
-
xe("Installation cancelled");
|
|
2213
|
-
process.exit(0);
|
|
2214
|
-
}
|
|
2215
|
-
targetAgents = selected;
|
|
2216
|
-
}
|
|
2217
|
-
}
|
|
2218
|
-
let installGlobally = options.global ?? false;
|
|
2219
|
-
const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== void 0);
|
|
2220
|
-
if (options.global === void 0 && !options.yes && supportsGlobal) {
|
|
2221
|
-
const scope = await ve({
|
|
2222
|
-
message: "Installation scope",
|
|
2223
|
-
options: [{
|
|
2224
|
-
value: false,
|
|
2225
|
-
label: "Project",
|
|
2226
|
-
hint: "Install in current directory (committed with your project)"
|
|
2227
|
-
}, {
|
|
2228
|
-
value: true,
|
|
2229
|
-
label: "Global",
|
|
2230
|
-
hint: "Install in home directory (available across all projects)"
|
|
2231
|
-
}]
|
|
2232
|
-
});
|
|
2233
|
-
if (pD(scope)) {
|
|
2234
|
-
xe("Installation cancelled");
|
|
2235
|
-
process.exit(0);
|
|
2236
|
-
}
|
|
2237
|
-
installGlobally = scope;
|
|
2238
|
-
}
|
|
2239
|
-
let installMode = options.copy ? "copy" : "symlink";
|
|
2240
|
-
if (!options.copy && !options.yes) {
|
|
2241
|
-
const modeChoice = await ve({
|
|
2242
|
-
message: "Installation method",
|
|
2243
|
-
options: [{
|
|
2244
|
-
value: "symlink",
|
|
2245
|
-
label: "Symlink (Recommended)",
|
|
2246
|
-
hint: "Single source of truth, easy updates"
|
|
2247
|
-
}, {
|
|
2248
|
-
value: "copy",
|
|
2249
|
-
label: "Copy to all agents",
|
|
2250
|
-
hint: "Independent copies for each agent"
|
|
2251
|
-
}]
|
|
2252
|
-
});
|
|
2253
|
-
if (pD(modeChoice)) {
|
|
2254
|
-
xe("Installation cancelled");
|
|
2255
|
-
process.exit(0);
|
|
2256
|
-
}
|
|
2257
|
-
installMode = modeChoice;
|
|
2258
|
-
}
|
|
2259
|
-
const cwd = process.cwd();
|
|
2260
|
-
const overwriteChecks = await Promise.all(targetAgents.map(async (agent) => ({
|
|
2261
|
-
agent,
|
|
2262
|
-
installed: await isSkillInstalled(remoteSkill.installName, agent, { global: installGlobally })
|
|
2263
|
-
})));
|
|
2264
|
-
const overwriteStatus = new Map(overwriteChecks.map(({ agent, installed }) => [agent, installed]));
|
|
2265
|
-
const summaryLines = [];
|
|
2266
|
-
const shortCanonical = shortenPath$2(getCanonicalPath(remoteSkill.installName, { global: installGlobally }), cwd);
|
|
2267
|
-
summaryLines.push(`${import_picocolors.default.cyan(shortCanonical)}`);
|
|
2268
|
-
summaryLines.push(...buildAgentSummaryLines(targetAgents, installMode));
|
|
2269
|
-
const overwriteAgents = targetAgents.filter((a) => overwriteStatus.get(a)).map((a) => agents[a].displayName);
|
|
2270
|
-
if (overwriteAgents.length > 0) summaryLines.push(` ${import_picocolors.default.yellow("overwrites:")} ${formatList$1(overwriteAgents)}`);
|
|
2271
|
-
console.log();
|
|
2272
|
-
Me(summaryLines.join("\n"), "Installation Summary");
|
|
2273
|
-
if (!options.yes) {
|
|
2274
|
-
const confirmed = await ye({ message: "Proceed with installation?" });
|
|
2275
|
-
if (pD(confirmed) || !confirmed) {
|
|
2276
|
-
xe("Installation cancelled");
|
|
2277
|
-
process.exit(0);
|
|
2278
|
-
}
|
|
2279
|
-
}
|
|
2280
|
-
spinner.start("Installing skill...");
|
|
2281
|
-
const results = [];
|
|
2282
|
-
for (const agent of targetAgents) {
|
|
2283
|
-
const result = await installRemoteSkillForAgent(remoteSkill, agent, {
|
|
2284
|
-
global: installGlobally,
|
|
2285
|
-
mode: installMode
|
|
2286
|
-
});
|
|
2287
|
-
results.push({
|
|
2288
|
-
skill: remoteSkill.installName,
|
|
2289
|
-
agent: agents[agent].displayName,
|
|
2290
|
-
...result
|
|
2291
|
-
});
|
|
2292
|
-
}
|
|
2293
|
-
spinner.stop("Installation complete");
|
|
2294
|
-
console.log();
|
|
2295
|
-
const successful = results.filter((r) => r.success);
|
|
2296
|
-
const failed = results.filter((r) => !r.success);
|
|
2297
|
-
if (await isSourcePrivate(remoteSkill.sourceIdentifier) !== true) track({
|
|
2298
|
-
event: "install",
|
|
2299
|
-
source: remoteSkill.sourceIdentifier,
|
|
2300
|
-
skills: remoteSkill.installName,
|
|
2301
|
-
agents: targetAgents.join(","),
|
|
2302
|
-
...installGlobally && { global: "1" },
|
|
2303
|
-
skillFiles: JSON.stringify({ [remoteSkill.installName]: url }),
|
|
2304
|
-
sourceType: remoteSkill.providerId
|
|
2305
|
-
});
|
|
2306
|
-
if (successful.length > 0 && installGlobally) try {
|
|
2307
|
-
let skillFolderHash = "";
|
|
2308
|
-
if (remoteSkill.providerId === "github") {
|
|
2309
|
-
const hash = await fetchSkillFolderHash(remoteSkill.sourceIdentifier, url);
|
|
2310
|
-
if (hash) skillFolderHash = hash;
|
|
2311
|
-
}
|
|
2312
|
-
await addSkillToLock(remoteSkill.installName, {
|
|
2313
|
-
source: remoteSkill.sourceIdentifier,
|
|
2314
|
-
sourceType: remoteSkill.providerId,
|
|
2315
|
-
sourceUrl: url,
|
|
2316
|
-
skillFolderHash
|
|
2317
|
-
});
|
|
2318
|
-
} catch {}
|
|
2319
|
-
if (successful.length > 0 && !installGlobally) try {
|
|
2320
|
-
const firstResult = successful[0];
|
|
2321
|
-
const computedHash = await computeSkillFolderHash(firstResult.canonicalPath || firstResult.path);
|
|
2322
|
-
await addSkillToLocalLock(remoteSkill.installName, {
|
|
2323
|
-
source: remoteSkill.sourceIdentifier,
|
|
2324
|
-
sourceType: remoteSkill.providerId,
|
|
2325
|
-
computedHash
|
|
2326
|
-
}, cwd);
|
|
2327
|
-
} catch {}
|
|
2328
|
-
if (successful.length > 0) {
|
|
2329
|
-
const resultLines = [];
|
|
2330
|
-
const firstResult = successful[0];
|
|
2331
|
-
if (firstResult.mode === "copy") {
|
|
2332
|
-
resultLines.push(`${import_picocolors.default.green("✓")} ${remoteSkill.installName} ${import_picocolors.default.dim("(copied)")}`);
|
|
2333
|
-
for (const r of successful) {
|
|
2334
|
-
const shortPath = shortenPath$2(r.path, cwd);
|
|
2335
|
-
resultLines.push(` ${import_picocolors.default.dim("→")} ${shortPath}`);
|
|
2336
|
-
}
|
|
2337
|
-
} else {
|
|
2338
|
-
if (firstResult.canonicalPath) {
|
|
2339
|
-
const shortPath = shortenPath$2(firstResult.canonicalPath, cwd);
|
|
2340
|
-
resultLines.push(`${import_picocolors.default.green("✓")} ${shortPath}`);
|
|
2341
|
-
} else resultLines.push(`${import_picocolors.default.green("✓")} ${remoteSkill.installName}`);
|
|
2342
|
-
resultLines.push(...buildResultLines(successful, targetAgents));
|
|
2343
|
-
}
|
|
2344
|
-
const title = import_picocolors.default.green("Installed 1 skill");
|
|
2345
|
-
Me(resultLines.join("\n"), title);
|
|
2346
|
-
const symlinkFailures = successful.filter((r) => r.mode === "symlink" && r.symlinkFailed);
|
|
2347
|
-
if (symlinkFailures.length > 0) {
|
|
2348
|
-
const copiedAgentNames = symlinkFailures.map((r) => r.agent);
|
|
2349
|
-
M.warn(import_picocolors.default.yellow(`Symlinks failed for: ${formatList$1(copiedAgentNames)}`));
|
|
2350
|
-
M.message(import_picocolors.default.dim(" Files were copied instead. On Windows, enable Developer Mode for symlink support."));
|
|
2351
|
-
}
|
|
2352
|
-
}
|
|
2353
|
-
if (failed.length > 0) {
|
|
2354
|
-
console.log();
|
|
2355
|
-
M.error(import_picocolors.default.red(`Failed to install ${failed.length}`));
|
|
2356
|
-
for (const r of failed) M.message(` ${import_picocolors.default.red("✗")} ${r.skill} → ${r.agent}: ${import_picocolors.default.dim(r.error)}`);
|
|
2357
|
-
}
|
|
2358
|
-
console.log();
|
|
2359
|
-
Se(import_picocolors.default.green("Done!") + import_picocolors.default.dim(" Review skills before use; they run with full agent permissions."));
|
|
2360
|
-
await promptForFindSkills(options, targetAgents);
|
|
2361
|
-
}
|
|
2362
1920
|
async function handleWellKnownSkills(source, url, options, spinner) {
|
|
2363
1921
|
spinner.start("Discovering skills from well-known endpoint...");
|
|
2364
1922
|
const skills = await wellKnownProvider.fetchAllSkills(url);
|
|
@@ -2639,188 +2197,6 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
2639
2197
|
Se(import_picocolors.default.green("Done!") + import_picocolors.default.dim(" Review skills before use; they run with full agent permissions."));
|
|
2640
2198
|
await promptForFindSkills(options, targetAgents);
|
|
2641
2199
|
}
|
|
2642
|
-
async function handleDirectUrlSkillLegacy(source, url, options, spinner) {
|
|
2643
|
-
spinner.start("Fetching skill.md...");
|
|
2644
|
-
const mintlifySkill = await fetchMintlifySkill(url);
|
|
2645
|
-
if (!mintlifySkill) {
|
|
2646
|
-
spinner.stop(import_picocolors.default.red("Invalid skill"));
|
|
2647
|
-
Se(import_picocolors.default.red("Could not fetch skill.md or missing required frontmatter (name, description, mintlify-proj)."));
|
|
2648
|
-
process.exit(1);
|
|
2649
|
-
}
|
|
2650
|
-
const remoteSkill = {
|
|
2651
|
-
name: mintlifySkill.name,
|
|
2652
|
-
description: mintlifySkill.description,
|
|
2653
|
-
content: mintlifySkill.content,
|
|
2654
|
-
installName: mintlifySkill.mintlifySite,
|
|
2655
|
-
sourceUrl: mintlifySkill.sourceUrl,
|
|
2656
|
-
providerId: "mintlify",
|
|
2657
|
-
sourceIdentifier: "mintlify/com"
|
|
2658
|
-
};
|
|
2659
|
-
spinner.stop(`Found skill: ${import_picocolors.default.cyan(remoteSkill.installName)}`);
|
|
2660
|
-
M.info(`Skill: ${import_picocolors.default.cyan(remoteSkill.name)}`);
|
|
2661
|
-
M.message(import_picocolors.default.dim(remoteSkill.description));
|
|
2662
|
-
if (options.list) {
|
|
2663
|
-
console.log();
|
|
2664
|
-
M.step(import_picocolors.default.bold("Skill Details"));
|
|
2665
|
-
M.message(` ${import_picocolors.default.cyan("Name:")} ${remoteSkill.name}`);
|
|
2666
|
-
M.message(` ${import_picocolors.default.cyan("Site:")} ${remoteSkill.installName}`);
|
|
2667
|
-
M.message(` ${import_picocolors.default.cyan("Description:")} ${remoteSkill.description}`);
|
|
2668
|
-
console.log();
|
|
2669
|
-
Se("Run without --list to install");
|
|
2670
|
-
process.exit(0);
|
|
2671
|
-
}
|
|
2672
|
-
let targetAgents;
|
|
2673
|
-
const validAgents = Object.keys(agents);
|
|
2674
|
-
if (options.agent?.includes("*")) {
|
|
2675
|
-
targetAgents = validAgents;
|
|
2676
|
-
M.info(`Installing to all ${targetAgents.length} agents`);
|
|
2677
|
-
} else if (options.agent && options.agent.length > 0) {
|
|
2678
|
-
const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
|
|
2679
|
-
if (invalidAgents.length > 0) {
|
|
2680
|
-
M.error(`Invalid agents: ${invalidAgents.join(", ")}`);
|
|
2681
|
-
M.info(`Valid agents: ${validAgents.join(", ")}`);
|
|
2682
|
-
process.exit(1);
|
|
2683
|
-
}
|
|
2684
|
-
targetAgents = options.agent;
|
|
2685
|
-
} else {
|
|
2686
|
-
spinner.start("Loading agents...");
|
|
2687
|
-
const installedAgents = await detectInstalledAgents();
|
|
2688
|
-
const totalAgents = Object.keys(agents).length;
|
|
2689
|
-
spinner.stop(`${totalAgents} agents`);
|
|
2690
|
-
if (installedAgents.length === 0) if (options.yes) {
|
|
2691
|
-
targetAgents = validAgents;
|
|
2692
|
-
M.info("Installing to all agents");
|
|
2693
|
-
} else {
|
|
2694
|
-
M.info("Select agents to install skills to");
|
|
2695
|
-
const selected = await promptForAgents("Which agents do you want to install to?", Object.entries(agents).map(([key, config]) => ({
|
|
2696
|
-
value: key,
|
|
2697
|
-
label: config.displayName
|
|
2698
|
-
})));
|
|
2699
|
-
if (pD(selected)) {
|
|
2700
|
-
xe("Installation cancelled");
|
|
2701
|
-
process.exit(0);
|
|
2702
|
-
}
|
|
2703
|
-
targetAgents = selected;
|
|
2704
|
-
}
|
|
2705
|
-
else if (installedAgents.length === 1 || options.yes) {
|
|
2706
|
-
targetAgents = ensureUniversalAgents(installedAgents);
|
|
2707
|
-
if (installedAgents.length === 1) {
|
|
2708
|
-
const firstAgent = installedAgents[0];
|
|
2709
|
-
M.info(`Installing to: ${import_picocolors.default.cyan(agents[firstAgent].displayName)}`);
|
|
2710
|
-
} else M.info(`Installing to: ${installedAgents.map((a) => import_picocolors.default.cyan(agents[a].displayName)).join(", ")}`);
|
|
2711
|
-
} else {
|
|
2712
|
-
const selected = await selectAgentsInteractive({ global: options.global });
|
|
2713
|
-
if (pD(selected)) {
|
|
2714
|
-
xe("Installation cancelled");
|
|
2715
|
-
process.exit(0);
|
|
2716
|
-
}
|
|
2717
|
-
targetAgents = selected;
|
|
2718
|
-
}
|
|
2719
|
-
}
|
|
2720
|
-
let installGlobally = options.global ?? false;
|
|
2721
|
-
const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== void 0);
|
|
2722
|
-
if (options.global === void 0 && !options.yes && supportsGlobal) {
|
|
2723
|
-
const scope = await ve({
|
|
2724
|
-
message: "Installation scope",
|
|
2725
|
-
options: [{
|
|
2726
|
-
value: false,
|
|
2727
|
-
label: "Project",
|
|
2728
|
-
hint: "Install in current directory (committed with your project)"
|
|
2729
|
-
}, {
|
|
2730
|
-
value: true,
|
|
2731
|
-
label: "Global",
|
|
2732
|
-
hint: "Install in home directory (available across all projects)"
|
|
2733
|
-
}]
|
|
2734
|
-
});
|
|
2735
|
-
if (pD(scope)) {
|
|
2736
|
-
xe("Installation cancelled");
|
|
2737
|
-
process.exit(0);
|
|
2738
|
-
}
|
|
2739
|
-
installGlobally = scope;
|
|
2740
|
-
}
|
|
2741
|
-
const installMode = "symlink";
|
|
2742
|
-
const cwd = process.cwd();
|
|
2743
|
-
const overwriteChecks = await Promise.all(targetAgents.map(async (agent) => ({
|
|
2744
|
-
agent,
|
|
2745
|
-
installed: await isSkillInstalled(remoteSkill.installName, agent, { global: installGlobally })
|
|
2746
|
-
})));
|
|
2747
|
-
const overwriteStatus = new Map(overwriteChecks.map(({ agent, installed }) => [agent, installed]));
|
|
2748
|
-
const summaryLines = [];
|
|
2749
|
-
targetAgents.map((a) => agents[a].displayName);
|
|
2750
|
-
const shortCanonical = shortenPath$2(getCanonicalPath(remoteSkill.installName, { global: installGlobally }), cwd);
|
|
2751
|
-
summaryLines.push(`${import_picocolors.default.cyan(shortCanonical)}`);
|
|
2752
|
-
summaryLines.push(...buildAgentSummaryLines(targetAgents, installMode));
|
|
2753
|
-
const overwriteAgents = targetAgents.filter((a) => overwriteStatus.get(a)).map((a) => agents[a].displayName);
|
|
2754
|
-
if (overwriteAgents.length > 0) summaryLines.push(` ${import_picocolors.default.yellow("overwrites:")} ${formatList$1(overwriteAgents)}`);
|
|
2755
|
-
console.log();
|
|
2756
|
-
Me(summaryLines.join("\n"), "Installation Summary");
|
|
2757
|
-
if (!options.yes) {
|
|
2758
|
-
const confirmed = await ye({ message: "Proceed with installation?" });
|
|
2759
|
-
if (pD(confirmed) || !confirmed) {
|
|
2760
|
-
xe("Installation cancelled");
|
|
2761
|
-
process.exit(0);
|
|
2762
|
-
}
|
|
2763
|
-
}
|
|
2764
|
-
spinner.start("Installing skill...");
|
|
2765
|
-
const results = [];
|
|
2766
|
-
for (const agent of targetAgents) {
|
|
2767
|
-
const result = await installRemoteSkillForAgent(remoteSkill, agent, {
|
|
2768
|
-
global: installGlobally,
|
|
2769
|
-
mode: installMode
|
|
2770
|
-
});
|
|
2771
|
-
results.push({
|
|
2772
|
-
skill: remoteSkill.installName,
|
|
2773
|
-
agent: agents[agent].displayName,
|
|
2774
|
-
...result
|
|
2775
|
-
});
|
|
2776
|
-
}
|
|
2777
|
-
spinner.stop("Installation complete");
|
|
2778
|
-
console.log();
|
|
2779
|
-
const successful = results.filter((r) => r.success);
|
|
2780
|
-
const failed = results.filter((r) => !r.success);
|
|
2781
|
-
track({
|
|
2782
|
-
event: "install",
|
|
2783
|
-
source: "mintlify/com",
|
|
2784
|
-
skills: remoteSkill.installName,
|
|
2785
|
-
agents: targetAgents.join(","),
|
|
2786
|
-
...installGlobally && { global: "1" },
|
|
2787
|
-
skillFiles: JSON.stringify({ [remoteSkill.installName]: url }),
|
|
2788
|
-
sourceType: "mintlify"
|
|
2789
|
-
});
|
|
2790
|
-
if (successful.length > 0 && installGlobally) try {
|
|
2791
|
-
await addSkillToLock(remoteSkill.installName, {
|
|
2792
|
-
source: `mintlify/${remoteSkill.installName}`,
|
|
2793
|
-
sourceType: "mintlify",
|
|
2794
|
-
sourceUrl: url,
|
|
2795
|
-
skillFolderHash: ""
|
|
2796
|
-
});
|
|
2797
|
-
} catch {}
|
|
2798
|
-
if (successful.length > 0) {
|
|
2799
|
-
const resultLines = [];
|
|
2800
|
-
const firstResult = successful[0];
|
|
2801
|
-
if (firstResult.canonicalPath) {
|
|
2802
|
-
const shortPath = shortenPath$2(firstResult.canonicalPath, cwd);
|
|
2803
|
-
resultLines.push(`${import_picocolors.default.green("✓")} ${shortPath}`);
|
|
2804
|
-
} else resultLines.push(`${import_picocolors.default.green("✓")} ${remoteSkill.installName}`);
|
|
2805
|
-
resultLines.push(...buildResultLines(successful, targetAgents));
|
|
2806
|
-
const title = import_picocolors.default.green("Installed 1 skill");
|
|
2807
|
-
Me(resultLines.join("\n"), title);
|
|
2808
|
-
const symlinkFailures = successful.filter((r) => r.mode === "symlink" && r.symlinkFailed);
|
|
2809
|
-
if (symlinkFailures.length > 0) {
|
|
2810
|
-
const copiedAgentNames = symlinkFailures.map((r) => r.agent);
|
|
2811
|
-
M.warn(import_picocolors.default.yellow(`Symlinks failed for: ${formatList$1(copiedAgentNames)}`));
|
|
2812
|
-
M.message(import_picocolors.default.dim(" Files were copied instead. On Windows, enable Developer Mode for symlink support."));
|
|
2813
|
-
}
|
|
2814
|
-
}
|
|
2815
|
-
if (failed.length > 0) {
|
|
2816
|
-
console.log();
|
|
2817
|
-
M.error(import_picocolors.default.red(`Failed to install ${failed.length}`));
|
|
2818
|
-
for (const r of failed) M.message(` ${import_picocolors.default.red("✗")} ${r.skill} → ${r.agent}: ${import_picocolors.default.dim(r.error)}`);
|
|
2819
|
-
}
|
|
2820
|
-
console.log();
|
|
2821
|
-
Se(import_picocolors.default.green("Done!") + import_picocolors.default.dim(" Review skills before use; they run with full agent permissions."));
|
|
2822
|
-
await promptForFindSkills(options, targetAgents);
|
|
2823
|
-
}
|
|
2824
2200
|
async function runAdd(args, options = {}) {
|
|
2825
2201
|
const source = args[0];
|
|
2826
2202
|
let installTipShown = false;
|
|
@@ -2855,10 +2231,6 @@ async function runAdd(args, options = {}) {
|
|
|
2855
2231
|
spinner.start("Parsing source...");
|
|
2856
2232
|
const parsed = parseSource(source);
|
|
2857
2233
|
spinner.stop(`Source: ${parsed.type === "local" ? parsed.localPath : parsed.url}${parsed.ref ? ` @ ${import_picocolors.default.yellow(parsed.ref)}` : ""}${parsed.subpath ? ` (${parsed.subpath})` : ""}${parsed.skillFilter ? ` ${import_picocolors.default.dim("@")}${import_picocolors.default.cyan(parsed.skillFilter)}` : ""}`);
|
|
2858
|
-
if (parsed.type === "direct-url") {
|
|
2859
|
-
await handleRemoteSkill(source, parsed.url, options, spinner);
|
|
2860
|
-
return;
|
|
2861
|
-
}
|
|
2862
2234
|
if (parsed.type === "well-known") {
|
|
2863
2235
|
await handleWellKnownSkills(source, parsed.url, options, spinner);
|
|
2864
2236
|
return;
|