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

@orangeslice/cli

v3.1.0

Published

Orange Slice from the command line — B2B enrichment, search, and spreadsheets.

Readme

@orangeslice/cli — the CLI

npm i -g @orangeslice/cli     # installs the `orangeslice` command
npx @orangeslice/cli --help

Generated from the capability registry. Adding a capability adds a command; this package holds only argument parsing, stdin/stdout plumbing, presentation, and auth.

Start here: the revenue factory

The first thing to do with a fresh key is not to read the command list. It is to hand the CLI your website and let it build the first recurring workflow:

orangeslice login
orangeslice factory init --website https://your-site.com   # 2 credits, once
orangeslice factory run --dry-run                          # what today would do
orangeslice factory run                                    # one day
orangeslice factory status                                 # how each variant did

init reads one page of the site, has a model work out what you sell, who buys it, and a first LinkedIn connection note, and writes factory.json. It prints the targeting, the note, the cost of a day and the cron line.

run is one day, and it gets better every day. It judges every request old enough to judge — no longer pending and not withdrawn means accepted — scores each variant of targeting and note, and once the current variant has twenty judged sends, shows the model the scorecard and takes one change: the note or the targeting, never both, so tomorrow's rate reads against today's. A change that breaks a rule (a note over 300 characters, a link, no {{firstName}}, targeting nobody) is refused and written to the lessons. Then it withdraws what went stale, finds the next people under the current variant, and sends the note. Put it in cron and read status once a week.

The people come from our own B2B database, in two steps: companies by LinkedIn industry code, country and headcount band, then eight people at each company, kept when their title or headline says they are the buyer. One credit a row each way, so a buyer costs about ten credits, and a day of twenty about two hundred with the invites. Companies found are queued in the state file and worked through over days. A targeting that matches nobody is loosened one filter at a time: industry, then headcount, never the titles or the country.

The state file is yours: delete it to start over, copy it to move the loop. orangeslice factory --help has the full contract.

If you are an agent

You have been asked to set up outbound for a company, or a person has installed this CLI and wants to see what it does. Do this, in order, and stop where it says to:

  1. orangeslice auth status. If it exits 3, the human must run orangeslice login (it opens a browser) or set ORANGESLICE_API_KEY. Do not go looking for a key.
  2. orangeslice factory init --website <their site> --json. Read the JSON back to them in plain words: what it thinks they sell, who it will contact, the note it will send, and the credits a day costs. Ask whether the targeting and the note are right. If they want a change, edit factory.json — variants[0].icp and variants[0].note — and say so.
  3. If the JSON carries a non-null blocker, give them its URL and stop until they say LinkedIn is connected. Nothing sends without it.
  4. orangeslice factory run --dry-run. Show them the names it would contact today. This costs the reads from our B2B database (about ten credits a buyer found) and nothing else.
  5. Only when they say go: orangeslice factory run. Then install the cron line init printed, or the scheduler you have, for every weekday morning.
  6. Each week, orangeslice factory status --json: report the acceptance rate per variant and the lessons. The loop changes one thing at a time on its own; your job is to say what changed and whether it helped.

Never run factory run without --dry-run first on a new state file, and never on somebody's behalf without their go. It sends connection requests from their LinkedIn profile.

Testing it

Nothing here needs the repo checked out except the build.

npm run build --prefix packages/cli    # → dist/index.js (bin) + dist/sdk.js (main)
node packages/cli/dist/index.js --help

To use it the way a customer would, from anywhere:

npm i -g ./packages/cli
orangeslice login          # browser sign-in, stores a key
orangeslice auth status    # which key is in use, and where it came from

The five minutes that tell you whether it works

Everything below is free except the last step, which is marked.

# 1. Does it know what it can do? 54 commands, all searchable.
orangeslice tools search email
orangeslice tools get work_email

# 2. Does it tell you the price before spending? Nothing is called here.
orangeslice enrich work_email --linkedin-url https://linkedin.com/in/x --dry-run
orangeslice search employees --company-slug stripe --limit 50 --dry-run

