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

jithox

v0.3.0

Published

Jithox Connect Kit — OAuth-first: connect the AI client you already use to Jithox; the client signs in itself, no credential in any file. Preview first, explicit consent, backup, atomic write, test, undo.

Readme

Jithox Connect Kit

The jithox CLI connects an AI client to Jithox's MCP servers, and checks that the connection is real before you trust it.

Install

npm install -g jithox

Which platforms this is tested on

Honestly, and only from what CI actually runs:

| | how it is tested | | --- | --- | | Linux | the whole suite, plus the packed tarball installed into an empty project | | Windows | the whole suite on windows-latest, plus the packed tarball installed into an empty project and the first journey walked through it. Eighteen tests are skipped there, each naming the POSIX capability Windows lacks (file mode bits, FIFOs, /proc/self/fd, path separators) | | macOS | not tested. No CI lane runs it. It is a POSIX system and is expected to work, but expected is not tested, and this table will say so until a lane exists |

One difference worth knowing about on Windows: O_NOFOLLOW does not exist there, so the kit checks with lstat before it opens. That closes the case that happens — a symbolic link already sitting where one of the kit's own files belongs — but not the race of a link planted in the instant between the check and the open. On Linux the kernel closes both.

First run

jithox init                                  # prepare this machine (no credential, no network)
jithox discover --json                       # what is reachable, and what may it do?
jithox call verify_iban --input '{"iban":"BE68 5390 0754 7034"}'
                                             # ONE real, free tool call — no credential, a receipt
jithox doctor --local --json                 # verify the evidence that real call left behind
jithox test --sandbox --client generic_mcp   # a local simulation — nothing leaves your machine

init writes up to two small local files after showing you exactly what they will contain: ~/.jithox/config.json and an inert sandbox marker, both mode 600 inside a 700 directory. It asks nothing secret, makes no network call, and activates nothing in the cloud. Answering n writes nothing at all. In a script or container, pass --non-interactive — without a terminal to ask, init refuses rather than silently doing nothing.

doctor --local is strict: it passes only for a real connection. Use doctor --local --sandbox to check the local simulation; a sandbox pass is never a cloud connection and never means authenticated.

Undo

init is reversible on the machine, not just in the repository.

jithox init --undo --dry-run     # show exactly what would go; changes nothing
jithox init --undo               # remove it, after showing the list and asking
jithox init --undo --json        # the same, as a machine-readable envelope
jithox init --undo --verify-receipt

It removes only what init itself created, checked by content rather than by name: init records every path it writes with the SHA-256 of the bytes it wrote, and undo deletes a file only when the bytes on disk still match. A config you edited is kept and reported MODIFIED_BY_USER; a file that predates init is kept as NOT_CREATED_BY_INIT. If there is no record, nothing is removed at all — this command will not delete a file it cannot prove it wrote.

auth.json, connection, last-execution.json and receipts/ belong to auth login, connect and test, and are never touched. A symlink, hard link, FIFO or device where a regular file was recorded is refused rather than followed.

The directory itself is never removed. rmdir takes a name in the parent directory, and no descriptor can bind that call to the directory the command validated; when an earlier version lost that race it could re-create only a mode — not the inode, owner, ACLs or extended attributes of what it had just destroyed. So ~/.jithox is left standing even when empty, directoryRemoved and the receipt's directory_removed are always false, and removing the directory is yours to do. The closing message lists what was still in the directory when the command last looked at it; it deliberately does not print a rm -r line, because the path could name a different directory than the one that listing came from.

An empty ~/.jithox that init created keeps its init-manifest.json, listing no files. That file records that init made the directory, and it is what lets you tell init's leftovers from your own.

For the same reason, a leftover temp file (.<name>.jithox-tmp-<pid>-<ts>, from a write that was killed) is kept, not swept, unless the manifest records that exact name and hash. Matching the name, having a dead pid, even opening with the same bytes a Jithox document starts with — none of that identifies the writer, and each of those tests, in turn, deleted a user's file. Anything unproven is reported in kept[] as NOT_PROVEN_OURS and is yours to delete.

Two limits stated plainly. The manifest is bookkeeping, not an authenticated record: anyone who can write it can name a file in it, and the temp-name pattern is what keeps that from reaching arbitrary basenames. And re-reading a file immediately before removing it narrows the window in which it could be swapped — it does not close it, because POSIX offers no unlink-if-unchanged.

kept[].reason is an open set. NOT_PROVEN_OURS was added in 0.2.2, and more values may follow; a program reading --json must treat an unrecognised reason as "kept, for a reason this version does not know" rather than failing.

