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

aicade

v0.7.0

Published

An arcade for agent downtime. Wraps your AI coding CLI and pops up chess puzzles while it works.

Readme

aicade

An arcade for agent downtime.

aicade wraps an AI coding CLI — Claude Code, Codex, aider, anything with a terminal — and watches how long it has been working. When a run passes a few seconds, a small window appears beside your terminal with a chess puzzle in it. When the run finishes, the window pulses once, plays a soft chime, and gets out of the way.

It never takes keyboard focus, and it leaves on its own when the run is over.

npm install -g aicade
aicade setup
aicade claude

aicade claude behaves exactly like claude. Colours, cursor addressing, raw keystrokes, window resizing and the exit code all pass through untouched — if you could tell the difference, it would be broken.


Install

npm install -g aicade      # ~2 MB, no Electron yet
aicade setup               # fetch the window runtime and the puzzle database

npm install deliberately pulls only the CLI. The Electron runtime (~100 MB) is downloaded on first use into ~/.aicade/runtime, straight from the official GitHub release and verified against its published checksum. If you never open the window, you never pay for it. aicade setup just does that eagerly, along with the puzzles, so your first real run is instant.

Requires macOS or Linux and Node 20.11+.

Use

aicade claude
aicade codex --model o3
aicade -- npm run build       # -- when the command name collides with a subcommand

| Command | | |---|---| | aicade stats | wait time captured, puzzles solved, rating | | aicade setup | fetch the runtime and puzzles | | aicade puzzles sync | re-download the puzzle subset | | aicade puzzles status | what is on disk, by rating band | | aicade casino <url> | point the casino pane at a site | | aicade config --set k=v | change one setting, e.g. timing.idle_threshold_ms=5000 | | aicade tune | replay a recorded session against different thresholds | | aicade join <handle> | take a handle on the shared board (opt-in) | | aicade board | the shared board — --all for all time | | aicade leave | forget your handle and stop syncing | | aicade doctor | check everything is wired up | | aicade quit | close the resident window process |

In the window

| | | |---|---| | Cmd/Ctrl+Enter | hide, and raise the terminal you launched from | | Esc | hide, leave the run going | | Cmd/Ctrl+Tab | next pane · Cmd/Ctrl+1…9 jump to one | | type a move | Nf3 or g1f3, then Enter | | Alt+H / Alt+N | hint (counts as a miss) / skip |

How it decides you are waiting

This is the part that has to be right, and the numbers below come from measuring real Claude Code sessions rather than from guessing.

While an agent is actually working it streams densely — median gap between writes is about 100ms, 95th percentile under half a second. Between tool calls it goes quiet for a second or three. When it is done and waiting for you, it goes quiet for as long as you leave it.

So:

  • ACTIVE — a byte arrived within idle_threshold_ms.
  • WORKING — the run has lasted working_threshold_ms (4s). The window opens.
  • IDLE — nothing for idle_threshold_ms (4s). The run is over: pulse, chime, and the window hides itself.

Two things that are easy to get wrong, and were wrong in 0.1.0:

A run's age is wall-clock from its first byte, not the length of the current unbroken stretch of output. Restarting the clock every time the agent paused to think meant the threshold was reached tens of seconds late, or never. You are waiting during the pause too, so the pause counts.

Output that arrives while you are typing is the TUI redrawing around your keystrokes, not the agent working. Left alone it starts phantom runs and pops the window open mid-sentence, so the run clock is held until your typing settles (typing_suppress_ms). When that happens you get a run-held line in the log explaining why nothing appeared.

Everything is logged to ~/.aicade/state.log:

2026-08-31T16:17:15.169Z run[48743] state from=IDLE to=ACTIVE runId=-
2026-08-31T16:17:16.774Z run[48743] state from=ACTIVE to=WORKING runId=48743-1
2026-08-31T16:17:16.774Z run[48743] show runId=48743-1 reason=working
2026-08-31T16:17:21.530Z run[48743] state from=WORKING to=IDLE runId=48743-1
2026-08-31T16:17:21.530Z run[48743] finished runId=48743-1 ms=4827

Tuning it against your own sessions

Don't guess — record and replay:

AICADE_TRACE=1 aicade claude     # records byte timings to ~/.aicade/trace.log
aicade tune                      # where the window would open and close
aicade tune --working 3000 --idle 5000
aicade config --set timing.idle_threshold_ms=5000

