argorant 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -2
- package/bin/argorant.js +135 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,8 +34,11 @@ CI, and agents.
|
|
|
34
34
|
| `company <company.com> -n 5` | Count people at a company, split business-email coverage, preview masked roles | free |
|
|
35
35
|
| `search "<query>" -n 10` | Preview matches (masked identity, details redacted) | free |
|
|
36
36
|
| `sample <company.com> [-o sample.csv]` | Read a website and build 25 distinct, live-valid company leads from it | free sample |
|
|
37
|
-
| `reveal "<query>" -n 25` | Reveal full contact details (name, email,
|
|
38
|
-
| `
|
|
37
|
+
| `reveal "<query>" -n 25` | Reveal full contact details (name, work email, LinkedIn) | 1 credit per new working email |
|
|
38
|
+
| `reveal "<query>" -n 25 --phones` | Same, plus each person's phone number (direct dial or mobile) | + 10 credits per number found |
|
|
39
|
+
| `enrich --email <a@b.com> [--phones]` | The person behind an address, optionally with their phone number | 1 credit per match, + 10 if a number is found |
|
|
40
|
+
| `export "<query>" -n 1000 -o leads.csv` | Verified CSV export, polled until ready | 1 credit per working email |
|
|
41
|
+
| `export "<query>" -n 1000 --phones -o leads.csv` | Same, with phone numbers in the file | + 10 credits per number in the file |
|
|
39
42
|
| `export status <job_id> [--batch]` | Status of an export you already created | free |
|
|
40
43
|
| `export download <job_id> [--batch] -o leads.csv` | Re-download a finished export | free |
|
|
41
44
|
| `list create --name "<n>" [filters]` | Save a reusable filtered list (server counts it) | free |
|
|
@@ -45,6 +48,20 @@ CI, and agents.
|
|
|
45
48
|
| `find status \| download \| resume \| cancel <job_id>`, `find pricing` | Manage a find job; show prices, balance and limits | free |
|
|
46
49
|
| `campaigns …` | Live outbound campaigns - **operator keys only**, see below | - |
|
|
47
50
|
|
|
51
|
+
## Phone numbers
|
|
52
|
+
|
|
53
|
+
Phone numbers are never included unless you ask for them with `--phones` (reveal, enrich, export).
|
|
54
|
+
A phone number costs 10 credits, and only when a number is actually returned. People without a number
|
|
55
|
+
cost nothing, and numbers you already unlocked (in the app, the API or the connector) are free. Phone
|
|
56
|
+
numbers come with the Pro plan and higher. The CLI shows the price before it spends anything, and the
|
|
57
|
+
result says per person whether a number came back and what it cost. Company and HQ numbers stay free.
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
npx argorant reveal --title CFO --domain stripe.com -n 5 --phones
|
|
61
|
+
npx argorant enrich --email patrick@stripe.com --phones --json
|
|
62
|
+
npx argorant export --title CFO --country Germany -n 200 --phones -o cfos.csv
|
|
63
|
+
```
|
|
64
|
+
|
|
48
65
|
Exports above 50,000 rows are created as a multi-chunk batch: the CLI polls
|
|
49
66
|
`export status --batch` for you and writes one file per chunk
|
|
50
67
|
(`leads-part1.csv`, `leads-part2.csv`, …). The batch id is printed so you can
|
package/bin/argorant.js
CHANGED
|
@@ -146,7 +146,7 @@ function parseLimit(raw, flag) {
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
function parseArgs(argv) {
|
|
149
|
-
const out = { _: [], filters: {}, limit: null, output: null, file: null, column: null, json: false, yes: false, base: DEFAULT_BASE, baseExplicit: false, batch: false, name: null, includeExported: false, grade: "valid", gradeExplicit: false };
|
|
149
|
+
const out = { _: [], filters: {}, limit: null, output: null, file: null, column: null, json: false, yes: false, base: DEFAULT_BASE, baseExplicit: false, batch: false, name: null, includeExported: false, grade: "valid", gradeExplicit: false, phones: false };
|
|
150
150
|
for (let i = 0; i < argv.length; i++) {
|
|
151
151
|
const a = argv[i];
|
|
152
152
|
if (a === "--json") out.json = true;
|
|
@@ -158,6 +158,9 @@ function parseArgs(argv) {
|
|
|
158
158
|
else if (a === "--base") { out.base = flagValue(argv, i++, a); out.baseExplicit = true; }
|
|
159
159
|
else if (a === "--name") out.name = flagValue(argv, i++, a);
|
|
160
160
|
else if (a === "--include-exported") out.includeExported = true;
|
|
161
|
+
// Phone numbers are opt-in on every surface (2026-10-07): only with --phones, 10 credits per
|
|
162
|
+
// number actually returned, nothing when none is found or the account already has it.
|
|
163
|
+
else if (a === "--phones" || a === "--include-phones") out.phones = true;
|
|
161
164
|
else if (a === "--batch") out.batch = true;
|
|
162
165
|
else if (a === "--grade") setGrade(out, flagValue(argv, i++, a));
|
|
163
166
|
else if (a in VALUE_FLAGS) out.filters[VALUE_FLAGS[a]] = flagValue(argv, i++, a);
|
|
@@ -554,22 +557,106 @@ async function cmdSample(args) {
|
|
|
554
557
|
console.log(dim(`These 25 are the sample; the full pool contains ${Number(job.total_companies || 0).toLocaleString()} companies.`));
|
|
555
558
|
}
|
|
556
559
|
|
|
560
|
+
// ---- phone numbers (opt-in, --phones) ----
|
|
561
|
+
const PHONE_FIELDS = ["phone", "phone_1", "phone_2", "phones_all", "additional_phones", "phone_masked"];
|
|
562
|
+
function stripPhones(rec) {
|
|
563
|
+
if (rec && typeof rec === "object") for (const k of PHONE_FIELDS) delete rec[k];
|
|
564
|
+
return rec;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// The price and whether the plan includes phone numbers, before anything is spent. An older server
|
|
568
|
+
// without the pricing route falls back to the published price.
|
|
569
|
+
async function phonePricing(args, key) {
|
|
570
|
+
try {
|
|
571
|
+
const res = await request("GET", args.base, "/api/v1/people/phones/pricing", { key });
|
|
572
|
+
if (res.status === 200 && res.json) return res.json;
|
|
573
|
+
} catch {
|
|
574
|
+
/* fall back below */
|
|
575
|
+
}
|
|
576
|
+
return { price_per_phone: 10, plan_includes_phones: null };
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
function phonePriceText(pricing) {
|
|
580
|
+
const price = Number((pricing && pricing.price_per_phone) || 10);
|
|
581
|
+
return `Phone numbers cost ${price} credits each, only when a number is found. Numbers you already have are free.`;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// Phone numbers for people already revealed (POST /api/v1/people/phones). A refusal never undoes the
|
|
585
|
+
// emails that were just revealed: it comes back as {included:false, message}.
|
|
586
|
+
async function addPhones(args, key, records) {
|
|
587
|
+
const ids = [];
|
|
588
|
+
for (const r of records) {
|
|
589
|
+
const id = String(r.person_id || r.record_id || "").trim();
|
|
590
|
+
if (id && !ids.includes(id)) ids.push(id);
|
|
591
|
+
}
|
|
592
|
+
records.forEach(stripPhones);
|
|
593
|
+
if (!ids.length) return { included: true, phones_returned: 0, credits_charged: 0, summary: "No people to look up phone numbers for, so nothing was charged." };
|
|
594
|
+
const res = await request("POST", args.base, "/api/v1/people/phones", {
|
|
595
|
+
key,
|
|
596
|
+
body: { record_ids: ids.slice(0, 100), channel: "cli" },
|
|
597
|
+
headers: { "X-Argorant-Channel": "cli" },
|
|
598
|
+
});
|
|
599
|
+
if (res.status !== 200 || !res.json) {
|
|
600
|
+
const detail = res.json && res.json.detail;
|
|
601
|
+
const code = detail && typeof detail === "object" ? detail.error : null;
|
|
602
|
+
let message = detailMsg(detail) || `phone numbers failed (HTTP ${res.status}).`;
|
|
603
|
+
if (code === "phones_not_in_plan") message = "Your plan does not include phone numbers, so none were added and nothing was charged for them.";
|
|
604
|
+
else if (code === "insufficient_credits") message = "Not enough credits for a phone number, so none were added and nothing was charged for them.";
|
|
605
|
+
else if (code === "mcp_quota_exceeded") message = "Today's reveal limit is used up, so no phone numbers were added. It resets at midnight UTC.";
|
|
606
|
+
for (const r of records) r.phone_status = "not_added";
|
|
607
|
+
return { included: false, status: res.status, error: code || "error", message, summary: message };
|
|
608
|
+
}
|
|
609
|
+
const byId = new Map((res.json.results || []).map((row) => [String(row.record_id), row]));
|
|
610
|
+
for (const r of records) {
|
|
611
|
+
const row = byId.get(String(r.person_id || r.record_id || "")) || {};
|
|
612
|
+
r.phone = row.phone || null;
|
|
613
|
+
if (row.additional_phones && row.additional_phones.length) r.additional_phones = row.additional_phones;
|
|
614
|
+
r.phone_status = row.phone_status || "not_found";
|
|
615
|
+
r.phone_credits_charged = Number(row.credits_charged || 0);
|
|
616
|
+
}
|
|
617
|
+
return { included: true, ...res.json, results: undefined };
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
function phoneLine(p) {
|
|
621
|
+
if (!p || !p.phone_status) return null;
|
|
622
|
+
if (p.phone) {
|
|
623
|
+
const extra = p.additional_phones && p.additional_phones.length ? dim(` (+${p.additional_phones.length} more)`) : "";
|
|
624
|
+
const cost = p.phone_credits_charged ? dim(` · ${p.phone_credits_charged} credits`) : p.phone_status === "already_unlocked" ? dim(" · already yours") : "";
|
|
625
|
+
return `${p.phone}${extra}${cost}`;
|
|
626
|
+
}
|
|
627
|
+
if (p.phone_status === "none_found" || p.phone_status === "not_found") return dim("no phone number on record · not charged");
|
|
628
|
+
if (p.phone_status === "not_enough_credits") return dim("phone not added · not enough credits");
|
|
629
|
+
if (p.phone_status === "not_in_plan") return dim("phone not added · not in your plan");
|
|
630
|
+
if (p.phone_status === "daily_limit_reached") return dim("phone not added · daily limit reached");
|
|
631
|
+
return null;
|
|
632
|
+
}
|
|
633
|
+
|
|
557
634
|
async function cmdReveal(args) {
|
|
558
635
|
const key = requireKey();
|
|
559
636
|
warnExcludeTitleGap(args.filters);
|
|
560
637
|
if (args.gradeExplicit) warnGradeGap("reveal");
|
|
561
638
|
const limit = args.limit || 10;
|
|
639
|
+
const pricing = args.phones ? await phonePricing(args, key) : null;
|
|
640
|
+
if (pricing && pricing.plan_includes_phones === false) {
|
|
641
|
+
warn("Your plan does not include phone numbers. Emails are revealed as usual; no phone numbers will be added or charged.");
|
|
642
|
+
}
|
|
562
643
|
// Confirmation is interactive-only by design: with --yes, --json, or a
|
|
563
644
|
// non-TTY stdin (CI, agents, pipes) this spends credits with no prompt.
|
|
564
645
|
if (!args.yes && !args.json && process.stdin.isTTY) {
|
|
565
|
-
const
|
|
646
|
+
const phonesText = args.phones ? ` ${phonePriceText(pricing)}` : "";
|
|
647
|
+
const ans = await prompt(`Reveal up to ${bold(limit)} contacts${args.phones ? " with phone numbers" : ""}? Each new working email costs 1 credit.${phonesText} [y/N] `);
|
|
566
648
|
if (!/^y(es)?$/i.test(ans)) return console.log(dim("aborted."));
|
|
649
|
+
} else if (args.phones && !args.json) {
|
|
650
|
+
process.stderr.write(dim(phonePriceText(pricing) + "\n"));
|
|
567
651
|
}
|
|
568
652
|
// Sent for forward-compatibility: the platform has no per-request grade
|
|
569
653
|
// control on reveal yet (see GODMODE-PLAN.md), so this is a no-op today.
|
|
570
654
|
const query = { ...args.filters, limit, grade: args.grade === "valid-plus-catchall" ? "valid_plus_catchall" : "valid" };
|
|
571
655
|
const res = await request("GET", args.base, "/api/mcp/people/reveal", { key, query });
|
|
572
656
|
const r = need(res, "reveal");
|
|
657
|
+
const people = (r.results || []).filter((x) => x && typeof x === "object");
|
|
658
|
+
if (args.phones && people.length) r.phones = await addPhones(args, key, people);
|
|
659
|
+
else people.forEach(stripPhones);
|
|
573
660
|
if (args.json) return console.log(JSON.stringify(r, null, 2));
|
|
574
661
|
console.log(dim(`${Number(r.total).toLocaleString()} total · revealed ${r.returned}`));
|
|
575
662
|
for (const p of r.results || []) {
|
|
@@ -578,8 +665,16 @@ async function cmdReveal(args) {
|
|
|
578
665
|
const name = p.full_name || [p.first_name, p.last_name].filter(Boolean).join(" ") || p.name;
|
|
579
666
|
const who = [name, p.title].filter(Boolean).join(" · ");
|
|
580
667
|
console.log(` ${bold(who || "-")}`);
|
|
581
|
-
const bits = [p.email && cyan(p.email), p.
|
|
668
|
+
const bits = [p.email && cyan(p.email), p.linkedin_url, [p.company || p.company_name, p.country].filter(Boolean).join(", ")].filter(Boolean);
|
|
582
669
|
if (bits.length) console.log(" " + bits.join(dim(" · ")));
|
|
670
|
+
const phone = args.phones ? phoneLine(p) : null;
|
|
671
|
+
if (phone) console.log(" " + phone);
|
|
672
|
+
}
|
|
673
|
+
const charged = Number(r.charged || 0);
|
|
674
|
+
console.log(dim(`${charged} credit${charged === 1 ? "" : "s"} charged for emails`));
|
|
675
|
+
if (r.phones) {
|
|
676
|
+
if (r.phones.included) console.log(dim(r.phones.summary || `${r.phones.credits_charged || 0} credits charged for phone numbers`));
|
|
677
|
+
else warn(r.phones.message || "No phone numbers were added.");
|
|
583
678
|
}
|
|
584
679
|
}
|
|
585
680
|
|
|
@@ -622,16 +717,30 @@ async function cmdEnrich(args) {
|
|
|
622
717
|
else if (name) { body.name = name; body.domain = domain; }
|
|
623
718
|
else body.domain = domain;
|
|
624
719
|
const personMode = Boolean(body.email || body.name);
|
|
720
|
+
if (args.phones && !personMode) warn("Phone numbers are for people. A company lookup returns the company profile only.");
|
|
721
|
+
const wantPhones = args.phones && personMode;
|
|
722
|
+
const pricing = wantPhones ? await phonePricing(args, key) : null;
|
|
723
|
+
if (pricing && pricing.plan_includes_phones === false) {
|
|
724
|
+
warn("Your plan does not include phone numbers. The email lookup runs as usual; no phone number will be added or charged.");
|
|
725
|
+
}
|
|
625
726
|
// Company mode is free, so it never asks. Person mode is billed exactly like
|
|
626
727
|
// a reveal, so it gets the same interactive-only confirmation as `reveal`.
|
|
627
728
|
if (personMode && !args.yes && !args.json && process.stdin.isTTY) {
|
|
628
729
|
const ans = await prompt(
|
|
629
|
-
`Enrich this contact? A match costs 1 credit; a miss and a non-deliverable address are free
|
|
730
|
+
`Enrich this contact? A match costs 1 credit; a miss and a non-deliverable address are free.` +
|
|
731
|
+
(wantPhones ? ` ${phonePriceText(pricing)}` : "") + ` [y/N] `
|
|
630
732
|
);
|
|
631
733
|
if (!/^y(es)?$/i.test(ans)) return console.log(dim("aborted."));
|
|
734
|
+
} else if (wantPhones && !args.json) {
|
|
735
|
+
process.stderr.write(dim(phonePriceText(pricing) + "\n"));
|
|
632
736
|
}
|
|
633
737
|
const res = await request("POST", args.base, "/api/v1/enrich", { key, body });
|
|
634
738
|
const r = need(res, "enrich");
|
|
739
|
+
if (r && r.type === "person" && r.person && typeof r.person === "object") {
|
|
740
|
+
if (!r.person.person_id && r.person_id) r.person.person_id = r.person_id;
|
|
741
|
+
if (wantPhones && r.found) r.phones = await addPhones(args, key, [r.person]);
|
|
742
|
+
else stripPhones(r.person);
|
|
743
|
+
}
|
|
635
744
|
if (args.json) {
|
|
636
745
|
console.log(JSON.stringify(r, null, 2));
|
|
637
746
|
if (!r.found) process.exit(EXIT.ERROR);
|
|
@@ -656,11 +765,13 @@ async function cmdEnrich(args) {
|
|
|
656
765
|
console.log(` ${bold(who || "-")}`);
|
|
657
766
|
const bits = [
|
|
658
767
|
p.email && cyan(p.email),
|
|
659
|
-
p.phone,
|
|
660
768
|
p.linkedin_url,
|
|
661
769
|
[p.current_company_name, p.current_company_domain, p.country].filter(Boolean).join(", "),
|
|
662
770
|
].filter(Boolean);
|
|
663
771
|
if (bits.length) console.log(" " + bits.join(dim(" · ")));
|
|
772
|
+
const phone = wantPhones ? phoneLine(p) : null;
|
|
773
|
+
if (phone) console.log(" " + phone);
|
|
774
|
+
if (r.phones && !r.phones.included) warn(r.phones.message || "No phone number was added.");
|
|
664
775
|
if (r.deliverable === false) {
|
|
665
776
|
console.log(" " + dim(r.message || "This address did not pass live verification, so nothing was charged."));
|
|
666
777
|
}
|
|
@@ -791,9 +902,18 @@ async function cmdExport(args) {
|
|
|
791
902
|
const dest = ensureWritable(args.output || "argorant-leads.csv");
|
|
792
903
|
// Confirmation is interactive-only by design: with --yes, --json, or a
|
|
793
904
|
// non-TTY stdin (CI, agents, pipes) this spends credits with no prompt.
|
|
905
|
+
const pricing = args.phones ? await phonePricing(args, key) : null;
|
|
906
|
+
if (pricing && pricing.plan_includes_phones === false) {
|
|
907
|
+
die("Your plan does not include phone numbers. Run the export without --phones.", EXIT.UPGRADE);
|
|
908
|
+
}
|
|
794
909
|
if (!args.yes && !args.json && process.stdin.isTTY) {
|
|
795
|
-
const
|
|
910
|
+
const phonesText = args.phones
|
|
911
|
+
? ` Phone numbers are included. Each number in the file costs ${Number((pricing && pricing.price_per_phone) || 10)} more credits, and people without one cost nothing extra.`
|
|
912
|
+
: "";
|
|
913
|
+
const ans = await prompt(`Export up to ${bold(limit)} verified contacts to ${bold(dest)}? Each person with a working email costs 1 credit.${phonesText} [y/N] `);
|
|
796
914
|
if (!/^y(es)?$/i.test(ans)) return console.log(dim("aborted."));
|
|
915
|
+
} else if (args.phones && !args.json) {
|
|
916
|
+
process.stderr.write(dim(`Phone numbers are included. Each number in the file costs ${Number((pricing && pricing.price_per_phone) || 10)} more credits.\n`));
|
|
797
917
|
}
|
|
798
918
|
// Match the MCP/app defaults so the CLI yields the same rows: business email
|
|
799
919
|
// present by default, and skip rows already exported (override with
|
|
@@ -808,7 +928,7 @@ async function cmdExport(args) {
|
|
|
808
928
|
const grades = args.grade === "valid-plus-catchall" ? ["valid", "catch_all"] : ["valid"];
|
|
809
929
|
const create = await request("POST", args.base, "/api/mcp/exports/create", {
|
|
810
930
|
key,
|
|
811
|
-
body: { limit, filters: exportFilters, exclude_previously_exported: !args.includeExported, grades },
|
|
931
|
+
body: { limit, filters: exportFilters, exclude_previously_exported: !args.includeExported, grades, ...(args.phones ? { include_phones: true } : {}) },
|
|
812
932
|
});
|
|
813
933
|
const job = need(create, "export");
|
|
814
934
|
// >EXPORT_MAX_ROWS (50k) → a multi-chunk batch, a different status endpoint
|
|
@@ -2386,10 +2506,13 @@ ${bold("COMMANDS")}
|
|
|
2386
2506
|
${cyan("search")} "<query>" -n 10 Preview matches, details redacted ${dim("(0 contact credits)")}
|
|
2387
2507
|
${cyan("sample")} <company.com> Build 25 distinct, live-valid company leads ${dim("(free sample)")}
|
|
2388
2508
|
${cyan("reveal")} "<query>" -n 25 Reveal full contact details ${dim("(uses credits; live-verified, pay only for deliverable)")}
|
|
2509
|
+
${cyan("reveal")} ... --phones Also add phone numbers ${dim("(10 credits per number found; none found = free)")}
|
|
2389
2510
|
${cyan("enrich")} --email <a@b.com> One address → the full person profile ${dim("(1 credit per match; miss = free)")}
|
|
2390
2511
|
${cyan("enrich")} --name "<n>" --domain <d> Find that person + reveal a verified email ${dim("(1 credit per match)")}
|
|
2391
2512
|
${cyan("enrich")} --domain <d> Company profile ${dim("(0 contact credits)")}
|
|
2513
|
+
${cyan("enrich")} ... --phones Also add the person's phone number ${dim("(10 credits if found)")}
|
|
2392
2514
|
${cyan("export")} "<query>" -n 1000 -o leads.csv Verified CSV export ${dim("(uses credits)")}
|
|
2515
|
+
${cyan("export")} ... --phones Include phone numbers in the file ${dim("(10 credits per number in the file)")}
|
|
2393
2516
|
${cyan("export status")} <job_id> Status of an existing export ${dim("(free; add --batch for >50k)")}
|
|
2394
2517
|
${cyan("export download")} <job_id> -o leads.csv Re-download a finished export ${dim("(free)")}
|
|
2395
2518
|
${cyan("list create")} --name "<n>" [filters] Save a reusable list ${dim("(free)")}
|
|
@@ -2424,6 +2547,9 @@ ${bold("OPTIONS")}
|
|
|
2424
2547
|
--json Raw JSON output -y, --yes Skip confirmations
|
|
2425
2548
|
--base <url> Override API base (or ARGORANT_API_BASE)
|
|
2426
2549
|
--batch Treat the id in \`export status/download\` as a batch id
|
|
2550
|
+
--phones Include phone numbers (reveal, enrich, export). Off by default.
|
|
2551
|
+
10 credits per phone number returned, nothing if none is found;
|
|
2552
|
+
numbers you already unlocked are free. From the Pro plan.
|
|
2427
2553
|
--max-credits <n> Credit cap for a \`find --file\` job (it pauses at the cap)
|
|
2428
2554
|
--grade <g> valid (default) or valid-plus-catchall - which deliverable
|
|
2429
2555
|
grade to include on reveal/export. You only ever pay for
|
|
@@ -2451,6 +2577,8 @@ ${bold("EXAMPLES")}
|
|
|
2451
2577
|
${p} enrich --email patrick@stripe.com --json
|
|
2452
2578
|
${p} enrich --name "Patrick Collison" --domain stripe.com
|
|
2453
2579
|
${p} enrich --domain stripe.com
|
|
2580
|
+
${p} reveal --title CFO --domain stripe.com -n 5 --phones
|
|
2581
|
+
${p} export --title CFO --country Germany -n 200 --phones -o cfos.csv
|
|
2454
2582
|
${p} verify ceo@stripe.com
|
|
2455
2583
|
${p} verify --file my-list.csv -o verified.csv
|
|
2456
2584
|
${p} find "Patrick Collison" --domain stripe.com
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "argorant",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Search, count, reveal, export, and verify B2B contacts from the Argorant database, and find work emails by name and company domain, from your terminal, scripts, or coding agent.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"argorant": "bin/argorant.js"
|