salesprompter-cli 0.1.15 → 0.1.17

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.
Files changed (2) hide show
  1. package/dist/cli.js +185 -114
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawn } from "node:child_process";
3
+ import { access } from "node:fs/promises";
3
4
  import { createRequire } from "node:module";
4
5
  import { emitKeypressEvents } from "node:readline";
5
6
  import { createInterface } from "node:readline/promises";
@@ -176,6 +177,13 @@ function deriveCompanyNameFromDomain(domain) {
176
177
  function writeWizardLine(message = "") {
177
178
  process.stdout.write(`${message}\n`);
178
179
  }
180
+ function writeWizardSection(title, description) {
181
+ writeWizardLine(title);
182
+ if (description) {
183
+ writeWizardLine(description);
184
+ }
185
+ writeWizardLine();
186
+ }
179
187
  function isOpaqueOrgId(value) {
180
188
  return /^org_[A-Za-z0-9]+$/.test(value);
181
189
  }
@@ -196,6 +204,22 @@ function writeSessionSummary(session) {
196
204
  writeWizardLine(`Workspace: ${orgLabel}`);
197
205
  }
198
206
  }
207
+ async function fileExists(filePath) {
208
+ try {
209
+ await access(filePath);
210
+ return true;
211
+ }
212
+ catch {
213
+ return false;
214
+ }
215
+ }
216
+ function buildLeadOutputPaths(baseSlug) {
217
+ return {
218
+ leadsPath: `./data/${baseSlug}-leads.json`,
219
+ enrichedPath: `./data/${baseSlug}-enriched.json`,
220
+ scoredPath: `./data/${baseSlug}-scored.json`
221
+ };
222
+ }
199
223
  function normalizeChoiceText(value) {
200
224
  return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, " ").replace(/\s+/g, " ").trim();
201
225
  }
@@ -385,6 +409,46 @@ async function promptYesNo(rl, prompt, defaultValue) {
385
409
  writeWizardLine("Please answer yes or no.");
386
410
  }
387
411
  }
