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

@quaivault/cli

v0.7.0

Published

Command-line client for QuaiVault multisig vaults on Quai Network

Readme

@quaivault/cli

Command-line client for QuaiVault multisig vaults on Quai Network.

npm install -g @quaivault/cli

Two surfaces, one core: one-shot commands for people and agents, and a TUI for watching.


Reading needs no key

No wallet, no account, no configuration. This works the moment you install:

qv vault show 0x005f2629A632962f4944d23686efDa5c160d535b

Then tell it who you are — still no key:

qv use --as 0x<your-address>
qv inbox        # what is waiting on you, across every vault

Add a key only when you want to sign:

qv key import mykey --use

qv key import reads a raw private key from your terminal, or takes an existing Web3 Secret Storage (V3) keystore with --keystore geth.json — the format Pelagus, MetaMask, Geth and ethers all export.

The commands

Reading (no key required)
  qv status · qv doctor · qv inbox · qv vault show|ls|receive
  qv tx ls|history|show|wait · qv balance · qv messages · qv addr check
  qv activity deposits|token-transfers · qv recovery status|history

Acting on transactions
  qv tx approve · qv tx unapprove · qv tx execute · qv tx cancel · qv tx expire

Proposing changes  (every one of these asks your co-owners to act)
  qv propose transfer|token|nft|erc1155|call|batch
  qv propose add-owner|remove-owner|threshold|delay
  qv propose module|delegatecall|sign-message|cancel-by-consensus
  qv propose enable-recovery|disable-recovery|setup-recovery

Vaults, recovery, setup
  qv vault create · qv vault mine-salt
  qv recovery approve|unapprove|execute|cancel|expire|initiate
  qv key import|ls|use|rm|rename|change-password|export
  qv use · qv alias · qv contact · qv policy · qv watch · qv tui

Everything except approve/execute/cancel/expire is a proposal: it asks N−1 other people to act. The naming says so, because qv owner add would read like it adds an owner when it actually asks two other people to.

Social recovery is deliberately enabled in two reviewed proposals. First enable the module configured for the active network, then configure its guardians:

qv propose enable-recovery <vault>
qv propose setup-recovery <vault> --guardian 0x… 0x… --threshold 2 --recovery-period 7d
qv recovery status <vault> --json

recovery status reports the module address, enabled/configured state, guardian set, threshold, recovery period, and pending requests. In the TUI recovery pane, s opens the applicable enable or guardian-setup flow; d proposes disabling an enabled module.

Terminal workspace

CLI 0.7.0 provides eight panes: inbox, history, activity, assets, vault, recovery, policy, and proposals. Start with qv tui --profile <name> --as <address>. The active profile and identity are preserved when a command opens for signing.

| Keys | Action | |---|---| | Tab / Shift-Tab, 1–8 | Change pane | | [ / ] | Change vault | | Arrows or j / k, PgUp / PgDn, Home / End | Navigate lists and scroll full details | | /, then Enter; Esc | Filter inbox/transaction history; clear search | | Enter | Open transaction details | | ← / → in history | Transactions, deposits, token transfers, recovery history | | m in history | Load the next 50 records | | ← / → in recovery | Choose a pending recovery request | | r, ?, q | Refresh, keyboard guide, back/quit |

Proposal forms support native and token transfers, raw and ABI-assisted calls, batches, vault administration, message signatures, vault creation, and recovery. Token forms require explicit decimals. Every proposal form includes expiry, execution delay, and an optional idempotency key. Paste calldata, address lists, or file paths normally; oversized inputs are rejected with a visible message.

Within a field, use arrows, Home/End, Backspace/Delete, Ctrl-U (clear), Ctrl-W (delete word), and Ctrl-K (delete to end). Tab/Shift-Tab changes fields. Enter advances until the last field, where it opens the command for review. The result stays visible until you press a key, so transaction hashes can be copied.

The display adapts to terminal resizing down to 40 columns × 12 rows. Kitty's keyboard protocol is detected through Ink; unsupported terminals use standard input. No special font or Kitty configuration is required. Mouse reporting is left off so normal terminal text selection remains available. --color never and NO_COLOR support monochrome terminals. Use a larger window for long tables.

Discovery and pending lists page beyond the SDK's defaults. Each is bounded at 1,000 records per role/vault, with a visible warning if that bound is reached. History loads on demand. Indexed lists are not an atomic chain snapshot; the one-shot command rereads chain state before signing. Failed reads stay visibly unavailable or stale, and delayed responses cannot overwrite another vault.

