skillmds 1.3.6 → 1.3.8
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/CHANGELOG.md +9 -1
- package/README.md +11 -11
- package/bin/skillmd.mjs +1 -1
- package/dist/{chunk-HGVEADWS.js → chunk-MPBRLZWJ.js} +3 -3
- package/dist/cli.js +32 -31
- package/dist/mcp.js +17 -18
- package/package.json +6 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
All notable changes to `skillmds` are documented here. Versions follow [semver](https://semver.org).
|
|
3
|
+
All notable changes to `get-skill` (published as `skillmds` until 1.3.6) are documented here. Versions follow [semver](https://semver.org).
|
|
4
|
+
|
|
5
|
+
## 1.3.8
|
|
6
|
+
|
|
7
|
+
- **Skills install all their files.** `add`, `update` and the MCP install tool now fetch every registry skill's bundle, not only skills marked as packs. Some skills were recorded as single-file while carrying scripts or references, and installed only their SKILL.md. A single-file skill whose bundle can't be reached still installs from its SKILL.md, as before.
|
|
8
|
+
|
|
9
|
+
## 1.3.7
|
|
10
|
+
|
|
11
|
+
- **The package is now `get-skill`.** Install and run it as `npx get-skill add owner/name`, `npx get-skill search "pdf"`, and so on; MCP clients start the server with `npx -y get-skill`. `npm i -g get-skill` installs the `get-skill` and `skillmd` commands. Every release is still published as `skillmds` too, with identical contents, so existing setups keep working.
|
|
4
12
|
|
|
5
13
|
## 1.3.6
|
|
6
14
|
|
package/README.md
CHANGED
|
@@ -2,32 +2,32 @@
|
|
|
2
2
|
<img src="https://skillmd.com/brand/banner.png" alt="SkillMD" width="560">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# get-skill
|
|
6
6
|
|
|
7
|
-
[](https://www.npmjs.com/package/get-skill)
|
|
8
|
+
[](https://github.com/skillmds/skillmd/blob/main/LICENSE)
|
|
9
9
|
[](https://github.com/skillmds/skillmd)
|
|
10
10
|
|
|
11
11
|
Tools for working with [Agent Skills](https://docs.claude.com/en/docs/agents-and-tools/agent-skills) (`SKILL.md`) from the [SkillMD](https://skillmd.com) registry. One package, two binaries:
|
|
12
12
|
|
|
13
13
|
- **`skillmd`** — a CLI to lint, scan, search, install, and publish skills.
|
|
14
|
-
- **`
|
|
14
|
+
- **`get-skill`** — the same CLI, and an MCP server exposing the registry to MCP clients (Claude Code, Claude Desktop, Cursor, …).
|
|
15
15
|
|
|
16
16
|
Both validate `SKILL.md` with the same engine ([`@skillmds/core`](https://www.npmjs.com/package/@skillmds/core)), so the CLI and the registry apply identical rules. Source lives at [github.com/skillmds/skillmd](https://github.com/skillmds/skillmd).
|
|
17
17
|
|
|
18
18
|
## Install
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
npm i -g
|
|
21
|
+
npm i -g get-skill
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
This installs both the `
|
|
24
|
+
This installs both the `get-skill` and `skillmd` commands. To run the CLI without installing:
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
|
-
npx
|
|
27
|
+
npx get-skill lint .
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
**Which binary runs what.** `
|
|
30
|
+
**Which binary runs what.** `get-skill` with any argument runs the CLI. `get-skill` with no arguments starts the **MCP server** when stdin is piped (how an MCP client launches it), and opens the interactive CLI menu when there's a terminal attached. `skillmd` is always the CLI.
|
|
31
31
|
|
|
32
32
|
## CLI: `skillmd`
|
|
33
33
|
|
|
@@ -152,12 +152,12 @@ skillmd publish ./my-skill --dry-run
|
|
|
152
152
|
skillmd publish ./my-skill --force # publish despite warnings; never bypasses errors
|
|
153
153
|
```
|
|
154
154
|
|
|
155
|
-
## MCP server: `
|
|
155
|
+
## MCP server: `get-skill`
|
|
156
156
|
|
|
157
157
|
Claude Code:
|
|
158
158
|
|
|
159
159
|
```bash
|
|
160
|
-
claude mcp add skillmd -- npx -y
|
|
160
|
+
claude mcp add skillmd -- npx -y get-skill
|
|
161
161
|
```
|
|
162
162
|
|
|
163
163
|
Other MCP clients:
|
|
@@ -165,7 +165,7 @@ Other MCP clients:
|
|
|
165
165
|
```jsonc
|
|
166
166
|
{
|
|
167
167
|
"mcpServers": {
|
|
168
|
-
"skillmd": { "command": "npx", "args": ["-y", "
|
|
168
|
+
"skillmd": { "command": "npx", "args": ["-y", "get-skill"] }
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
```
|
package/bin/skillmd.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { existsSync } from "fs";
|
|
3
3
|
import { homedir } from "os";
|
|
4
4
|
import { join } from "path";
|
|
5
|
-
var UNSUPPORTED = (what) => new Error(`${what} sources are not supported yet \u2014 clone it locally and run \`
|
|
5
|
+
var UNSUPPORTED = (what) => new Error(`${what} sources are not supported yet \u2014 clone it locally and run \`npx get-skill add ./path/to/skill\`.`);
|
|
6
6
|
function assertSubpath(sub) {
|
|
7
7
|
if (!sub) return void 0;
|
|
8
8
|
const clean = sub.replace(/^\/+|\/+$/g, "");
|
|
@@ -321,7 +321,7 @@ async function resolveSource(arg, opts = {}) {
|
|
|
321
321
|
if (st.isFile()) return [loadLocal(spec.path)];
|
|
322
322
|
const files = findSkillFiles(spec.path);
|
|
323
323
|
if (files.length === 0) {
|
|
324
|
-
throw new Error(`No SKILL.md found under ${spec.path}. Point at a skill directory, e.g. "
|
|
324
|
+
throw new Error(`No SKILL.md found under ${spec.path}. Point at a skill directory, e.g. "npx get-skill lint ./my-skill", or run "npx get-skill init" to create one.`);
|
|
325
325
|
}
|
|
326
326
|
return files.map(loadLocal);
|
|
327
327
|
}
|
|
@@ -337,7 +337,7 @@ async function resolveSource(arg, opts = {}) {
|
|
|
337
337
|
return [{ path: spec.display, raw, slug: `gist-${spec.id.slice(0, 8)}` }];
|
|
338
338
|
}
|
|
339
339
|
if (spec.kind === "plugin") {
|
|
340
|
-
throw new Error(`"${spec.display}" is a plugin, not a single skill \u2014 install it with \`
|
|
340
|
+
throw new Error(`"${spec.display}" is a plugin, not a single skill \u2014 install it with \`npx get-skill add ${spec.display}\`.`);
|
|
341
341
|
}
|
|
342
342
|
const gh = asGithub(spec);
|
|
343
343
|
const { dir, cleanup } = await downloadGithub(gh, "skillmd-src-", opts, Boolean(gh.subpath));
|
package/dist/cli.js
CHANGED
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
uninstallSkill,
|
|
32
32
|
upsertEntry,
|
|
33
33
|
writeConfig
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-MPBRLZWJ.js";
|
|
35
35
|
|
|
36
36
|
// src/index.ts
|
|
37
37
|
import { Command as Command13 } from "commander";
|
|
@@ -608,7 +608,7 @@ async function runInfo(slug, flags, deps = {}) {
|
|
|
608
608
|
const commitSha = safeText(s.provenance?.commit_sha ?? s.commit_sha, 100);
|
|
609
609
|
if (sourceRepo) lines.push(pc7.dim(` source: ${sourceRepo}${commitSha ? ` @ ${commitSha.slice(0, 8)}` : ""}`));
|
|
610
610
|
lines.push(pc7.dim(` page: https://skillmd.com/skills/${slugTxt}`));
|
|
611
|
-
lines.push(pc7.dim(` install: ${safeText(s.install?.cli, 300) || `npx
|
|
611
|
+
lines.push(pc7.dim(` install: ${safeText(s.install?.cli, 300) || `npx get-skill add ${slugTxt}`}`));
|
|
612
612
|
return { ok: true, exitCode: 0, output: lines.join("\n"), skill: s };
|
|
613
613
|
}
|
|
614
614
|
function infoCommand() {
|
|
@@ -920,19 +920,20 @@ async function registryCandidate(owner, name, source, client) {
|
|
|
920
920
|
type: skill.type,
|
|
921
921
|
securityFlags: skill.security_flags
|
|
922
922
|
};
|
|
923
|
+
const missing = [];
|
|
924
|
+
const bundle = await fetchBundle(client.base, registrySlug, client.token, { missing });
|
|
925
|
+
if (bundle && bundle.length) {
|
|
926
|
+
const sk = bundle.find((file) => file.path === "SKILL.md");
|
|
927
|
+
const note2 = bundleNote(bundle, missing);
|
|
928
|
+
return {
|
|
929
|
+
...meta,
|
|
930
|
+
type: bundle.length > 1 ? "pack" : meta.type,
|
|
931
|
+
raw: sk ? sk.contents.toString("utf8") : skillMdFor(skill),
|
|
932
|
+
files: bundle,
|
|
933
|
+
...note2 ? { note: note2 } : {}
|
|
934
|
+
};
|
|
935
|
+
}
|
|
923
936
|
if (skill.type === "pack") {
|
|
924
|
-
const missing = [];
|
|
925
|
-
const bundle = await fetchBundle(client.base, registrySlug, client.token, { missing });
|
|
926
|
-
if (bundle && bundle.length) {
|
|
927
|
-
const sk = bundle.find((file) => file.path === "SKILL.md");
|
|
928
|
-
const note2 = bundleNote(bundle, missing);
|
|
929
|
-
return {
|
|
930
|
-
...meta,
|
|
931
|
-
raw: sk ? sk.contents.toString("utf8") : skillMdFor(skill),
|
|
932
|
-
files: bundle,
|
|
933
|
-
...note2 ? { note: note2 } : {}
|
|
934
|
-
};
|
|
935
|
-
}
|
|
936
937
|
const pack = await resolvePackFiles(skill);
|
|
937
938
|
if (pack) return { ...meta, ...pack };
|
|
938
939
|
}
|
|
@@ -1421,7 +1422,7 @@ async function offerFindSkills(source, flags, run2, ui, deps) {
|
|
|
1421
1422
|
project: !global,
|
|
1422
1423
|
agent: run2.agents
|
|
1423
1424
|
}, deps);
|
|
1424
|
-
ui.message(r.exitCode === 0 ? `${pc8.green(GLYPH.ok)} find-skills added` : pc8.yellow(`${GLYPH.warn} find-skills could not be added. Try later: npx
|
|
1425
|
+
ui.message(r.exitCode === 0 ? `${pc8.green(GLYPH.ok)} find-skills added` : pc8.yellow(`${GLYPH.warn} find-skills could not be added. Try later: npx get-skill add ${FIND_SKILLS}`));
|
|
1425
1426
|
}
|
|
1426
1427
|
async function runAddWithUI(source, flags, opts = {}) {
|
|
1427
1428
|
const term = opts.term ?? { ...realTerminal(), env: flags.env ?? process.env };
|
|
@@ -1456,7 +1457,7 @@ async function runAddWithUI(source, flags, opts = {}) {
|
|
|
1456
1457
|
}
|
|
1457
1458
|
ui.message(run2.output);
|
|
1458
1459
|
await offerFindSkills(source, flags, run2, ui, base);
|
|
1459
|
-
ui.outro(run2.exitCode === 0 ? `Done. Run ${pc8.cyan("
|
|
1460
|
+
ui.outro(run2.exitCode === 0 ? `Done. Run ${pc8.cyan("npx get-skill list")} to see everything installed.` : pc8.red("Some skills were not installed."));
|
|
1460
1461
|
return { run: run2, printed: true };
|
|
1461
1462
|
} catch (e) {
|
|
1462
1463
|
ui.outro(pc8.red("Nothing was installed."));
|
|
@@ -1489,7 +1490,7 @@ function runList(flags = {}) {
|
|
|
1489
1490
|
if (flags.json) {
|
|
1490
1491
|
return { items, output: JSON.stringify(items.map(({ name, scope, path, agents, source, mode, tracked, description }) => ({ name, scope, path, agents, source: source ?? null, mode, tracked, description })), null, 2) };
|
|
1491
1492
|
}
|
|
1492
|
-
if (items.length === 0) return { items, output: pc9.dim("No installed skills found. Install one with `
|
|
1493
|
+
if (items.length === 0) return { items, output: pc9.dim("No installed skills found. Install one with `npx get-skill add owner/name`.") };
|
|
1493
1494
|
const w = Math.max(...items.map((i) => i.name.length), 4);
|
|
1494
1495
|
const lines = items.map((i) => {
|
|
1495
1496
|
const tag = i.tracked ? pc9.dim(i.source ?? "") : pc9.yellow("untracked");
|
|
@@ -1666,9 +1667,9 @@ function makeDefaultUpdateDeps(opts = {}) {
|
|
|
1666
1667
|
if (e.status === 404) return null;
|
|
1667
1668
|
throw e;
|
|
1668
1669
|
}
|
|
1670
|
+
const bundle = await fetchBundle(base, slug, token);
|
|
1671
|
+
if (bundle?.length) return { files: bundle, commit_sha: skill.commit_sha ?? void 0 };
|
|
1669
1672
|
if (skill.type === "pack") {
|
|
1670
|
-
const bundle = await fetchBundle(base, slug, token);
|
|
1671
|
-
if (bundle?.length) return { files: bundle, commit_sha: skill.commit_sha ?? void 0 };
|
|
1672
1673
|
const pack = await resolvePackFiles(skill);
|
|
1673
1674
|
if (pack) return { files: pack.files, commit_sha: skill.commit_sha ?? void 0 };
|
|
1674
1675
|
}
|
|
@@ -1707,7 +1708,7 @@ async function runUpdate(names, flags, deps = defaultUpdateDeps) {
|
|
|
1707
1708
|
const label2 = `${s.name}${scopes.length > 1 ? pc11.dim(` [${s.scope}]`) : ""}`;
|
|
1708
1709
|
const entry = lock.skills[s.name];
|
|
1709
1710
|
if (!entry) {
|
|
1710
|
-
lines.push(pc11.dim(`- ${label2} untracked \u2014 reinstall with \`
|
|
1711
|
+
lines.push(pc11.dim(`- ${label2} untracked \u2014 reinstall with \`npx get-skill add\` to track updates`));
|
|
1711
1712
|
continue;
|
|
1712
1713
|
}
|
|
1713
1714
|
if (entry.source.startsWith("local:")) {
|
|
@@ -1787,7 +1788,7 @@ var defaultDeps2 = {
|
|
|
1787
1788
|
resolve: resolveSource,
|
|
1788
1789
|
async submit(payload, flags) {
|
|
1789
1790
|
const { api, hasToken } = createClient(flags);
|
|
1790
|
-
if (!hasToken) throw new Error("No token. Run `
|
|
1791
|
+
if (!hasToken) throw new Error("No token. Run `npx get-skill login` or pass --token.");
|
|
1791
1792
|
return api(`/api/skills`, {
|
|
1792
1793
|
method: "POST",
|
|
1793
1794
|
headers: { "content-type": "application/json" },
|
|
@@ -2113,18 +2114,18 @@ try {
|
|
|
2113
2114
|
version = JSON.parse(readFileSync3(new URL("../package.json", import.meta.url), "utf8")).version;
|
|
2114
2115
|
} catch {
|
|
2115
2116
|
}
|
|
2116
|
-
var program = new Command13("
|
|
2117
|
+
var program = new Command13("get-skill").version(version).description("Lint, validate, and install Agent Skills from the SkillMD registry.").option("--json", "machine-readable output").option("--token <token>", "personal access token (prefer `npx get-skill login` or SKILLMD_TOKEN \u2014 command-line tokens show up in process lists)").option("--api <url>", "override the registry API base URL").option("--insecure-http", "allow an http:// --api base (local development only)");
|
|
2117
2118
|
program.configureHelp({ sortSubcommands: false });
|
|
2118
2119
|
program.addHelpText("after", `
|
|
2119
2120
|
Examples:
|
|
2120
|
-
$
|
|
2121
|
-
$
|
|
2122
|
-
$
|
|
2123
|
-
$
|
|
2124
|
-
$
|
|
2125
|
-
$
|
|
2126
|
-
$
|
|
2127
|
-
$
|
|
2121
|
+
$ npx get-skill add anthropic/pdf install from the registry (asks project vs global)
|
|
2122
|
+
$ npx get-skill add owner/repo/skills/x#main -g a GitHub subfolder at a ref, into your user dirs
|
|
2123
|
+
$ npx get-skill add ./my-skill -a claude-code -p a local skill into this project for one agent
|
|
2124
|
+
$ npx get-skill add anthropic/pdf -y --json non-interactive, machine-readable
|
|
2125
|
+
$ npx get-skill list everything installed, project and global
|
|
2126
|
+
$ npx get-skill check which installed skills have updates
|
|
2127
|
+
$ npx get-skill update -g update your user-level skills
|
|
2128
|
+
$ npx get-skill remove pdf remove a skill from every agent
|
|
2128
2129
|
|
|
2129
2130
|
Quality: lint scan rules init
|
|
2130
2131
|
Registry: search info add list remove update check
|
|
@@ -2134,7 +2135,7 @@ Docs: https://skillmd.com/docs/cli`);
|
|
|
2134
2135
|
program.hook("preAction", (thisCmd) => {
|
|
2135
2136
|
const opts = thisCmd.opts();
|
|
2136
2137
|
if (opts.token && process.stderr.isTTY) {
|
|
2137
|
-
console.error(pc15.yellow("\u26A0 --token is visible in your shell history and process list; prefer `
|
|
2138
|
+
console.error(pc15.yellow("\u26A0 --token is visible in your shell history and process list; prefer `npx get-skill login` or SKILLMD_TOKEN."));
|
|
2138
2139
|
}
|
|
2139
2140
|
});
|
|
2140
2141
|
program.addCommand(lintCommand());
|
package/dist/mcp.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
safeText,
|
|
14
14
|
stripTerminalEscapes,
|
|
15
15
|
telemetryDisabled
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-MPBRLZWJ.js";
|
|
17
17
|
|
|
18
18
|
// src/mcp/server.ts
|
|
19
19
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -205,24 +205,23 @@ async function installFromRegistry(args, ctx, deps = {}) {
|
|
|
205
205
|
if (bad) return bad;
|
|
206
206
|
let files = [{ path: "SKILL.md", contents: raw }];
|
|
207
207
|
let note = "";
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
} catch (e) {
|
|
223
|
-
if (e instanceof IntegrityError) return notice(`Refused: ${owner}/${name} failed integrity verification \u2014 ${e.message}. Not installed.`);
|
|
224
|
-
note = `pack assets could not be fetched (${e instanceof Error ? e.message : String(e)}) \u2014 only SKILL.md was written`;
|
|
208
|
+
const pack = skill.type === "pack";
|
|
209
|
+
try {
|
|
210
|
+
const missing = [];
|
|
211
|
+
const bundle = await getBundle(ctx.base, `${owner}/${name}`, ctx.token, { missing });
|
|
212
|
+
if (bundle?.length) {
|
|
213
|
+
files = bundle.some((f) => f.path === "SKILL.md") ? bundle : [...bundle, { path: "SKILL.md", contents: raw }];
|
|
214
|
+
if (missing.length) note = missingFilesNote(missing);
|
|
215
|
+
} else if (pack) {
|
|
216
|
+
const fromGitHub = await getPackFiles(skill);
|
|
217
|
+
if (fromGitHub) {
|
|
218
|
+
files = fromGitHub.files;
|
|
219
|
+
if (fromGitHub.pinMiss) note = "pinned commit unavailable upstream \u2014 fetched the source repo's default branch instead";
|
|
220
|
+
} else note = "pack assets could not be fetched \u2014 only SKILL.md was written";
|
|
225
221
|
}
|
|
222
|
+
} catch (e) {
|
|
223
|
+
if (e instanceof IntegrityError) return notice(`Refused: ${owner}/${name} failed integrity verification \u2014 ${e.message}. Not installed.`);
|
|
224
|
+
if (pack) note = `pack assets could not be fetched (${e instanceof Error ? e.message : String(e)}) \u2014 only SKILL.md was written`;
|
|
226
225
|
}
|
|
227
226
|
const written = skillMdOf(files);
|
|
228
227
|
if (written === null) files = [...files, { path: "SKILL.md", contents: raw }];
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillmds",
|
|
3
|
-
"version": "1.3.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.3.8",
|
|
4
|
+
"description": "Find, install, lint and publish Agent Skills (SKILL.md) from skillmd.com: the get-skill CLI and MCP server.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "SkillMD",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"mcpName": "com.skillmd/skillmd",
|
|
9
9
|
"bin": {
|
|
10
|
-
"
|
|
11
|
-
"skillmd": "bin/skillmd.mjs"
|
|
10
|
+
"get-skill": "bin/skillmd-mcp.mjs",
|
|
11
|
+
"skillmd": "bin/skillmd.mjs",
|
|
12
|
+
"skillmds": "bin/skillmd-mcp.mjs"
|
|
12
13
|
},
|
|
13
14
|
"files": [
|
|
14
15
|
"bin",
|
|
@@ -21,6 +22,7 @@
|
|
|
21
22
|
"node": ">=18"
|
|
22
23
|
},
|
|
23
24
|
"keywords": [
|
|
25
|
+
"get-skill",
|
|
24
26
|
"mcp",
|
|
25
27
|
"model-context-protocol",
|
|
26
28
|
"cli",
|