salesprompter-cli 0.1.71 → 0.1.72

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 (3) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.js +22 -5
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -175,12 +175,12 @@ the app's CLI imports view.
175
175
  - Respect provider terms and customer data boundaries.
176
176
  - `affiliate:grow` is an alias for `affiliate:run`. It excludes repeated `--seed-profile` customers, removes profiles already stored in prior workspace affiliate audiences, and verifies the final persisted count before preparing Instantly.
177
177
  - If every collected profile is known or excluded, no audience or Instantly campaign is created. A stale Sales Navigator session also fails before persistence with a safe retry instruction.
178
- - Affiliate outreach uses direct email enrichment first, then Phantombuster Email Finder for unresolved people before creating a draft Instantly campaign.
178
+ - Affiliate outreach uses Hunter first, requires Hunter's `valid` verdict before import, and sends recovered addresses through Hunter Email Verifier before creating a draft Instantly campaign. Catch-all, disposable, webmail, invalid, unknown, claimed, and unresolved addresses are excluded. Instantly verification remains enabled as a second gate.
179
179
  - Affiliate preparation uses exactly three emails with three observable variants per step; `affiliate:regenerate-sequence` rebuilds and syncs them through the Salesprompter app.
180
180
  - `affiliate:list` shows safe workspace summaries. `affiliate:analytics` shows aggregate and step/variant outcomes without exposing lead data; unsupported per-step meeting and won fields render as `n/a`.
181
181
  - `affiliate:run` defaults to `--timing-mode custom`, so its daily limit and weekday sending window are honored. Use `--timing-mode auto` only when capacity-derived scheduling is intended.
182
182
  - `affiliate:enrich` starts durable email recovery and adds only newly found addresses to an existing campaign. It returns a background-processing status for large audiences instead of blocking the terminal. Pass `--source-audience-run-id` to merge a newer compatible audience into that campaign without creating a duplicate campaign.
183
- - `affiliate:finish` closes the loop: it repairs stalled verification in 1,000-lead batches, quarantines stale pending or invalid leads outside the sending campaign, accepts an explicitly audited recovery fallback, activates only a fully verified campaign, and reads the live state back. Use `--requeue-pending` only after restoring Instantly verification capacity.
183
+ - `affiliate:finish` closes the loop: it requires persisted Hunter-valid evidence for new campaigns, repairs stalled Instantly verification in 1,000-lead batches, quarantines stale pending or invalid leads outside the sending campaign, accepts an explicitly audited recovery fallback, activates only a fully verified campaign, and reads the live state back. Use `--requeue-pending` only after restoring Instantly verification capacity.
184
184
  - A draft campaign does not send until `affiliate:activate` is run.
185
185
  - The CLI is designed for interactive users and agent-assisted workflows.
186
186
  - A repo-local Chrome extension compatibility copy is available in `chrome-extension/` for local LinkedIn session sync and popup copy/debug flows.
