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

@zappimoney/zappi-cli

v0.4.0

Published

Buyer CLI for Zappi agent pots — propose register links, pay ResourcePaywall (402/settle), consume metered grants.

Readme

@zappimoney/zappi-cli

Buyer CLI (zappi-cli) for prepaid Zappi agent pots. Propose a register deep link, pay a nest PaidResource (HTTP 402 → sign USDB from the pot → settle), then consume metered grant units.

Install

npm (recommended):

npm install -g @zappimoney/zappi-cli
zappi-cli --help

npx (no install):

npx @zappimoney/zappi-cli --help

From GitHub (global):

npm i -g github:armmosikyan66/zappi-cli
zappi-cli --help

Clone + link (local development):

git clone https://github.com/armmosikyan66/zappi-cli.git
cd zappi-cli
npm install
npm link
zappi-cli --help

Requires Node.js ≥ 20.9. The package compiles TypeScript to dist/ on install (prepare); the zappi-cli bin runs compiled JS via bin/cli.js (no experimental flags).

Commands

Global flag: --json prints machine-readable JSON (never includes pot seeds, pot client tokens, unlock tokens, or a guest secret). need_choice and a refusal exit 0. allowance_required and an uncertain allowance pull exit 1.

A person or an agent uses these commands to create a pot, deposit, and send. zappi-cli login saves the session. zappi-cli guest starts a free pot without an account and does not print the secret.

| Command | What it does | | --- | --- | | whoami | Account email, or guest mode from ~/.zappi/agent.json | | login / logout | Save or revoke this login | | guest | Start a free pot without an account | | guest claim --pot <id> | Move that pot onto the account | | pots | List pots on this login. --origin or --spend-mode, or a project API key, keeps the wallet list | | pots create | Create a pot. The only question is the name: --label or --skip-name. There is no spend mode and no per-pot limit | | pots connect --pot <name-or-id> | Connect a free pot. --default moves the default | | pots disconnect --pot <name-or-id> | Remove it from this login | | pots pair | Approve URL for an auth-required pot | | pots balance | Balance | | pots challenge --address <spark> | Address challenge | | deposit rails / deposit assets / deposit networks / deposit address | Deposit catalog and address | | pots spender [pubkey] | Register the allowance spender. Omit the key to run zappi-allowance-spender pubkey | | pots send | Send. --amount-cents, --to, optional --asset, --chain, --memo, --pot, --idempotency-key, --no-wait. A signed allowance pulls with zappi-allowance-spender; otherwise the result is an approve URL | | pots send-status <requestId> | Read one send |

pots connect is not pots attach. pots send is not send. deposit address is not deposit-address.

propose on a terminal asks before it generates or registers: existing vs new, spend mode, Spark network (unless SPARK_NETWORK is set), app origin (unless ZAPPI_APP_ORIGIN / NEXT_PUBLIC_SITE_URL / --origin is set), and a label. A blank label asks you to confirm auto pot_<unique> or type a custom name. Flags: --mode free|auth_required, --origin, --label.

zappi-cli login                       # optional: sign this terminal into Zappi
zappi-cli propose                     # on the agent host (wizard)
zappi-cli pay <resourceId>            # free pot: agent signs after the pot is funded
zappi-cli request --amount-cents 100 --to <spark-address>
zappi-cli consume <resourceId> [--units N]
zappi-cli invite                      # Nest invite URL for this pot
zappi-cli sign <requestId>           # local signer: human confirms in the terminal
zappi-cli sign <requestId> --yes     # agent with a shell

| Command | What it does | | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | login | Optional, human. Opens the Zappi sign-in screen (email or passkey). Saves a user session in ~/.zappi/credentials.json (0600). Wallet commands use it when ZAPPI_ACCESS_TOKEN is unset. Never prints the session. Propose and pay do not need it. | | whoami | Prints the email of the saved login. With a guest file and no login, reports guest mode and does not print the secret. | | logout | Revokes that session and deletes the credentials file and the guest file. | | propose | Host setup on the agent host. Wizard: existing or generate → spend mode → network → app origin → label (blank confirms auto pot_<unique>) → opens the register link. Writes a mode 0600 key file when generating. Never prints the pot key. | | pay | Free pot. GET resource → 402 → accepts[0].network + asset must be spark / USDB → sign pot USDB → settle { sparkTxHash, potId }. Other rails fail closed. Metered auto-consumes one unit (--no-consume to skip). ZAPPI_POT_SPEND_MODE=auth_required refuses this and points at request. | | request | Auth-required pot. No TTY. POST …/spend-requests with x-zappi-pot-client and prints only the approve URL (?panel=pots&spend=, no code=). --json includes that URL and never the zpc_ token. Does not sign. | | consume | Agent spend. POST …/consume with X-Zappi-Unlock-Token and { units } (default 1). | | invite | Recommend Zappi. GET /api/invite/pots/$ZAPPI_POT_ID/link (no session, no pot key). Prints the Nest invite URL. Fails closed if the flag is off or the pot has no code — it never invents one. | | sign | Local signer. Spawns zappi-signer sign <requestId>. Without --yes, a human confirms in the terminal. | | signer-status | Local signer. Spawns zappi-signer status <requestId>. | | provision, prove-address, policy, backup, restore | Local signer. Same subcommand, plus your remaining arguments. |

