salesprompter-cli 0.1.16 → 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 +46 -16
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -177,6 +177,13 @@ function deriveCompanyNameFromDomain(domain) {
177
177
  function writeWizardLine(message = "") {
178
178
  process.stdout.write(`${message}\n`);
179
179
  }
180
+ function writeWizardSection(title, description) {
181
+ writeWizardLine(title);
182
+ if (description) {
183
+ writeWizardLine(description);
184
+ }
185
+ writeWizardLine();
186
+ }
180
187
  function isOpaqueOrgId(value) {
181
188
  return /^org_[A-Za-z0-9]+$/.test(value);
182
189
  }
@@ -408,6 +415,7 @@ async function maybeSearchLeadDataNow(rl, options) {
408
415
  if (!shouldSearch) {
409
416
  return;
410
417
  }
418
+ writeWizardSection("Search your lead data", "I will use the ICP you just saved.");
411
419
  await runVendorLookupWizard(rl, { icpPath: options.icpPath });
412
420
  }
413
421
  async function maybePrepareLeadsForOutreach(rl, options) {
@@ -416,6 +424,7 @@ async function maybePrepareLeadsForOutreach(rl, options) {
416
424
  if (!shouldScore) {
417
425
  return;
418
426
  }
427
+ writeWizardSection("Prepare for outreach", "I will enrich and score the leads you just saved.");
419
428
  const { enrichedPath, scoredPath } = buildLeadOutputPaths(options.baseSlug);
420
429
  const enriched = await enrichmentProvider.enrichLeads(options.leads);
421
430
  const scored = await scoringProvider.scoreLeads(options.icp, enriched);
@@ -483,15 +492,27 @@ async function runVendorIcpWizard(rl) {
483
492
  ], "custom");
484
493
  writeWizardLine();
485
494
  if (startPoint === "custom") {
495
+ writeWizardSection("Define your ICP", "Start with the basics. You can add more filters if you want.");
486
496
  const productName = await promptText(rl, "What do you sell?", { required: true });
487
497
  const description = await promptText(rl, "Short description (optional)");
488
- const industries = await promptText(rl, "Industries to target (optional, comma-separated)");
489
- const companySizes = await promptText(rl, "Company sizes to target (optional, comma-separated)");
490
- const regions = await promptText(rl, "Regions to target (optional, comma-separated)");
491
- const countries = await promptText(rl, "Countries to target (optional, comma-separated)");
492
- const titles = await promptText(rl, "Job titles to target (optional, comma-separated)");
493
- const keywords = await promptText(rl, "Keywords or buying signals (optional, comma-separated)");
494
498
  writeWizardLine();
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);
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
+ }
495
516
  const slug = slugify(productName) || "icp";
496
517
  const outPath = `./data/${slug}-icp.json`;
497
518
  const icp = IcpSchema.parse({
@@ -538,6 +559,7 @@ async function runVendorIcpWizard(rl) {
538
559
  return;
539
560
  }
540
561
  const vendor = "deel";
562
+ writeWizardSection("Define your ICP", "Use the built-in Deel template and choose a market.");
541
563
  writeWizardLine("Using the built-in Deel ICP template.");
542
564
  writeWizardLine();
543
565
  const market = await promptChoice(rl, "Which market do you want to focus on?", [
@@ -558,15 +580,23 @@ async function runVendorIcpWizard(rl) {
558
580
  await maybeSearchLeadDataNow(rl, { icpPath: outPath });
559
581
  }
560
582
  async function runTargetAccountWizard(rl) {
583
+ writeWizardSection("Pick a company", "Start with the company and how many people you want.");
561
584
  const domain = normalizeDomainInput(await promptText(rl, "Which company do you want leads from? Enter the domain", { required: true }));
562
585
  writeWizardLine();
563
- const companyName = await promptText(rl, "Company name (optional)");
564
- const displayName = companyName || deriveCompanyNameFromDomain(domain);
586
+ const displayName = deriveCompanyNameFromDomain(domain);
565
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 }));
566
- const region = await promptText(rl, "Region", { defaultValue: "Global", required: true });
567
- const industries = await promptText(rl, "Industries (optional, comma-separated)");
568
- const titles = await promptText(rl, "Job titles (optional, comma-separated)");
569
588
  writeWizardLine();
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);
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
+ }
570
600
  const slug = slugify(domain);
571
601
  const icpPath = `./data/${slug}-target-icp.json`;
572
602
  const { leadsPath } = buildLeadOutputPaths(slug);
@@ -578,8 +608,7 @@ async function runTargetAccountWizard(rl) {
578
608
  });
579
609
  await writeJsonFile(icpPath, icp);
580
610
  const result = await leadProvider.generateLeads(icp, leadCount, {
581
- companyDomain: domain,
582
- companyName: companyName || undefined
611
+ companyDomain: domain
583
612
  });
584
613
  await writeJsonFile(leadsPath, result.leads);
585
614
  writeWizardLine(`Generated ${result.leads.length} leads for ${result.account.companyName} (${result.account.domain}).`);
@@ -604,9 +633,6 @@ async function runTargetAccountWizard(rl) {
604
633
  defineArgs.push("--out", icpPath);
605
634
  writeWizardLine(` ${buildCommandLine(defineArgs)}`);
606
635
  const leadArgs = ["salesprompter", "leads:generate", "--icp", icpPath, "--count", String(leadCount), "--domain", domain];
607
- if (companyName.trim().length > 0) {
608
- leadArgs.push("--company-name", companyName);
609
- }
610
636
  leadArgs.push("--out", leadsPath);
611
637
  writeWizardLine(` ${buildCommandLine(leadArgs)}`);
612
638
  writeWizardLine();
@@ -641,6 +667,9 @@ async function runLeadGenerationWizard(rl) {
641
667
  await runVendorLookupWizard(rl);
642
668
  }
643
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
+ }
644
673
  const icpPath = options?.icpPath
645
674
  ? options.icpPath
646
675
  : await promptText(rl, "Which saved ICP should I use?", {
@@ -713,6 +742,7 @@ async function runVendorLookupWizard(rl, options) {
713
742
  async function runOutreachSyncWizard(rl, options) {
714
743
  const target = "instantly";
715
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.");
716
746
  writeWizardLine(`Using ${targetLabel}.`);
717
747
  writeWizardLine();
718
748
  if (!process.env.INSTANTLY_API_KEY || process.env.INSTANTLY_API_KEY.trim().length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "salesprompter-cli",
3
- "version": "0.1.16",
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": {