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

@nook-space/gadget-cli

v0.2.0

Published

Unofficial CLI for self-hosted Cloudflare OS instances: make and push gadgets from the terminal.

Readme

gadgetCLI

Make and push apps ("gadgets") to a self-hosted Cloudflare OS instance from the terminal: real files, git, your own editor, your own coding agent. The workshop is browser-only; gadgetCLI gives it a headless lane.

An independent community project, not affiliated with Cloudflare.

Principles

  • The instance's commit history is truth; local files are a working copy. The CLI behaves like git against a remote — pull, diff, head-checked push — never a deployer.
  • Code is pushable; authority is not. Anything granting capability (OAuth, connections) ends at a URL a human opens.
  • Pure API client: the same capnweb WebSocket the browser frontend speaks. No scraping.
  • Agent-native: every flow has a non-interactive lane, --json where it matters, and errors are one cause plus one next step.

A gadget is not an ordinary Workers project

Both run on workerd, Cloudflare's Workers runtime. The project shapes differ. Cloudflare OS supplies everything except your files — write the gadget shape natively:

  • Ordinary Worker: wrangler.toml, export default { fetch }, own routing, hosting, deploy.
  • Gadget: server.js exports one Durable Object class named Gadget. No config, no fetch handler — the platform routes; your public API is the class's methods.
  • client.js builds the whole UI in a sandboxed iframe and calls the server through the global gadget RPC stub. No index.html, no bundler, no build step.
  • No deploy step: gadget push lands a commit on the gadget; the instance restarts the gadget with it.
  • Gadget code cannot reach the network; external services arrive as bindings a human wires in the workshop UI.

This is the same shape the web editor and the in-app agent write — the terminal and the browser edit ONE gadget: push lands as a merged chat the workshop shows (-m is the commit message), pull reads the gadget's head commit. The scaffold (gadget new) and skill/SKILL.md teach it; code in the ordinary-Worker shape will not run on the instance.

Install

Prerequisites: Node >= 22 — the global WebSocket the transport needs arrived in 22.

If (and only if) your instance sits behind Cloudflare Access, you also need cloudflared (brew install cloudflared on macOS). The CLI detects the gate and asks for it only then, so nobody installs it who does not need it.

npx @nook-space/gadget-cli --help       # no install
npm install -g @nook-space/gadget-cli   # then: gadget --help

From source:

git clone https://github.com/nook-space/gadgetCLI && cd gadgetCLI
pnpm install && pnpm build
node dist/cli/main.js --help            # or: pnpm link --global → gadget --help

The command is gadget however you install it. gadget --help (and gadget <command> --help) lists every command — enough for an agent to discover the surface on its own.

Teach your coding agent

The CLI ships an agent skill (verbs + the gadget idiom). Any shell-capable agent can drive gadget; the skill just teaches it how.

gadget skill                       # print the skill to stdout
gadget skill install               # place it where Claude Code looks (~/.claude/skills/gadget/)
gadget skill install --path .claude/skills/gadget/   # or a project dir, committed for the team
gadget skill refresh               # re-copy it everywhere it was installed

Installs are recorded, so gadget skill refresh updates every copy after a CLI update — a copy is a snapshot, and a stale skill teaches an agent the wrong commands.

Staying up to date

A cached background check notices new releases and prints one line to stderr — never for machines (non-TTY, CI, --json, GADGET_NO_UPDATE_CHECK/NO_UPDATE_NOTIFIER). It never self-updates: run gadget update (or --check). For npx, Homebrew, or a source checkout it prints that install's own command instead of guessing.

Quickstart

# sign in — one login per instance, kept as a named profile
gadget login https://os.your.dev --create --username you  # password (prompt, or GADGET_PASSWORD)
gadget login https://os.your.dev --vendor github          # "Continue with X": prints a URL to open
gadget login https://os.your.dev                          # behind Cloudflare Access: detected, via cloudflared
gadget doctor                                             # reachability, sign-in modes, auth state

gadget new tracker && cd tracker  # scaffold: server.js, client.js, README.md
gadget push --new                 # create workspace + gadget, link this directory
gadget open                       # the workspace URL (auto-opens a browser on mac/Linux TTYs)

# the loop
vim server.js
gadget status && gadget diff
gadget push -m "wire the button"  # one commit; refuses if the remote moved: pull, resolve, push
gadget pull                       # aborts whole rather than clobber dirty files
gadget logs                       # live console stream (Ctrl-C stops)

Share it

gadget blueprint publish          # pushed code → https://<instance>/blueprint/<id>
gadget blueprint publish --update <id>   # bump the same URL to the current code
gadget pack                       # offline .gadget archive for git/CI
gadget new my-copy --from <blueprint-url>  # start from any instance's blueprint, no login
gadget install <url|id>           # your own instance of a zero-binding blueprint

Collaborators keep their own credentials: blueprints carry code and binding shapes, never connections.

Behavior worth knowing

  • Conflicts: push refuses when the same gadget changed remotely (exit 4); pull refuses rather than overwrite local edits. Different files: pull, then push. Same file on both sides: copy yours aside, pull --force, merge, push. Identical content never conflicts. --force is last-writer-wins; the losing edit survives in the gadget's commit log. A push is atomic: if the remote moves while it is in flight, nothing lands (exit 4).
  • Each push shows up in the workshop as one chat, already merged — that is upstream's only write path, and it doubles as the push log. Upgrading from 0.1: delete .gadget/ and pull.
  • Files are UTF-8 text, at most 512K characters each (the instance's cap). Dotfiles, node_modules/, mocks/, and *.gadget archives never sync, in either direction.
  • Sessions: one login per instance profile (--profile to switch, one login per instance); tokens live in ~/.config/gadget/config.json (0600). gadget logout [--all] clears them locally (no server-side revoke yet).
  • Cloudflare Access instances work: gadget login <url> detects the gate and uses cloudflared for the session (brew install cloudflared, one browser hop, then silent refresh). An Access profile stores no token at all — identity is proven per connection. Headless CI against an Access instance is not possible: Access service tokens carry no email claim, which the instance requires.
  • Exit codes: 0 ok · 1 error · 2 usage · 3 auth · 4 conflict · 5 rpc.

Development

pnpm check                        # typecheck + lint
pnpm test                         # unit; add GADGET_TEST_URL=http://localhost:8787 for live
                                  # (requires cloudflare-os main at or after #275, Aug 2026)

Live tests need a local instance:

git clone https://github.com/cloudflare/cloudflare-os && cd cloudflare-os
corepack pnpm run-local          # serves http://localhost:8787

Design notes and trade-offs: DESIGN.md. Roadmap: idea.md. The agent skill lives in skill/SKILL.md.