aicade tune replays the recording through the real state machine, so you can see the effect of a threshold before committing to it. The trace records only timestamps and byte counts — never what was typed or printed.

AICADE_NO_UI=1 aicade claude runs the wrapper and the state machine with no window at all.

Panes

Chess — the default, and the reason the tool exists. Puzzles come from the Lichess puzzle database (CC0). A rating-stratified subset of about 17,000 puzzles is downloaded once (~3 MB on disk) and served locally, so puzzles appear instantly and work with no network at all.

Your rating is Glicko-2, stored locally, and puzzles are served within ±150 points of it. A single puzzle moves you at most 100 points while the rating is still provisional and 40 after that — unclamped Glicko-2 will happily move a fresh rating 200 points on one puzzle, which is correct and reads as broken. Drag or click to move, or type the move. A wrong move shakes and lets you retry, but the puzzle counts as missed — as does a hint. If the window hides mid-puzzle you get that exact puzzle back, not a new one.

Profile — who you are, what you play, where you rank, and what you have earned. Your rank badge and points up top, then your games, then achievements. Open a game for its own analytics: rating over time, accuracy broken down by puzzle difficulty, activity by day, fastest and typical solve times, and which motifs you actually see — forks, pins, back-rank mates.

Achievements — 28 of them across rank, skill, streaks, volume, time and novelty, in four tiers. They key off rank rather than score wherever they can: "top 10 this week" means something to everyone, "10,000 points" only means something to whoever knows what a point is worth. A few are novelty — being one of the first players, solving at 3am, coming back from three misses in a row, solving one cleanly in under five seconds. Momentary ones are recorded when they happen rather than recomputed, because solving at 3am is not a state you can work out again tomorrow.

Casino — a browser view pointed at whatever you put in casino.url:

aicade casino https://example.com    # sets it and restarts the window
aicade casino                        # show the current value and what it does
aicade casino --clear

Then log in by hand, once. The pane uses a persistent session partition, so the login survives restarts, and a normal desktop user agent, because some sites misbehave under Electron's default. There are no injected scripts, no request interception and no automation: it is a window onto a site and nothing more. Links that open a new window go to your system browser instead.

Left unset, the pane shows an empty state rather than a broken page.

Wallet buttons will not work. Electron has no browser extensions, so Phantom and Solflare cannot inject and a "Connect wallet" button does nothing. Sign in with email instead; the persistent partition keeps you signed in.

Affiliate disclosure. aicade ships with the author's affiliate code and attaches it to the casino URL, so wagering on a site they are an affiliate of earns them a commission. It costs you nothing and changes nothing about the site. aicade casino prints this too. To clear or replace it:

aicade casino --ref ""          # no referral at all
aicade casino --ref <yours>     # or use your own
aicade casino --ref <yours> --param ref   # if the site expects ?ref= instead

Adding a third is one file in src/ui/panes/:

// src/ui/panes/reader.js
import path from 'node:path';

export default {
  id: 'reader',
  title: 'Reader',
  order: 30,
  create({ config, dist }) {
    return { url: config.reader?.url || 'https://example.com', external: true, preload: false };
  },
};

Every .js in that directory is discovered at startup. Return { file } for a local page or { url, external: true } for a remote one; add partition for a persistent session and preload: false to keep aicade's API away from a third-party page.

Points, streaks and the board

Two numbers, deliberately.

Rating is Glicko-2 and answers "how strong are you". Nothing inflates it — not streaks, not volume — because the moment it rewards anything but solving, it stops being an estimate of your strength.

Points are the other thing: a record of effort, and what the board ranks on.

points = 10 × (puzzle rating / 1500)^1.5 × streak multiplier
  • Skill pays. Difficulty is absolute, not relative to you, so a 2500 puzzle is worth about four times a 1000 puzzle for everybody. Since puzzles are served near your rating, getting stronger earns more on its own.
  • Streaks pay. +8% per consecutive solve, capped at double at thirteen in a row. A miss resets it, and so does skipping — a skip is not a solve.
  • Volume wins the long game. Because the multiplier is bounded, points stay linear in puzzles solved. No streak, however hot, out-earns simply doing more over a month. The cap is the only dial that decides how fast a hot run climbs in the short term.

The board is ranked over two windows, this week and all time, because an all-time-only board is just "who installed aicade first" and nobody new can ever win it.

The shared board is opt-in

aicade touches the network exactly twice: once at setup, to download puzzles, and then never again — unless you join.

