skillmds 1.0.8 → 1.0.9
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/dist/cli.js +52 -29
- 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.9
|
|
6
|
+
|
|
7
|
+
- Compact lint output: one line per skill (status dot, score, name, rule-id chips) with a single summary line, instead of a tall multi-row block per skill. Linting a single skill still shows full diagnostic messages.
|
|
8
|
+
|
|
5
9
|
## 1.0.8
|
|
6
10
|
|
|
7
11
|
- `skillmds` with no command in a terminal now opens the interactive CLI menu; it only starts the MCP server when launched over piped stdio (how MCP clients run it). Previously a bare `npx skillmds` in a terminal appeared to hang on the silent MCP server.
|
package/dist/cli.js
CHANGED
|
@@ -370,40 +370,63 @@ var decorate = (text3, kind) => {
|
|
|
370
370
|
return pc.dim(text3);
|
|
371
371
|
}
|
|
372
372
|
};
|
|
373
|
-
var
|
|
374
|
-
error: pc.
|
|
375
|
-
warn: pc.
|
|
376
|
-
info: pc.
|
|
373
|
+
var GLYPH = {
|
|
374
|
+
error: pc.red("\u2716"),
|
|
375
|
+
warn: pc.yellow("\u26A0"),
|
|
376
|
+
info: pc.cyan("\xB7")
|
|
377
377
|
};
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
const
|
|
381
|
-
const
|
|
382
|
-
return
|
|
378
|
+
var scoreColor = (s) => s >= 80 ? pc.green : s >= 50 ? pc.yellow : pc.red;
|
|
379
|
+
function label(file) {
|
|
380
|
+
const parts = file.split(/[\\/]/).filter(Boolean);
|
|
381
|
+
const i = parts.lastIndexOf("SKILL.md");
|
|
382
|
+
return i > 0 ? parts[i - 1] : parts[parts.length - 1] || file;
|
|
383
383
|
}
|
|
384
|
-
function
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
const
|
|
396
|
-
|
|
384
|
+
function statusDot(result) {
|
|
385
|
+
if (!result.ok) return pc.red("\u25CF");
|
|
386
|
+
return result.diagnostics.some((d) => d.severity === "warn") ? pc.yellow("\u25CF") : pc.green("\u25CF");
|
|
387
|
+
}
|
|
388
|
+
function securityFlags(result) {
|
|
389
|
+
return result.security.flags.filter((f) => f !== "docs_only");
|
|
390
|
+
}
|
|
391
|
+
function renderOne(file, result) {
|
|
392
|
+
const status = result.ok ? pc.green("\u25CF PASS") : pc.red("\u25CF FAIL");
|
|
393
|
+
const out = [`${status} ${pc.bold(label(file))} ${scoreColor(result.score)(`${result.score}/100`)}`];
|
|
394
|
+
for (const d of result.diagnostics) {
|
|
395
|
+
const loc = d.line !== void 0 ? pc.dim(`:${d.line}`) : "";
|
|
396
|
+
out.push(` ${GLYPH[d.severity]} ${pc.dim(d.id)}${loc} ${d.message}`);
|
|
397
397
|
}
|
|
398
|
+
const flags = securityFlags(result);
|
|
399
|
+
if (flags.length) out.push(` ${pc.magenta(`\u2691 ${flags.join(", ")}`)}`);
|
|
400
|
+
return out.join("\n");
|
|
401
|
+
}
|
|
402
|
+
function renderMany(results) {
|
|
403
|
+
const names = results.map((r) => label(r.file));
|
|
404
|
+
const w = Math.min(34, Math.max(4, ...names.map((n) => n.length)));
|
|
405
|
+
const out = [];
|
|
406
|
+
results.forEach(({ result }, i) => {
|
|
407
|
+
const score = scoreColor(result.score)(String(result.score).padStart(3));
|
|
408
|
+
const name = names[i].length > w ? names[i].slice(0, w - 1) + "\u2026" : names[i].padEnd(w);
|
|
409
|
+
const issues = result.diagnostics.map((d) => `${GLYPH[d.severity]}${pc.dim(d.id)}`).join(" ");
|
|
410
|
+
const flags = securityFlags(result);
|
|
411
|
+
const sec = flags.length ? ` ${pc.magenta(`\u2691 ${flags.join(",")}`)}` : "";
|
|
412
|
+
out.push(`${statusDot(result)} ${score} ${name} ${issues}${sec}`.trimEnd());
|
|
413
|
+
});
|
|
398
414
|
const failed = results.filter((r) => !r.result.ok).length;
|
|
399
|
-
const
|
|
400
|
-
const
|
|
415
|
+
const warned = results.filter((r) => r.result.ok && r.result.diagnostics.some((d) => d.severity === "warn")).length;
|
|
416
|
+
const clean = results.length - failed - warned;
|
|
417
|
+
const avg = Math.round(results.reduce((s, r) => s + r.result.score, 0) / results.length);
|
|
401
418
|
out.push("");
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
419
|
+
const parts = [pc.green(`${clean} clean`)];
|
|
420
|
+
if (warned) parts.push(pc.yellow(`${warned} warn`));
|
|
421
|
+
if (failed) parts.push(pc.red(`${failed} fail`));
|
|
422
|
+
out.push(`${parts.join(pc.dim(" \xB7 "))} ${pc.dim("avg")} ${scoreColor(avg)(`${avg}/100`)}`);
|
|
405
423
|
return out.join("\n");
|
|
406
424
|
}
|
|
425
|
+
function renderReport(results) {
|
|
426
|
+
if (results.length === 0) return pc.dim("No skills found.");
|
|
427
|
+
if (results.length === 1) return renderOne(results[0].file, results[0].result);
|
|
428
|
+
return renderMany(results);
|
|
429
|
+
}
|
|
407
430
|
function exitCodeFor(results, policy = {}) {
|
|
408
431
|
for (const { result } of results) {
|
|
409
432
|
const hasError = result.diagnostics.some((d) => d.severity === "error");
|
|
@@ -540,9 +563,9 @@ function rulesCommand() {
|
|
|
540
563
|
console.log(JSON.stringify(list.map((r) => ({ id: r.id, severity: r.severity, description: r.description })), null, 2));
|
|
541
564
|
return;
|
|
542
565
|
}
|
|
543
|
-
const
|
|
566
|
+
const badge = (sev) => sev === "error" ? pc4.bgRed(pc4.white(" error ")) : sev === "warn" ? pc4.bgYellow(pc4.black(" warn ")) : pc4.bgCyan(pc4.black(" info "));
|
|
544
567
|
console.log(pc4.bold("\nLint rules\n"));
|
|
545
|
-
for (const r of list) console.log(` ${pc4.bold(r.id)} ${
|
|
568
|
+
for (const r of list) console.log(` ${pc4.bold(r.id)} ${badge(r.severity)} ${r.description}`);
|
|
546
569
|
console.log("");
|
|
547
570
|
});
|
|
548
571
|
}
|
package/package.json
CHANGED