skillmds 1.0.10 → 1.0.12
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/bin/skillmd-mcp.mjs +2 -2
- package/dist/cli.js +15 -13
- 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.0.11
|
|
6
|
+
|
|
7
|
+
- Security flags render with full readable labels, each with its own marker: `⚑ Executes Scripts ⚑ Calls Network ⚑ Reads Secrets`.
|
|
8
|
+
|
|
5
9
|
## 1.0.10
|
|
6
10
|
|
|
7
11
|
- Quality score is now a composite of spec correctness, completeness, and **security risk** — skills that read secrets, execute scripts, or make network calls score lower (a risky/stub skill is no longer a green 100).
|
package/bin/skillmd-mcp.mjs
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// claude mcp add skillmd -- npx -y skillmds
|
|
6
6
|
//
|
|
7
7
|
// Env:
|
|
8
|
-
// SKILLMD_API override API base (default https://
|
|
8
|
+
// SKILLMD_API override API base (default https://api.skillmd.com)
|
|
9
9
|
// SKILLMD_TOKEN personal access token (enables skillmd_list_saved / personalized recommend)
|
|
10
10
|
|
|
11
11
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -32,7 +32,7 @@ try {
|
|
|
32
32
|
/* skillmd_lint will report that validation is unavailable */
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
const API = process.env.SKILLMD_API || "https://
|
|
35
|
+
const API = process.env.SKILLMD_API || "https://api.skillmd.com";
|
|
36
36
|
const TOKEN = process.env.SKILLMD_TOKEN || "";
|
|
37
37
|
|
|
38
38
|
async function api(path, init = {}) {
|
package/dist/cli.js
CHANGED
|
@@ -397,11 +397,12 @@ function chips(result) {
|
|
|
397
397
|
for (const d of result.diagnostics) bySev[d.severity].push(d.id);
|
|
398
398
|
return SEV_ORDER.filter((s) => bySev[s].length).map((s) => `${GLYPH[s]} ${SEV_COLOR[s](bySev[s].join(" "))}`).join(" ");
|
|
399
399
|
}
|
|
400
|
-
var
|
|
401
|
-
network_calls: "
|
|
402
|
-
executes_scripts: "
|
|
403
|
-
reads_secrets: "
|
|
400
|
+
var SEC_LABEL = {
|
|
401
|
+
network_calls: "Calls Network",
|
|
402
|
+
executes_scripts: "Executes Scripts",
|
|
403
|
+
reads_secrets: "Reads Secrets"
|
|
404
404
|
};
|
|
405
|
+
var titleCase = (flag) => flag.split("_").map((w) => w[0].toUpperCase() + w.slice(1)).join(" ");
|
|
405
406
|
var scoreColor = (s) => s >= 80 ? pc.green : s >= 50 ? pc.yellow : pc.red;
|
|
406
407
|
function label(file) {
|
|
407
408
|
const parts = file.split(/[\\/]/).filter(Boolean);
|
|
@@ -411,8 +412,9 @@ function label(file) {
|
|
|
411
412
|
function securityFlags(result) {
|
|
412
413
|
return result.security.flags.filter((f) => f !== "docs_only");
|
|
413
414
|
}
|
|
414
|
-
function
|
|
415
|
-
|
|
415
|
+
function secLabels(result) {
|
|
416
|
+
const flags = securityFlags(result);
|
|
417
|
+
return flags.map((f) => pc.magenta(`${SEC_GLYPH} ${SEC_LABEL[f] ?? titleCase(f)}`)).join(" ");
|
|
416
418
|
}
|
|
417
419
|
function statusDot(result) {
|
|
418
420
|
if (!result.ok) return pc.red("\u25CF");
|
|
@@ -435,8 +437,8 @@ function renderOne(file, result) {
|
|
|
435
437
|
const loc = d.line !== void 0 ? pc.dim(`:${d.line}`) : "";
|
|
436
438
|
out.push(` ${GLYPH[d.severity]} ${SEV_COLOR[d.severity](d.id)}${loc} ${d.message}`);
|
|
437
439
|
}
|
|
438
|
-
const
|
|
439
|
-
if (
|
|
440
|
+
const sec = secLabels(result);
|
|
441
|
+
if (sec) out.push(` ${sec}`);
|
|
440
442
|
return out.join("\n");
|
|
441
443
|
}
|
|
442
444
|
function renderMany(results) {
|
|
@@ -448,9 +450,9 @@ function renderMany(results) {
|
|
|
448
450
|
const score = scoreColor(result.score)(String(result.score).padStart(3));
|
|
449
451
|
const nm = names[i];
|
|
450
452
|
const name = (nm.length > w ? nm.slice(0, w - 1) + "\u2026" : nm).padEnd(w);
|
|
451
|
-
const
|
|
452
|
-
if (
|
|
453
|
-
const sec =
|
|
453
|
+
const secStr = secLabels(result);
|
|
454
|
+
if (secStr) anySec = true;
|
|
455
|
+
const sec = secStr ? ` ${secStr}` : "";
|
|
454
456
|
out.push(`${statusDot(result)} ${score} ${name} ${chips(result)}${sec}`.trimEnd());
|
|
455
457
|
});
|
|
456
458
|
const failed = results.filter((r) => !r.result.ok).length;
|
|
@@ -462,7 +464,7 @@ function renderMany(results) {
|
|
|
462
464
|
if (warned) parts.push(pc.yellow(`${warned} warn`));
|
|
463
465
|
if (failed) parts.push(pc.red(`${failed} fail`));
|
|
464
466
|
out.push(`${parts.join(pc.dim(" \xB7 "))} ${pc.dim("avg score")} ${scoreColor(avg)(`${avg}/100`)}`);
|
|
465
|
-
if (anySec) out.push(pc.dim(
|
|
467
|
+
if (anySec) out.push(pc.dim(`${SEC_GLYPH} = risky behaviour, factored into the score alongside spec correctness and completeness`));
|
|
466
468
|
const fails = results.filter((r) => !r.result.ok);
|
|
467
469
|
if (fails.length) {
|
|
468
470
|
out.push("");
|
|
@@ -699,7 +701,7 @@ import pc5 from "picocolors";
|
|
|
699
701
|
import { readFileSync as readFileSync2, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
700
702
|
import { homedir as homedir2 } from "os";
|
|
701
703
|
import { join as join3 } from "path";
|
|
702
|
-
var DEFAULT_API = "https://
|
|
704
|
+
var DEFAULT_API = "https://api.skillmd.com";
|
|
703
705
|
function configPath() {
|
|
704
706
|
return join3(homedir2(), ".skillmd", "config.json");
|
|
705
707
|
}
|
package/package.json
CHANGED