aicade join <handle>     # takes a handle, turns on syncing
aicade board             # this week
aicade board --all
aicade leave             # forget the handle, stop syncing

What gets sent: your handle, and for each puzzle its Lichess id, whether you solved it, and when.

What never gets sent: what you ran, how long you waited, your working directory, which terminal you use, anything from the casino pane, and anything from state.log or trace.log. There is a test that fails if any of it starts leaking.

The server does not trust your numbers. A client says only which puzzles it attempted; the server looks each one up on Lichess, then recomputes the rating and points itself. Each puzzle counts once per player. Your local rating and the board's may drift apart slightly — the board's is the one that counts on the board.

There is no account recovery. No email, no password. The token in ~/.aicade/identity.json is the only proof the handle is yours, so back it up if you care. Nothing to leak, nothing to reset.

Run your own board instead if you'd rather — the Worker is in worker/.

Config

~/.aicade/config.toml, written with commented defaults on first run.

[timing]
working_threshold_ms = 4000   # how long a run must last before the window opens
idle_threshold_ms = 4000      # silence this long means the run is over
typing_suppress_ms = 2500     # hold the window while you are still typing

[window]
position = "bottom-right"     # or bottom-left / top-right / top-left / center
default_pane = "chess"
width = 560
height = 680
hide_on_finish = true         # leave on its own once the run is done
hide_delay_ms = 1400          # long enough to see the pulse

[chess]
rating_band = 150
auto_advance_ms = 1200

[casino]
url = ""

[sound]
enabled = true

[leaderboard]
enabled = false               # nothing leaves this machine while false
url = "https://aicade-leaderboard.noah-haufer.workers.dev"

Position and size are only used the first time; after that the window remembers where you left it.

Files

~/.aicade/
  config.toml     yours to edit
  state.log       every state transition, for tuning
  trace.log       byte timings, only when AICADE_TRACE=1
  identity.json   your board token, if you joined — chmod 600, back it up
  store.json      rating, stats, the puzzle you were part-way through
  puzzles/        one NDJSON file per 100-point rating band
  runtime/        Electron, fetched on demand — shared, so it ignores AICADE_HOME
  ui.log          the window process
  sock            the wrapper talks to the window over this

Notes

Focus. The window is shown with showInactive() and, on macOS, the process is a dock-less accessory app, so it cannot take focus even if it wanted to. There is no modal, no system alert, nothing that demands dismissal. It floats above other windows but is not on every space.

Transparency. The wrapper is a pure byte pipe. One subtlety worth recording: a pty applies its own newline translation, and so does your terminal, so a naive wrapper adds carriage returns the bare command never emitted — invisible for ordinary output, but visible corruption for any full-screen TUI, which is every agent CLI. aicade turns off output post-processing on its own terminal for the duration and restores it on exit, which makes the byte stream identical. There are tests for exactly this.

Multiple terminals. Run aicade in several at once; they share one window process, and any of them can open it.

AICADE_HOME relocates config, stats, puzzles and the socket, which is useful for a second profile or for testing. It deliberately does not relocate the Electron runtime — that is a downloaded binary cache, and one copy is enough.

Troubleshooting

aicade doctor first — it checks the runtime, the puzzles, node-pty, and whether the parent terminal was identified.

The window never appears, or appears late. Check ~/.aicade/state.log. A run-held reason=typing line means the output was keystroke echo and the clock was held. Otherwise record a session with AICADE_TRACE=1 and run aicade tune to see exactly where the thresholds fire.

The window does not go away. aicade config --set window.hide_on_finish=true, then aicade quit so the window picks it up. If it hides too fast to see the pulse, raise window.hide_delay_ms.

Cmd+Enter does not raise the terminal. On macOS this needs the parent terminal to be identified as an .app bundle; aicade doctor shows what it found. On Linux it needs wmctrl or xdotool, and under Wayland one app cannot raise another at all.

posix_spawnp failed. node-pty ships a helper binary that needs the executable bit, and npm 11 skips install scripts by default. aicade repairs this itself at startup; if you still hit it, aicade doctor will report it.

A rendering bug you want to report. AICADE_SHOT=/tmp/shots aicade ui writes a PNG of the chrome and of each pane — easier than screenshotting a window that never takes focus.

Licence

GPL-3.0-or-later. aicade bundles chessground, which is GPL-3.0-or-later, so the combined work is too. See NOTICE for the full attribution list, including the CC0 puzzle data and the CC-BY-SA piece artwork.