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-poker/agent

v0.2.1

Published

Poker CPU players that think with TypeSafe Jev, plus baseline bots and a play loop, on top of @jev-poker/engine.

Readme

@jev-poker/agent

Poker CPU players that think with TypeSafe Jev: the situation is compressed into typed features and Jev answers three typed questions — what to do, how much, and whether it means it — which are turned into a legal action. Also included: four baseline bots (random, caller, rules, heuristic), five personas, and playHand to run a table. ESM only, Node 20+ and browsers.

pnpm add @jev-poker/agent @jev-poker/engine

Ask the CPU what to do

import { JevAgent, createTypeSafeBackend, PRESET_PERSONAS } from "@jev-poker/agent";
import type { PlayerView, LegalActions } from "@jev-poker/engine";

const backend = createTypeSafeBackend({ apiKey: process.env.TYPESAFE_API_KEY! });
const tag = PRESET_PERSONAS.find((p) => p.id === "tag")!;
const cpu = new JevAgent({ persona: tag, backend, seed: 42 });

const action = await cpu.decide(view, legal); // view: PlayerView, legal: LegalActions

view is a PlayerView from @jev-poker/engine — build it with playerView(...) if you use the engine, or fill one in from your own game state. If Jev cannot be reached the agent fails open (check or fold) and reports why through onDecision.

Run a whole table

import { Table, fixedBlinds } from "@jev-poker/engine";
import { JevAgent, RulesAgent, createTypeSafeBackend, PRESET_PERSONAS, playHand } from "@jev-poker/agent";

const table = new Table({
  format: "cash", blinds: fixedBlinds(1, 2), startingStack: 200, seed: 1,
  seats: [{ id: 0, name: "Jev", kind: "cpu" }, { id: 1, name: "Rules", kind: "cpu" }],
});
const backend = createTypeSafeBackend({ apiKey: process.env.TYPESAFE_API_KEY! });
const tag = PRESET_PERSONAS.find((p) => p.id === "tag")!;
const agents = [new JevAgent({ persona: tag, backend, seed: 1 }), new RulesAgent()];
for (let i = 0; i < 5; i++) await playHand(table, agents);

Backends

createTypeSafeBackend({ apiKey, baseURL?, model?, headers?, timeoutMs?, fetch?, browser? }) talks to api.typesafe.ai by default. Point baseURL at a gateway that speaks the TypeSafe API (Vercel AI Gateway: https://ai-gateway.vercel.sh/typesafe, model typesafe-ai/jev; Lolipop: https://ai-gateway.lolipop.jp, model typesafe/jev-latest) or at your own proxy. In a browser set browser: true; the key then belongs to the person at the keyboard. createMockBackend() answers from hand strength alone, for tests.

Personas

PRESET_PERSONAS (rock, tag, lag, maniac, station). A persona is a paragraph of text and a variance; duplicatePersona makes an editable copy, loadPersonas(storage) / saveCustomPersonas(personas, storage) persist custom ones through any { getItem, setItem } you pass — the library never reads localStorage on its own.

Part of jev-poker — see it play at jev-poker.syou.io. MIT.