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

@kingsmaker/cli

v0.0.9

Published

The Kingsmaker command line — km.

Downloads

252

Readme

km — the Kingsmaker command line

km <noun> [<sub-noun>] <verb> [target] [--flags]
km auth login --host https://kingsmaker.example.com
km record list vendor --where status=active --json | jq '.[].label'
km record import vendor vendors.csv --key name
km concept create Supplier
km access check --user <id> --action edit --resource concept --id <id>

The grammar

Every command names the thing that owns the row. A relation edge belongs to a record, so it is record relation add; a relation type is a field on a concept, so it is concept field add --kind relation.

The first token after a noun is a verb or a sub-noun — never an id. Ids come after the verb. That is what makes task status list (the status catalogue) unambiguous next to task update <id> --status done (one task's status).

One verb set: list · get · create · update · delete · archive · restore, plus domain verbs where the domain has one (publish, transition, sync, assign, deactivate). A verb means the same thing under every noun: delete always purges, archive is always reversible.

Run km help for the full list, km <command> --help for one, and km --version (or -v) for the CLI's own version — no network and no sign-in. That last one is deliberately not km system version, which asks the DEPLOYMENT what it is running and warns if the two have drifted.

Output

Data on stdout, everything else on stderrkm … --json | jq never has to filter our chatter. --json, --csv, or an aligned table by default.

| exit | meaning | | --- | --- | | 0 | fine | | 1 | failed | | 2 | you typed something wrong | | 3 | not signed in | | 4 | not allowed | | 5 | not found | | 6 | conflict (something changed underneath, or is still in use) |

Configuration

One deployment, stored in $XDG_CONFIG_HOME/kingsmaker/config.json (mode 0600):

{ "host": "https://kingsmaker.example.com", "cookie": "…", "email": "[email protected]" }

km auth login --host <url> writes it; every later command reads it. There is no default host — an unconfigured CLI says so rather than quietly trying localhost. KM_HOST overrides it without touching the file, which is what CI wants.

Signing in through the browser

km auth login --browser     # or --sso, which is the same thing
  Open:  https://kingsmaker.example.com/api/cli/device?code=WDJB-MJHT

The CLI prints a link and waits. Open it in any browser, on any machine — your laptop, your phone — and sign in however this deployment allows (password, SSO, anything). Opening the link is the approval; there is nothing to type. The CLI is polling, and continues on its own.

Nothing is redirected anywhere and nothing listens on a local port, which is deliberate: the usual loopback-redirect flow needs the browser and the CLI on the same machine, so it breaks over ssh, in a devcontainer, or any time you would rather open the link on your phone. The CLI never talks to your identity provider either, which is why this works where a CLI-driven SSO flow cannot.

The credential is the browser's session, so signing out in the browser signs the CLI out too. That goes away when token credentials land.

Keeping the CLI current

km cli update            # upgrade to the newest published version
km cli update --dry-run  # print what it would run, change nothing

Why this matters more than it looks. The CLI carries a copy of the wire contract, compiled in at build time. Against a deployment built from newer sources, a procedure whose shape changed fails inside a schema decode with a message about a field nobody typed. km system version detects that skew and says "update the CLI first"; this is how you do it.

km cli update asks npm what the newest @kingsmaker/cli is and upgrades a global install in place, with no prompt. km system version asks your deployment what image it runs — different artifact, different registry. Set KM_REGISTRY to point at a mirror.

It works out which package manager owns the install from where the binary actually lives (npm, bun, pnpm, yarn) and refuses in three cases, naming the command to run instead:

| where it is | why it refuses | | --- | --- | | a source checkout or npm link | installing would write over a working tree | | a project dependency | it would rewrite that project's lockfile, and the CLI's CWD is not reliably that project's root | | an npx cache | it is ephemeral; there is nothing installed to update |

The package manager's output goes to stderr with all other chatter, so km cli update --json stays parseable.

What it cannot do yet

  • Unattended CI. A session expires, and km auth token create needs BetterAuth's API-key plugin server-side. Until then, CI needs a password-capable account and km auth login --email --password.
  • Filter or sort on the server. listRecords takes a concept and nothing else, so --where / --sort / --limit run client-side over the whole set, which the server caps at 50 000 records. Above that the CLI says so rather than returning a truncated list that looks complete.

Development

bun run --cwd packages/cli test      # unit tests, no server needed
bun run cli:build                    # bundle for Node -> dist/index.js
bun run --cwd packages/app scripts/verify-cli.ts   # end-to-end, needs a live server

The bundle is ~620 KB, ~190 KB installed, with no dependencies. Effect is about 80% of that: the wire contract is defined with effect/Schema and the client is @effect/rpc, so the CLI carries the server's runtime in order to speak its format. That is the price of one shared contract and no drift, and it is a price paid once at install.

The CLI targets Node, not Bun: @types/bun is deliberately absent, and TypeScript that emits (parameter properties, enums) breaks node --experimental-strip-types even though it typechecks. CI builds the bundle and smoke-tests it with plain node for exactly that reason.