For the terminal regression suite on Linux/macOS, install pyte==0.8.2 and wcwidth==0.8.3 in a Python environment, then run npm run test:tui-pty. QV_TUI_PYTHON can select that interpreter; QV_TUI_CAPTURE_DIR saves synthetic screen captures. The suite tests PTYs and protocol responses, not GUI terminal apps.

Before you sign

Every write prints a disclosure read from chain, not the indexer:

About to approve:
  Transfer 100 QUAI to alice
  0x8a3f9c21…7e6d

  Decoded as   verified
  To           0x001f4e8a9b0c1d2e3f405162738495a6b7c8d781  (alice)
  Value        100 QUAI
               exactly 100000000000000000000 wei
  Operation    call
  Data         (none)

  Approvals    1 of 2
    [x] 0x00a1b2…  (bob)
    [ ] 0x001f4e…  (alice)

When the ABI is unknown, it shows the hex — laid out one 32-byte word per line, because ABI encoding is word-aligned and a padded address reads as 12 zero bytes then 20. You can pick out a recipient and an amount with no ABI at all:

  Data         unknown ABI — 68 bytes, showing raw calldata
               selector  0xa9059cbb
               [000]     000000000000000000000000001f4e8a9b0c1d2e3f405162738495a6b7c8d781
               [032]     0000000000000000000000000000000000000000000000056bc75e2d63100000

A decode the SDK cannot vouch for — a selector-shape guess, a supplied ABI, or a delegatecall — is labelled as such and needs --i-understand-unverified to sign.

For agents and automation

qv inbox --json            # structured, with affordances
qv tx show <v> <h> --json  # includes a `verify` block to assert against
qv --schema --schema-version 1  # every command, flag and output shape
  • --json is a versioned CLI-owned schema ({"schema": 1, …}). Every bigint is a decimal string in wei, never a number — Number() loses precision above 0.009 QUAI.
  • Exit codes are a contract. 0 ok · 1 failure · 2 usage · 3 precondition or policy · 4 not executed (approved_only/timelock_started) · 5 declined · 130 interrupted. qv tx execute exits non-zero when the vault call failed even though the chain transaction succeeded.
  • changed is true/false/"unknown". Re-approving something you already approved is a no-op with changed: false, exit 0 — so a retry after a timeout is safe.
  • Assert, don't trust prose: --expect-data-hash, --expect-to, --expect-value, --expect-abi-source all fail closed against re-read chain state before signing.
  • Retry proposals deliberately: pass --idempotency-key <stable-operation-id>. Successful broadcasts are journaled durably, and a retry with the same inputs returns changed: false; reusing the key for different inputs fails closed. Keys are reserved before submission; an interrupted or unresolved submission blocks reuse until its chain history and local journal have been reconciled. Never work around this by inventing a new key.

A receipt timeout after submission reports BROADCAST_UNKNOWN, changed: "unknown", retryable: false, and chainTxHash in both data and error. Look up that hash before retrying. The SDK verifies the selected chain ID against both the read and signing RPCs before each broadcast; misspelled network names are rejected.

Signing locks are never reclaimed based on age. After a crash, verify the recorded PID and pending transactions before manually removing the lock named in the error.

Agents may sign, within a policy

Non-interactive signing requires a policy file in the CLI configuration directory:

qv policy init      # writes ~/.quaivault/policy.toml
max_value_per_approval_wei = "1000000000000000000"
max_approvals_per_hour     = 5
allow_to                   = []
deny_kinds                 = ["wallet_admin", "module_config", "recovery_setup"]
deny_delegatecall          = true
require_abi_source         = ["builtin"]
allow_recovery_actions     = ["cancel", "expire"]

There is deliberately no flag to relocate it and no environment override — a bound the caller can move is not a bound. An attended human at a terminal is not restricted by it.

The safest agent deployment is a UID or container that cannot read ~/.quaivault/keys/ and has no QUAIVAULT_PRIVATE_KEY*. The whole read surface still works, by construction.

