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.
Files changed (2) hide show
  1. package/dist/cli.mjs +4 -632
  2. 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
- const registry = new ProviderRegistryImpl();
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
- const parsed = new URL(url);
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/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.2";
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skills",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "description": "The open agent skills ecosystem",
5
5
  "type": "module",
6
6
  "bin": {