A real run writes ~/.jithox/undo-receipt.json (mode 600) whose digest anyone can verify, and which a later undo removes in turn. Exit codes: 0 removed or dry run, 2 nothing to undo.

Discovery

jithox discover reads only public sources and needs no login. It lists capabilities; it never installs anything and never calls a discovered tool. Anything a source did not state stays UNKNOWN — a price or a client compatibility is never guessed. If a source cannot be reached, discover says so and exits 2 rather than reporting "no tools".

jithox discover --read-only                      # only capabilities proven not to write
jithox discover --use-case invoice                # filter on real text
jithox discover --config-for <id>                 # a copy-pasteable client config
jithox discover --offline                         # a dated local snapshot only

An online run where every source answered records the result to ~/.jithox/discovery-snapshot.json (mode 600), which is what --offline reads back. An incomplete run never overwrites that file: a source outage would otherwise shrink the offline answer silently. Capabilities read from a snapshot are reported as SNAPSHOT, never as live evidence, and an undated or unparseable snapshot is refused rather than trusted.

The first real call

jithox call <tool> --input '<json>' makes one real tool call over the public endpoint discovery found and writes a receipt. The CLI sends no Authorization header for these requests; what the server checks is its own. It runs discovery itself, online, in the same run: only evidence read now may authorise a free call (a snapshot cannot, so there is no --offline).

Five free examples, also printed by jithox --help. Each line is a separate call; the JSON quoting is for POSIX shells. In Windows PowerShell or cmd, put the JSON in a file and use --input-file, or use field=value pairs for flat inputs (for example, iban=BE68539007547034 after the tool name).

jithox call verify_iban --input '{"iban":"BE68 5390 0754 7034"}'
jithox call check_payment_change --input '{"newIban":"DE89 3704 0044 0532 0130 00","ibanOnFile":"BE68 5390 0754 7034","supplierCountry":"BE"}'
jithox call lookup_peppol_participant --input '{"identifier":"BE0403170701"}'
jithox call check_peppol_ready --input '{"invoiceNumber":"CLI-EXAMPLE-001","issueDate":"2026-10-02","currency":"EUR","buyerReference":"EXAMPLE","supplier":{"name":"Example Supplier","countryCode":"BE","endpointId":"0403170701","endpointScheme":"0208"},"customer":{"name":"Example Customer","countryCode":"BE","endpointId":"0417497106","endpointScheme":"0208"},"lines":[{"description":"Example service","quantity":1,"unitPrice":100,"vatPercent":21}],"documentAllowances":[],"documentCharges":[],"totalWithoutVat":100,"totalVat":21,"totalWithVat":121}'
jithox call preflight_payment --input '{"rail":"invoice_bank","approved":{"amount":"121.00","currency":"EUR","payee":{"name":"Example Supplier","iban":"BE68 5390 0754 7034"}},"payment":{"iban":"BE68 5390 0754 7034","amount":"121.00","currency":"EUR","payeeName":"Example Supplier","supplierCountry":"BE"},"ibanOnFile":"BE68 5390 0754 7034","instructionSource":"human"}'

These are example inputs, not payment instructions or proof that an account belongs to a supplier. The Peppol checks can report unknown or unverified when a register does not answer; a completed call is not a passing check.

Read the result and the receipt from your own run: initialize and tools/list succeeding do not prove the tool ran; only the tools/call step does. Then use jithox doctor --local --json to verify the evidence it left behind.

What it refuses, before the endpoint is touched (discovery has read the public manifest by then; nothing else has been sent): a tool discovery does not know, a tool with any price other than included, a tool the manifest does not declare side-effect free, evidence that is only a snapshot, and an endpoint that is not on the --base origin (https, no port, no userinfo, no query — a look-alike host in a manifest is refused, and a redirect is never followed; "no port" here means "the same origin as --base", so a --base you give with a port is honoured as given). "Free" and "read-only" are the source's declarations; executing the call confirms neither, and the output says so. A refusal exits 3 and writes no execution record, so the record of your last real run is not overwritten. --sandbox and --offline are not modes of this command: they exit 2 with a KitError, like every other invalid invocation (test --sandbox is the simulation).

What the outcome words mean:

| Outcome | Meaning | Exit | |---|---|---| | EXECUTED | initialize, tools/list and the one tools/call all succeeded, the answer parsed as a JSON-RPC 2.0 MCP result whose isError is false or absent (the output says which), and a receipt verifies | 0 | | REFUSED | the gate said no; nothing was called | 3 | | NOT_REACHED | initialize or tools/list did not succeed, or the live endpoint does not list the tool; no tools/call was sent | 4 | | UNKNOWN_RESULT | a tools/call was attempted and the tool answered isError, the answer was unreadable or not a JSON-RPC 2.0 result, the endpoint answered 5xx, the transport failed, or the tool answered without a reported error and the receipt could not be stored. Delivery, execution, effects and cost are unknown; the output says to check first and never to retry blindly (in the last case: repair the evidence store, do not run the call again) | 4 |

