skillmds 1.2.1 → 1.3.1
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/dist/{chunk-4BFQJ3YZ.js → chunk-FVWCI37S.js} +13 -0
- package/dist/cli.js +325 -106
- package/dist/mcp.js +1 -1
- package/package.json +2 -1
|
@@ -19,6 +19,12 @@ function parseSource(arg, opts = {}) {
|
|
|
19
19
|
const exists = opts.exists ?? existsSync;
|
|
20
20
|
const a = arg.trim();
|
|
21
21
|
if (!a) throw new Error("a source is required: owner/name, a GitHub URL, or a local path");
|
|
22
|
+
if (/^(plugin|pack):/i.test(a)) {
|
|
23
|
+
const body2 = a.slice(a.indexOf(":") + 1);
|
|
24
|
+
const m2 = body2.match(/^([^/#@\s]+)\/([^/#@\s]+)$/);
|
|
25
|
+
if (!m2) throw new Error(`"${a}" is not a valid plugin source \u2014 expected plugin:owner/slug`);
|
|
26
|
+
return { kind: "plugin", owner: m2[1], slug: m2[2], display: a };
|
|
27
|
+
}
|
|
22
28
|
if (a === "~" || a.startsWith("~/") || a.startsWith("~\\")) {
|
|
23
29
|
return { kind: "local", path: join(homedir(), a.slice(1)), display: a };
|
|
24
30
|
}
|
|
@@ -54,6 +60,10 @@ function sourceId(spec) {
|
|
|
54
60
|
switch (spec.kind) {
|
|
55
61
|
case "slug":
|
|
56
62
|
return `registry:${spec.owner}/${spec.name}`;
|
|
63
|
+
// Members are recorded under their own registry slug, not this one — the
|
|
64
|
+
// lock file tracks what was written, and a plugin is only how they arrived.
|
|
65
|
+
case "plugin":
|
|
66
|
+
return `plugin:${spec.owner}/${spec.slug}`;
|
|
57
67
|
case "github":
|
|
58
68
|
return `github:${spec.owner}/${spec.repo}${spec.subpath ? `/${spec.subpath}` : ""}${spec.ref ? `#${spec.ref}` : ""}${spec.skill ? `@${spec.skill}` : ""}`;
|
|
59
69
|
case "gist":
|
|
@@ -314,6 +324,9 @@ async function resolveSource(arg, opts = {}) {
|
|
|
314
324
|
if (raw.length > MAX_PACK_BYTES) throw tooBig(raw.length);
|
|
315
325
|
return [{ path: spec.display, raw, slug: `gist-${spec.id.slice(0, 8)}` }];
|
|
316
326
|
}
|
|
327
|
+
if (spec.kind === "plugin") {
|
|
328
|
+
throw new Error(`"${spec.display}" is a plugin, not a single skill \u2014 install it with \`skillmd add ${spec.display}\`.`);
|
|
329
|
+
}
|
|
317
330
|
const gh = asGithub(spec);
|
|
318
331
|
const { dir, cleanup } = await downloadGithub(gh, "skillmd-src-", opts, Boolean(gh.subpath));
|
|
319
332
|
try {
|
package/dist/cli.js
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
uninstallSkill,
|
|
31
31
|
upsertEntry,
|
|
32
32
|
writeConfig
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-FVWCI37S.js";
|
|
34
34
|
|
|
35
35
|
// src/index.ts
|
|
36
36
|
import { Command as Command13 } from "commander";
|
|
@@ -319,12 +319,12 @@ function lintCommand() {
|
|
|
319
319
|
const s = p.spinner();
|
|
320
320
|
s.start(`Scanning ${target}`);
|
|
321
321
|
try {
|
|
322
|
-
const
|
|
323
|
-
s.stop(`Scanned ${
|
|
324
|
-
console.log(
|
|
325
|
-
const failed =
|
|
322
|
+
const run3 = await runLint(target, opts);
|
|
323
|
+
s.stop(`Scanned ${run3.results.length} skill${run3.results.length === 1 ? "" : "s"}`);
|
|
324
|
+
console.log(run3.output);
|
|
325
|
+
const failed = run3.results.filter((r) => !r.result.ok).length;
|
|
326
326
|
p.outro(failed === 0 ? pc2.green("All good") : pc2.red(`${failed} skill${failed === 1 ? "" : "s"} failed \u2014 details above`));
|
|
327
|
-
process.exitCode =
|
|
327
|
+
process.exitCode = run3.exitCode;
|
|
328
328
|
} catch (err) {
|
|
329
329
|
s.stop(pc2.red("No skills found"));
|
|
330
330
|
p.outro(err instanceof Error ? err.message : String(err));
|
|
@@ -334,9 +334,9 @@ function lintCommand() {
|
|
|
334
334
|
}
|
|
335
335
|
process.stderr.write(`Looking for SKILL.md under ${target} \u2026
|
|
336
336
|
`);
|
|
337
|
-
const
|
|
338
|
-
console.log(
|
|
339
|
-
process.exitCode =
|
|
337
|
+
const run2 = await runLint(target, opts);
|
|
338
|
+
console.log(run2.output);
|
|
339
|
+
process.exitCode = run2.exitCode;
|
|
340
340
|
});
|
|
341
341
|
}
|
|
342
342
|
|
|
@@ -375,9 +375,9 @@ async function runScan(target, flags) {
|
|
|
375
375
|
}
|
|
376
376
|
function scanCommand() {
|
|
377
377
|
return new Command2("scan").description("Security-scan SKILL.md file(s) for scripts, network calls and secret access").argument("[target]", "local path or GitHub source", ".").option("--deny <flags...>", "exit non-zero if any of these flags are present (e.g. executes_scripts)").option("--format <fmt>", "text | json", "text").action(async (target, opts) => {
|
|
378
|
-
const
|
|
379
|
-
console.log(
|
|
380
|
-
process.exitCode =
|
|
378
|
+
const run2 = await runScan(target, opts);
|
|
379
|
+
console.log(run2.output);
|
|
380
|
+
process.exitCode = run2.exitCode;
|
|
381
381
|
});
|
|
382
382
|
}
|
|
383
383
|
|
|
@@ -504,8 +504,8 @@ async function runInit(nameArg, flags, deps = defaultInitDeps(flags)) {
|
|
|
504
504
|
const file = initSkill(name, { dir: flags.dir, description: flags.description, license: flags.license });
|
|
505
505
|
return { exitCode: 0, file, output: flags.json ? JSON.stringify({ ok: true, file }, null, 2) : `Created ${file}` };
|
|
506
506
|
} catch (e) {
|
|
507
|
-
const
|
|
508
|
-
return { exitCode: 1, output: flags.json ? JSON.stringify({ ok: false, error:
|
|
507
|
+
const msg2 = e instanceof Error ? e.message : String(e);
|
|
508
|
+
return { exitCode: 1, output: flags.json ? JSON.stringify({ ok: false, error: msg2 }, null, 2) : pc5.red(msg2) };
|
|
509
509
|
}
|
|
510
510
|
}
|
|
511
511
|
function initCommand() {
|
|
@@ -563,8 +563,8 @@ async function runSearch(query, flags) {
|
|
|
563
563
|
function searchCommand() {
|
|
564
564
|
return new Command5("search").description("Search the SkillMD registry").argument("<query>", "search terms").option("--category <slug>", "filter by category").option("--verified", "only verified skills").option("--type <type>", "single | pack").option("--min-rating <n>", "minimum average rating (0-5)").option("--limit <n>", "max results", "20").option("--json", "machine-readable output").action(async (query, opts, cmd) => {
|
|
565
565
|
const merged = { ...cmd.parent?.opts(), ...opts };
|
|
566
|
-
const
|
|
567
|
-
console.log(
|
|
566
|
+
const run2 = await runSearch(query, merged);
|
|
567
|
+
console.log(run2.output);
|
|
568
568
|
});
|
|
569
569
|
}
|
|
570
570
|
|
|
@@ -613,19 +613,103 @@ async function runInfo(slug, flags, deps = {}) {
|
|
|
613
613
|
function infoCommand() {
|
|
614
614
|
return new Command6("info").description("Show registry details for a skill: verification, security flags, provenance, rating").argument("<slug>", "owner/name, e.g. anthropic/pdf").action(async (slug, _opts, cmd) => {
|
|
615
615
|
const flags = { ...cmd.parent?.opts() };
|
|
616
|
-
const
|
|
617
|
-
if (
|
|
618
|
-
process.exitCode =
|
|
616
|
+
const run2 = await runInfo(slug, flags);
|
|
617
|
+
if (run2.output) (run2.ok ? console.log : console.error)(run2.output);
|
|
618
|
+
process.exitCode = run2.exitCode;
|
|
619
619
|
});
|
|
620
620
|
}
|
|
621
621
|
|
|
622
622
|
// src/commands/add.ts
|
|
623
623
|
import { Command as Command7, Option } from "commander";
|
|
624
|
-
import { homedir as
|
|
624
|
+
import { homedir as homedir4 } from "os";
|
|
625
625
|
import * as p3 from "@clack/prompts";
|
|
626
626
|
import { dirname, resolve as resolve3 } from "path";
|
|
627
627
|
import pc8 from "picocolors";
|
|
628
628
|
import { lint as lint2, parseSkillMd as parseSkillMd2 } from "@skillmds/core";
|
|
629
|
+
|
|
630
|
+
// src/claudePlugin.ts
|
|
631
|
+
import { execFile } from "child_process";
|
|
632
|
+
import { existsSync as existsSync2 } from "fs";
|
|
633
|
+
import { homedir as homedir3 } from "os";
|
|
634
|
+
import { delimiter, join as join2 } from "path";
|
|
635
|
+
import { promisify } from "util";
|
|
636
|
+
var run = promisify(execFile);
|
|
637
|
+
function resolveClaudeBin(env = process.env) {
|
|
638
|
+
const override = env.SKILLMD_CLAUDE_BIN;
|
|
639
|
+
if (override) return existsSync2(override) ? override : null;
|
|
640
|
+
const win = process.platform === "win32";
|
|
641
|
+
const exts = win ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
642
|
+
const dirs = (env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
643
|
+
const home = env.USERPROFILE || env.HOME || homedir3();
|
|
644
|
+
dirs.push(join2(home, ".local", "bin"), join2(home, ".claude", "local"));
|
|
645
|
+
for (const dir of dirs) {
|
|
646
|
+
for (const ext of exts) {
|
|
647
|
+
const candidate = join2(dir, `claude${ext.toLowerCase()}`);
|
|
648
|
+
if (existsSync2(candidate)) return candidate;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
return null;
|
|
652
|
+
}
|
|
653
|
+
var needsShell = (bin) => /\.(cmd|bat)$/i.test(bin);
|
|
654
|
+
var MARKETPLACE_URL = "https://skillmd.com/.claude-plugin/marketplace.json";
|
|
655
|
+
var MARKETPLACE_NAME = "skillmd";
|
|
656
|
+
var TIMEOUT_MS = 12e4;
|
|
657
|
+
function exec(deps) {
|
|
658
|
+
return deps.exec ?? ((file, args) => {
|
|
659
|
+
const bin = file === "claude" ? resolveClaudeBin() : file;
|
|
660
|
+
if (!bin) return Promise.reject(new Error("claude not found on PATH"));
|
|
661
|
+
return run(bin, args, { timeout: TIMEOUT_MS, windowsHide: true, shell: needsShell(bin) }).then((r) => ({
|
|
662
|
+
stdout: String(r.stdout ?? ""),
|
|
663
|
+
stderr: String(r.stderr ?? "")
|
|
664
|
+
}));
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
function marketplacePluginName(owner, slug) {
|
|
668
|
+
const clean = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
669
|
+
const base = clean(slug) || "plugin";
|
|
670
|
+
return owner.toLowerCase() === "skillmd" ? base : `${clean(owner)}-${base}`;
|
|
671
|
+
}
|
|
672
|
+
async function claudeCliAvailable(deps = {}) {
|
|
673
|
+
try {
|
|
674
|
+
await exec(deps)("claude", ["--version"]);
|
|
675
|
+
return true;
|
|
676
|
+
} catch {
|
|
677
|
+
return false;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
async function installClaudePlugin(owner, slug, deps = {}) {
|
|
681
|
+
const sh = exec(deps);
|
|
682
|
+
const qualified = `${marketplacePluginName(owner, slug)}@${MARKETPLACE_NAME}`;
|
|
683
|
+
try {
|
|
684
|
+
await sh("claude", ["plugin", "marketplace", "add", MARKETPLACE_URL]);
|
|
685
|
+
} catch (e) {
|
|
686
|
+
return { ok: false, reason: `could not add the SkillMD marketplace: ${msg(e)}` };
|
|
687
|
+
}
|
|
688
|
+
try {
|
|
689
|
+
await sh("claude", ["plugin", "marketplace", "update", MARKETPLACE_NAME]);
|
|
690
|
+
} catch {
|
|
691
|
+
}
|
|
692
|
+
let out;
|
|
693
|
+
try {
|
|
694
|
+
const r = await sh("claude", ["plugin", "install", qualified]);
|
|
695
|
+
out = `${r.stdout}
|
|
696
|
+
${r.stderr}`;
|
|
697
|
+
} catch (e) {
|
|
698
|
+
return { ok: false, reason: msg(e) };
|
|
699
|
+
}
|
|
700
|
+
if (/Successfully installed plugin/i.test(out)) return { ok: true, name: qualified, marketplace: MARKETPLACE_NAME };
|
|
701
|
+
const failed = /Failed to install plugin[^:]*:\s*(.+)/i.exec(out);
|
|
702
|
+
return { ok: false, reason: (failed?.[1] ?? out).trim().split(/\r?\n/)[0] ?? "install did not report success" };
|
|
703
|
+
}
|
|
704
|
+
function msg(e) {
|
|
705
|
+
if (e && typeof e === "object" && "stderr" in e) {
|
|
706
|
+
const s = String(e.stderr ?? "").trim();
|
|
707
|
+
if (s) return s.split(/\r?\n/)[0];
|
|
708
|
+
}
|
|
709
|
+
return e instanceof Error ? e.message.split(/\r?\n/)[0] : String(e);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// src/commands/add.ts
|
|
629
713
|
var infoNotice = (text3) => ({ text: text3, style: "info" });
|
|
630
714
|
var warnNotice = (text3) => ({ text: text3, style: "warn" });
|
|
631
715
|
var skipNotice = (text3) => ({ text: text3, style: "skip" });
|
|
@@ -693,6 +777,77 @@ function provenanceFor(arg) {
|
|
|
693
777
|
return `unknown:${arg}`;
|
|
694
778
|
}
|
|
695
779
|
}
|
|
780
|
+
async function registryCandidate(owner, name, source, client) {
|
|
781
|
+
const registrySlug = `${owner}/${name}`;
|
|
782
|
+
const skill = await client.api(`/api/skills/${owner}/${name}`);
|
|
783
|
+
const skillName = skill.slug.split("/")[1] || name;
|
|
784
|
+
const meta = {
|
|
785
|
+
name: skillName,
|
|
786
|
+
slug: skillName,
|
|
787
|
+
registrySlug,
|
|
788
|
+
source,
|
|
789
|
+
commit_sha: skill.commit_sha ?? void 0,
|
|
790
|
+
verified: skill.verified,
|
|
791
|
+
type: skill.type,
|
|
792
|
+
securityFlags: skill.security_flags
|
|
793
|
+
};
|
|
794
|
+
if (skill.type === "pack") {
|
|
795
|
+
const bundle = await fetchBundle(client.base, registrySlug, client.token);
|
|
796
|
+
if (bundle && bundle.length) {
|
|
797
|
+
const sk = bundle.find((file) => file.path === "SKILL.md");
|
|
798
|
+
const unverified = bundle.filter((file) => file.unverified).length;
|
|
799
|
+
return {
|
|
800
|
+
...meta,
|
|
801
|
+
raw: sk ? sk.contents.toString("utf8") : skillMdFor(skill),
|
|
802
|
+
files: bundle,
|
|
803
|
+
...unverified ? { note: unverifiedFilesNote(unverified) } : {}
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
const pack = await resolvePackFiles(skill);
|
|
807
|
+
if (pack) return { ...meta, ...pack };
|
|
808
|
+
}
|
|
809
|
+
return { ...meta, raw: skillMdFor(skill) };
|
|
810
|
+
}
|
|
811
|
+
async function fetchPackMembers(api, owner, slug) {
|
|
812
|
+
const PAGE = 200;
|
|
813
|
+
const members = [];
|
|
814
|
+
let name = slug;
|
|
815
|
+
let total = Infinity;
|
|
816
|
+
for (let offset = 0; members.length < total; offset += PAGE) {
|
|
817
|
+
const page = await api(`/api/packs/${owner}/${slug}?limit=${PAGE}&offset=${offset}`);
|
|
818
|
+
name = page.name || name;
|
|
819
|
+
total = Number(page.item_total ?? 0);
|
|
820
|
+
const got = (page.items ?? []).map((i) => ({ slug: String(i.slug ?? ""), type: i.type, verified: Boolean(i.verified) })).filter((i) => i.slug);
|
|
821
|
+
if (!got.length) break;
|
|
822
|
+
members.push(...got);
|
|
823
|
+
}
|
|
824
|
+
return { name, members };
|
|
825
|
+
}
|
|
826
|
+
function packDirNames(slugs) {
|
|
827
|
+
const used = /* @__PURE__ */ new Set();
|
|
828
|
+
return slugs.map((slug) => {
|
|
829
|
+
const [owner, name] = slug.split("/");
|
|
830
|
+
let dir = name ?? slug;
|
|
831
|
+
if (used.has(dir)) dir = `${owner}-${name}`;
|
|
832
|
+
used.add(dir);
|
|
833
|
+
return dir;
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
async function fetchPackArchive(base, owner, slug, token, doFetch = fetch) {
|
|
837
|
+
const headers = { accept: "application/zip" };
|
|
838
|
+
if (token) headers.authorization = `Bearer ${token}`;
|
|
839
|
+
const res = await doFetch(`${base}/api/packs/${owner}/${slug}/download`, { headers });
|
|
840
|
+
if (!res.ok) throw new RegistryError(`SkillMD API ${res.status} on /api/packs/${owner}/${slug}/download`, res.status);
|
|
841
|
+
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
842
|
+
const { unzipSync, strFromU8 } = await import("fflate");
|
|
843
|
+
const entries = unzipSync(bytes);
|
|
844
|
+
const out = /* @__PURE__ */ new Map();
|
|
845
|
+
for (const [path, data] of Object.entries(entries)) {
|
|
846
|
+
const m = /^(.+)\/SKILL\.md$/.exec(path);
|
|
847
|
+
if (m) out.set(m[1], strFromU8(data));
|
|
848
|
+
}
|
|
849
|
+
return out;
|
|
850
|
+
}
|
|
696
851
|
function makeDefaultDeps(flags) {
|
|
697
852
|
const canPrompt = () => isInteractive(flags, {
|
|
698
853
|
stdinTTY: Boolean(process.stdin.isTTY),
|
|
@@ -703,6 +858,55 @@ function makeDefaultDeps(flags) {
|
|
|
703
858
|
async resolve(arg, f) {
|
|
704
859
|
const spec = parseSource(arg, { ref: f.ref });
|
|
705
860
|
const source = sourceId(spec);
|
|
861
|
+
if (spec.kind === "plugin") {
|
|
862
|
+
const { api: api2, base: apiBase2, token: token2, fetch: doFetch } = createClient(f);
|
|
863
|
+
const { name: packName, members } = await fetchPackMembers(api2, spec.owner, spec.slug);
|
|
864
|
+
if (!members.length) throw new Error(`plugin ${spec.owner}/${spec.slug} has no installable skills`);
|
|
865
|
+
const archive = await fetchPackArchive(apiBase2, spec.owner, spec.slug, token2, doFetch);
|
|
866
|
+
const dirs = packDirNames(members.map((m) => m.slug));
|
|
867
|
+
const out = [];
|
|
868
|
+
const missing = [];
|
|
869
|
+
members.forEach((m, i) => {
|
|
870
|
+
const raw = archive.get(dirs[i]);
|
|
871
|
+
if (!raw) {
|
|
872
|
+
missing.push(m.slug);
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
const name = dirs[i];
|
|
876
|
+
out.push({
|
|
877
|
+
name,
|
|
878
|
+
slug: name,
|
|
879
|
+
registrySlug: m.slug,
|
|
880
|
+
source,
|
|
881
|
+
raw,
|
|
882
|
+
verified: m.verified,
|
|
883
|
+
type: m.type
|
|
884
|
+
});
|
|
885
|
+
});
|
|
886
|
+
const multi = out.filter((c) => c.type === "pack");
|
|
887
|
+
if (multi.length) {
|
|
888
|
+
let n = 0;
|
|
889
|
+
await Promise.all(Array.from({ length: Math.min(4, multi.length) }, async () => {
|
|
890
|
+
for (let i = n++; i < multi.length; i = n++) {
|
|
891
|
+
const c = multi[i];
|
|
892
|
+
try {
|
|
893
|
+
const bundle = await fetchBundle(apiBase2, c.registrySlug, token2);
|
|
894
|
+
if (!bundle?.length) continue;
|
|
895
|
+
const sk = bundle.find((file) => file.path === "SKILL.md");
|
|
896
|
+
const unverified = bundle.filter((file) => file.unverified).length;
|
|
897
|
+
c.files = bundle;
|
|
898
|
+
if (sk) c.raw = sk.contents.toString("utf8");
|
|
899
|
+
if (unverified) c.note = unverifiedFilesNote(unverified);
|
|
900
|
+
} catch {
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
}));
|
|
904
|
+
}
|
|
905
|
+
if (!out.length) throw new Error(`plugin ${spec.owner}/${spec.slug} returned no readable skills`);
|
|
906
|
+
const first = out[0];
|
|
907
|
+
first.note = `${out.length} skill${out.length === 1 ? "" : "s"} from the ${packName} plugin` + (missing.length ? ` (${missing.length} member${missing.length === 1 ? "" : "s"} were not in the archive)` : "");
|
|
908
|
+
return out;
|
|
909
|
+
}
|
|
706
910
|
if (spec.kind !== "slug") {
|
|
707
911
|
const rs = await resolveSource(argWithRef(arg, f.ref));
|
|
708
912
|
return rs.map((r) => ({
|
|
@@ -724,34 +928,7 @@ function makeDefaultDeps(flags) {
|
|
|
724
928
|
})();
|
|
725
929
|
const registrySlug = `${spec.owner}/${spec.name}`;
|
|
726
930
|
try {
|
|
727
|
-
|
|
728
|
-
const skillName = skill.slug.split("/")[1] || spec.name;
|
|
729
|
-
const meta = {
|
|
730
|
-
name: skillName,
|
|
731
|
-
slug: skillName,
|
|
732
|
-
registrySlug,
|
|
733
|
-
source,
|
|
734
|
-
commit_sha: skill.commit_sha ?? void 0,
|
|
735
|
-
verified: skill.verified,
|
|
736
|
-
type: skill.type,
|
|
737
|
-
securityFlags: skill.security_flags
|
|
738
|
-
};
|
|
739
|
-
if (skill.type === "pack") {
|
|
740
|
-
const bundle = await fetchBundle(apiBase, registrySlug, token);
|
|
741
|
-
if (bundle && bundle.length) {
|
|
742
|
-
const sk = bundle.find((file) => file.path === "SKILL.md");
|
|
743
|
-
const unverified = bundle.filter((file) => file.unverified).length;
|
|
744
|
-
return [{
|
|
745
|
-
...meta,
|
|
746
|
-
raw: sk ? sk.contents.toString("utf8") : skillMdFor(skill),
|
|
747
|
-
files: bundle,
|
|
748
|
-
...unverified ? { note: unverifiedFilesNote(unverified) } : {}
|
|
749
|
-
}];
|
|
750
|
-
}
|
|
751
|
-
const pack = await resolvePackFiles(skill);
|
|
752
|
-
if (pack) return [{ ...meta, ...pack }];
|
|
753
|
-
}
|
|
754
|
-
return [{ ...meta, raw: skillMdFor(skill) }];
|
|
931
|
+
return [await registryCandidate(spec.owner, spec.name, source, { api, base: apiBase, token })];
|
|
755
932
|
} catch (e) {
|
|
756
933
|
if (e instanceof IntegrityError) throw e;
|
|
757
934
|
if (e instanceof RegistryError && e.status !== 404) registryDown = e;
|
|
@@ -785,7 +962,7 @@ function makeDefaultDeps(flags) {
|
|
|
785
962
|
};
|
|
786
963
|
}
|
|
787
964
|
async function resolveScope(flags, deps) {
|
|
788
|
-
const home = resolve3(flags.home ??
|
|
965
|
+
const home = resolve3(flags.home ?? homedir4());
|
|
789
966
|
const cwd = resolve3(flags.cwd ?? process.cwd());
|
|
790
967
|
const base = { cwd: flags.cwd, home: flags.home, env: flags.env };
|
|
791
968
|
if (flags.global) return { scope: { global: true, ...base } };
|
|
@@ -808,7 +985,7 @@ function defaultNeedsPrompt(flags) {
|
|
|
808
985
|
const env = flags.env ?? process.env;
|
|
809
986
|
if (flags.yes || flags.json || flags.global || flags.project || flags.list) return false;
|
|
810
987
|
if (detectHostAgent(env)) return false;
|
|
811
|
-
if (resolve3(flags.cwd ?? process.cwd()) === resolve3(flags.home ??
|
|
988
|
+
if (resolve3(flags.cwd ?? process.cwd()) === resolve3(flags.home ?? homedir4())) return false;
|
|
812
989
|
return !isInteractive(flags, { stdinTTY: Boolean(process.stdin.isTTY), stdoutTTY: Boolean(process.stdout.isTTY), env });
|
|
813
990
|
}
|
|
814
991
|
var CANCELLED_TEXT = "installation cancelled \u2014 nothing was installed";
|
|
@@ -823,7 +1000,7 @@ function finish2(flags, outcome) {
|
|
|
823
1000
|
...outcome.notices,
|
|
824
1001
|
...outcome.records.flatMap((r) => r.kind === "installed" ? r.notices : [])
|
|
825
1002
|
].map((n) => n.text);
|
|
826
|
-
const exitCode = blocked.length > 0 || installed.length === 0 ? 1 : 0;
|
|
1003
|
+
const exitCode = blocked.length > 0 || installed.length === 0 && !outcome.managed ? 1 : 0;
|
|
827
1004
|
const doc = { ok: exitCode === 0, scope: outcome.scope, installed, blocked, warnings };
|
|
828
1005
|
return {
|
|
829
1006
|
written,
|
|
@@ -985,9 +1162,49 @@ async function installOne(c, ctx) {
|
|
|
985
1162
|
...out.replaced ? { replaced: out.replaced } : {}
|
|
986
1163
|
};
|
|
987
1164
|
}
|
|
1165
|
+
async function tryPluginInstall(arg, flags) {
|
|
1166
|
+
let spec;
|
|
1167
|
+
try {
|
|
1168
|
+
spec = parseSource(arg, { ref: flags.ref });
|
|
1169
|
+
} catch {
|
|
1170
|
+
return null;
|
|
1171
|
+
}
|
|
1172
|
+
if (spec.kind !== "plugin") return null;
|
|
1173
|
+
if (flags.agent?.length || flags.skill?.length || flags.list || flags.mode === "copy") return null;
|
|
1174
|
+
if (!await claudeCliAvailable()) return null;
|
|
1175
|
+
const res = await installClaudePlugin(spec.owner, spec.slug);
|
|
1176
|
+
if (!res.ok) return { ok: false, reason: res.reason };
|
|
1177
|
+
return {
|
|
1178
|
+
ok: true,
|
|
1179
|
+
agent: "claude-code",
|
|
1180
|
+
name: res.name,
|
|
1181
|
+
note: `installed ${res.name} as a Claude Code plugin \u2014 manage it with \`claude plugin\` or /plugin`
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
988
1184
|
async function runAdd(arg, flags, deps) {
|
|
989
1185
|
const d = deps ?? makeDefaultDeps(flags);
|
|
990
1186
|
const env = flags.env ?? process.env;
|
|
1187
|
+
const attempt = await tryPluginInstall(arg, flags);
|
|
1188
|
+
const managed = attempt?.ok ? attempt : null;
|
|
1189
|
+
const managedNotices = !attempt ? [] : attempt.ok ? [infoNotice(attempt.note)] : [warnNotice(`could not install this as a Claude Code plugin (${attempt.reason}) \u2014 installing its skills instead`)];
|
|
1190
|
+
let scopeOnce;
|
|
1191
|
+
const scopeOf = async () => scopeOnce ??= await resolveScope(flags, d);
|
|
1192
|
+
if (managed) {
|
|
1193
|
+
const pre = await scopeOf();
|
|
1194
|
+
if (!pre) return finish2(flags, { kind: "cancel" });
|
|
1195
|
+
const others = detectAgents(pre.scope).filter((id) => id !== managed.agent);
|
|
1196
|
+
if (!others.length) {
|
|
1197
|
+
const paths2 = { home: flags.home ?? homedir4(), cwd: flags.cwd ?? process.cwd() };
|
|
1198
|
+
return finish2(flags, {
|
|
1199
|
+
kind: "install",
|
|
1200
|
+
scope: pre.scope.global ? "global" : "project",
|
|
1201
|
+
records: [],
|
|
1202
|
+
notices: [...pre.note ? [infoNotice(pre.note)] : [], ...managedNotices],
|
|
1203
|
+
paths: paths2,
|
|
1204
|
+
managed: managed.name
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
991
1208
|
let candidates;
|
|
992
1209
|
try {
|
|
993
1210
|
candidates = await resolveCandidates(arg, flags, d);
|
|
@@ -1000,18 +1217,20 @@ async function runAdd(arg, flags, deps) {
|
|
|
1000
1217
|
}
|
|
1001
1218
|
const early = gate(flags, d, candidates);
|
|
1002
1219
|
if (early) return early;
|
|
1003
|
-
const resolved = await
|
|
1220
|
+
const resolved = await scopeOf();
|
|
1004
1221
|
if (!resolved) return finish2(flags, { kind: "cancel" });
|
|
1005
1222
|
const scope = resolved.scope;
|
|
1006
1223
|
const notices = resolved.note ? [infoNotice(resolved.note)] : [];
|
|
1007
|
-
|
|
1224
|
+
notices.push(...managedNotices);
|
|
1225
|
+
const detected = detectAgents(scope).filter((id) => id !== managed?.agent);
|
|
1226
|
+
const chosen = await chooseTargets(flags, d, scope, detected);
|
|
1008
1227
|
if (!chosen) return finish2(flags, { kind: "cancel" });
|
|
1009
1228
|
notices.push(...chosen.notices);
|
|
1010
1229
|
const ctx = { arg, flags, deny: new Set(flags.deny ?? []), scope, targets: chosen.targets, env, deps: d };
|
|
1011
1230
|
const records = [];
|
|
1012
1231
|
for (const c of candidates) records.push(await installOne(c, ctx));
|
|
1013
|
-
const paths = { home: flags.home ??
|
|
1014
|
-
return finish2(flags, { kind: "install", scope: scope.global ? "global" : "project", records, notices, paths });
|
|
1232
|
+
const paths = { home: flags.home ?? homedir4(), cwd: flags.cwd ?? process.cwd() };
|
|
1233
|
+
return finish2(flags, { kind: "install", scope: scope.global ? "global" : "project", records, notices, paths, ...managed ? { managed: managed.name } : {} });
|
|
1015
1234
|
}
|
|
1016
1235
|
function addFlags(opts, parent) {
|
|
1017
1236
|
const merged = { ...parent, ...opts };
|
|
@@ -1021,12 +1240,12 @@ function addFlags(opts, parent) {
|
|
|
1021
1240
|
function addCommand() {
|
|
1022
1241
|
return new Command7("add").description("Install a skill from the registry, a GitHub repo, or a local path (lints before writing)").argument("<source>", "registry slug (owner/name), GitHub source, or local path").option("-g, --global", "install to your user-level agent folders (available in every project)").option("-p, --project", "install into the current directory's agent folders (committed with the project)").option("-a, --agent <agents...>", "target specific agents (default: every agent detected on this machine)").option("-s, --skill <names...>", "install only specific skills by name ('*' for all)").option("--ref <ref>", "git ref (branch, tag or commit) for GitHub sources").option("-l, --list", "list the skills a source contains without installing").addOption(new Option("--mode <mode>", "link (junction/symlink into each agent dir, default) or copy").choices(["link", "copy"]).default("link")).option("--force", "replace a skill installed from a different source, or an untracked directory").addOption(new Option("--copy", "alias of --mode copy").hideHelp()).option("-y, --yes", "skip prompts; scope is auto-detected (project if this folder looks like a project, else global)").addOption(new Option("--allow-unverified").hideHelp()).option("--skip-lint", "install even if the skill fails lint").option("--deny <flags...>", "refuse skills carrying any of these security flags (opt-in)").action(async (source, opts, cmd) => {
|
|
1023
1242
|
const merged = addFlags(opts, cmd.parent?.opts());
|
|
1024
|
-
const { run, printed } = await runAddWithUI(source, merged);
|
|
1243
|
+
const { run: run2, printed } = await runAddWithUI(source, merged);
|
|
1025
1244
|
if (!printed) {
|
|
1026
|
-
if (
|
|
1027
|
-
else console.log(
|
|
1245
|
+
if (run2.exitCode === 1 && !merged.json) console.error(run2.output);
|
|
1246
|
+
else console.log(run2.output);
|
|
1028
1247
|
}
|
|
1029
|
-
process.exitCode =
|
|
1248
|
+
process.exitCode = run2.exitCode;
|
|
1030
1249
|
});
|
|
1031
1250
|
}
|
|
1032
1251
|
var clackUI = {
|
|
@@ -1043,7 +1262,7 @@ async function runAddWithUI(source, flags, opts = {}) {
|
|
|
1043
1262
|
const ui = opts.ui ?? clackUI;
|
|
1044
1263
|
ui.intro(banner());
|
|
1045
1264
|
try {
|
|
1046
|
-
const
|
|
1265
|
+
const run2 = await runAdd(source, flags, {
|
|
1047
1266
|
// NOTE: spreading `base` reads makeDefaultDeps()'s promptScope/promptAgents
|
|
1048
1267
|
// getters right here, freezing their values for this run. That is exactly
|
|
1049
1268
|
// what we want (interactivity is decided once, up front), but it does mean
|
|
@@ -1063,13 +1282,13 @@ async function runAddWithUI(source, flags, opts = {}) {
|
|
|
1063
1282
|
}
|
|
1064
1283
|
}
|
|
1065
1284
|
});
|
|
1066
|
-
if (
|
|
1285
|
+
if (run2.cancelled) {
|
|
1067
1286
|
ui.cancel("Installation cancelled \u2014 nothing was installed.");
|
|
1068
|
-
return { run, printed: true };
|
|
1287
|
+
return { run: run2, printed: true };
|
|
1069
1288
|
}
|
|
1070
|
-
ui.message(
|
|
1071
|
-
ui.outro(
|
|
1072
|
-
return { run, printed: true };
|
|
1289
|
+
ui.message(run2.output);
|
|
1290
|
+
ui.outro(run2.exitCode === 0 ? `Done. Run ${pc8.cyan("skillmd list")} to see everything installed.` : pc8.red("Some skills were not installed."));
|
|
1291
|
+
return { run: run2, printed: true };
|
|
1073
1292
|
} catch (e) {
|
|
1074
1293
|
ui.outro(pc8.red("Nothing was installed."));
|
|
1075
1294
|
throw e;
|
|
@@ -1078,8 +1297,8 @@ async function runAddWithUI(source, flags, opts = {}) {
|
|
|
1078
1297
|
|
|
1079
1298
|
// src/commands/list.ts
|
|
1080
1299
|
import { Command as Command8 } from "commander";
|
|
1081
|
-
import { existsSync as
|
|
1082
|
-
import { join as
|
|
1300
|
+
import { existsSync as existsSync3, readFileSync } from "fs";
|
|
1301
|
+
import { join as join4 } from "path";
|
|
1083
1302
|
import pc9 from "picocolors";
|
|
1084
1303
|
import { parseSkillMd as parseSkillMd3 } from "@skillmds/core";
|
|
1085
1304
|
function runList(flags = {}) {
|
|
@@ -1087,9 +1306,9 @@ function runList(flags = {}) {
|
|
|
1087
1306
|
let items = [];
|
|
1088
1307
|
for (const global of scopes) {
|
|
1089
1308
|
for (const s of listInstalled({ global, cwd: flags.cwd, home: flags.home })) {
|
|
1090
|
-
const md =
|
|
1309
|
+
const md = join4(s.path, "SKILL.md");
|
|
1091
1310
|
let description = "";
|
|
1092
|
-
if (
|
|
1311
|
+
if (existsSync3(md)) {
|
|
1093
1312
|
const parsed = parseSkillMd3(readFileSync(md, "utf8"));
|
|
1094
1313
|
description = "error" in parsed ? `(invalid SKILL.md \u2014 ${parsed.error})` : parsed.description;
|
|
1095
1314
|
}
|
|
@@ -1120,12 +1339,12 @@ function listCommand() {
|
|
|
1120
1339
|
// src/commands/remove.ts
|
|
1121
1340
|
import { Command as Command9 } from "commander";
|
|
1122
1341
|
import { rmSync } from "fs";
|
|
1123
|
-
import { join as
|
|
1342
|
+
import { join as join5, resolve as resolve4 } from "path";
|
|
1124
1343
|
import * as p4 from "@clack/prompts";
|
|
1125
1344
|
import pc10 from "picocolors";
|
|
1126
1345
|
var defaultDeps = (flags) => isInteractive(flags) ? {
|
|
1127
|
-
confirm: async (
|
|
1128
|
-
const a = await p4.confirm({ message:
|
|
1346
|
+
confirm: async (msg2) => {
|
|
1347
|
+
const a = await p4.confirm({ message: msg2, initialValue: false });
|
|
1129
1348
|
return !p4.isCancel(a) && a;
|
|
1130
1349
|
},
|
|
1131
1350
|
pick: async ({ names }) => {
|
|
@@ -1208,7 +1427,7 @@ async function runRemove(names, flags, deps = defaultDeps(flags)) {
|
|
|
1208
1427
|
acted = true;
|
|
1209
1428
|
continue;
|
|
1210
1429
|
}
|
|
1211
|
-
const pth =
|
|
1430
|
+
const pth = join5(dir, name);
|
|
1212
1431
|
if (isSkillDirOrLink(pth)) {
|
|
1213
1432
|
rmSync(pth, { recursive: true, force: true });
|
|
1214
1433
|
removed.push(pth);
|
|
@@ -1242,9 +1461,9 @@ async function runRemove(names, flags, deps = defaultDeps(flags)) {
|
|
|
1242
1461
|
}
|
|
1243
1462
|
function removeCommand() {
|
|
1244
1463
|
return new Command9("remove").alias("rm").description("Remove installed skills (links, canonical copy and lock entry)").argument("[names...]", "skill names (omit to pick interactively)").option("-g, --global", "only user-level skills").option("-p, --project", "only this project's skills").option("-a, --agent <agents...>", "remove only from these agents").option("--all", "remove every skill in the scope").option("-y, --yes", "skip the confirmation").option("--json", "machine-readable output").action(async (names, opts, cmd) => {
|
|
1245
|
-
const
|
|
1246
|
-
console.log(
|
|
1247
|
-
process.exitCode =
|
|
1464
|
+
const run2 = await runRemove(names, { ...cmd.parent?.opts(), ...opts });
|
|
1465
|
+
console.log(run2.output);
|
|
1466
|
+
process.exitCode = run2.exitCode;
|
|
1248
1467
|
});
|
|
1249
1468
|
}
|
|
1250
1469
|
|
|
@@ -1378,16 +1597,16 @@ function scopeOptions(cmd) {
|
|
|
1378
1597
|
}
|
|
1379
1598
|
function updateCommand() {
|
|
1380
1599
|
return scopeOptions(new Command10("update").description("Update installed skills from the source recorded in the lock file (re-lints before writing)").argument("[names...]", "specific skills (default: all tracked)").option("--check", "only report which skills have updates")).action(async (names, opts, cmd) => {
|
|
1381
|
-
const
|
|
1382
|
-
console.log(
|
|
1383
|
-
process.exitCode =
|
|
1600
|
+
const run2 = await runUpdate(names, { ...cmd.parent?.opts(), ...opts });
|
|
1601
|
+
console.log(run2.output);
|
|
1602
|
+
process.exitCode = run2.exitCode;
|
|
1384
1603
|
});
|
|
1385
1604
|
}
|
|
1386
1605
|
function checkCommand() {
|
|
1387
1606
|
return scopeOptions(new Command10("check").description("Report installed skills that have updates (alias of `update --check`)").argument("[names...]", "specific skills (default: all tracked)")).action(async (names, opts, cmd) => {
|
|
1388
|
-
const
|
|
1389
|
-
console.log(
|
|
1390
|
-
process.exitCode =
|
|
1607
|
+
const run2 = await runUpdate(names, { ...cmd.parent?.opts(), ...opts, check: true });
|
|
1608
|
+
console.log(run2.output);
|
|
1609
|
+
process.exitCode = run2.exitCode;
|
|
1391
1610
|
});
|
|
1392
1611
|
}
|
|
1393
1612
|
|
|
@@ -1435,9 +1654,9 @@ ${pc12.green(`\u2713 Published ${res.slug ?? src.slug} (status: ${res.status ??
|
|
|
1435
1654
|
function publishCommand() {
|
|
1436
1655
|
return new Command11("publish").alias("submit").description("Publish a skill to the registry (refuses to publish on lint errors)").argument("[target]", "local path to the skill", ".").option("--type <type>", "single | pack", "single").option("--force", "publish despite warnings (never bypasses errors)").option("--dry-run", "lint only; do not publish").action(async (target, opts, cmd) => {
|
|
1437
1656
|
const merged = { ...cmd.parent?.opts(), ...opts };
|
|
1438
|
-
const
|
|
1439
|
-
console.log(
|
|
1440
|
-
process.exitCode =
|
|
1657
|
+
const run2 = await runPublish(target, merged);
|
|
1658
|
+
console.log(run2.output);
|
|
1659
|
+
process.exitCode = run2.exitCode;
|
|
1441
1660
|
});
|
|
1442
1661
|
}
|
|
1443
1662
|
|
|
@@ -1473,8 +1692,8 @@ async function runLogin(flags, deps = defaultLoginDeps(flags)) {
|
|
|
1473
1692
|
try {
|
|
1474
1693
|
host = hostOf(resolveApi({ api: flags.api, insecureHttp: flags.insecureHttp }, { env, config: { ...cfg, api: flags.api ?? cfg.api } }));
|
|
1475
1694
|
} catch (e) {
|
|
1476
|
-
const
|
|
1477
|
-
return { exitCode: 1, output: flags.json ? JSON.stringify({ ok: false, error:
|
|
1695
|
+
const msg2 = e instanceof Error ? e.message : String(e);
|
|
1696
|
+
return { exitCode: 1, output: flags.json ? JSON.stringify({ ok: false, error: msg2 }, null, 2) : pc13.red(msg2) };
|
|
1478
1697
|
}
|
|
1479
1698
|
cfg.token = token;
|
|
1480
1699
|
if (flags.api) cfg.api = flags.api;
|
|
@@ -1576,9 +1795,9 @@ async function browseOneResult(item) {
|
|
|
1576
1795
|
}
|
|
1577
1796
|
p6.log.step(`Installing ${slugTxt}\u2026`);
|
|
1578
1797
|
try {
|
|
1579
|
-
const
|
|
1580
|
-
console.log(
|
|
1581
|
-
if (
|
|
1798
|
+
const run2 = await runAdd(item.slug, action === "global" ? { global: true } : { project: true });
|
|
1799
|
+
console.log(run2.output);
|
|
1800
|
+
if (run2.exitCode === 0) p6.log.success("Installed.");
|
|
1582
1801
|
else p6.log.warn("Not installed.");
|
|
1583
1802
|
} catch (err) {
|
|
1584
1803
|
p6.log.error(err instanceof Error ? err.message : String(err));
|
|
@@ -1613,10 +1832,10 @@ async function runInteractive() {
|
|
|
1613
1832
|
const s = p6.spinner();
|
|
1614
1833
|
s.start(action === "lint" ? "Linting" : "Scanning");
|
|
1615
1834
|
try {
|
|
1616
|
-
const
|
|
1835
|
+
const run2 = action === "lint" ? await runLint(target, { format: "text" }) : await runScan(target, { format: "text" });
|
|
1617
1836
|
s.stop("Done");
|
|
1618
|
-
console.log(
|
|
1619
|
-
process.exitCode =
|
|
1837
|
+
console.log(run2.output);
|
|
1838
|
+
process.exitCode = run2.exitCode;
|
|
1620
1839
|
} catch (err) {
|
|
1621
1840
|
s.stop(pc14.red(err instanceof Error ? err.message : String(err)));
|
|
1622
1841
|
process.exitCode = 1;
|
|
@@ -1631,13 +1850,13 @@ async function runInteractive() {
|
|
|
1631
1850
|
const s = p6.spinner();
|
|
1632
1851
|
s.start("Searching");
|
|
1633
1852
|
try {
|
|
1634
|
-
const
|
|
1635
|
-
s.stop(`${
|
|
1636
|
-
if (
|
|
1853
|
+
const run2 = await runSearch(String(query), { verified: Boolean(verified), limit: "20" });
|
|
1854
|
+
s.stop(`${run2.items.length} result${run2.items.length === 1 ? "" : "s"}`);
|
|
1855
|
+
if (run2.items.length === 0) {
|
|
1637
1856
|
p6.log.info("No results.");
|
|
1638
1857
|
break;
|
|
1639
1858
|
}
|
|
1640
|
-
await browseSearchResults(
|
|
1859
|
+
await browseSearchResults(run2.items);
|
|
1641
1860
|
} catch (err) {
|
|
1642
1861
|
s.stop(pc14.red(err instanceof Error ? err.message : String(err)));
|
|
1643
1862
|
process.exitCode = 1;
|
|
@@ -1662,9 +1881,9 @@ async function runInteractive() {
|
|
|
1662
1881
|
const src = await p6.text({ message: "Skill source", placeholder: "owner/name, https://github.com/\u2026, or ./path" });
|
|
1663
1882
|
if (bail(src)) break;
|
|
1664
1883
|
try {
|
|
1665
|
-
const
|
|
1666
|
-
console.log(
|
|
1667
|
-
process.exitCode =
|
|
1884
|
+
const run2 = await runAdd(String(src), {});
|
|
1885
|
+
console.log(run2.output);
|
|
1886
|
+
process.exitCode = run2.exitCode;
|
|
1668
1887
|
} catch (err) {
|
|
1669
1888
|
p6.log.error(err instanceof Error ? err.message : String(err));
|
|
1670
1889
|
process.exitCode = 1;
|
|
@@ -1677,9 +1896,9 @@ async function runInteractive() {
|
|
|
1677
1896
|
}
|
|
1678
1897
|
case "update": {
|
|
1679
1898
|
try {
|
|
1680
|
-
const
|
|
1681
|
-
console.log(
|
|
1682
|
-
process.exitCode =
|
|
1899
|
+
const run2 = await runUpdate([], {});
|
|
1900
|
+
console.log(run2.output);
|
|
1901
|
+
process.exitCode = run2.exitCode;
|
|
1683
1902
|
} catch (err) {
|
|
1684
1903
|
p6.log.error(err instanceof Error ? err.message : String(err));
|
|
1685
1904
|
process.exitCode = 1;
|
|
@@ -1688,9 +1907,9 @@ async function runInteractive() {
|
|
|
1688
1907
|
}
|
|
1689
1908
|
case "remove": {
|
|
1690
1909
|
try {
|
|
1691
|
-
const
|
|
1692
|
-
console.log(
|
|
1693
|
-
process.exitCode =
|
|
1910
|
+
const run2 = await runRemove([], {});
|
|
1911
|
+
console.log(run2.output);
|
|
1912
|
+
process.exitCode = run2.exitCode;
|
|
1694
1913
|
} catch (err) {
|
|
1695
1914
|
p6.log.error(err instanceof Error ? err.message : String(err));
|
|
1696
1915
|
process.exitCode = 1;
|
package/dist/mcp.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillmds",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "SkillMD for agents: the `skillmds` MCP server + the `skillmd` CLI (lint, scan, search, install, publish Agent Skills) from skillmd.com.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "SkillMD",
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"@modelcontextprotocol/sdk": "^1.13.0",
|
|
60
60
|
"@skillmds/core": "^1.0.0",
|
|
61
61
|
"commander": "^12.1.0",
|
|
62
|
+
"fflate": "^0.8.3",
|
|
62
63
|
"giget": "^3.3.0",
|
|
63
64
|
"picocolors": "^1.1.0"
|
|
64
65
|
},
|