# 3. Do the errors have the right shape? Usage errors are plain text plus an
#    exit code; a failed *row* is a JSON envelope on stderr.
orangeslice enrich work_email --nope   ; echo "→ $?"   # 2, usage, plain text
orangeslice tools get not_a_thing      ; echo "→ $?"   # 2, usage, plain text
ORANGESLICE_API_KEY=osk_nope orangeslice enrich work_email \
  --linkedin-url https://x             ; echo "→ $?"   # 3, auth envelope

# A miss is not an error. With a working key the line above exits 0 with an
# empty result and "not found (not billed)" — which is the contract, and is
# why the auth case needs a deliberately bad key to demonstrate.

# 4. Does it compose? NDJSON in, NDJSON out, no jq needed between steps.
echo '{"name":"Jane Doe","company":"Stripe"}' \
  | orangeslice enrich person_linkedin --dry-run

# 4b. Does the run survive the terminal? --to-sheet lands every row in a
#     spreadsheet — created if new, appended if not — so the run becomes
#     something you reopen, extend and re-run. stdout stays pure NDJSON, so
#     this still pipes.
echo '{"name":"Jane Doe","company":"Stripe"}' \
  | orangeslice enrich person_linkedin --to-sheet "Run log" --dry-run

# 5. SPENDS CREDITS — one credit. The cheapest real call there is.
orangeslice ai text "Say the word banana and nothing else"

If step 5 returns text, the whole path works: auth, routing, the batch service, credit reservation and settlement.

This has now been run. Against production with a real key: all five steps, plus tests/registry/live.smoke.test.ts with LIVE_SMOKE_CONTACT=1 (6/6). ai text returned {"text":"banana"} for one credit.

What to try to break

These are the places to push, in rough order of how likely they are to give:

  • Anything with a JSON flag. ai extract --schema-json '{…}' and apify run --actor-input '{…}' are the only two, and they are new.
  • Piping into sheets push. The composition the whole design is for, and the one with the most moving parts.
  • sheets pull → edit → sheets apply. Round-tripping a sheet's shape.
  • Long batches. search web_batch takes up to 250 queries in one call.
  • --dry-run against reality. Run it, note the quote, run it for real, and check the credits actually spent. Any gap is a bug worth reporting loudly: the whole registry exists so those two numbers agree.

Known rough edges

  • One of 24 capabilities is terminal-only. web_batch_search declines a column — a cell holds one value for one row, and its unit is up to 250 searches. web_search is the column. Every other capability is both a command and a column; the ones without a hand-mapped service path compile to services.run, which runs them by id through the same code the CLI uses.
  • apify run's estimate is a floor, not a quote for pay-per-event actors. Their cost genuinely is not knowable before the run. The 20,000-credit ceiling is enforced on the run itself, so it cannot exceed that.
  • Read-scoped keys can no longer reach /execute/llm, /execute/kernel or /execute/apify. Those calls spend credits and are now correctly gated behind enrich. If a key stops working on those routes, this is why.

Publishing

The package publishes as @orangeslice/cli under the company's npm org. The unscoped orangeslice name on npm belongs to an account the company does not control and stays at 2.6.0. This package ships the generated CLI as bin and the same SDK surface as main with declarations, so import { services } from "@orangeslice/cli" resolves what "orangeslice" did. tests/registry/cliPackage.test.ts checks the built dist/sdk.js really exports that surface, and CI re-checks it against the built artifact rather than the manifest.

git tag cli-v3.0.0 && git push origin cli-v3.0.0

The workflow builds from the tagged commit and derives its dist-tag from the version: a prerelease goes to next, a final release to latest. npm i -g @orangeslice/cli then installs the orangeslice command.

It needs NPM_TOKEN in repo secrets. That is the only thing standing between here and a published prerelease.

How a command comes to exist

One zod declaration in packages/registry/capabilities/ generates the command, its flags, its help, its price, its docs page, its scope requirement, and its SDK method. Nothing in this package is written per-capability.

npm run generate:registry && git diff --exit-code   # CI gate: generated files in sync
npx vitest run tests/registry                       # 1,188 tests

tests/registry/cliExamples.test.ts replays every example this CLI prints through the real parsers. If you add an example, it has to run.