Security

  • No telemetry. No usage analytics, no crash reporting, no phone-home. On a chain where addresses are public and permanent, correlating one with an IP is a deanonymisation primitive that cannot be walked back. qv doctor prints a paste-able report when you choose to share one.
  • No --private-key, --password or --mnemonic flag, ever. /proc/*/cmdline is world-readable and rewriting argv does not change it. Keys come from a keystore, --key-file, --key-fd, or a terminal.
  • Quai ledger only. QuaiVault is an EVM contract on the Quai ledger. Qi is a separate UTXO ledger that executes no contracts, so a Qi address can never sign, approve, or hold any role in a vault — and enough Qi owners brick a vault permanently. Every place an address is committed to a role checks both its zone and its ledger, because the two are orthogonal: 0x0081… sits in a valid zone and is still Qi. This is not a gap awaiting support; it is what the ledgers are.
  • Keys are stored as Web3 Secret Storage V3 via quais — a decade-scrutinised standard, not something invented here. Files are 0600 in a 0700 directory, written atomically, and refused if they are symlinks or readable by others. KDF parameters are validated before derivation, which is what closes V3's unauthenticated-params gap.
  • qv tui never holds a key. It renders, and delegates every signature to a spawned one-shot qv process that reads its own password. kill -USR1 opens a V8 inspector on any Node process and serves a full heap read to anything on loopback; against a long-lived TUI that is a certainty rather than a race.
  • Terminal-escape and bidi injection is stripped from every attacker-authored string — token names, revert reasons, config entries. A token can be named "\x1b[2A\x1b[KAll checks passed".
  • The CLI refuses to run with NODE_OPTIONS set, since it can inject code before ours runs.

Report vulnerabilities per SECURITY.md.

Configuration

~/.quaivault/config.toml (or $XDG_CONFIG_HOME/quaivault/):

default_profile = "default"

[profiles.default]
network = "mainnet"      # or "testnet"
address = "0x00…"        # who you act as; no key needed
vault   = "0x00…"        # default vault

[aliases]
treasury = "0x005f…"

[contacts]                # so you can tell who signed
bob = "0x00a1…"

| Variable | Purpose | |---|---| | QUAIVAULT_ADDRESS | identity to act as | | QUAIVAULT_VAULT | default vault | | QUAIVAULT_PROFILE | profile to use | | QUAIVAULT_PRIVATE_KEY_FILE | key file for CI (preferred over the next one) | | QUAIVAULT_PRIVATE_KEY | raw key — supported, least preferred | | QUAIVAULT_KEYSTORE_PASSWORD_FILE | keystore password for non-interactive use |

NO_COLOR, FORCE_COLOR and --color all work. Output to a pipe drops all chrome: data goes to stdout, warnings and hints to stderr.

Shell completion

qv completion bash > ~/.local/share/bash-completion/completions/qv
qv completion zsh  > ~/.zfunc/_qv         # ensure ~/.zfunc is on $fpath
qv completion fish > ~/.config/fish/completions/qv.fish

The script is generated from the command registry, so it never goes stale. It is also deliberately static: it contains no vault aliases, contact names or paths, because a completion script lives in a dotfile that ends up in backups and dotfile repositories.

Further reading

  • CAPABILITIES.md — web-frontend capability parity and the intentional boundaries between one-shot and TUI workflows.
  • docs/agent-contract.md — the full {exitCode, changed, retryable} table, the verify block, and how to bind an agent to bytes rather than to prose.
  • docs/r4-ipfs-measurement.md — why on-chain ABI resolution is measured and deferred rather than built.
  • SECURITY.md — what this tool protects against, what it does not, and every irreversible action with its guard.
  • docs/environment-notes.md — Quai and quais behaviours observed directly against live networks: checksummed-address requirements, why a static block number proves nothing, and the expiry floor that is not what it looks like.

Development

npm run check    # typecheck + lint + production build + test
npm pack         # inspect the tarball before publishing

Requires Node 22 or later. Releases go out through npm trusted publishing (OIDC), so there is no NPM_TOKEN to leak and every release carries a provenance attestation — verify with npm audit signatures.

License

MIT

Security checks in 0.6.1

Policy files reject unknown fields, malformed values, and invalid numeric limits rather than dropping those bounds. The hourly limit reserves an approval slot before signing, including attempts whose result is uncertain; reservations expire after one hour.

Keystore import bounds scrypt N, r, p and combined memory/CPU cost, plus PBKDF2 iterations, before deriving a key. The default floor is scrypt N=131072 and r=8, or 600000 PBKDF2 iterations. --accept-weak-kdf permits a lower floor at import but never bypasses resource limits. Imported keys are re-encrypted with the normal scrypt settings. Concurrent imports cannot overwrite an existing key file.