skills 1.5.26 → 1.6.0

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 (3) hide show
  1. package/README.md +12 -1
  2. package/dist/cli.mjs +46 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -6,7 +6,13 @@ The CLI for the open agent skills ecosystem.
6
6
  Supports **OpenCode**, **Claude Code**, **Codex**, **Cursor**, and [75 more](#supported-agents).
7
7
  <!-- agent-list:end -->
8
8
 
9
- [![skills.sh](https://skills.sh/b/vercel-labs/skills)](https://skills.sh/vercel-labs/skills)
9
+ <p>
10
+ <a href="https://vercel.com/labs#labs-products"><img alt="Vercel Labs Product" src="https://img.shields.io/badge/LABS-PRODUCT-0a0a0a.svg?style=for-the-badge&amp;logo=Vercel&amp;labelColor=000000" height="28"></a>
11
+ <a href="https://www.npmjs.com/package/skills"><img alt="npm version: skills" src="https://img.shields.io/npm/v/skills.svg?style=for-the-badge&amp;labelColor=000000" height="28"></a>
12
+ <a href="https://github.com/vercel-labs/skills/blob/main/LICENSE"><img alt="License: MIT" src="https://img.shields.io/github/license/vercel-labs/skills.svg?style=for-the-badge&amp;labelColor=000000" height="28"></a>
13
+ <a href="https://www.npmjs.com/package/skills"><img alt="npm downloads per month: skills" src="https://img.shields.io/npm/dm/skills.svg?style=for-the-badge&amp;labelColor=000000&amp;label=npm%20downloads" height="28"></a>
14
+ <a href="https://skills.sh/vercel-labs/skills"><img alt="skills.sh" src="https://skills.sh/b/vercel-labs/skills?style=for-the-badge" height="28"></a>
15
+ </p>
10
16
 
11
17
  ## Install a Skill
12
18
 
@@ -40,6 +46,10 @@ npx skills add https://github.com/vercel-labs/agent-skills/tree/main/skills/web-
40
46
  # GitLab URL
41
47
  npx skills add https://gitlab.com/org/repo
42
48
 
49
+ # Azure Repos (Azure DevOps Services or Server)
50
+ npx skills add https://dev.azure.com/org/project/_git/repo
51
+ npx skills add https://dev.azure.com/org/project/_git/repo?path=/skills/web-design&version=GBmain
52
+
43
53
  # Any git URL
44
54
  npx skills add git@github.com:vercel-labs/agent-skills.git
45
55
 
@@ -61,6 +71,7 @@ npx skills add ssh://git@git.example.com/acme/private-skills.git
61
71
 
62
72
  # HTTPS on any Git host (uses your configured Git credential helper)
63
73
  npx skills add https://git.example.com/acme/private-skills.git
74
+ npx skills add https://dev.azure.com/org/project/_git/private-skills
64
75
  ```
65
76
 
66
77
  For GitHub HTTPS and shorthand sources, `skills` first uses normal Git credentials. If that fails and GitHub CLI is authenticated, it tries `gh repo clone`, followed by SSH. It does not execute `gh auth token` or copy the stored GitHub CLI credential into the Node.js process.
package/dist/cli.mjs CHANGED
@@ -91,6 +91,46 @@ function sanitizeSubpath(subpath) {
91
91
  for (const segment of segments) if (segment === "..") throw new Error(`Unsafe subpath: "${subpath}" contains path traversal segments. Subpaths must not contain ".." components.`);
92
92
  return subpath;
93
93
  }
94
+ function azureReposVersionToRef(version) {
95
+ if (!version) return;
96
+ return /^(?:GB|GT)(.+)$/i.exec(version)?.[1] || void 0;
97
+ }
98
+ function parseAzureReposSource(input, fragmentRef, fragmentSkillFilter) {
99
+ if (!input.startsWith("http://") && !input.startsWith("https://")) return null;
100
+ let parsed;
101
+ try {
102
+ parsed = new URL(input);
103
+ } catch {
104
+ return null;
105
+ }
106
+ const segments = parsed.pathname.split("/").filter(Boolean);
107
+ const gitIndex = segments.indexOf("_git");
108
+ if (gitIndex < 0 || gitIndex === segments.length - 1) return null;
109
+ const repo = segments[gitIndex + 1].replace(/\.git$/, "");
110
+ if (!repo) return null;
111
+ const clonePath = "/" + [
112
+ ...segments.slice(0, gitIndex),
113
+ "_git",
114
+ repo
115
+ ].map((segment) => {
116
+ try {
117
+ return encodeURIComponent(decodeURIComponent(segment));
118
+ } catch {
119
+ return encodeURIComponent(segment);
120
+ }
121
+ }).join("/");
122
+ const cloneUrl = `${parsed.protocol}//${parsed.host}${clonePath}`;
123
+ const ref = azureReposVersionToRef(parsed.searchParams.get("version")) || fragmentRef;
124
+ const pathParam = parsed.searchParams.get("path");
125
+ const subpath = pathParam ? sanitizeSubpath(pathParam.replace(/^\/+/, "")) : void 0;
126
+ return {
127
+ type: "git",
128
+ url: cloneUrl,
129
+ ...ref ? { ref } : {},
130
+ ...subpath ? { subpath } : {},
131
+ ...fragmentSkillFilter ? { skillFilter: fragmentSkillFilter } : {}
132
+ };
133
+ }
94
134
  function isLocalPath(input) {
95
135
  return isAbsolute(input) || input.startsWith("./") || input.startsWith("../") || input === "." || input === ".." || /^[a-zA-Z]:[/\\]/.test(input);
96
136
  }
@@ -113,6 +153,9 @@ function looksLikeGitSource(input) {
113
153
  const pathname = parsed.pathname;
114
154
  if (isGitHubHost(parsed.host)) return /^\/[^/]+\/[^/]+(?:\.git)?(?:\/tree\/[^/]+(?:\/.*)?)?\/?$/.test(pathname);
115
155
  if (parsed.hostname === "gitlab.com") return /^\/.+?\/[^/]+(?:\.git)?(?:\/-\/tree\/[^/]+(?:\/.*)?)?\/?$/.test(pathname);
156
+ const azureSegments = pathname.split("/").filter(Boolean);
157
+ const azureGitIndex = azureSegments.indexOf("_git");
158
+ if (azureGitIndex >= 0 && azureGitIndex < azureSegments.length - 1) return true;
116
159
  } catch {}
117
160
  if (/^https?:\/\/.+\.git(?:$|[/?])/i.test(input)) return true;
118
161
  return !input.includes(":") && !input.startsWith(".") && !input.startsWith("/") && /^([^/]+)\/([^/]+)(?:\/(.+)|@(.+))?$/.test(input);
@@ -245,6 +288,8 @@ function parseSource(input) {
245
288
  ...fragmentRef ? { ref: fragmentRef } : {}
246
289
  };
247
290
  }
291
+ const azureRepos = parseAzureReposSource(input, fragmentRef, fragmentSkillFilter);
292
+ if (azureRepos) return azureRepos;
248
293
  const githubHost = getGitHubHost();
249
294
  const shorthandSourceType = githubHost === "github.com" ? "github" : "git";
250
295
  const atSkillMatch = input.match(/^([^/]+)\/([^/@]+)@(.+)$/);
@@ -4124,7 +4169,7 @@ async function tryBlobInstall(ownerRepo, options = {}) {
4124
4169
  tree
4125
4170
  };
4126
4171
  }
4127
- var version$1 = "1.5.26";
4172
+ var version$1 = "1.6.0";
4128
4173
  const isCancelled$1 = (value) => typeof value === "symbol";
4129
4174
  const EVE_AGENT_LABEL = "eve agent";
4130
4175
  async function isSourcePrivate(source) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skills",
3
- "version": "1.5.26",
3
+ "version": "1.6.0",
4
4
  "description": "The open agent skills ecosystem",
5
5
  "type": "module",
6
6
  "bin": {