skills 1.2.2 → 1.2.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/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  The CLI for the open agent skills ecosystem.
4
4
 
5
5
  <!-- agent-list:start -->
6
- Supports **OpenCode**, **Claude Code**, **Codex**, **Cursor**, and [31 more](#available-agents).
6
+ Supports **OpenCode**, **Claude Code**, **Codex**, **Cursor**, and [32 more](#available-agents).
7
7
  <!-- agent-list:end -->
8
8
 
9
9
  ## Install a Skill
@@ -39,8 +39,8 @@ npx skills add ./my-local-skills
39
39
  | Option | Description |
40
40
  | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
41
41
  | `-g, --global` | Install to user directory instead of project |
42
- | `-a, --agent <agents...>` | <!-- agent-names:start -->Target specific agents (e.g., `claude-code`, `codex`). See [Available Agents](#available-agents)<!-- agent-names:end --> |
43
- | `-s, --skill <skills...>` | Install specific skills by name (quote multi-word names: `--skill "My Skill"`) |
42
+ | `-a, --agent <agents...>` | <!-- agent-names:start -->Target specific agents (e.g., `claude-code`, `codex`). Use `'*'` for all agents<!-- agent-names:end --> |
43
+ | `-s, --skill <skills...>` | Install specific skills by name (use `'*'` for all skills) |
44
44
  | `-l, --list` | List available skills without installing |
45
45
  | `-y, --yes` | Skip all confirmation prompts |
46
46
  | `--all` | Install all skills to all agents without prompts |
@@ -65,6 +65,12 @@ npx skills add vercel-labs/agent-skills --skill frontend-design -g -a claude-cod
65
65
 
66
66
  # Install all skills from a repo to all agents
67
67
  npx skills add vercel-labs/agent-skills --all
68
+
69
+ # Install all skills to specific agents
70
+ npx skills add vercel-labs/agent-skills --skill '*' -a claude-code
71
+
72
+ # Install specific skills to all agents
73
+ npx skills add vercel-labs/agent-skills --agent '*' --skill frontend-design
68
74
  ```
69
75
 
70
76
  ### Installation Scope
@@ -93,7 +99,6 @@ When installing interactively, you can choose:
93
99
  | `npx skills check` | Check for available skill updates |
94
100
  | `npx skills update` | Update all installed skills to latest versions |
95
101
  | `npx skills init [name]` | Create a new SKILL.md template |
96
- | `npx skills generate-lock` | Match installed skills to sources for update tracking |
97
102
 
98
103
  ### `skills list`
99
104
 
@@ -142,16 +147,6 @@ npx skills init
142
147
  npx skills init my-skill
143
148
  ```
144
149
 
145
- ### `skills generate-lock`
146
-
147
- ```bash
148
- # Match installed skills to sources for update tracking
149
- npx skills generate-lock
150
-
151
- # Preview without writing
152
- npx skills generate-lock --dry-run
153
- ```
154
-
155
150
  ### `skills remove`
156
151
 
157
152
  Remove installed skills from agents.
@@ -173,7 +168,13 @@ npx skills remove --global web-design-guidelines
173
168
  npx skills remove --agent claude-code cursor my-skill
174
169
 
175
170
  # Remove all installed skills without confirmation
176
- npx skills remove --all -y
171
+ npx skills remove --all
172
+
173
+ # Remove all skills from a specific agent
174
+ npx skills remove --skill '*' -a cursor
175
+
176
+ # Remove a specific skill from all agents
177
+ npx skills remove my-skill --agent '*'
177
178
 
178
179
  # Use 'rm' alias
179
180
  npx skills rm my-skill
@@ -182,9 +183,10 @@ npx skills rm my-skill
182
183
  | Option | Description |
183
184
  | ------------------- | ---------------------------------------------------- |
184
185
  | `-g, --global` | Remove from global scope (~/) instead of project |
185
- | `-a, --agent` | Remove from specific agents only |
186
+ | `-a, --agent` | Remove from specific agents (use `'*'` for all) |
187
+ | `-s, --skill` | Specify skills to remove (use `'*'` for all) |
186
188
  | `-y, --yes` | Skip confirmation prompts |
187
- | `--all` | Remove all installed skills |
189
+ | `--all` | Shorthand for `--skill '*' --agent '*' -y` |
188
190
 
189
191
  ## What are Agent Skills?
190
192
 
@@ -233,6 +235,7 @@ Skills can be installed to any of these agents:
233
235
  | Pi | `pi` | `.pi/skills/` | `~/.pi/agent/skills/` |
234
236
  | Qoder | `qoder` | `.qoder/skills/` | `~/.qoder/skills/` |
235
237
  | Qwen Code | `qwen-code` | `.qwen/skills/` | `~/.qwen/skills/` |
238
+ | Replit | `replit` | `.agent/skills/` | N/A (project-only) |
236
239
  | Roo Code | `roo` | `.roo/skills/` | `~/.roo/skills/` |
237
240
  | Trae | `trae` | `.trae/skills/` | `~/.trae/skills/` |
238
241
  | Trae CN | `trae-cn` | `.trae/skills/` | `~/.trae-cn/skills/` |
@@ -420,6 +423,7 @@ Telemetry is automatically disabled in CI environments.
420
423
  - [OpenHands Skills Documentation](https://docs.openhands.ai/modules/usage/how-to/using-skills)
421
424
  - [Pi Skills Documentation](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/skills.md)
422
425
  - [Qoder Skills Documentation](https://docs.qoder.com/cli/Skills)
426
+ - [Replit Skills Documentation](https://docs.replit.com/replitai/skills)
423
427
  - [Roo Code Skills Documentation](https://docs.roocode.com/features/skills)
424
428
  - [Trae Skills Documentation](https://docs.trae.ai/ide/skills)
425
429
  - [Vercel Agent Skills Repository](https://github.com/vercel-labs/agent-skills)
package/dist/cli.d.mts CHANGED
@@ -1,4 +1 @@
1
- //#region src/cli.d.ts
2
- declare function formatSkippedMessage(skippedSkills: string[]): string | null;
3
- //#endregion
4
- export { formatSkippedMessage };
1
+ export { };
package/dist/cli.mjs CHANGED
@@ -9,7 +9,7 @@ import { t as require_gray_matter } from "./_chunks/libs/gray-matter.mjs";
9
9
  import "./_chunks/libs/extend-shallow.mjs";
10
10
  import "./_chunks/libs/esprima.mjs";
11
11
  import { spawn, spawnSync } from "child_process";
12
- import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
12
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
13
13
  import { basename, dirname, isAbsolute, join, normalize, relative, resolve, sep } from "path";
14
14
  import { homedir, platform, tmpdir } from "os";
15
15
  import "crypto";
@@ -266,7 +266,8 @@ async function discoverSkills(basePath, subpath, options) {
266
266
  const skill = await parseSkillMd(join(searchPath, "SKILL.md"), options);
267
267
  if (skill) {
268
268
  skills.push(skill);
269
- return skills;
269
+ seenNames.add(skill.name);
270
+ if (!options?.fullDepth) return skills;
270
271
  }
271
272
  }
272
273
  const prioritySearchDirs = [
@@ -360,6 +361,15 @@ const agents = {
360
361
  return existsSync(join(process.cwd(), ".agent")) || existsSync(join(home, ".gemini/antigravity"));
361
362
  }
362
363
  },
364
+ augment: {
365
+ name: "augment",
366
+ displayName: "Augment",
367
+ skillsDir: ".augment/rules",
368
+ globalSkillsDir: join(home, ".augment/rules"),
369
+ detectInstalled: async () => {
370
+ return existsSync(join(home, ".augment"));
371
+ }
372
+ },
363
373
  "claude-code": {
364
374
  name: "claude-code",
365
375
  displayName: "Claude Code",
@@ -531,6 +541,15 @@ const agents = {
531
541
  return existsSync(join(home, ".mcpjam"));
532
542
  }
533
543
  },
544
+ "mistral-vibe": {
545
+ name: "mistral-vibe",
546
+ displayName: "Mistral Vibe",
547
+ skillsDir: ".vibe/skills",
548
+ globalSkillsDir: join(home, ".vibe/skills"),
549
+ detectInstalled: async () => {
550
+ return existsSync(join(home, ".vibe"));
551
+ }
552
+ },
534
553
  mux: {
535
554
  name: "mux",
536
555
  displayName: "Mux",
@@ -594,6 +613,15 @@ const agents = {
594
613
  return existsSync(join(home, ".qwen"));
595
614
  }
596
615
  },
616
+ replit: {
617
+ name: "replit",
618
+ displayName: "Replit",
619
+ skillsDir: ".agent/skills",
620
+ globalSkillsDir: void 0,
621
+ detectInstalled: async () => {
622
+ return existsSync(join(process.cwd(), ".agent"));
623
+ }
624
+ },
597
625
  roo: {
598
626
  name: "roo",
599
627
  displayName: "Roo Code",
@@ -656,6 +684,15 @@ const agents = {
656
684
  detectInstalled: async () => {
657
685
  return existsSync(join(home, ".pochi"));
658
686
  }
687
+ },
688
+ adal: {
689
+ name: "adal",
690
+ displayName: "AdaL",
691
+ skillsDir: ".adal/skills",
692
+ globalSkillsDir: join(home, ".adal/skills"),
693
+ detectInstalled: async () => {
694
+ return existsSync(join(home, ".adal"));
695
+ }
659
696
  }
660
697
  };
661
698
  async function detectInstalledAgents() {
@@ -665,7 +702,7 @@ async function detectInstalledAgents() {
665
702
  })))).filter((r) => r.installed).map((r) => r.type);
666
703
  }
667
704
  const AGENTS_DIR$2 = ".agents";
668
- const SKILLS_SUBDIR$1 = "skills";
705
+ const SKILLS_SUBDIR = "skills";
669
706
  function sanitizeName(name) {
670
707
  return name.toLowerCase().replace(/[^a-z0-9._]+/g, "-").replace(/^[.\-]+|[.\-]+$/g, "").substring(0, 255) || "unnamed-skill";
671
708
  }
@@ -675,7 +712,7 @@ function isPathSafe(basePath, targetPath) {
675
712
  return normalizedTarget.startsWith(normalizedBase + sep) || normalizedTarget === normalizedBase;
676
713
  }
677
714
  function getCanonicalSkillsDir(global, cwd) {
678
- return join(global ? homedir() : cwd || process.cwd(), AGENTS_DIR$2, SKILLS_SUBDIR$1);
715
+ return join(global ? homedir() : cwd || process.cwd(), AGENTS_DIR$2, SKILLS_SUBDIR);
679
716
  }
680
717
  function resolveSymlinkTarget(linkPath, linkTarget) {
681
718
  return resolve(dirname(linkPath), linkTarget);
@@ -715,6 +752,12 @@ async function installSkillForAgent(skill, agentType, options = {}) {
715
752
  const agent = agents[agentType];
716
753
  const isGlobal = options.global ?? false;
717
754
  const cwd = options.cwd || process.cwd();
755
+ if (isGlobal && agent.globalSkillsDir === void 0) return {
756
+ success: false,
757
+ path: "",
758
+ mode: options.mode ?? "symlink",
759
+ error: `${agent.displayName} does not support global skill installation`
760
+ };
718
761
  const skillName = sanitizeName(skill.name || basename(skill.path));
719
762
  const canonicalBase = getCanonicalSkillsDir(isGlobal, cwd);
720
763
  const canonicalDir = join(canonicalBase, skillName);
@@ -795,6 +838,7 @@ async function copyDirectory(src, dest) {
795
838
  async function isSkillInstalled(skillName, agentType, options = {}) {
796
839
  const agent = agents[agentType];
797
840
  const sanitized = sanitizeName(skillName);
841
+ if (options.global && agent.globalSkillsDir === void 0) return false;
798
842
  const targetBase = options.global ? agent.globalSkillsDir : join(options.cwd || process.cwd(), agent.skillsDir);
799
843
  const skillDir = join(targetBase, sanitized);
800
844
  if (!isPathSafe(targetBase, skillDir)) return false;
@@ -809,7 +853,7 @@ function getInstallPath(skillName, agentType, options = {}) {
809
853
  const agent = agents[agentType];
810
854
  const cwd = options.cwd || process.cwd();
811
855
  const sanitized = sanitizeName(skillName);
812
- const targetBase = options.global ? agent.globalSkillsDir : join(cwd, agent.skillsDir);
856
+ const targetBase = options.global && agent.globalSkillsDir !== void 0 ? agent.globalSkillsDir : join(cwd, agent.skillsDir);
813
857
  const installPath = join(targetBase, sanitized);
814
858
  if (!isPathSafe(targetBase, installPath)) throw new Error("Invalid skill name: potential path traversal detected");
815
859
  return installPath;
@@ -826,6 +870,12 @@ async function installRemoteSkillForAgent(skill, agentType, options = {}) {
826
870
  const isGlobal = options.global ?? false;
827
871
  const cwd = options.cwd || process.cwd();
828
872
  const installMode = options.mode ?? "symlink";
873
+ if (isGlobal && agent.globalSkillsDir === void 0) return {
874
+ success: false,
875
+ path: "",
876
+ mode: installMode,
877
+ error: `${agent.displayName} does not support global skill installation`
878
+ };
829
879
  const skillName = sanitizeName(skill.installName);
830
880
  const canonicalBase = getCanonicalSkillsDir(isGlobal, cwd);
831
881
  const canonicalDir = join(canonicalBase, skillName);
@@ -886,6 +936,12 @@ async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
886
936
  const isGlobal = options.global ?? false;
887
937
  const cwd = options.cwd || process.cwd();
888
938
  const installMode = options.mode ?? "symlink";
939
+ if (isGlobal && agent.globalSkillsDir === void 0) return {
940
+ success: false,
941
+ path: "",
942
+ mode: installMode,
943
+ error: `${agent.displayName} does not support global skill installation`
944
+ };
889
945
  const skillName = sanitizeName(skill.installName);
890
946
  const canonicalBase = getCanonicalSkillsDir(isGlobal, cwd);
891
947
  const canonicalDir = join(canonicalBase, skillName);
@@ -985,6 +1041,7 @@ async function listInstalledSkills(options = {}) {
985
1041
  const agentsToCheck = options.agentFilter || Object.keys(agents);
986
1042
  for (const agentType of agentsToCheck) {
987
1043
  const agent = agents[agentType];
1044
+ if (scope.global && agent.globalSkillsDir === void 0) continue;
988
1045
  const agentBase = scope.global ? agent.globalSkillsDir : join(cwd, agent.skillsDir);
989
1046
  let found = false;
990
1047
  const possibleNames = [
@@ -1382,7 +1439,7 @@ async function readSkillLock$1() {
1382
1439
  return createEmptyLockFile();
1383
1440
  }
1384
1441
  }
1385
- async function writeSkillLock$1(lock) {
1442
+ async function writeSkillLock(lock) {
1386
1443
  const lockPath = getSkillLockPath$1();
1387
1444
  await mkdir(dirname(lockPath), { recursive: true });
1388
1445
  await writeFile(lockPath, JSON.stringify(lock, null, 2), "utf-8");
@@ -1417,13 +1474,13 @@ async function addSkillToLock(skillName, entry) {
1417
1474
  installedAt: existingEntry?.installedAt ?? now,
1418
1475
  updatedAt: now
1419
1476
  };
1420
- await writeSkillLock$1(lock);
1477
+ await writeSkillLock(lock);
1421
1478
  }
1422
1479
  async function removeSkillFromLock(skillName) {
1423
1480
  const lock = await readSkillLock$1();
1424
1481
  if (!(skillName in lock.skills)) return false;
1425
1482
  delete lock.skills[skillName];
1426
- await writeSkillLock$1(lock);
1483
+ await writeSkillLock(lock);
1427
1484
  return true;
1428
1485
  }
1429
1486
  async function getSkillFromLock(skillName) {
@@ -1443,7 +1500,7 @@ async function dismissPrompt(promptKey) {
1443
1500
  const lock = await readSkillLock$1();
1444
1501
  if (!lock.dismissed) lock.dismissed = {};
1445
1502
  lock.dismissed[promptKey] = true;
1446
- await writeSkillLock$1(lock);
1503
+ await writeSkillLock(lock);
1447
1504
  }
1448
1505
  async function getLastSelectedAgents() {
1449
1506
  return (await readSkillLock$1()).lastSelectedAgents;
@@ -1451,9 +1508,9 @@ async function getLastSelectedAgents() {
1451
1508
  async function saveSelectedAgents(agents) {
1452
1509
  const lock = await readSkillLock$1();
1453
1510
  lock.lastSelectedAgents = agents;
1454
- await writeSkillLock$1(lock);
1511
+ await writeSkillLock(lock);
1455
1512
  }
1456
- var version$1 = "1.2.2";
1513
+ var version$1 = "1.2.3";
1457
1514
  async function isSourcePrivate(source) {
1458
1515
  const ownerRepo = parseOwnerRepo(source);
1459
1516
  if (!ownerRepo) return false;
@@ -1583,7 +1640,10 @@ async function handleRemoteSkill(source, url, options, spinner) {
1583
1640
  }
1584
1641
  let targetAgents;
1585
1642
  const validAgents = Object.keys(agents);
1586
- if (options.agent && options.agent.length > 0) {
1643
+ if (options.agent?.includes("*")) {
1644
+ targetAgents = validAgents;
1645
+ M.info(`Installing to all ${targetAgents.length} agents`);
1646
+ } else if (options.agent && options.agent.length > 0) {
1587
1647
  const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
1588
1648
  if (invalidAgents.length > 0) {
1589
1649
  M.error(`Invalid agents: ${invalidAgents.join(", ")}`);
@@ -1626,7 +1686,8 @@ async function handleRemoteSkill(source, url, options, spinner) {
1626
1686
  }
1627
1687
  }
1628
1688
  let installGlobally = options.global ?? false;
1629
- if (options.global === void 0 && !options.yes) {
1689
+ const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== void 0);
1690
+ if (options.global === void 0 && !options.yes && supportsGlobal) {
1630
1691
  const scope = await ve({
1631
1692
  message: "Installation scope",
1632
1693
  options: [{
@@ -1795,7 +1856,10 @@ async function handleWellKnownSkills(source, url, options, spinner) {
1795
1856
  process.exit(0);
1796
1857
  }
1797
1858
  let selectedSkills;
1798
- if (options.skill && options.skill.length > 0) {
1859
+ if (options.skill?.includes("*")) {
1860
+ selectedSkills = skills;
1861
+ M.info(`Installing all ${skills.length} skills`);
1862
+ } else if (options.skill && options.skill.length > 0) {
1799
1863
  selectedSkills = skills.filter((s) => options.skill.some((name) => s.installName.toLowerCase() === name.toLowerCase() || s.name.toLowerCase() === name.toLowerCase()));
1800
1864
  if (selectedSkills.length === 0) {
1801
1865
  M.error(`No matching skills found for: ${options.skill.join(", ")}`);
@@ -1829,7 +1893,10 @@ async function handleWellKnownSkills(source, url, options, spinner) {
1829
1893
  }
1830
1894
  let targetAgents;
1831
1895
  const validAgents = Object.keys(agents);
1832
- if (options.agent && options.agent.length > 0) {
1896
+ if (options.agent?.includes("*")) {
1897
+ targetAgents = validAgents;
1898
+ M.info(`Installing to all ${targetAgents.length} agents`);
1899
+ } else if (options.agent && options.agent.length > 0) {
1833
1900
  const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
1834
1901
  if (invalidAgents.length > 0) {
1835
1902
  M.error(`Invalid agents: ${invalidAgents.join(", ")}`);
@@ -1837,9 +1904,6 @@ async function handleWellKnownSkills(source, url, options, spinner) {
1837
1904
  process.exit(1);
1838
1905
  }
1839
1906
  targetAgents = options.agent;
1840
- } else if (options.all) {
1841
- targetAgents = validAgents;
1842
- M.info(`Installing to all ${targetAgents.length} agents`);
1843
1907
  } else {
1844
1908
  spinner.start("Detecting installed agents...");
1845
1909
  const installedAgents = await detectInstalledAgents();
@@ -1875,7 +1939,8 @@ async function handleWellKnownSkills(source, url, options, spinner) {
1875
1939
  }
1876
1940
  }
1877
1941
  let installGlobally = options.global ?? false;
1878
- if (options.global === void 0 && !options.yes) {
1942
+ const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== void 0);
1943
+ if (options.global === void 0 && !options.yes && supportsGlobal) {
1879
1944
  const scope = await ve({
1880
1945
  message: "Installation scope",
1881
1946
  options: [{
@@ -2070,7 +2135,10 @@ async function handleDirectUrlSkillLegacy(source, url, options, spinner) {
2070
2135
  }
2071
2136
  let targetAgents;
2072
2137
  const validAgents = Object.keys(agents);
2073
- if (options.agent && options.agent.length > 0) {
2138
+ if (options.agent?.includes("*")) {
2139
+ targetAgents = validAgents;
2140
+ M.info(`Installing to all ${targetAgents.length} agents`);
2141
+ } else if (options.agent && options.agent.length > 0) {
2074
2142
  const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
2075
2143
  if (invalidAgents.length > 0) {
2076
2144
  M.error(`Invalid agents: ${invalidAgents.join(", ")}`);
@@ -2113,7 +2181,8 @@ async function handleDirectUrlSkillLegacy(source, url, options, spinner) {
2113
2181
  }
2114
2182
  }
2115
2183
  let installGlobally = options.global ?? false;
2116
- if (options.global === void 0 && !options.yes) {
2184
+ const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== void 0);
2185
+ if (options.global === void 0 && !options.yes && supportsGlobal) {
2117
2186
  const scope = await ve({
2118
2187
  message: "Installation scope",
2119
2188
  options: [{
@@ -2238,7 +2307,11 @@ async function runAdd(args, options = {}) {
2238
2307
  console.log();
2239
2308
  process.exit(1);
2240
2309
  }
2241
- if (options.all) options.yes = true;
2310
+ if (options.all) {
2311
+ options.skill = ["*"];
2312
+ options.agent = ["*"];
2313
+ options.yes = true;
2314
+ }
2242
2315
  console.log();
2243
2316
  Ie(import_picocolors.default.bgCyan(import_picocolors.default.black(" skills ")));
2244
2317
  if (!process.stdin.isTTY) showInstallTip();
@@ -2278,7 +2351,10 @@ async function runAdd(args, options = {}) {
2278
2351
  }
2279
2352
  const includeInternal = !!(options.skill && options.skill.length > 0);
2280
2353
  spinner.start("Discovering skills...");
2281
- const skills = await discoverSkills(skillsDir, parsed.subpath, { includeInternal });
2354
+ const skills = await discoverSkills(skillsDir, parsed.subpath, {
2355
+ includeInternal,
2356
+ fullDepth: options.fullDepth
2357
+ });
2282
2358
  if (skills.length === 0) {
2283
2359
  spinner.stop(import_picocolors.default.red("No skills found"));
2284
2360
  Se(import_picocolors.default.red("No valid skills found. Skills require a SKILL.md with name and description."));
@@ -2299,7 +2375,10 @@ async function runAdd(args, options = {}) {
2299
2375
  process.exit(0);
2300
2376
  }
2301
2377
  let selectedSkills;
2302
- if (options.skill && options.skill.length > 0) {
2378
+ if (options.skill?.includes("*")) {
2379
+ selectedSkills = skills;
2380
+ M.info(`Installing all ${skills.length} skills`);
2381
+ } else if (options.skill && options.skill.length > 0) {
2303
2382
  selectedSkills = filterSkills(skills, options.skill);
2304
2383
  if (selectedSkills.length === 0) {
2305
2384
  M.error(`No matching skills found for: ${options.skill.join(", ")}`);
@@ -2336,7 +2415,10 @@ async function runAdd(args, options = {}) {
2336
2415
  }
2337
2416
  let targetAgents;
2338
2417
  const validAgents = Object.keys(agents);
2339
- if (options.agent && options.agent.length > 0) {
2418
+ if (options.agent?.includes("*")) {
2419
+ targetAgents = validAgents;
2420
+ M.info(`Installing to all ${targetAgents.length} agents`);
2421
+ } else if (options.agent && options.agent.length > 0) {
2340
2422
  const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
2341
2423
  if (invalidAgents.length > 0) {
2342
2424
  M.error(`Invalid agents: ${invalidAgents.join(", ")}`);
@@ -2345,9 +2427,6 @@ async function runAdd(args, options = {}) {
2345
2427
  process.exit(1);
2346
2428
  }
2347
2429
  targetAgents = options.agent;
2348
- } else if (options.all) {
2349
- targetAgents = validAgents;
2350
- M.info(`Installing to all ${targetAgents.length} agents`);
2351
2430
  } else {
2352
2431
  spinner.start("Detecting installed agents...");
2353
2432
  const installedAgents = await detectInstalledAgents();
@@ -2385,7 +2464,8 @@ async function runAdd(args, options = {}) {
2385
2464
  }
2386
2465
  }
2387
2466
  let installGlobally = options.global ?? false;
2388
- if (options.global === void 0 && !options.yes) {
2467
+ const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== void 0);
2468
+ if (options.global === void 0 && !options.yes && supportsGlobal) {
2389
2469
  const scope = await ve({
2390
2470
  message: "Installation scope",
2391
2471
  options: [{
@@ -2659,7 +2739,8 @@ function parseAddOptions(args) {
2659
2739
  nextArg = args[i];
2660
2740
  }
2661
2741
  i--;
2662
- } else if (arg && !arg.startsWith("-")) source.push(arg);
2742
+ } else if (arg === "--full-depth") options.fullDepth = true;
2743
+ else if (arg && !arg.startsWith("-")) source.push(arg);
2663
2744
  }
2664
2745
  return {
2665
2746
  source,
@@ -2961,7 +3042,7 @@ async function removeCommand(skillNames, options) {
2961
3042
  };
2962
3043
  if (isGlobal) {
2963
3044
  await scanDir(getCanonicalSkillsDir(true, cwd));
2964
- for (const agent of Object.values(agents)) await scanDir(agent.globalSkillsDir);
3045
+ for (const agent of Object.values(agents)) if (agent.globalSkillsDir !== void 0) await scanDir(agent.globalSkillsDir);
2965
3046
  } else {
2966
3047
  await scanDir(getCanonicalSkillsDir(false, cwd));
2967
3048
  for (const agent of Object.values(agents)) await scanDir(join(cwd, agent.skillsDir));
@@ -3120,12 +3201,6 @@ function parseRemoveOptions(args) {
3120
3201
  options
3121
3202
  };
3122
3203
  }
3123
- function formatSkippedMessage(skippedSkills) {
3124
- if (skippedSkills.length === 0) return null;
3125
- const lines = [`Skipped ${skippedSkills.length} (reinstall needed):`];
3126
- for (const skill of skippedSkills) lines.push(` - ${skill}`);
3127
- return lines.join("\n");
3128
- }
3129
3204
  const __dirname = dirname(fileURLToPath(import.meta.url));
3130
3205
  function getVersion() {
3131
3206
  try {
@@ -3195,21 +3270,22 @@ ${BOLD}Commands:${RESET}
3195
3270
  init [name] Initialize a skill (creates <name>/SKILL.md or ./SKILL.md)
3196
3271
  check Check for available skill updates
3197
3272
  update Update all skills to latest versions
3198
- generate-lock Generate lock file from installed skills
3199
3273
 
3200
3274
  ${BOLD}Add Options:${RESET}
3201
3275
  -g, --global Install skill globally (user-level) instead of project-level
3202
- -a, --agent <agents> Specify agents to install to
3203
- -s, --skill <skills> Specify skill names to install (skip selection prompt)
3276
+ -a, --agent <agents> Specify agents to install to (use '*' for all agents)
3277
+ -s, --skill <skills> Specify skill names to install (use '*' for all skills)
3204
3278
  -l, --list List available skills in the repository without installing
3205
3279
  -y, --yes Skip confirmation prompts
3206
- --all Install all skills to all agents without any prompts
3280
+ --all Shorthand for --skill '*' --agent '*' -y
3281
+ --full-depth Search all subdirectories even when a root SKILL.md exists
3207
3282
 
3208
3283
  ${BOLD}Remove Options:${RESET}
3209
3284
  -g, --global Remove from global scope
3210
- -a, --agent <agents> Remove from specific agents
3285
+ -a, --agent <agents> Remove from specific agents (use '*' for all agents)
3286
+ -s, --skill <skills> Specify skills to remove (use '*' for all skills)
3211
3287
  -y, --yes Skip confirmation prompts
3212
- --all Remove all installed skills
3288
+ --all Shorthand for --skill '*' --agent '*' -y
3213
3289
 
3214
3290
  ${BOLD}List Options:${RESET}
3215
3291
  -g, --global List global skills (default: project)
@@ -3218,7 +3294,6 @@ ${BOLD}List Options:${RESET}
3218
3294
  ${BOLD}Options:${RESET}
3219
3295
  --help, -h Show this help message
3220
3296
  --version, -v Show version number
3221
- --dry-run Preview changes without writing (generate-lock)
3222
3297
 
3223
3298
  ${BOLD}Examples:${RESET}
3224
3299
  ${DIM}$${RESET} skills add vercel-labs/agent-skills
@@ -3253,9 +3328,10 @@ ${BOLD}Arguments:${RESET}
3253
3328
 
3254
3329
  ${BOLD}Options:${RESET}
3255
3330
  -g, --global Remove from global scope (~/) instead of project scope
3256
- -a, --agent Remove from specific agents only
3331
+ -a, --agent Remove from specific agents (use '*' for all agents)
3332
+ -s, --skill Specify skills to remove (use '*' for all skills)
3257
3333
  -y, --yes Skip confirmation prompts
3258
- --all Remove all installed skills
3334
+ --all Shorthand for --skill '*' --agent '*' -y
3259
3335
 
3260
3336
  ${BOLD}Examples:${RESET}
3261
3337
  ${DIM}$${RESET} skills remove ${DIM}# interactive selection${RESET}
@@ -3263,7 +3339,8 @@ ${BOLD}Examples:${RESET}
3263
3339
  ${DIM}$${RESET} skills remove skill1 skill2 -y ${DIM}# remove multiple skills${RESET}
3264
3340
  ${DIM}$${RESET} skills remove --global my-skill ${DIM}# remove from global scope${RESET}
3265
3341
  ${DIM}$${RESET} skills rm --agent claude-code my-skill ${DIM}# remove from specific agent${RESET}
3266
- ${DIM}$${RESET} skills remove --all -y ${DIM}# remove all skills${RESET}
3342
+ ${DIM}$${RESET} skills remove --all ${DIM}# remove all skills${RESET}
3343
+ ${DIM}$${RESET} skills remove --skill '*' -a cursor ${DIM}# remove all skills from cursor${RESET}
3267
3344
 
3268
3345
  Discover more skills at ${TEXT}https://skills.sh/${RESET}
3269
3346
  `);
@@ -3316,9 +3393,7 @@ Describe when this skill should be used.
3316
3393
  console.log();
3317
3394
  }
3318
3395
  const AGENTS_DIR = ".agents";
3319
- const SKILLS_SUBDIR = "skills";
3320
3396
  const LOCK_FILE = ".skill-lock.json";
3321
- const SEARCH_API_URL = "https://skills.sh/api/skills/search";
3322
3397
  const CHECK_UPDATES_API_URL = "https://add-skill.vercel.sh/check-updates";
3323
3398
  const CURRENT_LOCK_VERSION = 3;
3324
3399
  function getSkillLockPath() {
@@ -3345,115 +3420,6 @@ function readSkillLock() {
3345
3420
  };
3346
3421
  }
3347
3422
  }
3348
- function writeSkillLock(lock) {
3349
- const lockPath = getSkillLockPath();
3350
- const dir = join(homedir(), AGENTS_DIR);
3351
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
3352
- writeFileSync(lockPath, JSON.stringify(lock, null, 2), "utf-8");
3353
- }
3354
- function getInstalledSkillNames() {
3355
- const skillsDir = join(homedir(), AGENTS_DIR, SKILLS_SUBDIR);
3356
- const skillNames = [];
3357
- try {
3358
- const entries = readdirSync(skillsDir, { withFileTypes: true });
3359
- for (const entry of entries) if (entry.isDirectory() || entry.isSymbolicLink()) {
3360
- const skillMdPath = join(skillsDir, entry.name, "SKILL.md");
3361
- try {
3362
- if (statSync(skillMdPath).isFile()) skillNames.push(entry.name);
3363
- } catch {
3364
- try {
3365
- if (readdirSync(join(skillsDir, entry.name)).length > 0) skillNames.push(entry.name);
3366
- } catch {}
3367
- }
3368
- }
3369
- } catch {}
3370
- return skillNames;
3371
- }
3372
- async function fuzzyMatchSkills(skillNames, apiUrl = SEARCH_API_URL) {
3373
- if (skillNames.length === 0) return {};
3374
- const response = await fetch(apiUrl, {
3375
- method: "POST",
3376
- headers: { "Content-Type": "application/json" },
3377
- body: JSON.stringify({ skills: skillNames })
3378
- });
3379
- if (!response.ok) throw new Error(`API request failed: ${response.status} ${response.statusText}`);
3380
- return (await response.json()).matches;
3381
- }
3382
- function inferSourceType(source) {
3383
- if (source.startsWith("mintlify/")) return "mintlify";
3384
- if (source.startsWith("huggingface/")) return "huggingface";
3385
- return "github";
3386
- }
3387
- function buildSourceUrl(source, sourceType) {
3388
- switch (sourceType) {
3389
- case "github": return `https://github.com/${source}.git`;
3390
- case "mintlify": return source;
3391
- case "huggingface": return `https://huggingface.co/spaces/${source.replace("huggingface/", "").split("/").join("/")}`;
3392
- default: return source;
3393
- }
3394
- }
3395
- async function runGenerateLock(args) {
3396
- const dryRun = args.includes("--dry-run");
3397
- const apiUrlIdx = args.indexOf("--api-url");
3398
- const apiUrl = apiUrlIdx !== -1 && args[apiUrlIdx + 1] ? args[apiUrlIdx + 1] : SEARCH_API_URL;
3399
- console.log(`${TEXT}Scanning for installed skills...${RESET}`);
3400
- const installedSkills = getInstalledSkillNames();
3401
- if (installedSkills.length === 0) {
3402
- console.log(`${DIM}No installed skills found.${RESET}`);
3403
- return;
3404
- }
3405
- console.log(`${DIM}Found ${installedSkills.length} installed skill(s)${RESET}`);
3406
- console.log();
3407
- const existingLock = readSkillLock();
3408
- Object.keys(existingLock.skills).length;
3409
- const skillsToMatch = installedSkills.filter((skill) => !(skill in existingLock.skills));
3410
- if (skillsToMatch.length === 0) {
3411
- console.log(`${TEXT}All skills already in lock file.${RESET}`);
3412
- return;
3413
- }
3414
- console.log(`${TEXT}Matching ${skillsToMatch.length} skill(s) against database...${RESET}`);
3415
- console.log();
3416
- const matches = await fuzzyMatchSkills(skillsToMatch, apiUrl);
3417
- const now = (/* @__PURE__ */ new Date()).toISOString();
3418
- const updatedLock = { ...existingLock };
3419
- let matchedCount = 0;
3420
- let skippedCount = 0;
3421
- const EXACT_MATCH_THRESHOLD = 1e3;
3422
- for (const skillName of skillsToMatch) {
3423
- const match = matches[skillName];
3424
- if (match && match.score >= EXACT_MATCH_THRESHOLD) {
3425
- matchedCount++;
3426
- const sourceType = inferSourceType(match.source);
3427
- const sourceUrl = match.sourceUrl || buildSourceUrl(match.source, sourceType);
3428
- console.log(`${TEXT}✓${RESET} ${skillName}`);
3429
- console.log(` ${DIM}source: ${match.source}${RESET}`);
3430
- updatedLock.skills[skillName] = {
3431
- source: match.source,
3432
- sourceType,
3433
- sourceUrl,
3434
- skillFolderHash: "",
3435
- installedAt: now,
3436
- updatedAt: now
3437
- };
3438
- } else skippedCount++;
3439
- }
3440
- console.log();
3441
- console.log(`${TEXT}Matched:${RESET} ${matchedCount}`);
3442
- console.log(`${DIM}Skipped: ${skippedCount} (no exact match)${RESET}`);
3443
- console.log();
3444
- if (matchedCount === 0) {
3445
- console.log(`${DIM}No new skills to add to lock file.${RESET}`);
3446
- return;
3447
- }
3448
- if (dryRun) {
3449
- console.log(`${DIM}Dry run - no changes written${RESET}`);
3450
- console.log();
3451
- console.log(JSON.stringify(updatedLock, null, 2));
3452
- } else {
3453
- writeSkillLock(updatedLock);
3454
- console.log(`${TEXT}Lock file updated:${RESET} ${DIM}~/.agents/.skill-lock.json${RESET}`);
3455
- }
3456
- }
3457
3423
  async function runCheck(args = []) {
3458
3424
  console.log(`${TEXT}Checking for skill updates...${RESET}`);
3459
3425
  console.log();
@@ -3465,14 +3431,10 @@ async function runCheck(args = []) {
3465
3431
  return;
3466
3432
  }
3467
3433
  const checkRequest = { skills: [] };
3468
- const skippedSkills = [];
3469
3434
  for (const skillName of skillNames) {
3470
3435
  const entry = lock.skills[skillName];
3471
3436
  if (!entry) continue;
3472
- if (!entry.skillFolderHash) {
3473
- skippedSkills.push(skillName);
3474
- continue;
3475
- }
3437
+ if (!entry.skillFolderHash) continue;
3476
3438
  checkRequest.skills.push({
3477
3439
  name: skillName,
3478
3440
  source: entry.source,
@@ -3480,8 +3442,6 @@ async function runCheck(args = []) {
3480
3442
  skillFolderHash: entry.skillFolderHash
3481
3443
  });
3482
3444
  }
3483
- const skippedMsg = formatSkippedMessage(skippedSkills);
3484
- if (skippedMsg) console.log(`${DIM}${skippedMsg}${RESET}`);
3485
3445
  if (checkRequest.skills.length === 0) {
3486
3446
  console.log(`${DIM}No skills to check.${RESET}`);
3487
3447
  return;
@@ -3533,14 +3493,10 @@ async function runUpdate() {
3533
3493
  return;
3534
3494
  }
3535
3495
  const checkRequest = { skills: [] };
3536
- const skippedSkills = [];
3537
3496
  for (const skillName of skillNames) {
3538
3497
  const entry = lock.skills[skillName];
3539
3498
  if (!entry) continue;
3540
- if (!entry.skillFolderHash) {
3541
- skippedSkills.push(skillName);
3542
- continue;
3543
- }
3499
+ if (!entry.skillFolderHash) continue;
3544
3500
  checkRequest.skills.push({
3545
3501
  name: skillName,
3546
3502
  source: entry.source,
@@ -3548,8 +3504,6 @@ async function runUpdate() {
3548
3504
  skillFolderHash: entry.skillFolderHash
3549
3505
  });
3550
3506
  }
3551
- const skippedMsg = formatSkippedMessage(skippedSkills);
3552
- if (skippedMsg) console.log(`${DIM}${skippedMsg}${RESET}`);
3553
3507
  if (checkRequest.skills.length === 0) {
3554
3508
  console.log(`${DIM}No skills to check.${RESET}`);
3555
3509
  return;
@@ -3663,10 +3617,6 @@ async function main() {
3663
3617
  case "upgrade":
3664
3618
  runUpdate();
3665
3619
  break;
3666
- case "generate-lock":
3667
- case "gen-lock":
3668
- runGenerateLock(restArgs);
3669
- break;
3670
3620
  case "--help":
3671
3621
  case "-h":
3672
3622
  showHelp();
@@ -3681,4 +3631,4 @@ async function main() {
3681
3631
  }
3682
3632
  }
3683
3633
  main();
3684
- export { formatSkippedMessage };
3634
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skills",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "The open agent skills ecosystem",
5
5
  "type": "module",
6
6
  "bin": {
@@ -62,6 +62,7 @@
62
62
  "pi",
63
63
  "qoder",
64
64
  "qwen-code",
65
+ "replit",
65
66
  "roo",
66
67
  "trae",
67
68
  "trae-cn",