412
+ async function maybeSearchLeadDataNow(rl, options) {
413
+ const shouldSearch = await promptYesNo(rl, "Do you want to search your lead data for matches now?", false);
414
+ writeWizardLine();
415
+ if (!shouldSearch) {
416
+ return;
417
+ }
418
+ writeWizardSection("Search your lead data", "I will use the ICP you just saved.");
419
+ await runVendorLookupWizard(rl, { icpPath: options.icpPath });
420
+ }
421
+ async function maybePrepareLeadsForOutreach(rl, options) {
422
+ const shouldScore = await promptYesNo(rl, "Do you want me to score these leads for outreach?", false);
423
+ writeWizardLine();
424
+ if (!shouldScore) {
425
+ return;
426
+ }
427
+ writeWizardSection("Prepare for outreach", "I will enrich and score the leads you just saved.");
428
+ const { enrichedPath, scoredPath } = buildLeadOutputPaths(options.baseSlug);
429
+ const enriched = await enrichmentProvider.enrichLeads(options.leads);
430
+ const scored = await scoringProvider.scoreLeads(options.icp, enriched);
431
+ await writeJsonFile(enrichedPath, enriched);
432
+ await writeJsonFile(scoredPath, scored);
433
+ writeWizardLine(`Saved enriched leads to ${enrichedPath}.`);
434
+ writeWizardLine(`Saved scored leads to ${scoredPath}.`);
435
+ writeWizardLine();
436
+ writeWizardLine("Equivalent raw commands:");
437
+ writeWizardLine(` ${buildCommandLine(["salesprompter", "leads:enrich", "--in", options.leadPath, "--out", enrichedPath])}`);
438
+ writeWizardLine(` ${buildCommandLine(["salesprompter", "leads:score", "--icp", options.icpPath, "--in", enrichedPath, "--out", scoredPath])}`);
439
+ if (!process.env.INSTANTLY_API_KEY || process.env.INSTANTLY_API_KEY.trim().length === 0) {
440
+ writeWizardLine();
441
+ writeWizardLine("You can send the scored leads to Instantly later from the main menu.");
442
+ return;
443
+ }
444
+ writeWizardLine();
445
+ const shouldSync = await promptYesNo(rl, "Do you want to send these leads to Instantly now?", false);
446
+ writeWizardLine();
447
+ if (!shouldSync) {
448
+ return;
449
+ }
450
+ await runOutreachSyncWizard(rl, { inputPath: scoredPath });
451
+ }
388
452
  async function ensureWizardSession(options) {
389
453
  if (shouldBypassAuth()) {
390
454
  return null;
@@ -412,11 +476,11 @@ async function ensureWizardSession(options) {
412
476
  return result.session;
413
477
  }
414
478
  async function runVendorIcpWizard(rl) {
415
- const startPoint = await promptChoice(rl, "How do you want to start?", [
479
+ const startPoint = await promptChoice(rl, "How do you want to build your ICP?", [
416
480
  {
417
481
  value: "custom",
418
- label: "Create a custom profile",
419
- description: "Answer a few questions about who you want to sell to",
482
+ label: "Start from scratch",
483
+ description: "Answer a few questions about the companies you want to sell to",
420
484
  aliases: ["custom", "from scratch", "new profile"]
421
485
  },
422
486
  {
@@ -428,21 +492,29 @@ async function runVendorIcpWizard(rl) {
428
492
  ], "custom");
429
493
  writeWizardLine();
430
494
  if (startPoint === "custom") {
431
- const productName = await promptText(rl, "What are you selling?", { required: true });
432
- const description = await promptText(rl, "Who is this for? (optional)");
433
- const industries = await promptText(rl, "Target industries (optional, comma-separated)");
434
- const companySizes = await promptText(rl, "Target company sizes (optional, comma-separated)");
435
- const regions = await promptText(rl, "Target regions (optional, comma-separated)");
436
- const countries = await promptText(rl, "Target countries (optional, comma-separated)");
437
- const titles = await promptText(rl, "Target job titles (optional, comma-separated)");
438
- const keywords = await promptText(rl, "Keywords or buying signals (optional, comma-separated)");
495
+ writeWizardSection("Define your ICP", "Start with the basics. You can add more filters if you want.");
496
+ const productName = await promptText(rl, "What do you sell?", { required: true });
497
+ const description = await promptText(rl, "Short description (optional)");
439
498
  writeWizardLine();
440
- const slug = slugify(productName) || "icp";
441
- const outPath = await promptText(rl, "Where should I save the ICP JSON?", {
442
- defaultValue: `./data/${slug}-icp.json`,
443
- required: true
444
- });
499
+ let industries = "";
500
+ let companySizes = "";
501
+ let regions = "";
502
+ let countries = "";
503
+ let titles = "";
504
+ let keywords = "";
505
+ const addDetails = await promptYesNo(rl, "Do you want to add industries, company size, region, or title filters?", false);
445
506
  writeWizardLine();
507
+ if (addDetails) {
508
+ industries = await promptText(rl, "Industries to target (optional, comma-separated)");
509
+ companySizes = await promptText(rl, "Company sizes to target (optional, comma-separated)");
510
+ regions = await promptText(rl, "Regions to target (optional, comma-separated)");
511
+ countries = await promptText(rl, "Countries to target (optional, comma-separated)");
512
+ titles = await promptText(rl, "Job titles to target (optional, comma-separated)");
513
+ keywords = await promptText(rl, "Keywords or buying signals (optional, comma-separated)");
514
+ writeWizardLine();
515
+ }
516
+ const slug = slugify(productName) || "icp";
517
+ const outPath = `./data/${slug}-icp.json`;
446
518
  const icp = IcpSchema.parse({
447
519
  name: `${productName} ICP`,
448
520
  description,
@@ -455,7 +527,7 @@ async function runVendorIcpWizard(rl) {
455
527
  });
456
528
  await writeJsonFile(outPath, icp);
457
529
  writeWizardLine(`Created ${icp.name}.`);
458
- writeWizardLine(`Saved ICP to ${outPath}.`);
530
+ writeWizardLine(`Saved profile to ${outPath}.`);
459
531
  writeWizardLine();
460
532
  writeWizardLine("Equivalent raw command:");
461
533
  const defineArgs = ["salesprompter", "icp:define", "--name", icp.name];
@@ -483,73 +555,51 @@ async function runVendorIcpWizard(rl) {
483
555
  defineArgs.push("--out", outPath);
484
556
  writeWizardLine(` ${buildCommandLine(defineArgs)}`);
485
557
  writeWizardLine();
486
- writeWizardLine("Next suggested command:");
487
- writeWizardLine(` ${buildCommandLine([
488
- "salesprompter",
489
- "leads:generate",
490
- "--icp",
491
- outPath,
492
- "--count",
493
- "5",
494
- "--out",
495
- `./data/${slug}-leads.json`
496
- ])}`);
558
+ await maybeSearchLeadDataNow(rl, { icpPath: outPath });
497
559
  return;
498
560
  }
499
561
  const vendor = "deel";
562
+ writeWizardSection("Define your ICP", "Use the built-in Deel template and choose a market.");
500
563
  writeWizardLine("Using the built-in Deel ICP template.");
501
564
  writeWizardLine();
502
- const market = await promptChoice(rl, "Which market do you want to target?", [
565
+ const market = await promptChoice(rl, "Which market do you want to focus on?", [
503
566
  { value: "dach", label: "DACH", description: "Germany, Austria, Switzerland" },
504
567
  { value: "europe", label: "Europe" },
505
568
  { value: "global", label: "Global" }
506
569
  ], "dach");
507
570
  writeWizardLine();
508
- const outPath = await promptText(rl, "Where should I save the ICP JSON?", {
509
- defaultValue: `./data/${slugify(vendor)}-icp-${market}.json`,
510
- required: true
511
- });
512
- writeWizardLine();
571
+ const outPath = `./data/${slugify(vendor)}-icp-${market}.json`;
513
572
  const icp = buildVendorIcp(vendor, market);
514
573
  await writeJsonFile(outPath, icp);
515
574
  writeWizardLine(`Created ${icp.name}.`);
516
- writeWizardLine(`Saved ICP to ${outPath}.`);
575
+ writeWizardLine(`Saved profile to ${outPath}.`);
517
576
  writeWizardLine();
518
577
  writeWizardLine("Equivalent raw command:");
519
578
  writeWizardLine(` ${buildCommandLine(["salesprompter", "icp:vendor", "--vendor", vendor, "--market", market, "--out", outPath])}`);
520
579
  writeWizardLine();
521
- writeWizardLine("Next suggested command:");
522
- writeWizardLine(` ${buildCommandLine([
523
- "salesprompter",
524
- "leads:lookup:bq",
525
- "--icp",
526
- outPath,
527
- "--limit",
528
- "100",
529
- "--lead-out",
530
- `./data/${slugify(vendor)}-leads.json`
531
- ])}`);
580
+ await maybeSearchLeadDataNow(rl, { icpPath: outPath });
532
581
  }
533
582
  async function runTargetAccountWizard(rl) {
534
- const domain = normalizeDomainInput(await promptText(rl, "Which company are you targeting? Enter the domain", { required: true }));
583
+ writeWizardSection("Pick a company", "Start with the company and how many people you want.");
584
+ const domain = normalizeDomainInput(await promptText(rl, "Which company do you want leads from? Enter the domain", { required: true }));
535
585
  writeWizardLine();
536
- const companyName = await promptText(rl, "Company name override (optional)");
537
- const displayName = companyName || deriveCompanyNameFromDomain(domain);
538
- const leadCount = z.coerce.number().int().min(1).max(1000).parse(await promptText(rl, "How many leads should I generate?", { defaultValue: "5", required: true }));
539
- const region = await promptText(rl, "Primary region hint", { defaultValue: "Global", required: true });
540
- const industries = await promptText(rl, "Industry hint (optional, comma-separated)");
541
- const titles = await promptText(rl, "Target titles (optional, comma-separated)");
586
+ const displayName = deriveCompanyNameFromDomain(domain);
587
+ const leadCount = z.coerce.number().int().min(1).max(1000).parse(await promptText(rl, "How many people do you want?", { defaultValue: "5", required: true }));
542
588
  writeWizardLine();
543
- const slug = slugify(domain);
544
- const icpPath = await promptText(rl, "Where should I save the ad-hoc ICP JSON?", {
545
- defaultValue: `./data/${slug}-target-icp.json`,
546
- required: true
547
- });
548
- const leadsPath = await promptText(rl, "Where should I save the generated leads JSON?", {
549
- defaultValue: `./data/${slug}-leads.json`,
550
- required: true
551
- });
589
+ let region = "Global";
590
+ let industries = "";
591
+ let titles = "";
592
+ const narrowResults = await promptYesNo(rl, "Do you want to narrow the results by region, industry, or title?", false);
552
593
  writeWizardLine();
594
+ if (narrowResults) {
595
+ region = await promptText(rl, "Region", { defaultValue: "Global", required: true });
596
+ industries = await promptText(rl, "Industries (optional, comma-separated)");
597
+ titles = await promptText(rl, "Job titles (optional, comma-separated)");
598
+ writeWizardLine();
599
+ }
600
+ const slug = slugify(domain);
601
+ const icpPath = `./data/${slug}-target-icp.json`;
602
+ const { leadsPath } = buildLeadOutputPaths(slug);
553
603
  const icp = IcpSchema.parse({
554
604
  name: `${displayName} target account`,
555
605
  regions: region.length > 0 ? [region] : [],
@@ -558,12 +608,11 @@ async function runTargetAccountWizard(rl) {
558
608
  });
559
609
  await writeJsonFile(icpPath, icp);
560
610
  const result = await leadProvider.generateLeads(icp, leadCount, {
561
- companyDomain: domain,
562
- companyName: companyName || undefined
611
+ companyDomain: domain
563
612
  });
564
613
  await writeJsonFile(leadsPath, result.leads);
565
614
  writeWizardLine(`Generated ${result.leads.length} leads for ${result.account.companyName} (${result.account.domain}).`);
566
- writeWizardLine(`Saved ad-hoc ICP to ${icpPath}.`);
615
+ writeWizardLine(`Saved profile to ${icpPath}.`);
567
616
  writeWizardLine(`Saved leads to ${leadsPath}.`);
568
617
  if (result.warnings.length > 0) {
569
618
  writeWizardLine();
@@ -584,11 +633,16 @@ async function runTargetAccountWizard(rl) {
584
633
  defineArgs.push("--out", icpPath);
585
634
  writeWizardLine(` ${buildCommandLine(defineArgs)}`);
586
635
  const leadArgs = ["salesprompter", "leads:generate", "--icp", icpPath, "--count", String(leadCount), "--domain", domain];
587
- if (companyName.trim().length > 0) {
588
- leadArgs.push("--company-name", companyName);
589
- }
590
636
  leadArgs.push("--out", leadsPath);
591
637
  writeWizardLine(` ${buildCommandLine(leadArgs)}`);
638
+ writeWizardLine();
639
+ await maybePrepareLeadsForOutreach(rl, {
640
+ baseSlug: slug,
641
+ icp,
642
+ icpPath,
643
+ leadPath: leadsPath,
644
+ leads: result.leads
645
+ });
592
646
  }
593
647
  async function runLeadGenerationWizard(rl) {
594
648
  const source = await promptChoice(rl, "How do you want to generate leads?", [
@@ -600,8 +654,8 @@ async function runLeadGenerationWizard(rl) {
600
654
  },
601
655
  {
602
656
  value: "vendor-lookup",
603
- label: "From my BigQuery data",
604
- description: "Use a saved profile to search the lead data you already have",
657
+ label: "From my own lead data",
658
+ description: "Search leads you already have in BigQuery",
605
659
  aliases: ["bigquery", "warehouse", "my data", "from bigquery"]
606
660
  }
607
661
  ], "target-account");
@@ -612,33 +666,27 @@ async function runLeadGenerationWizard(rl) {
612
666
  }
613
667
  await runVendorLookupWizard(rl);
614
668
  }
615
- async function runVendorLookupWizard(rl) {
616
- const icpPath = await promptText(rl, "Where is your ICP JSON file?", {
617
- defaultValue: "./data/icp.json",
618
- required: true
619
- });
620
- const limit = z.coerce.number().int().min(1).max(5000).parse(await promptText(rl, "How many leads should I look up?", { defaultValue: "100", required: true }));
621
- const execute = await promptYesNo(rl, "Execute the BigQuery lookup now?", false);
669
+ async function runVendorLookupWizard(rl, options) {
670
+ if (!options?.icpPath) {
671
+ writeWizardSection("Search your lead data", "Use a saved ICP to build the lookup.");
672
+ }
673
+ const icpPath = options?.icpPath
674
+ ? options.icpPath
675
+ : await promptText(rl, "Which saved ICP should I use?", {
676
+ defaultValue: "./data/icp.json",
677
+ required: true
678
+ });
679
+ if (options?.icpPath) {
680
+ writeWizardLine(`Using profile from ${icpPath}.`);
681
+ }
682
+ const limit = z.coerce.number().int().min(1).max(5000).parse(await promptText(rl, "How many leads do you want?", { defaultValue: "100", required: true }));
683
+ const execute = await promptYesNo(rl, "Do you want me to run the BigQuery search now?", false);
622
684
  writeWizardLine();
623
685
  const icp = await readJsonFile(icpPath, IcpSchema);
624
686
  const slug = slugify(icp.name) || "icp";
625
- const sqlPath = await promptText(rl, "Where should I save the generated SQL?", {
626
- defaultValue: `./data/${slug}-lookup.sql`,
627
- required: true
628
- });
629
- const rawPath = execute
630
- ? await promptText(rl, "Where should I save raw BigQuery rows?", {
631
- defaultValue: `./data/${slug}-leads-raw.json`,
632
- required: true
633
- })
634
- : "";
635
- const leadPath = execute
636
- ? await promptText(rl, "Where should I save normalized leads?", {
637
- defaultValue: `./data/${slug}-leads.json`,
638
- required: true
639
- })
640
- : "";
641
- writeWizardLine();
687
+ const sqlPath = `./data/${slug}-lookup.sql`;
688
+ const rawPath = `./data/${slug}-leads-raw.json`;
689
+ const { leadsPath: leadPath } = buildLeadOutputPaths(slug);
642
690
  const sql = buildBigQueryLeadLookupSql(icp, {
643
691
  table: "icpidentifier.SalesGPT.leadPool_new",
644
692
  companyField: "companyName",
@@ -658,19 +706,19 @@ async function runVendorLookupWizard(rl) {
658
706
  });
659
707
  await writeTextFile(sqlPath, `${sql}\n`);
660
708
  let executedRowCount = null;
709
+ let normalizedLeads = [];
661
710
  if (execute) {
662
711
  const rows = await runBigQueryQuery(sql, { maxRows: limit });
663
712
  const parsedRows = z.array(z.record(z.string(), z.unknown())).parse(rows);
664
713
  await writeJsonFile(rawPath, parsedRows);
665
- const normalizedLeads = normalizeBigQueryLeadRows(parsedRows);
714
+ normalizedLeads = normalizeBigQueryLeadRows(parsedRows);
666
715
  await writeJsonFile(leadPath, normalizedLeads);
667
716
  executedRowCount = parsedRows.length;
668
717
  }
669
- writeWizardLine(`Using ICP from ${icpPath}.`);
670
- writeWizardLine(`Saved lookup SQL to ${sqlPath}.`);
718
+ writeWizardLine(`Saved search SQL to ${sqlPath}.`);
671
719
  if (execute) {
672
720
  writeWizardLine(`Saved ${executedRowCount ?? 0} raw rows to ${rawPath}.`);
673
- writeWizardLine(`Saved normalized leads to ${leadPath}.`);
721
+ writeWizardLine(`Saved leads to ${leadPath}.`);
674
722
  }
675
723
  writeWizardLine();
676
724
  writeWizardLine("Equivalent raw command:");
@@ -679,25 +727,48 @@ async function runVendorLookupWizard(rl) {
679
727
  lookupArgs.push("--execute", "--out", rawPath, "--lead-out", leadPath);
680
728
  }
681
729
  writeWizardLine(` ${buildCommandLine(lookupArgs)}`);
730
+ if (!execute) {
731
+ return;
732
+ }
733
+ writeWizardLine();
734
+ await maybePrepareLeadsForOutreach(rl, {
735
+ baseSlug: slug,
736
+ icp,
737
+ icpPath,
738
+ leadPath,
739
+ leads: normalizedLeads
740
+ });
682
741
  }
683
- async function runOutreachSyncWizard(rl) {
742
+ async function runOutreachSyncWizard(rl, options) {
684
743
  const target = "instantly";
685
- writeWizardLine("Using Instantly.");
744
+ const targetLabel = "Instantly";
745
+ writeWizardSection("Send to Instantly", options?.inputPath ? "I already have the scored leads ready." : "Use a scored leads file to fill a campaign.");
746
+ writeWizardLine(`Using ${targetLabel}.`);
686
747
  writeWizardLine();
687
748
  if (!process.env.INSTANTLY_API_KEY || process.env.INSTANTLY_API_KEY.trim().length === 0) {
688
749
  throw new Error("INSTANTLY_API_KEY is required for the Instantly sync flow.");
689
750
  }
690
- const inputPath = await promptText(rl, "Where is your scored leads JSON file?", {
691
- defaultValue: "./data/scored.json",
692
- required: true
693
- });
751
+ let inputPath = options?.inputPath?.trim() ?? "";
752
+ if (inputPath.length === 0 && (await fileExists("./data/scored.json"))) {
753
+ inputPath = "./data/scored.json";
754
+ }
755
+ if (inputPath.length === 0) {
756
+ inputPath = await promptText(rl, "Where is your scored leads file?", {
757
+ defaultValue: "./data/scored.json",
758
+ required: true
759
+ });
760
+ }
761
+ else {
762
+ writeWizardLine(`Using scored leads from ${inputPath}.`);
763
+ writeWizardLine();
764
+ }
694
765
  const defaultCampaignId = process.env.INSTANTLY_CAMPAIGN_ID?.trim();
695
- const campaignId = await promptText(rl, "Instantly campaign ID", {
766
+ const campaignId = await promptText(rl, "Which Instantly campaign should I use?", {
696
767
  defaultValue: defaultCampaignId && defaultCampaignId.length > 0 ? defaultCampaignId : undefined,
697
768
  required: defaultCampaignId === undefined || defaultCampaignId.length === 0
698
769
  });
699
- const apply = await promptYesNo(rl, "Create the leads in Instantly now?", false);
700
- const allowDuplicates = await promptYesNo(rl, "Allow duplicate emails in the campaign?", false);
770
+ const apply = await promptYesNo(rl, "Add these leads to Instantly now?", false);
771
+ const allowDuplicates = await promptYesNo(rl, "Keep leads that are already in the campaign?", false);
701
772
  writeWizardLine();
702
773
  const leads = await readJsonFile(inputPath, z.array(ScoredLeadSchema));
703
774
  const result = await syncProvider.sync(target, leads, {
@@ -706,12 +777,12 @@ async function runOutreachSyncWizard(rl) {
706
777
  allowDuplicates
707
778
  });
708
779
  const skipped = result.skipped ?? 0;
709
- writeWizardLine(`${apply ? "Sent" : "Prepared"} ${result.synced} lead${result.synced === 1 ? "" : "s"} for ${target}.`);
780
+ writeWizardLine(`${apply ? "Sent" : "Prepared"} ${result.synced} lead${result.synced === 1 ? "" : "s"} for ${targetLabel}.`);
710
781
  if (skipped > 0) {
711
782
  writeWizardLine(`Skipped ${skipped} duplicate lead${skipped === 1 ? "" : "s"}.`);
712
783
  }
713
784
  if (result.dryRun) {
714
- writeWizardLine("This was a dry run. Re-run and confirm the write when you are ready.");
785
+ writeWizardLine("Nothing was sent yet. Re-run and confirm when you are ready.");
715
786
  }
716
787
  writeWizardLine();
717
788
  writeWizardLine("Equivalent raw command:");
@@ -749,20 +820,20 @@ async function runWizard(options) {
749
820
  const flow = await promptChoice(rl, "What do you want help with?", [
750
821
  {
751
822
  value: "vendor-icp",
752
- label: "Figure out who to target",
753
- description: "Create an ideal customer profile for your product",
823
+ label: "Define my ICP",
824
+ description: "Build the company profile you want to sell to",
754
825
  aliases: ["icp", "ideal customer", "who to target", "targeting", "profile"]
755
826
  },
756
827
  {
757
828
  value: "lead-generation",
758
829
  label: "Generate leads",
759
- description: "Find people at one company or from your BigQuery data",
830
+ description: "Find people at one company or from your own lead data",
760
831
  aliases: ["leads", "find leads", "lead generation", "find people"]
761
832
  },
762
833
  {
763
834
  value: "outreach-sync",
764
- label: "Add leads to Instantly",
765
- description: "Send a scored leads file to an Instantly campaign",
835
+ label: "Send leads to Instantly",
836
+ description: "Use a scored leads file to fill an Instantly campaign",
766
837
  aliases: ["instantly", "outreach", "send leads", "campaign"]
767
838
  }
768
839
  ], "vendor-icp");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "salesprompter-cli",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "JSON-first sales prospecting CLI for ICP definition, lead generation, enrichment, scoring, and CRM/outreach sync.",
5
5
  "type": "module",
6
6
  "bin": {