Local signer

sign, signer-status, provision, prove-address, policy, backup, and restore start the zappi-signer binary and forward the terminal (stdin, stdout, and stderr) and the child exit code. This CLI does not sign, does not ask for a mnemonic, and does not drop a second sign for the same request. The signer confirms on its own terminal, and idempotency is the signer's job.

zappi-cli sign <requestId> [--yes] [--signer <path>]
zappi-cli signer-status <requestId> [--signer <path>]
zappi-cli provision [args…]
zappi-cli prove-address [args…]
zappi-cli policy [args…]
zappi-cli backup [args…]
zappi-cli restore [args…]

The binary is --signer <path>, otherwise ZAPPI_SIGNER_BIN, otherwise zappi-signer on PATH. If that file is missing, the command prints a short hint that names ZAPPI_SIGNER_BIN and exits non-zero. --signer is not passed to the child. --yes is passed only when you passed it.

Without --yes, a human confirms in the terminal. An agent with a shell passes --yes. A host without a shell shows zappi sign <requestId>.

The propose wizard

npx @zappimoney/zappi-cli propose
Do you already have a pot, or should this host generate a new one?
◉ Generate a new pot (create a fresh key on this host)
○ Use an existing pot (I already registered one)
(↑/↓ to move, ENTER to select)