The receipt records step names and outcomes only — never your input, the tool's output or a host name — through the same writer test and connect use, so doctor --local reads it and receipt-integrity verifies it. The digest is self-contained: a verified receipt is internally consistent, which catches truncation and accidental edits, not an author who rewrites file and digest together — and it proves nothing about who answered on the wire (TLS to the endpoint is the only trust). The kit never retries a call by itself: one call is one call.

A call through your connection

jithox call never sends a credential, so it cannot reach anything that needs your connection. jithox run <tool> is that route: one tool call through the connection gateway (/api/agent-connection/v1/mcp) — the same authorisation, the same tools and the same rules the website and your MCP client get. Nothing is decided in the kit.

jithox run <tool> [field=value ...] [--input-file <path>] [--input '<json>']
           [--max-cost <minor units>] [--credential-file <path>] [--sandbox] [--json]

What it does, in this order:

  1. The credential. From --credential-file <path> when you give one, otherwise your OAuth login (jithox auth login), otherwise ~/.jithox/connection. It is never accepted as an argument, never printed, and never written to a receipt, a log or --json. No credential: refused before any request, with the next step — create a connection on https://jithox.com/mcp/account ("Connect another device or agent"), save the credential it shows once in a private file, pass --credential-file. A file that does not hold a jxc_live_… credential is never sent anywhere on a guess. --sandbox refuses a production credential, as everywhere else.
  2. Discovery, with the credential. The gateway's discovery document says what this connection may do. An unknown tool, a tool that is not on offer, or a right the connection does not carry is refused before the call. The missing right is named in words and as its scope string. A connection's rights are fixed when it is created, so a missing one takes a new connection with that option ticked; trying again never helps.
  3. Cost is never implicit. When discovery says one attempt can cost money, the call is refused unless you pass --max-cost <minor units> of at least that amount (EUR 0.10 is --max-cost 10). It is a ceiling for one attempt, not an amount to spend. A cost that cannot be read is refused. --yes is refused by the whole kit.
  4. It says what will happen, then calls once. One block: tool, capability, mode (read / prepare / act after a person's approval), the right used, the maximum cost, the endpoint — and, for a tool that acts, discovery's approval rule verbatim. Then exactly one tools/call with an idempotency key made for this attempt. It never retries, and it follows no redirect.
  5. The result: the tool's structured result (redacted), and the gateway's own account of the call — executed (true / false / "uncertain"), what it charged for the call, and its receipt reference.

The quote desk, from the terminal

A connection needs two options that are off by default and are ticked when the connection is created: "Draft quotes, show me the exact e-mail, and ask for my approval" (actions:prepare:quote-desk) and, for the fourth line, "Carry out a send I have approved" (actions:prepare:quote-desk-send).

request.json — the same file works from PowerShell 5.1, cmd.exe and a POSIX shell, because nothing is quoted on the command line:

{
  "customer": { "name": "Peters BV" },
  "lines": [
    { "description": "Painting the living room", "quantity": 2, "unitPrice": 85, "vatPercent": 21 }
  ],
  "quoteDate": "2026-09-18"
}

QUOTE_ID and ACTION_ID are what the step before printed:

jithox run quote_desk_prepare --input-file request.json
jithox run quote_desk_preview_email quoteId=QUOTE_ID [email protected]
jithox run quote_desk_request_approval quoteId=QUOTE_ID
jithox run quote_desk_execute_approved actionId=ACTION_ID --max-cost 10
jithox run quote_desk_status quoteId=QUOTE_ID

Between the third and the fourth line a person approves on https://jithox.com/quote-desk. This command can never approve, and the approval is bound to the exact e-mail (snapshotSha256): change the quote, the recipient or the text and it takes a new preview and a new approval. The fourth line costs at most EUR 0.10 — the call is free; the approved e-mail it carries out is metered — which is why it needs --max-cost 10.

What the fourth line can answer, and what each answer means:

| Outcome | Meaning | Exit | |---|---|---| | SENT | the service reports that the e-mail provider confirmed this send | 0 | | WAITING_FOR_APPROVAL | no person has approved yet; nothing was sent and the provider was not contacted. Run the same command again afterwards (IN_PROGRESS, another delivery of the same e-mail is running, exits 10 as well) | 10 | | REJECTED | the request was rejected or withdrawn; nothing was sent and nothing will be | 11 | | NOT_SENT | confirmed: nothing left, nothing is pending. A new preview and a new approval start again | 12 | | UNCERTAIN | unknown: the message may or may not have left. This command never retries it, and calling again sends nothing. A person settles it on the quote desk (delivered / not delivered) | 13 |

NOT_SENT and UNCERTAIN are different things and are never merged: the first is an answer, the second is the absence of one. About a second e-mail, only what the service itself documents: when a person approves the same e-mail again after an uncertain outcome, the e-mail provider's idempotency key keeps that re-approved send from becoming a second message for 24 hours — not for ever. After that window the provider has forgotten the key, which is why the quote desk asks the owner to check with the customer first.

Exit codes of run

| Exit | Meaning | |---|---| | 0 | the tool answered (a tool that acts after approval: SENT) | | 2 | usage error (KitError): bad input, unreadable --input-file, --offline, a production credential under --sandbox | | 3 | refused before the tool call: no credential (before any request at all), unknown tool, missing right, a cost you did not allow. No execution record is written | | 4 | discovery could not be reached, or the outcome is unknown: 5xx, timeout, an unreadable answer, isError, a tool that did not finish, or HTTP 409 (the key was fresh, so a copy of this request arrived before). Check first; never retry blindly | | 5 | a request was made and the gateway or the tool refused it before anything ran (401, 403, 402, 404, 429, or the tool's own refusal such as package_stale); the reason is printed | | 10–13 | only for a tool whose capability acts after approval — see the table above |

The kit's receipt (~/.jithox/receipts/…, read by doctor --local) records step names and outcomes only — never the input, the output, a recipient, an amount or the credential. The tool's own receipt (quote_desk_status → receipt) is the service's, and what it is worth is stated in discovery.

Rehearse it offline

Add --sandbox to every line. It is a local simulation: nothing leaves the machine, nothing is charged, every line says LOCAL_SIMULATION, quote numbers start with OFF-SBX- and identifiers with sbx_. It needs the sandbox marker jithox init writes, and never takes a real credential. The person who approves is simulated by a tool that exists only there — jithox.com does not know the name, and jithox run without --sandbox refuses it before any call:

jithox run sandbox_person_decides actionId=ACTION_ID decision=approve --sandbox

decision=reject rejects; delivery=not_sent or delivery=uncertain makes the simulated provider answer that way, so every exit code above can be rehearsed. The simulated desk is kept between commands in ~/.jithox/sandbox-state.json (mode 600; simulation data only — delete it whenever you like).

Building from a checkout

If you have the repository instead of the published package:

npm ci
npm --prefix packages/jithox-cli run build
node packages/jithox-cli/dist/cli.js --help

For a checkout whose path contains spaces, quote both paths:

"$(command -v node)" "/path with spaces/jithox/packages/jithox-cli/dist/cli.js" --help

In PowerShell, use the call operator with single-quoted paths:

& 'C:\path with spaces\node.exe' 'C:\path with spaces\jithox\packages\jithox-cli\dist\cli.js' --help

The kit prints recovery, rollback, and next-step commands in the form that suits the copy you are running. From a checkout that is the running Node executable plus the compiled entrypoint, so build first or the referenced dist/cli.js will not exist. From an installed package it is plain jithox <command> — an installed user has no checkout, and a command naming an interpreter path stops working as soon as that path moves (an nvm install plus a version cleanup, a reinstalled runtime, another machine).

Two limits worth knowing. jithox <command> assumes the package's bin is on your PATH; if it is not, use npx jithox <command>, which the help banner also names. And "installed" is decided from whether the running entrypoint sits under a node_modules directory — a heuristic, not a guarantee: a checkout placed under such a directory is treated as installed, and a layout that resolves the entrypoint elsewhere (some pnpm/Yarn PnP setups) is treated as a checkout. Either way the command is still a printed instruction, never something the kit executes for you.

Safe local checks

node packages/jithox-cli/dist/cli.js doctor --sandbox --json
node packages/jithox-cli/dist/cli.js connect --prepare --sandbox --client generic_mcp --json

--sandbox is local simulation only. --prepare writes nothing and does not request a credential. A real connection always shows its plan and waits for an interactive confirmation; OAuth sign-in happens in the selected client or browser, never through a secret passed on the command line.

Checkout workflow

Use the package scripts from this repository:

npm --prefix packages/jithox-cli run build
node packages/jithox-cli/dist/cli.js doctor
node packages/jithox-cli/dist/cli.js connect --prepare --client <client> --json

Supported client ids are claude, claude_desktop, chatgpt, gemini, grok_cursor, generic_mcp, and generic_http.

The CLI never accepts credentials or tokens as command-line arguments. It does not publish, install, purchase, or call a provider during --help, doctor --sandbox, or connect --prepare --sandbox.