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

jev-browser

v0.1.1

Published

Browser automation where an LLM plans and Jev (Typesafe System One) makes every per-step decision. Library, CLI and MCP server.

Readme

jev-browser

Browser automation where an LLM plans and Jev decides.

Unofficial project, not affiliated with TypeSafe. It calls the TypeSafe System One API with your own API key.

The calling LLM (Claude, via MCP) says what outcome it wants, one step at a time, and hands over any text to type. For each round of a step, code describes the page. Then one ~300 ms Typesafe System One request asks Jev several questions at once: which element, which action, which value, and is the step done / blocked / showing an error / about to do something irreversible. Playwright performs the action. The LLM never reads page snapshots unless it chooses to take over.

Claude ── browser_do("Log in", {email, password}) ──▶ jev-browser
                                                       │  loop until done / stuck / needs confirmation
                                                       │   1. settle   (network + DOM quiet)
                                                       │   2. describe (elements, labels, state, visible text, diff, counts)
                                                       │   3. Jev      (done? error? irreversible? tool? target? value?)
                                                       │   4. act      (Playwright)
Claude ◀── { status: "done", url, actions[], done_score } ─┘

Jev only answers with probability distributions: yes/no (noul), pick one option (choice) or a rating (score). It never writes text. So everything free-form comes from the caller as candidates, and code turns disagreement or low confidence into a status the LLM can act on.

Results

42 tasks in 16 categories on live sites (see RESULTS.md):

  • 40/42 correct in the latest run, 0 false "done" claims (38/41 twice before the latest fixes). Remaining misses: counting ("add until 3", flagged likely_done) and verifying a sort.
  • ~300 ms per Jev call, 2–4 calls for most steps; a 5-step checkout takes ~14 s end to end.
  • Pause before irreversible actions: across ~200 rounds it flagged only saucedemo's "Finish" (place order) button.
  • Less page content for the LLM than a Playwright-MCP-style loop on the same tasks (estimate): median 5× per task, ≈8k vs ≈557k tokens in total. Big pages dominate the total: a Wikipedia article is ~149k snapshot tokens. On tiny pages there is no saving. The page reading moves to Jev.

Works on: forms, native and custom dropdowns, checkboxes and radios (including styled replacements), dynamic loading, modals, JS dialogs, hover, right-click, drag and drop, key presses, file upload, iframes, shadow DOM, new tabs, pages with 2,000+ elements (two-stage selection), and non-English UIs.

Known limits, so write steps around them:

  • Ordered sub-goals in one step ("add two todos, complete one, clear completed") → split into one outcome per step.
  • Open-ended goals ("scroll to load more") → make them measurable or check yourself.
  • Judgements that compare many values (is this table sorted, did exactly one thing change) → verify with browser_check or browser_snapshot.

Quick start (MCP, from npm)

npx playwright install chromium          # once
claude mcp add jev-browser -e TYPESAFE_API_KEY=your-key -- npx -y -p jev-browser jev-browser-mcp

Any MCP client works the same way: command npx, args -y -p jev-browser jev-browser-mcp, env TYPESAFE_API_KEY. Add JEV_BROWSER_HEADED=1 to watch it work.

Setup (from source)

git clone https://github.com/Ying-Kai-Liao/jev-browser && cd jev-browser
npm install
npm run setup                    # downloads Chromium for Playwright
cp .env.example .env             # add TYPESAFE_API_KEY
npm test                         # offline tests (no network, no key)
npm run test:e2e                 # MCP server end to end (network + key)

Use from Claude Code (MCP, from source)

claude mcp add jev-browser -- node /absolute/path/to/jev-browser/bin/jev-browser-mcp.mjs

From a source checkout the server reads TYPESAFE_API_KEY from the repo's .env.

