skillmds 1.3.2 → 1.3.4
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 +4 -0
- package/README.md +1 -1
- package/dist/{chunk-FVWCI37S.js → chunk-6JVWN3IG.js} +14 -1
- package/dist/cli.js +46 -16
- package/dist/mcp.js +6 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `skillmds` are documented here. Versions follow [semver](https://semver.org).
|
|
4
4
|
|
|
5
|
+
## 1.3.4
|
|
6
|
+
|
|
7
|
+
- **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.
|
|
8
|
+
|
|
5
9
|
## 1.2.0
|
|
6
10
|
|
|
7
11
|
`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";
|
|
@@ -655,6 +656,7 @@ function resolveClaudeBin(env = process.env) {
|
|
|
655
656
|
var needsShell = (bin) => /\.(cmd|bat)$/i.test(bin);
|
|
656
657
|
var MARKETPLACE_URL = "https://skillmd.com/.claude-plugin/marketplace.json";
|
|
657
658
|
var MARKETPLACE_NAME = "skillmd";
|
|
659
|
+
var MARKETPLACE_SCHEMA = "https://anthropic.com/claude-code/marketplace.schema.json";
|
|
658
660
|
var TIMEOUT_MS = 12e4;
|
|
659
661
|
function exec(deps) {
|
|
660
662
|
return deps.exec ?? ((file, args) => {
|
|
@@ -776,17 +778,36 @@ async function installPluginNatively(owner, slug, deps = {}) {
|
|
|
776
778
|
writeFileSync3(dest, data);
|
|
777
779
|
}
|
|
778
780
|
writeFileSync3(join2(installPath, ".in_use"), "");
|
|
779
|
-
mkdirSync2(join2(pluginsDir, "marketplaces", MARKETPLACE_NAME), { recursive: true });
|
|
780
781
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
781
782
|
const source = { source: "url", url: MARKETPLACE_URL };
|
|
783
|
+
const marketplaceDir = join2(pluginsDir, "marketplaces", MARKETPLACE_NAME);
|
|
784
|
+
const cachedPath = join2(marketplaceDir, ".claude-plugin", "marketplace.json");
|
|
785
|
+
const cached = readJson(cachedPath);
|
|
786
|
+
if (cached === "unparsable") return { ok: false, reason: "the cached marketplace manifest is not readable JSON \u2014 left untouched" };
|
|
787
|
+
const cachedDoc = cached === "absent" ? {
|
|
788
|
+
$schema: MARKETPLACE_SCHEMA,
|
|
789
|
+
name: MARKETPLACE_NAME,
|
|
790
|
+
owner: { name: "SkillMD", email: "hi@skillmd.com" },
|
|
791
|
+
description: "Agent Skill plugins from the SkillMD registry.",
|
|
792
|
+
plugins: []
|
|
793
|
+
} : cached;
|
|
794
|
+
const list = Array.isArray(cachedDoc.plugins) ? cachedDoc.plugins : [];
|
|
795
|
+
cachedDoc.plugins = [
|
|
796
|
+
...list.filter((e) => e?.name !== name),
|
|
797
|
+
{
|
|
798
|
+
name,
|
|
799
|
+
version: version2,
|
|
800
|
+
homepage: `${SITE_URL}/plugins/${owner}/${slug}`,
|
|
801
|
+
author: { name: owner === "skillmd" ? "SkillMD" : `@${owner}` },
|
|
802
|
+
source: { source: "archive", url: `${SITE_URL}/plugins/${owner}/${slug}/plugin.zip` }
|
|
803
|
+
}
|
|
804
|
+
];
|
|
805
|
+
writeJson(cachedPath, cachedDoc);
|
|
782
806
|
const knownDoc = known === "absent" ? {} : known;
|
|
783
|
-
knownDoc[MARKETPLACE_NAME]
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
lastUpdated: now
|
|
788
|
-
};
|
|
789
|
-
writeJson(knownPath, knownDoc);
|
|
807
|
+
if (!knownDoc[MARKETPLACE_NAME]) {
|
|
808
|
+
knownDoc[MARKETPLACE_NAME] = { source, installLocation: marketplaceDir, lastUpdated: now };
|
|
809
|
+
writeJson(knownPath, knownDoc);
|
|
810
|
+
}
|
|
790
811
|
const installedDoc = installed === "absent" ? { version: 2, plugins: {} } : installed;
|
|
791
812
|
const plugins = obj(installedDoc.plugins);
|
|
792
813
|
const prior = Array.isArray(plugins[qualified]) ? plugins[qualified] : [];
|
|
@@ -798,7 +819,9 @@ async function installPluginNatively(owner, slug, deps = {}) {
|
|
|
798
819
|
if (typeof installedDoc.version !== "number") installedDoc.version = 2;
|
|
799
820
|
writeJson(installedPath, installedDoc);
|
|
800
821
|
const settingsDoc = settings === "absent" ? {} : settings;
|
|
801
|
-
|
|
822
|
+
const declared = obj(settingsDoc.extraKnownMarketplaces);
|
|
823
|
+
if (!declared[MARKETPLACE_NAME]) declared[MARKETPLACE_NAME] = { source };
|
|
824
|
+
settingsDoc.extraKnownMarketplaces = declared;
|
|
802
825
|
settingsDoc.enabledPlugins = { ...obj(settingsDoc.enabledPlugins), [qualified]: true };
|
|
803
826
|
writeJson(settingsPath, settingsDoc);
|
|
804
827
|
} catch (e) {
|
|
@@ -848,6 +871,11 @@ function unverifiedFilesNote(n) {
|
|
|
848
871
|
const [f, it] = n === 1 ? ["file", "it"] : ["files", "them"];
|
|
849
872
|
return `${n} companion ${f} came straight from the source repo \u2014 the registry holds no checksum for ${it}, so only the connection was verified`;
|
|
850
873
|
}
|
|
874
|
+
function bundleNote(bundle, missing) {
|
|
875
|
+
const unverified = bundle.filter((file) => file.unverified).length;
|
|
876
|
+
const notes = [unverified ? unverifiedFilesNote(unverified) : "", missing.length ? missingFilesNote(missing) : ""].filter(Boolean);
|
|
877
|
+
return notes.length ? notes.join("; ") : void 0;
|
|
878
|
+
}
|
|
851
879
|
function registryFallbackNote(host) {
|
|
852
880
|
return `installed from GitHub because the SkillMD registry (${host}) was unreachable \u2014 this copy is not the registry-reviewed version`;
|
|
853
881
|
}
|
|
@@ -890,15 +918,16 @@ async function registryCandidate(owner, name, source, client) {
|
|
|
890
918
|
securityFlags: skill.security_flags
|
|
891
919
|
};
|
|
892
920
|
if (skill.type === "pack") {
|
|
893
|
-
const
|
|
921
|
+
const missing = [];
|
|
922
|
+
const bundle = await fetchBundle(client.base, registrySlug, client.token, { missing });
|
|
894
923
|
if (bundle && bundle.length) {
|
|
895
924
|
const sk = bundle.find((file) => file.path === "SKILL.md");
|
|
896
|
-
const
|
|
925
|
+
const note2 = bundleNote(bundle, missing);
|
|
897
926
|
return {
|
|
898
927
|
...meta,
|
|
899
928
|
raw: sk ? sk.contents.toString("utf8") : skillMdFor(skill),
|
|
900
929
|
files: bundle,
|
|
901
|
-
...
|
|
930
|
+
...note2 ? { note: note2 } : {}
|
|
902
931
|
};
|
|
903
932
|
}
|
|
904
933
|
const pack = await resolvePackFiles(skill);
|
|
@@ -988,13 +1017,14 @@ function makeDefaultDeps(flags) {
|
|
|
988
1017
|
for (let i = n++; i < multi.length; i = n++) {
|
|
989
1018
|
const c = multi[i];
|
|
990
1019
|
try {
|
|
991
|
-
const
|
|
1020
|
+
const missing2 = [];
|
|
1021
|
+
const bundle = await fetchBundle(apiBase2, c.registrySlug, token2, { missing: missing2 });
|
|
992
1022
|
if (!bundle?.length) continue;
|
|
993
1023
|
const sk = bundle.find((file) => file.path === "SKILL.md");
|
|
994
|
-
const
|
|
1024
|
+
const note2 = bundleNote(bundle, missing2);
|
|
995
1025
|
c.files = bundle;
|
|
996
1026
|
if (sk) c.raw = sk.contents.toString("utf8");
|
|
997
|
-
if (
|
|
1027
|
+
if (note2) c.note = note2;
|
|
998
1028
|
} catch {
|
|
999
1029
|
}
|
|
1000
1030
|
}
|
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