vet-skills 0.4.0 → 0.5.0

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.
Files changed (2) hide show
  1. package/dist/index.js +36 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7629,7 +7629,7 @@ import { mkdirSync, readFileSync, writeFileSync, existsSync, appendFileSync, chm
7629
7629
  import { homedir } from "node:os";
7630
7630
  import { join } from "node:path";
7631
7631
  import { randomUUID } from "node:crypto";
7632
- var VERSION = "0.4.0";
7632
+ var VERSION = "0.5.0";
7633
7633
  var HOME = process.env.VET_SKILLS_HOME ?? join(homedir(), ".vet-skills");
7634
7634
  var API = (process.env.KILLERSKILLS_API ?? "https://killerskills.ai").replace(/\/$/, "");
7635
7635
  var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
@@ -7859,7 +7859,7 @@ async function check(q, opts = {}) {
7859
7859
  let source = "api";
7860
7860
  let offline = false;
7861
7861
  let cacheAge;
7862
- let res = await resolveSkill(q);
7862
+ let res = await resolveSkill(q, opts.registry);
7863
7863
  if (!res.ok && !res.offline && org) {
7864
7864
  const bare = q.replace(/^[^/]+\//, "");
7865
7865
  const priv = await resolveSkill(`${org.slug}/${bare}`, "private");
@@ -8071,10 +8071,41 @@ function extractRemoteMcp(command) {
8071
8071
  const name = positional.find((a) => a !== url) ?? new URL(url).hostname;
8072
8072
  return { name, url };
8073
8073
  }
8074
+ function extractStdioPackage(command) {
8075
+ const tail = command.split(/\s--\s/)[1];
8076
+ if (!tail) return null;
8077
+ const args = (tail.match(/"[^"]*"|'[^']*'|\S+/g) ?? []).map((a) => a.replace(/^(['"])(.*)\1$/, "$2"));
8078
+ const [bin, ...rest2] = args;
8079
+ const strip = (s) => s.replace(/(.)@[^@/]+$/, "$1");
8080
+ if (/^(npx|bunx|pnpm)$/.test(bin ?? "")) {
8081
+ const pkg = rest2.find((a) => !a.startsWith("-") && a !== "dlx" && a !== "exec");
8082
+ return pkg ? { q: strip(pkg).replace(/^@/, ""), registry: "npm" } : null;
8083
+ }
8084
+ if (/^(uvx|pipx)$/.test(bin ?? "")) {
8085
+ const pkg = rest2.find((a) => !a.startsWith("-") && a !== "run");
8086
+ return pkg ? { q: strip(pkg).toLowerCase().replace(/\[.*\]$/, ""), registry: "pypi" } : null;
8087
+ }
8088
+ if (bin === "docker") {
8089
+ const img = rest2.find((a) => /^(ghcr\.io\/|docker\.io\/)?[\w.-]+\/[\w.-]+(:[\w.-]+)?$/.test(a) && !a.startsWith("-"));
8090
+ if (!img) return null;
8091
+ const m = img.replace(/:[\w.-]+$/, "").match(/mcp\/([\w.-]+)$/);
8092
+ return m ? { q: m[1], registry: "docker" } : null;
8093
+ }
8094
+ return null;
8095
+ }
8074
8096
  function extractInstall(command) {
8075
8097
  for (const p of INSTALL_PATTERNS) {
8076
8098
  const m = command.match(p.re);
8077
- if (m) return { q: m[1].replace(/^['"]|['"]$/g, ""), kind: p.kind };
8099
+ if (!m) continue;
8100
+ const q = m[1].replace(/^['"]|['"]$/g, "");
8101
+ if (p.kind === "mcp") {
8102
+ const pkg = extractStdioPackage(command);
8103
+ if (pkg) return { q: pkg.q, kind: "mcp", registry: pkg.registry };
8104
+ const remote = extractRemoteMcp(command);
8105
+ if (remote) return { q: remote.name, kind: "mcp" };
8106
+ }
8107
+ if (p.kind === "plugin") return { q: q.split("@")[0], kind: "plugin", registry: "plugins" };
8108
+ return { q, kind: p.kind };
8078
8109
  }
8079
8110
  return null;
8080
8111
  }
@@ -8090,7 +8121,7 @@ async function hookEval(stdin) {
8090
8121
  if (/^\s*vet-skills\s+(check|why|status|sync|policy|detonate|hook|join|leave|block|publish)\b/.test(cmd2)) return 0;
8091
8122
  const found = extractInstall(cmd2);
8092
8123
  if (!found) return 0;
8093
- const r = await check(found.q, { quiet: true, agentKind: "claude_code" });
8124
+ const r = await check(found.q, { quiet: true, agentKind: "claude_code", registry: found.registry });
8094
8125
  const out = renderOutcome(r);
8095
8126
  const remote = found.kind === "mcp" ? extractRemoteMcp(cmd2) : null;
8096
8127
  const watch = async () => {
@@ -8214,7 +8245,7 @@ async function main() {
8214
8245
  usage();
8215
8246
  return 1;
8216
8247
  }
8217
- const r = await check(rest[0], { agentKind: values.agent });
8248
+ const r = await check(rest[0], { agentKind: values.agent, registry: values.registry });
8218
8249
  if (values.json) {
8219
8250
  console.log(JSON.stringify({ decision: r.decision, resolved: r.resolved, source: r.source, offline: r.offline }, null, 2));
8220
8251
  return r.decision.decision === "block" ? 2 : 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vet-skills",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Vet agent skills and MCP servers before they run. Verdicts from KillerSkills, policy from your org.",
5
5
  "type": "module",
6
6
  "bin": {