With no flags and no app-origin env, the same run then asks spend mode, app origin, and label before it generates a key or opens the register link. Spark is MAINNET.

  • Radio-circle menu: the selected row shows a green ◉, others a hollow ○; ↑/↓ move, ENTER confirms — Generate a new pot is the default. Digits (1/2) and j/k also work. (Set NO_COLOR=1 to disable the green.)
  • Spend mode — Auth not required (free) vs Auth required (auth_required).
  • Network — MAINNET. Unset SPARK_NETWORK is MAINNET. Any other value is rejected. New pots use Spark account index 1.
  • App origin — staging https://dev.zappi.money (pair with https://api-dev.zappi.money), production https://zappi.money, local http://localhost:3000, or a custom http(s) URL. Asked only when ZAPPI_APP_ORIGIN, NEXT_PUBLIC_SITE_URL, and --origin are all unset. Staging is the first row and the silent default.
  • Existing pot → paste the public pot address from your agent (validated for the network you chose; blank cancels).
  • Label — both modes. A name you type is used as-is. A blank answer asks you to confirm auto pot_<8-hex> or enter a custom name. Auto, or a custom name left blank, accepts pot_<unique>.
  • Key file prompt: blank uses ~/.zappi/…txt. If you paste a folder (e.g. ~/Documents/zappi/packages), the CLI writes the .txt inside that folder instead of crashing with EISDIR.
  • The browser step opens the origin you chose (ENTER / auto-open / c to copy). Ctrl+C quits cleanly.
  • Bare propose without a terminal (no TTY) prints flag usage instead of hanging.
  • Flags (--generate, --address, --mode, --origin, --label, …) are for CI. When those flags fully specify the run, nothing is prompted. A non-TTY flag run keeps the published defaults (free, MAINNET, https://dev.zappi.money, API https://api-dev.zappi.money) and does not hang.

Flow (propose → fund → pay or request → consume)

  1. Propose — run on the agent host. The CLI generates the pot key there and opens a register URL. Human signs in to Zappi and taps Register.
  2. Fund — human funds the pot in the Zappi app. The CLI does not call deposit APIs.
  3. Pay (free pot) — after ZAPPI_POT_ID + ZAPPI_POT_SEED (or key file) are set, pay a PaidResource. Nest returns an unlock bearer once on first settle. The CLI withholds that token from stdout/logs. Metered resources auto-consume one unit in the same pay (opt out with --no-consume).
  4. Request (auth-required pot) — ZAPPI_POT_CLIENT_TOKEN + zappi-cli request prints one approve URL. The human approves in Zappi. This command does not sign and does not ask for a session token.
  5. Consume — further metered units on a free pot: zappi-cli consume <id> with ZAPPI_UNLOCK_TOKEN set as a host secret.

Exact (url_once) resources stop after settle; use unlockUrl when nest returns it. Empty pot = stop. Do not fall back to the main wallet.

Fail closed (agents)

If a CLI command fails (env / apiUrl mismatch, not attached, etc.): stop and report. Forbidden: reading ~/.zappi/pot-client-*, inventing fetch/curl/Node with zpc_, or calling Nest with attach secrets. Pot balance for attached pots: zappi-cli balance --pot <id> (CLI sends x-zappi-pot-client to Nest). Use zappi-cli doctor to compare saved login apiUrl vs the resolved API — no secrets printed.

Environment

| Variable | Role | | -------------------- | --------------------------------------------------------------- | | ZAPPI_POT_ID | Required for pay and request. Public pot id from the Zappi prompt. | | ZAPPI_POT_CLIENT_TOKEN | zpc_ for request (host secret), or ~/.zappi/pot-client-*.txt after attach. Missing = not attached. Never a CLI flag. | | ZAPPI_ATTACH_DEVICE_CODE | Attach reclaim secret (RFC 8628 device_code) from pots attach create (host secret). Wins over ~/.zappi/attach-device-<requestId>.txt. Never print. | | ZAPPI_POT_SEED | Preferred pot spend key for free pay (host secret). | | ZAPPI_POT_KEY_FILE | Fallback mode-0600 key file if the seed env is unset. | | ZAPPI_API_URL | Nest origin. Default https://api-dev.zappi.money. Local: http://localhost:3011. Production: https://api.zappi.money. | | ZAPPI_PAYWALL_BASE | Optional paywall origin override (wins over ZAPPI_API_URL). | | ZAPPI_UNLOCK_TOKEN | Unlock bearer for consume (preferred over --unlock-token). | | ZAPPI_POT_SPEND_MODE | Runtime spend mode. auth_required refuses pay and tells the agent to run request. Unset / free for agent-held pots. | | ZAPPI_APP_ORIGIN | Web origin for links the human opens. Default https://dev.zappi.money. Follows the API when unset. Local: http://localhost:3000. Production: https://zappi.money. | | SPARK_NETWORK | MAINNET (default). Any other value is rejected. Account index is 1. | | ZAPPI_PROJECT_API_KEY | Project API key for server-to-server wallet routes (balance, pots, withdraw, …). | | ZAPPI_ACCESS_TOKEN | User access JWT. Wins over zappi-cli login. | | ZAPPI_CREDENTIALS_FILE | Override for the login file. Default ~/.zappi/credentials.json (0600). | | ZAPPI_CLI_GUEST_FILE | Override for the guest secret file. Default ~/.zappi/agent.json (0600). Never printed. | | ZAPPI_COOKIE | Optional cookie header forwarded for session auth (e.g. zappi_access=…). | | ZAPPI_USER_AGENT | Optional user-agent forwarded for session auth. | | ZAPPI_SIGNER_BIN | Path to the zappi-signer binary. Used when --signer is omitted. Unset uses zappi-signer on PATH. |

--unlock-token exists for one-off calls. Scripts should use ZAPPI_UNLOCK_TOKEN so the bearer does not land in ps / shell history. Env wins when both are set.

Staging dogfood

Unset ZAPPI_API_URL and ZAPPI_APP_ORIGIN already use this pair. http://dev.zappi.money redirects to https://dev.zappi.money.

export ZAPPI_POT_ID='<pot id>'
# set ZAPPI_POT_SEED / ZAPPI_POT_CLIENT_TOKEN / ZAPPI_UNLOCK_TOKEN as host secrets — never echo / never commit

npx @zappimoney/zappi-cli propose --generate --label Staging --mode free
# SPARK_NETWORK unset is MAINNET. Account index is 1.
# human registers + funds in the staging app
zappi-cli pay '<paidResourceId>'
# metered: pay already consumed one unit; more:
zappi-cli consume '<paidResourceId>' --units 1

Local nest is explicit: ZAPPI_API_URL=http://localhost:3011 and ZAPPI_APP_ORIGIN=http://localhost:3000. Production is ZAPPI_API_URL=https://api.zappi.money and ZAPPI_APP_ORIGIN=https://zappi.money. Set those two together.

CI vs live dogfood

  • CI (npm test): mocked HTTP + mocked Spark. Covers 402 → settle { sparkTxHash, potId } → consume, empty pot fail-closed, 402 network/asset required (refuse non-spark/USDB before sign), secret redaction (including BIP-39), ZAPPI_POT_SPEND_MODE=auth_required refusing CLI free-sign, and request printing a bare approve URL (no code=, no zpc_). No live Spark spend / no paywall network.
  • Staging dogfood (this section): human registers + funds in the app, then pay / consume against api-dev. Never commit seeds.
  • --json is the CLI trace contract: command, potId, sparkTxHash, network, asset, unlockTokenReceived (boolean). request --json adds approveUrl, requestId, amountCents, and destinationAddress. pots attach / attach-status JSON uses deviceCodeReceived / potClientTokenReceived booleans — never raw deviceCode or zpc_. It never includes the mnemonic, ZAPPI_POT_SEED, or zpu_… / zpc_… values.

Install has no --pot flag. Runtime pot id is ZAPPI_POT_ID after the human registers.

Develop

npm install
npm test          # tsc → node --test dist/ (mocked HTTP + Spark)
npm run build

package-lock.json resolves @zappimoney/zappi-sdk from the npm registry (0.3.8). A clean checkout does not use a sibling ../zappi-sdk link.

Labels: active pot names are unique per user (case-insensitive), not across the app. Nest returns 409 AGENT_POT_LABEL_EXISTS if that user already has the name.

Pot attach (device code / 1-203)

zappi-cli pots attach --pot <potId> --spend-mode auth_required creates a pending pairing for that pot (1-554).

  • Pot is required for auth-required: pass --pot <potId> or set ZAPPI_POT_ID. If both are set and differ, the command fails closed. The pot id is always sent to Nest as potId.
  • Nest must confirm the pot: the create response (approveUrl pot= or a requestedPotId field) must name the same pot, or no link is printed and no device code is stored. Polling and reclaim fail closed if the request or the approval names a different pot; the client token is then not stored.

Nest returns deviceCode once to the agent host and an approveUrl that carries only the request id. The verification code is not in that response and not in the URL.

  • Host secret: the CLI writes deviceCode to ~/.zappi/attach-device-<requestId>.txt (mode 0600). You can also set ZAPPI_ATTACH_DEVICE_CODE for reclaim. Never echo / never commit.
  • Human: open/print approveUrl only.
  • Poll: public GET …/pots/attach/:requestId is status-only (never zpc_).
  • Reclaim: after approved, the CLI calls POST …/pots/attach/:requestId/credentials with header X-Zappi-Device-Code and stores zpc_ under ~/.zappi/pot-client-<requestId>.txt (0600). Set ZAPPI_POT_CLIENT_TOKEN from that file.
  • Output: pretty/plain show zpc_… (withheld). JSON uses deviceCodeReceived / potClientTokenReceived booleans — never raw secrets.
  • attach-status <requestId> reclaims the same way when a device code is available from env or file.

Reclaim path locked to Nest tip df7aafc / zappi-nest#82: POST …/pots/attach/:requestId/credentials + X-Zappi-Device-Code.

Hard rules

  • Never print, log, echo, or set -x ZAPPI_POT_SEED, ZAPPI_POT_CLIENT_TOKEN, ZAPPI_ATTACH_DEVICE_CODE, the key file, attach-device / pot-client files under ~/.zappi/, or ZAPPI_UNLOCK_TOKEN.
  • Never ask for ZAPPI_ACCESS_TOKEN, zappi_access, a zpc_ paste, the pot seed, a verification code, or a recovery phrase. Pair with pots attach (URL only). Paste the request approve URL for a send.
  • Until an auth-required pot is attached, request, pay, consume, and invite fail closed. The only bot command is pots attach.
  • Never pass a recovery phrase as --address or put one in a deep link.
  • Nest never holds the pot key. Cap v1 is an empty pot.
  • Do not invent a payment chain from an address. Paywall 402 must include accepts[0].network and accepts[0].asset; this CLI only pays spark / USDB.
  • Do not invent an invite code. zappi-cli invite prints a Nest URL or fails closed.
  • Seller / project API is out of scope for this package.
  • Create, deposit, and send for this login are pots create, deposit address, and pots send. A chat can still use the remote MCP server. propose, pay, request, pots attach, and send stay for host setup and the wallet.