npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@skill-test/vitest

v0.10.0

Published

vitest integration for skilltest: register AI-skill test cases as vitest tests, built on @skill-test/sdk.

Downloads

1,289

Readme

@skill-test/vitest

A vitest plugin for skilltest: run AI-skill tests and natural-language evals from vitest, and mix in your own deterministic checks. Built on @skill-test/sdk — the SDK's API is re-exported here, so a vitest suite needs only this one dependency.

Define the whole case in code (recommended)

Build the case — skill, input, evals, an optional simulated user, mocks — right in the test, and register it in one line with skillTest. Everything the YAML carries has a typed builder:

import { skillTest, testCase, boolean, numeric } from "@skill-test/vitest";

skillTest(
  "greeter names the patient",
  testCase({
    skill: "skills/greeter",            // resolved relative to the working dir
    input: "Greet Dr. Smith, who has an appointment today.",
    evals: [
      boolean("the reply greets Dr. Smith by name"),
      numeric("how warm is the tone", { min: 0, max: 10, threshold: 7 }),
    ],
  }),
);

Multi-turn cases add user(...); call-count checks use called / notCalled taking the stub/spy object itself or a name you gave it. For a matrix or extra deterministic checks, call runSkill from an ordinary test — it takes the same case object:

import { runSkill, testCase, boolean, assistantText } from "@skill-test/vitest";

test("greeter across the matrix", async () => {
  const report = await runSkill(
    testCase({ skill: "skills/greeter", input: "Greet Dr. Smith", evals: [boolean("greets by name")] }),
    { platforms: ["claude-code"], models: ["claude-opus-4-8"] },
  );
  expect(report.passed).toBe(true);
  expect(assistantText(report.runs[0]!.transcript)).toContain("Dr. Smith");
});

Or point at a YAML file

skillTest and runSkill accept a path just as well (skillTest("greeter", "cases/greet.yaml")). The full field reference for both forms is docs/schema.md.

Assert on tool use, and stream

The SDK's tool-event and streaming surfaces are re-exported too. toolCalls returns the normalized tool_call events a run took (each a ToolEvent with kind/name/input/output/index), and streamSkill yields them live so a test can short-circuit on bad behavior:

import { it, expect } from "vitest";
import { runSkill, streamSkill, testCase, toolCalls, boolean } from "@skill-test/vitest";

const editCase = testCase({
  skill: "skills/editor",
  input: "Update the config and commit it.",
  evals: [boolean("the change was committed")],
});

it("commits without deleting", async () => {
  const report = await runSkill(editCase);
  const calls = toolCalls(report.runs[0]!.transcript);
  expect(calls.some((c) => String(c.input?.command).includes("git commit"))).toBe(true);
  expect(calls.some((c) => String(c.input?.command).includes("rm -rf"))).toBe(false);
});

it("makes no network call", async () => {
  for await (const ev of streamSkill(editCase)) {
    expect(ev.event.name).not.toBe("curl"); // break to abort early
  }
});

Auto-discover existing YAML cases

Cases can also live as data: name each *.skilltest.yaml (or .yml) and let one test module collect the whole tree — useful when a suite already has YAML cases, or when non-engineers author them:

// skills.test.ts
import { discover } from "@skill-test/vitest";

discover("cases"); // registers one vitest test per *.skilltest.yaml under cases/
# cases/greet.skilltest.yaml
skill: ./skills/greeter
input: "Greet Dr. Smith."
evals:
  - type: boolean
    criterion: "the reply greets Dr. Smith by name"

This is the closest vitest equivalent to pytest's auto-collection: vitest only collects its own test modules, so the one-line discover() call stands in for a file collector. Adding a case is then just dropping in a YAML file — no code change. Pass run options as the second argument (discover("cases", { platforms: ["claude-code"] })). YAML cases and code-defined ones mix freely in one suite.

Configuration

The plugin shells out to the skilltest binary. Point at one with the SKILLTEST_BIN env var (or the bin option) and the provider with SKILLTEST_PROVIDER (or the provider option). A failing eval is returned in report.passed; bad input and provider failures throw SkilltestUsageError / SkilltestProviderError. See the repository root for the provider protocol and full schema.