package/dist/cli.js CHANGED
@@ -283,6 +283,8 @@ const AffiliateOutreachHealthSchema = z.object({
283
283
  pendingVerification: z.number().int().nonnegative(),
284
284
  invalid: z.number().int().nonnegative(),
285
285
  unsafe: z.number().int().nonnegative(),
286
+ hunterVerified: z.number().int().nonnegative().default(0),
287
+ hunterEvidenceMissing: z.number().int().nonnegative().default(0),
286
288
  contacted: z.number().int().nonnegative(),
287
289
  replied: z.number().int().nonnegative(),
288
290
  statusCounts: z.record(z.string(), z.number().int().nonnegative()),
@@ -6903,18 +6905,23 @@ async function finishAffiliateOutreachViaApp(session, audienceRunId, options) {
6903
6905
  }
6904
6906
  function describeAffiliateOutreachHealth(health) {
6905
6907
  const leads = health.leads;
6908
+ const hunterSummary = leads
6909
+ ? leads.hunterEvidenceMissing > 0
6910
+ ? `Hunter evidence recorded for ${leads.hunterVerified}/${leads.total} leads (${leads.hunterEvidenceMissing} legacy or missing)`
6911
+ : `${leads.hunterVerified}/${leads.total} Hunter-valid`
6912
+ : null;
6906
6913
  if (health.done && leads) {
6907
- return `Done: the campaign is running with ${leads.verified}/${leads.total} verified leads.`;
6914
+ return `Done: the campaign is running with ${leads.verified}/${leads.total} Instantly-verified leads; ${hunterSummary}.`;
6908
6915
  }
6909
6916
  if (health.verdict === "unsafe_running" && leads) {
6910
6917
  return `Attention: the campaign is running with ${leads.unsafe} unsafe leads.`;
6911
6918
  }
6912
6919
  if (health.verdict === "ready_to_activate" && leads) {
6913
- return `Ready to activate: ${leads.verified}/${leads.total} leads are verified.`;
6920
+ return `Ready to activate: ${leads.verified}/${leads.total} Instantly-verified; ${hunterSummary}.`;
6914
6921
  }
6915
6922
  if (health.liveChecked && leads) {
6916
6923
  const campaignState = health.campaign?.statusLabel ?? "unknown";
6917
- return `Not done: the campaign is ${campaignState}; ${leads.verified}/${leads.total} leads are verified; ${leads.contacted} contacted.`;
6924
+ return `Not done: the campaign is ${campaignState}; ${leads.verified}/${leads.total} Instantly-verified; ${hunterSummary}; ${leads.contacted} contacted.`;
6918
6925
  }
6919
6926
  return health.blockers[0]?.message ?? "Live campaign status could not be verified.";
6920
6927
  }
@@ -13985,6 +13992,9 @@ function parseAffiliateOutreachCommandOptions(options) {
13985
13992
  if (!parsedTimingMode.success) {
13986
13993
  throw new Error("--timing-mode must be either auto or custom.");
13987
13994
  }
13995
+ if (options.allowAcceptAll) {
13996
+ throw new Error("--allow-accept-all is no longer supported. Affiliate outreach requires Hunter status valid.");
13997
+ }
13988
13998
  const trimmedCampaignName = options.campaignName?.trim();
13989
13999
  const campaignName = trimmedCampaignName
13990
14000
  ? z.string().max(120, "--campaign-name must be 120 characters or fewer.").parse(trimmedCampaignName)
@@ -13994,7 +14004,7 @@ function parseAffiliateOutreachCommandOptions(options) {
13994
14004
  language: z.string().trim().min(1).max(40).parse(options.language),
13995
14005
  numberOfSteps: 3,
13996
14006
  minEmailScore: z.coerce.number().int().min(0).max(100).parse(options.minEmailScore),
13997
- allowAcceptAll: Boolean(options.allowAcceptAll),
14007
+ allowAcceptAll: false,
13998
14008
  timingMode: parsedTimingMode.data,
13999
14009
  dailyLimit: z.coerce.number().int().min(1).max(1000).parse(options.dailyLimit),
14000
14010
  timezone: z.string().trim().min(1).max(100).parse(options.timezone),
@@ -15169,7 +15179,7 @@ addAffiliateAudienceOptions(program
15169
15179
  .option("--language <language>", "Sequence language", "English")
15170
15180
  .option("--steps <number>", "Exactly 3 sequence emails (fixed)", "3")
15171
15181
  .option("--min-email-score <number>", "Minimum Hunter confidence score", "80")
15172
- .option("--allow-accept-all", "Include catch-all domains that meet the score threshold", false)
15182
+ .option("--allow-accept-all", "Deprecated: catch-all emails are rejected", false)
15173
15183
  .option("--timing-mode <mode>", "Schedule mode: custom honors the daily limit and sending window; auto derives them from capacity", "custom")
15174
15184
  .option("--daily-limit <number>", "Maximum new leads contacted per day", "25")
15175
15185
  .option("--timezone <timezone>", "Instantly sending timezone", "America/Detroit")
@@ -15243,6 +15253,13 @@ addAffiliateAudienceOptions(program
15243
15253
  ? "complete"
15244
15254
  : "not_reported",
15245
15255
  persistence: "verified",
15256
+ emailVerification: {
15257
+ provider: "hunter",
15258
+ policy: "valid_only",
15259
+ verified: Number(finalOutreach.stats.hunterVerifiedEmails ?? 0),
15260
+ rejected: Number(finalOutreach.stats.hunterRejectedEmails ?? 0),
15261
+ secondaryProvider: "instantly"
15262
+ },
15246
15263
  outreach: finalOutreach.status,
15247
15264
  activation: finalOutreach.status === "active" ? "complete" : "not_requested",
15248
15265
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "salesprompter-cli",
3
- "version": "0.1.71",
3
+ "version": "0.1.72",
4
4
  "description": "Sales workflow CLI for guided lead generation, enrichment, scoring, and sync.",
5
5
  "author": "Daniel Sinewe <hello@danielsinewe.com>",
6
6
  "type": "module",