| tool | purpose | |---|---| | browser_open(url) | navigate and wait for the page to settle | | browser_do(goal, values?, max_actions?, allow_irreversible?, explain?) | work toward one outcome; returns a status | | browser_check(question) | yes/no about the page → p_yes | | browser_choose(question, options) | pick among given options → distribution | | browser_snapshot() | compact numbered element list, for taking over | | browser_act(action, element, value?, key?, destination?, accept_dialog?) | act on an element directly, no model; confirm/prompt dialogs are dismissed unless accept_dialog | | browser_screenshot(full_page?) | PNG image | | browser_close() | end the session |

browser_do statuses:

| status | meaning / what the caller should do | |---|---| | done | goal reached | | likely_done | the page looks done but Jev is unsure: verify before moving on | | needs_login | a sign-in wall and no credentials in values; log in yourself (headed + JEV_BROWSER_PROFILE) or pass credentials | | needs_confirmation | next action, or a confirm dialog it opened (then dismissed), looks irreversible (order, pay, send, delete); see pending, re-call with allow_irreversible: true only if the user wants it | | error | the page shows an error after the last action (e.g. wrong password); see page_text | | stuck / max_actions | no progress; see info, page_text, candidates | | ambiguous | low confidence in the target; pick from candidates with browser_act | | blocked | captcha, access denied, error page |

Env: JEV_BROWSER_HEADED=1 shows the browser, JEV_BROWSER_PROFILE=/dir keeps a persistent profile (logins survive restarts), JEV_BROWSER_LOG=1 prints per-round decisions to stderr.

Library

// npm install jev-browser && npx playwright install chromium
import { JevBrowser } from "jev-browser";

const b = await JevBrowser.launch({ headed: true });
await b.open("https://www.saucedemo.com/");
await b.do("Log in", { values: { username: "standard_user", password: "secret_sauce" } });
await b.do("Add the Sauce Labs Backpack to the cart");
const p = await b.check("Does the cart badge show 1 item?");   // 0..1
await b.close();

Watch it

node examples/x-profile-demo.mjs     # headed, read-only x.com walkthrough with decision highlights

Each action is outlined in red with Jev's choice and scores before it happens (highlight: true, on by default in the MCP server when JEV_BROWSER_HEADED=1). Some sites, x.com included, serve a blank page to headless Chromium: use headed mode there.

CLI

node bin/jev-browser.mjs do https://the-internet.herokuapp.com/login "Log in" username=tomsmith 'password=SuperSecretPassword!'
node bin/jev-browser.mjs run examples/flows/todomvc.json --headed

Writing good steps

  • One observable outcome per step: "Log in", "Open the Pull requests tab", "Mark 'buy milk' completed".
  • Every string goes in values with a meaningful key (email, postal_code, file).
  • Treat likely_done, needs_confirmation, ambiguous and stuck as your turn: check, snapshot or ask the user, don't just retry.
  • After steps with side effects, browser_check what must not have changed.

Benchmark

node bench/run.mjs --set all            # base, hard, guard (+ bench/tasks.local.mjs if present)
node bench/run.mjs --only ti-login,drag
node bench/context-cost.mjs bench/results/<run>.json

Private sites and credentials go in bench/tasks.local.mjs (git-ignored), exporting LOCAL.

Layout

src/session.mjs      JevBrowser: settle, snapshot, decide (1 or 2 stages), resolve, act, do, check, choose
src/page-script.mjs  runs in each frame: elements, labels, state, visible text, metrics, dialogs
src/page-model.mjs   pure helpers: diff between pages, counts, compact rendering
src/jev.mjs          System One API client
src/flow.mjs         JSON flow runner
bin/                 CLI and MCP server
bench/               tasks with ground-truth checks, runner, context-cost estimate
test/                offline fixture tests, MCP end-to-end test
NOTES.md             design notes: what works with Jev, what doesn't, and why

Releasing

CI runs the offline tests on every push and pull request. To publish, bump the version and push the tag; .github/workflows/release.yml tests, publishes to npm with provenance and creates a GitHub release:

npm version patch            # or minor / major: commits and tags vX.Y.Z
git push --follow-tags

Publishing uses npm trusted publishing, set up once with npx npm@latest trust github jev-browser --file release.yml --repo Ying-Kai-Liao/jev-browser --allow-publish.

License

MIT