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

salesprompter-cli

v0.1.17

Published

JSON-first sales prospecting CLI for ICP definition, lead generation, enrichment, scoring, and CRM/outreach sync.

Readme

salesprompter-cli

salesprompter-cli is a JSON-first command line interface for running a practical sales workflow:

  • Authenticate via Salesprompter app backend
  • Define an ideal customer profile
  • Resolve a target account from a domain
  • Generate seed leads
  • Enrich leads
  • Score leads
  • Sync leads into CRM and outreach systems
  • Analyze upstream lead-list and domain-enrichment bottlenecks
  • Replace opaque Pipedream logic with deterministic CLI workflows

It is built for two users at the same time:

  • humans working in a terminal
  • coding agents such as Codex, Claude Code, and other LLM-driven shell workflows

Start Here

If someone discovers Salesprompter from a vague prompt, give them the shortest working path for their context.

## Human-friendly guided path
npx -y salesprompter-cli@latest

## Explicit guided path
npx -y salesprompter-cli@latest wizard

## Raw command surface for agents and scripts
npx salesprompter-cli@latest --help

Or install it globally:

npm install -g salesprompter-cli
salesprompter
salesprompter wizard
salesprompter --help

Bare salesprompter now opens a guided wizard in an interactive terminal. Keep using explicit subcommands for agents, CI, and copy-paste docs. If your Salesprompter user belongs to multiple organizations, browser login asks which organization the CLI session should use.

Prompt To Command

If the user says something like "I need to determine the ICP of deel.com", there are two different meanings.

1. They want leads at Deel itself

This means Deel is the target account.

salesprompter account:resolve --domain deel.com --company-name Deel --out ./data/deel-account.json
salesprompter leads:generate --icp ./data/icp.json --count 5 --domain deel.com --company-name Deel --out ./data/deel-leads.json

2. They sell for Deel and need Deel's ideal customer profile

This means Deel is the vendor, not the target account.

salesprompter icp:vendor --vendor deel --market dach --out ./data/deel-icp.json
salesprompter leads:lookup:bq --icp ./data/deel-icp.json --limit 100 --execute --out ./data/deel-leads-raw.json --lead-out ./data/deel-leads.json
salesprompter leads:enrich --in ./data/deel-leads.json --out ./data/deel-enriched.json
salesprompter leads:score --icp ./data/deel-icp.json --in ./data/deel-enriched.json --out ./data/deel-scored.json

3. They want the LLM to call the CLI directly

Use the same commands, but prefer machine-readable output:

salesprompter --json icp:vendor --vendor deel --market dach
salesprompter --json icp:vendor --vendor deel --market dach --out ./data/deel-icp.json
salesprompter --json leads:lookup:bq --icp ./data/deel-icp.json --limit 100 --lead-out ./data/deel-leads.json

Documentation

This repository now includes the public Salesprompter docs site for the wider Salesprompter universe, including the app contract, CLI surface, Chrome extension contract, and the main warehouse-backed workflows.

  • Live docs: https://salesprompter-cli.vercel.app

  • Docs home: ./index.mdx

  • Quickstart: ./quickstart.mdx

  • Architecture: ./architecture.mdx

  • App: ./platform/app.mdx

  • CLI: ./platform/cli.mdx

  • Chrome extension: ./platform/chrome-extension.mdx

  • Domain finder: ./workflows/domain-finder.mdx

  • Command reference: ./reference/cli.mdx

  • Environment variables: ./reference/environment-variables.mdx

  • Troubleshooting: ./operations/troubleshooting.mdx

Run the docs locally with:

npm run docs:dev

Build the deployable static docs site with:

npm run build:docs:site

Integration Contract

This CLI is not a standalone toy. It is a production integration surface for the Salesprompter app.

  • The Domain Finder flow in this repository is a real end-to-end test case for Salesprompter app integration.
  • CLI behavior should be treated as an app contract: auth, BigQuery execution, artifacts, and writeback semantics must remain stable.
  • Changes to domain selection, writeback, or audit logic should always be validated with:
    • CLI tests (npm test)
    • BigQuery-backed runs (domainfinder:run:bq, domainfinder:audit-existing:bq)
    • before/after delta checks (domainfinder:audit-delta)

The current version is account-first. It resolves a company from a domain, then generates contacts for that account through provider interfaces. The default providers are still fallback heuristics, but the JSON contracts are now stable for real company and people-data integrations.

When the output mode is fallback, the leads are modeled contacts for workflow testing, not verified real contacts. A real provider path should return mode: "real" using the same JSON shape.

All non-auth commands require a logged-in CLI session. This gives you one identity model across Salesprompter app, CLI, and Chrome extension.

Global output flags:

  • --json: compact machine-readable JSON (optimized for agent/LLM parsers)
  • --quiet: suppress successful stdout payloads (errors still surface)

Auth and Session

The CLI stores a local session file at ~/.config/salesprompter/auth-session.json (or SALESPROMPTER_CONFIG_DIR).

# Preferred path: browser/device login
salesprompter auth:login

