skillmds 1.3.3 → 1.3.5
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 +8 -0
- package/README.md +1 -1
- package/dist/{chunk-FVWCI37S.js → chunk-6JVWN3IG.js} +14 -1
- package/dist/cli.js +22 -11
- package/dist/mcp.js +6 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `skillmds` are documented here. Versions follow [semver](https://semver.org).
|
|
4
4
|
|
|
5
|
+
## 1.3.5
|
|
6
|
+
|
|
7
|
+
- **The agent picker now says why Claude Code isn't in it.** `add plugin:owner/slug` installs the plugin into Claude Code as a real plugin first, then asks which other agents should get its skills, leaving Claude Code out so it doesn't get the same skills twice. The question read "Which agents do you want to install to?", and the confirmation only printed after the run, so the list looked as if Claude Code hadn't been detected. It now asks: `Claude Code already has <plugin> as a plugin. Which other agents should get its skills too?`
|
|
8
|
+
|
|
9
|
+
## 1.3.4
|
|
10
|
+
|
|
11
|
+
- **A companion file that its source repo no longer serves no longer fails the install.** When a registry pack links to a file the upstream repo has since deleted or moved, `add` (and the MCP install tool) now installs everything else and warns which files are missing, e.g. `1 companion file is gone from the source repo and was not installed (scripts/gone.ts)`. Before, one such link failed the whole bundle and `add owner/name` fell back to fetching the slug as a GitHub repo, ending in a misleading 404 with nothing installed. `update` stays strict: it never replaces a full install with a partial one.
|
|
12
|
+
|
|
5
13
|
## 1.2.0
|
|
6
14
|
|
|
7
15
|
`skillmd add` was rewritten. It no longer copies a skill into every agent folder it can find: it writes **one canonical copy** and links that copy into the agents you chose, in the scope you chose, and records what it did in a lock file.
|
package/README.md
CHANGED
|
@@ -186,7 +186,7 @@ No auth required. It exposes `skillmd_search`, `skillmd_get`, `skillmd_download`
|
|
|
186
186
|
|
|
187
187
|
## Find skills on skillmd.com
|
|
188
188
|
|
|
189
|
-
The registry behind these tools is [skillmd.com](https://skillmd.com):
|
|
189
|
+
The registry behind these tools is [skillmd.com](https://skillmd.com): 1,000,000+ Agent Skills, each linted, security-scanned and content-pinned.
|
|
190
190
|
|
|
191
191
|
- [Search all skills](https://skillmd.com/search) · [browse by category](https://skillmd.com/categories) · [by publisher](https://skillmd.com/publishers)
|
|
192
192
|
- Install guides per agent: [Claude Code](https://skillmd.com/agents/claude-code) · [Cursor](https://skillmd.com/agents/cursor) · [Codex](https://skillmd.com/agents/codex) · [all 60+ agents](https://skillmd.com/agents)
|
|
@@ -197,7 +197,13 @@ async function fetchBundle(base, slug, token, opts = {}) {
|
|
|
197
197
|
contents = Buffer.from(f.content_base64, "base64");
|
|
198
198
|
} else if (f.source_url && isAllowedSourceUrl(f.source_url)) {
|
|
199
199
|
const r = await doFetch(f.source_url).catch(() => null);
|
|
200
|
-
if (!r || !r.ok)
|
|
200
|
+
if (!r || !r.ok) {
|
|
201
|
+
if (opts.missing) {
|
|
202
|
+
opts.missing.push(f.path);
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
throw new Error(`could not fetch companion file "${f.path}" from ${hostOf(f.source_url)}`);
|
|
206
|
+
}
|
|
201
207
|
contents = Buffer.from(await r.arrayBuffer());
|
|
202
208
|
fromUrl = true;
|
|
203
209
|
} else {
|
|
@@ -215,6 +221,12 @@ async function fetchBundle(base, slug, token, opts = {}) {
|
|
|
215
221
|
}
|
|
216
222
|
return out;
|
|
217
223
|
}
|
|
224
|
+
function missingFilesNote(paths) {
|
|
225
|
+
const n = paths.length;
|
|
226
|
+
const shown = paths.slice(0, 5).join(", ") + (n > 5 ? `, and ${n - 5} more` : "");
|
|
227
|
+
const [f, was, it] = n === 1 ? ["file is", "was", "it"] : ["files are", "were", "them"];
|
|
228
|
+
return `${n} companion ${f} gone from the source repo and ${was} not installed (${shown}); the skill may still refer to ${it}`;
|
|
229
|
+
}
|
|
218
230
|
|
|
219
231
|
// src/source.ts
|
|
220
232
|
import { existsSync as existsSync2, statSync, lstatSync, readFileSync as readFileSync2, readdirSync, mkdtempSync, rmSync } from "fs";
|
|
@@ -841,6 +853,7 @@ export {
|
|
|
841
853
|
RegistryError,
|
|
842
854
|
createClient,
|
|
843
855
|
fetchBundle,
|
|
856
|
+
missingFilesNote,
|
|
844
857
|
skillMdFor,
|
|
845
858
|
resolveSource,
|
|
846
859
|
collectFiles,
|
package/dist/cli.js
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
isSkillDirOrLink,
|
|
17
17
|
listInstalled,
|
|
18
18
|
looksLikeProject,
|
|
19
|
+
missingFilesNote,
|
|
19
20
|
parseSource,
|
|
20
21
|
readConfig,
|
|
21
22
|
readLock,
|
|
@@ -30,7 +31,7 @@ import {
|
|
|
30
31
|
uninstallSkill,
|
|
31
32
|
upsertEntry,
|
|
32
33
|
writeConfig
|
|
33
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-6JVWN3IG.js";
|
|
34
35
|
|
|
35
36
|
// src/index.ts
|
|
36
37
|
import { Command as Command13 } from "commander";
|
|
@@ -855,11 +856,14 @@ async function promptScopeInteractive(ctx) {
|
|
|
855
856
|
});
|
|
856
857
|
return p3.isCancel(choice) ? null : choice;
|
|
857
858
|
}
|
|
859
|
+
function agentsPromptMessage(managed) {
|
|
860
|
+
return managed ? `Claude Code already has ${managed} as a plugin. Which other agents should get its skills too?` : "Which agents do you want to install to?";
|
|
861
|
+
}
|
|
858
862
|
async function promptAgentsInteractive(ctx) {
|
|
859
863
|
if (ctx.detected.length < 2) return ctx.detected;
|
|
860
864
|
const remembered = (readConfig().lastAgents ?? []).filter((id) => ctx.detected.includes(id));
|
|
861
865
|
const picked = await p3.multiselect({
|
|
862
|
-
message:
|
|
866
|
+
message: agentsPromptMessage(ctx.managed),
|
|
863
867
|
options: ctx.detected.map((id) => ({ value: id, label: id, hint: ctx.dirFor(id) })),
|
|
864
868
|
initialValues: remembered.length ? remembered : ctx.detected,
|
|
865
869
|
required: true
|
|
@@ -870,6 +874,11 @@ function unverifiedFilesNote(n) {
|
|
|
870
874
|
const [f, it] = n === 1 ? ["file", "it"] : ["files", "them"];
|
|
871
875
|
return `${n} companion ${f} came straight from the source repo \u2014 the registry holds no checksum for ${it}, so only the connection was verified`;
|
|
872
876
|
}
|
|
877
|
+
function bundleNote(bundle, missing) {
|
|
878
|
+
const unverified = bundle.filter((file) => file.unverified).length;
|
|
879
|
+
const notes = [unverified ? unverifiedFilesNote(unverified) : "", missing.length ? missingFilesNote(missing) : ""].filter(Boolean);
|
|
880
|
+
return notes.length ? notes.join("; ") : void 0;
|
|
881
|
+
}
|
|
873
882
|
function registryFallbackNote(host) {
|
|
874
883
|
return `installed from GitHub because the SkillMD registry (${host}) was unreachable \u2014 this copy is not the registry-reviewed version`;
|
|
875
884
|
}
|
|
@@ -912,15 +921,16 @@ async function registryCandidate(owner, name, source, client) {
|
|
|
912
921
|
securityFlags: skill.security_flags
|
|
913
922
|
};
|
|
914
923
|
if (skill.type === "pack") {
|
|
915
|
-
const
|
|
924
|
+
const missing = [];
|
|
925
|
+
const bundle = await fetchBundle(client.base, registrySlug, client.token, { missing });
|
|
916
926
|
if (bundle && bundle.length) {
|
|
917
927
|
const sk = bundle.find((file) => file.path === "SKILL.md");
|
|
918
|
-
const
|
|
928
|
+
const note2 = bundleNote(bundle, missing);
|
|
919
929
|
return {
|
|
920
930
|
...meta,
|
|
921
931
|
raw: sk ? sk.contents.toString("utf8") : skillMdFor(skill),
|
|
922
932
|
files: bundle,
|
|
923
|
-
...
|
|
933
|
+
...note2 ? { note: note2 } : {}
|
|
924
934
|
};
|
|
925
935
|
}
|
|
926
936
|
const pack = await resolvePackFiles(skill);
|
|
@@ -1010,13 +1020,14 @@ function makeDefaultDeps(flags) {
|
|
|
1010
1020
|
for (let i = n++; i < multi.length; i = n++) {
|
|
1011
1021
|
const c = multi[i];
|
|
1012
1022
|
try {
|
|
1013
|
-
const
|
|
1023
|
+
const missing2 = [];
|
|
1024
|
+
const bundle = await fetchBundle(apiBase2, c.registrySlug, token2, { missing: missing2 });
|
|
1014
1025
|
if (!bundle?.length) continue;
|
|
1015
1026
|
const sk = bundle.find((file) => file.path === "SKILL.md");
|
|
1016
|
-
const
|
|
1027
|
+
const note2 = bundleNote(bundle, missing2);
|
|
1017
1028
|
c.files = bundle;
|
|
1018
1029
|
if (sk) c.raw = sk.contents.toString("utf8");
|
|
1019
|
-
if (
|
|
1030
|
+
if (note2) c.note = note2;
|
|
1020
1031
|
} catch {
|
|
1021
1032
|
}
|
|
1022
1033
|
}
|
|
@@ -1202,7 +1213,7 @@ function gate(flags, deps, candidates) {
|
|
|
1202
1213
|
}
|
|
1203
1214
|
return null;
|
|
1204
1215
|
}
|
|
1205
|
-
async function chooseTargets(flags, deps, scope, detected) {
|
|
1216
|
+
async function chooseTargets(flags, deps, scope, detected, managed) {
|
|
1206
1217
|
const notices = [];
|
|
1207
1218
|
let targets = flags.agent?.length ? flags.agent : detected.length ? detected : ["claude-code"];
|
|
1208
1219
|
if (scope.global) {
|
|
@@ -1214,7 +1225,7 @@ async function chooseTargets(flags, deps, scope, detected) {
|
|
|
1214
1225
|
targets = kept;
|
|
1215
1226
|
}
|
|
1216
1227
|
if (!flags.agent?.length && deps.promptAgents && !flags.yes && !flags.json && !detectHostAgent(flags.env ?? process.env)) {
|
|
1217
|
-
const picked = await deps.promptAgents({ detected: targets, dirFor: (id) => agentDir(id, scope) });
|
|
1228
|
+
const picked = await deps.promptAgents({ detected: targets, dirFor: (id) => agentDir(id, scope), ...managed ? { managed } : {} });
|
|
1218
1229
|
if (picked === null) return null;
|
|
1219
1230
|
targets = picked;
|
|
1220
1231
|
if (flags.home === void 0 && picked.length) {
|
|
@@ -1346,7 +1357,7 @@ async function runAdd(arg, flags, deps) {
|
|
|
1346
1357
|
const notices = resolved.note ? [infoNotice(resolved.note)] : [];
|
|
1347
1358
|
notices.push(...managedNotices);
|
|
1348
1359
|
const detected = detectAgents(scope).filter((id) => id !== managed?.agent);
|
|
1349
|
-
const chosen = await chooseTargets(flags, d, scope, detected);
|
|
1360
|
+
const chosen = await chooseTargets(flags, d, scope, detected, managed?.name);
|
|
1350
1361
|
if (!chosen) return finish2(flags, { kind: "cancel" });
|
|
1351
1362
|
notices.push(...chosen.notices);
|
|
1352
1363
|
const ctx = { arg, flags, deny: new Set(flags.deny ?? []), scope, targets: chosen.targets, env, deps: d };
|
package/dist/mcp.js
CHANGED
|
@@ -8,11 +8,12 @@ import {
|
|
|
8
8
|
fetchBundle,
|
|
9
9
|
installSkill,
|
|
10
10
|
looksLikeProject,
|
|
11
|
+
missingFilesNote,
|
|
11
12
|
resolvePackFiles,
|
|
12
13
|
safeText,
|
|
13
14
|
stripTerminalEscapes,
|
|
14
15
|
telemetryDisabled
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-6JVWN3IG.js";
|
|
16
17
|
|
|
17
18
|
// src/mcp/server.ts
|
|
18
19
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -206,9 +207,11 @@ async function installFromRegistry(args, ctx, deps = {}) {
|
|
|
206
207
|
let note = "";
|
|
207
208
|
if (skill.type === "pack") {
|
|
208
209
|
try {
|
|
209
|
-
const
|
|
210
|
+
const missing = [];
|
|
211
|
+
const bundle = await getBundle(ctx.base, `${owner}/${name}`, ctx.token, { missing });
|
|
210
212
|
if (bundle?.length) {
|
|
211
213
|
files = bundle.some((f) => f.path === "SKILL.md") ? bundle : [...bundle, { path: "SKILL.md", contents: raw }];
|
|
214
|
+
if (missing.length) note = missingFilesNote(missing);
|
|
212
215
|
} else {
|
|
213
216
|
const pack = await getPackFiles(skill);
|
|
214
217
|
if (pack) {
|
|
@@ -549,7 +552,7 @@ async function startMcpServer() {
|
|
|
549
552
|
name: "skillmd",
|
|
550
553
|
version: VERSION,
|
|
551
554
|
title: "SkillMD",
|
|
552
|
-
description: "The open registry of Agent Skills: search, inspect, lint and install
|
|
555
|
+
description: "The open registry of Agent Skills: search, inspect, lint and install 1,000,000+ linted, security-reviewed SKILL.md files for Claude Code, Cursor, Codex and 60+ other agents.",
|
|
553
556
|
websiteUrl: "https://skillmd.com",
|
|
554
557
|
icons: [
|
|
555
558
|
{ src: "https://skillmd.com/favicon.png", mimeType: "image/png", sizes: ["512x512"] },
|
package/package.json
CHANGED