# Fallback path: generate a short-lived CLI token in the Salesprompter app
salesprompter auth:login --token "$SALESPROMPTER_TOKEN" --api-url "https://salesprompter.ai"

# Verify active identity with backend
salesprompter auth:whoami --verify

# Clear local session
salesprompter auth:logout

If your user belongs to multiple organizations, the browser flow asks you to choose the organization for that CLI session before returning to the terminal.

Environment variables:

  • SALESPROMPTER_API_BASE_URL: override backend URL (default https://salesprompter.ai)
  • SALESPROMPTER_CONFIG_DIR: override local config dir
  • SALESPROMPTER_SKIP_AUTH=1: bypass auth guard (tests/dev only)
  • INSTANTLY_API_KEY: required for real sync:outreach --target instantly
  • INSTANTLY_CAMPAIGN_ID: default campaign id for Instantly sync
  • SALESPROMPTER_INSTANTLY_BASE_URL: override Instantly API base URL (tests/local proxies)

App compatibility:

  • Salesprompter app should expose /api/cli/auth/device/start, /api/cli/auth/device/poll, and /api/cli/auth/me.
  • salesprompter auth:login uses browser/device login and prints the verification URL plus code before polling.
  • POST /api/cli/auth/token remains the fallback path when browser/device login is disabled or unavailable.

Fallback command:

salesprompter auth:login --token "<token-from-app>" --api-url "https://salesprompter.ai"

Why this shape works for humans and LLMs

  • Every command reads and writes plain JSON.
  • Output is machine-readable and composable (--json for compact transport).
  • The top-level use cases map ambiguous prompts like "determine the ICP of deel.com" into explicit command paths.
  • Domain contracts are explicit and validated with zod.
  • External integrations are behind narrow provider interfaces.
  • Lead generation reports which provider and mode produced the result.
  • Workflow bottlenecks become inspectable artifacts instead of hidden Pipedream state.
  • Real prospect lookup can be normalized straight into the CLI lead schema with --lead-out.

Commands

salesprompter icp:define --name "EU SaaS RevOps" \
  --description "RevOps and sales leaders in European growth-stage software companies" \
  --industries "Software,Financial Services" \
  --company-sizes "50-199,200-499" \
  --regions "Europe" \
  --countries "DE,NL,GB" \
  --titles "Head of Revenue Operations,VP Sales" \
  --required-signals "recent funding,growing outbound team" \
  --keywords "revenue operations,outbound,sales tooling" \
  --out ./data/icp.json

salesprompter auth:login
salesprompter auth:whoami --verify
salesprompter icp:vendor --vendor deel --market dach --out ./data/deel-icp.json
salesprompter leads:lookup:bq --icp ./data/deel-icp.json --limit 100 --execute --out ./data/deel-leads-raw.json --lead-out ./data/deel-leads.json
salesprompter leads:enrich --in ./data/deel-leads.json --out ./data/deel-enriched.json
salesprompter leads:score --icp ./data/deel-icp.json --in ./data/deel-enriched.json --out ./data/deel-scored.json
salesprompter sync:outreach --target instantly --in ./data/deel-scored.json --campaign-id "$INSTANTLY_CAMPAIGN_ID"
salesprompter sync:outreach --target instantly --in ./data/deel-scored.json --campaign-id "$INSTANTLY_CAMPAIGN_ID" --apply
salesprompter icp:from-historical-queries:bq --vendor deel --market dach --out ./data/deel-icp-historical.json --report-out ./data/deel-historical-report.json
salesprompter leadlists:funnel:bq --vendor deel --market dach --out ./data/deel-leadlists-funnel.json
salesprompter domainfinder:backlog:bq --market dach --out ./data/deel-domainfinder-backlog.json
salesprompter domainfinder:candidates:bq --market dach --limit 500 --out ./data/domain-candidates.json --sql-out ./data/domain-candidates.sql
salesprompter domainfinder:input-sql --market dach --out ./data/domainFinder_input_v2.sql
salesprompter domainfinder:select --in ./data/domain-candidates.json --out ./data/domain-decisions.json
salesprompter domainfinder:audit --in ./data/domain-decisions.json --out ./data/domain-audit.json
salesprompter domainfinder:compare-pipedream --in ./data/domain-candidates.json --out ./data/domain-comparison.json
salesprompter domainfinder:audit-existing:bq --market dach --out ./data/domain-existing-audit.json
salesprompter domainfinder:audit-delta --before ./data/domain-existing-audit-before.json --after ./data/domain-existing-audit-after.json --out ./data/domain-existing-audit-delta.json
salesprompter domainfinder:repair-existing:bq --market dach --mode conservative --limit 5000 --out ./data/domain-repair.sql --trace-id salesprompter-cli-repair-dach
salesprompter domainfinder:writeback-sql --in ./data/domain-decisions.json --out ./data/domain-writeback.sql --trace-id salesprompter-cli-dach-20260308
salesprompter domainfinder:writeback:bq --in ./data/domain-decisions.json --out ./data/domain-writeback.sql --trace-id salesprompter-cli-dach-20260308
salesprompter domainfinder:run:bq --market dach --limit 500 --out-dir ./data/domainfinder-run --trace-id salesprompter-cli-dach-20260308
salesprompter account:resolve --domain deel.com --company-name Deel --out ./data/deel-account.json
salesprompter leads:generate --icp ./data/icp.json --count 5 --out ./data/leads.json
salesprompter leads:generate --icp ./data/icp.json --count 5 --domain deel.com --company-name Deel --out ./data/deel-leads.json
salesprompter leads:enrich --in ./data/leads.json --out ./data/enriched.json
salesprompter leads:score --icp ./data/icp.json --in ./data/enriched.json --out ./data/scored.json
salesprompter leads:lookup:bq --icp ./data/deel-icp.json --limit 100
salesprompter queries:analyze:bq --search-kind sales-people --include-function "Human Resources" --out ./data/hr-query-report.json
salesprompter sync:crm --target hubspot --in ./data/scored.json
salesprompter sync:outreach --target instantly --in ./data/scored.json

Domain Finder Migration

The original Pipedream domainFinder workflow was doing three things:

  1. fetch a small input set from BigQuery
  2. ask OpenAI / Hunter for candidate domains
  3. pick a domain and write it back

The CLI now models that logic directly and improves it:

  • domainfinder:backlog:bq measures whether the backlog is being starved before enrichment
  • domainfinder:candidates:bq fetches real candidate rows from BigQuery for backlog companies
  • domainfinder:input-sql generates a replacement input view driven by linkedin_companies, not leadPool_new
  • domainfinder:select applies deterministic domain selection rules
  • domainfinder:audit turns decisions into a review queue and writeback summary
  • domainfinder:compare-pipedream quantifies how often the old selector would disagree with the improved selector
  • domainfinder:audit-existing:bq measures current warehouse-visible mismatches and bad chosen domains
  • domainfinder:audit-delta compares two audit snapshots and reports metric deltas
  • domainfinder:repair-existing:bq generates (and optionally executes) targeted repair writes with selectable mode:
    • conservative: only missing/blacklisted chosen domains
    • aggressive: missing/blacklisted plus all mismatches
    • mismatch-only: only mismatched chosen domains
  • domainfinder:writeback-sql emits conservative SQL for domainFinder_output
  • domainfinder:writeback:bq can execute that writeback in BigQuery when explicitly asked
  • domainfinder:run:bq runs the full candidate -> decision -> audit -> writeback pipeline and stores all artifacts

Improved selection policy:

  1. prefer domain_linkedin when present and not blacklisted
  2. otherwise prefer website_linkedin root domain when present and not blacklisted
  3. otherwise choose the non-blacklisted candidate with the highest Hunter email count
  4. otherwise fall back to the first non-null candidate

This removes the earlier failure mode where OpenAI or Hunter could override a good LinkedIn domain purely because of a higher Hunter count.

Writeback policy:

  • write to SalesPrompter.domainFinder_output, which is the source feeding linkedin_companies.domain
  • exclude no-domain decisions
  • exclude blacklisted domains from generated writeback SQL
  • preserve batch provenance through trace_id

Development

npm install
npm run build
node ./dist/cli.js --help
npm test

BigQuery project selection:

  • The CLI runs bq query with --project_id from BQ_PROJECT_ID.
  • Fallback order: BQ_PROJECT_ID -> GOOGLE_CLOUD_PROJECT -> GCLOUD_PROJECT -> icpidentifier.

Real Deel Flow

For Deel as the vendor you sell for, do not use --domain deel.com. That path targets contacts at Deel itself.

Use this path instead:

  1. salesprompter icp:vendor --vendor deel --market dach --out ./data/deel-icp.json
  2. salesprompter leads:lookup:bq --icp ./data/deel-icp.json --limit 100 --execute --out ./data/deel-leads-raw.json --lead-out ./data/deel-leads.json
  3. salesprompter leads:enrich --in ./data/deel-leads.json --out ./data/deel-enriched.json
  4. salesprompter leads:score --icp ./data/deel-icp.json --in ./data/deel-enriched.json --out ./data/deel-scored.json
  5. salesprompter sync:outreach --target instantly --in ./data/deel-scored.json --campaign-id "$INSTANTLY_CAMPAIGN_ID"
  6. Add --apply only when the dry-run output looks correct.

Next integrations

  • Replace HeuristicCompanyProvider with a real account lookup provider.
  • Replace HeuristicPeopleSearchProvider with Apollo, Clay, LinkedIn, or custom people-data providers.
  • Replace HeuristicEnrichmentProvider with enrichment APIs such as Clearbit, FullEnrich, or custom LLM workflows.
  • Replace DryRunSyncProvider with real HubSpot, Salesforce, Pipedrive, Instantly, Apollo, or Outreach clients.
  • Add provider selection and credentials for a first real --domain deel.com workflow.
  • Replace configurable bq field mapping with a typed adapter per warehouse schema.
  • Add a real candidate-fetch command that reads domain candidates from BigQuery and feeds them into domainfinder:select.