salesprompter-cli 0.1.53 → 0.1.54
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 +2 -1
- package/dist/cli.js +83 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -72,7 +72,8 @@ salesprompter leads:collect \
|
|
|
72
72
|
|
|
73
73
|
# Enrich one or more stored imports: Sales Navigator company -> official domain -> Hunter email
|
|
74
74
|
# This updates workspace data only. It does not create or start outreach.
|
|
75
|
-
# Stale
|
|
75
|
+
# Stale ids and raw legal-name misses use conservative exact-name recovery.
|
|
76
|
+
# Hunter prefers official domains and can fall back to the exact company name.
|
|
76
77
|
salesprompter leads:enrich-import \
|
|
77
78
|
--run-id "$CLI_IMPORT_RUN_ID"
|
|
78
79
|
|
package/dist/cli.js
CHANGED
|
@@ -284,6 +284,8 @@ const CliImportHunterBatchResponseSchema = z.object({
|
|
|
284
284
|
found: z.number().int().nonnegative(),
|
|
285
285
|
notFound: z.number().int().nonnegative(),
|
|
286
286
|
failed: z.number().int().nonnegative(),
|
|
287
|
+
domainLookups: z.number().int().nonnegative().default(0),
|
|
288
|
+
companyLookups: z.number().int().nonnegative().default(0),
|
|
287
289
|
halted: z.boolean(),
|
|
288
290
|
error: z.string().nullable()
|
|
289
291
|
});
|
|
@@ -6756,7 +6758,11 @@ async function runCliImportEnrichmentAction(session, body, schema) {
|
|
|
6756
6758
|
return value;
|
|
6757
6759
|
}
|
|
6758
6760
|
async function getCliImportCompanyCandidatesViaApp(session, input) {
|
|
6759
|
-
return runCliImportEnrichmentAction(session, {
|
|
6761
|
+
return runCliImportEnrichmentAction(session, {
|
|
6762
|
+
action: "company-candidates",
|
|
6763
|
+
...input,
|
|
6764
|
+
retry: input.retryMode === "all",
|
|
6765
|
+
}, CliImportCompanyCandidatesResponseSchema);
|
|
6760
6766
|
}
|
|
6761
6767
|
async function saveCliImportCompanyProfilesViaApp(session, profiles) {
|
|
6762
6768
|
return runCliImportEnrichmentAction(session, { action: "save-companies", profiles }, CliImportCompanySaveResponseSchema);
|
|
@@ -13446,6 +13452,7 @@ function normalizeCompanyWebsite(value) {
|
|
|
13446
13452
|
}
|
|
13447
13453
|
}
|
|
13448
13454
|
const CLI_IMPORT_COMPANY_DECORATION = "(entityUrn,name,employeeCount,employeeDisplayCount,employeeCountRange,account(saved,noteCount,listCount,crmStatus,starred),pictureInfo,companyPictureDisplayImage,companyBackgroundCoverImage,description,industry,location,headquarters,website,revenueRange,crmOpportunities,flagshipCompanyUrl,employeeGrowthPercentages,employees*~fs_salesProfile(entityUrn,firstName,lastName,fullName,pictureInfo,profilePictureDisplayImage),specialties,type,yearFounded)";
|
|
13455
|
+
const CLI_IMPORT_COMPANY_RESOLUTION_VERSION = "cleaned-search-v1";
|
|
13449
13456
|
class CliImportCompanySessionError extends Error {
|
|
13450
13457
|
constructor(message) {
|
|
13451
13458
|
super(message);
|
|
@@ -13591,24 +13598,39 @@ async function resolveCliImportCompanyIdentity(candidate, config, timeoutMs, bro
|
|
|
13591
13598
|
let account = null;
|
|
13592
13599
|
if (!resolvedCompanyId && candidate.companyName) {
|
|
13593
13600
|
accountSearchUsed = true;
|
|
13594
|
-
const
|
|
13595
|
-
const
|
|
13596
|
-
|
|
13597
|
-
|
|
13598
|
-
|
|
13599
|
-
|
|
13600
|
-
|
|
13601
|
+
const seenSearchNames = new Set();
|
|
13602
|
+
const searchNames = [
|
|
13603
|
+
candidate.companyName,
|
|
13604
|
+
aggressivelyCleanLookupCompanyName(candidate.companyName),
|
|
13605
|
+
].filter((value) => {
|
|
13606
|
+
const key = normalizeLookupWhitespace(value).toLowerCase();
|
|
13607
|
+
if (!key || seenSearchNames.has(key))
|
|
13608
|
+
return false;
|
|
13609
|
+
seenSearchNames.add(key);
|
|
13610
|
+
return true;
|
|
13601
13611
|
});
|
|
13602
|
-
|
|
13603
|
-
|
|
13604
|
-
|
|
13605
|
-
|
|
13606
|
-
|
|
13607
|
-
|
|
13608
|
-
|
|
13609
|
-
:
|
|
13610
|
-
|
|
13611
|
-
|
|
13612
|
+
for (const searchName of searchNames) {
|
|
13613
|
+
const queryUrl = buildCliImportAccountSearchUrl(searchName);
|
|
13614
|
+
const response = await fetchCliImportSalesNavigatorJson({
|
|
13615
|
+
url: queryUrl,
|
|
13616
|
+
config,
|
|
13617
|
+
browserRelay,
|
|
13618
|
+
timeoutMs,
|
|
13619
|
+
label: `Sales Navigator Account Search for ${searchName}`,
|
|
13620
|
+
});
|
|
13621
|
+
if (response.status < 200 || response.status >= 300) {
|
|
13622
|
+
throw new Error(`Sales Navigator Account Search for ${searchName} returned ${response.status}.`);
|
|
13623
|
+
}
|
|
13624
|
+
if (response.body) {
|
|
13625
|
+
const accounts = extractLocalSalesNavigatorElements(response.body)
|
|
13626
|
+
.map((element) => typeof element === "object" && element !== null && !Array.isArray(element)
|
|
13627
|
+
? normalizeLocalSalesNavigatorAccount(element, queryUrl)
|
|
13628
|
+
: null)
|
|
13629
|
+
.filter((value) => value !== null);
|
|
13630
|
+
account = exactCliImportAccountMatch(candidate, accounts);
|
|
13631
|
+
}
|
|
13632
|
+
if (account)
|
|
13633
|
+
break;
|
|
13612
13634
|
}
|
|
13613
13635
|
salesNavCompanyUrl =
|
|
13614
13636
|
(typeof account?.salesNavCompanyUrl === "string"
|
|
@@ -13708,6 +13730,7 @@ function buildCliImportCompanyProfile(resolution, detail, input) {
|
|
|
13708
13730
|
error: input.error ??
|
|
13709
13731
|
`Sales Navigator company detail returned ${input.status || "no result"}`,
|
|
13710
13732
|
rawPayload: {
|
|
13733
|
+
resolutionVersion: CLI_IMPORT_COMPANY_RESOLUTION_VERSION,
|
|
13711
13734
|
accountSearchUsed: resolution.accountSearchUsed,
|
|
13712
13735
|
httpStatus: input.status,
|
|
13713
13736
|
},
|
|
@@ -13780,6 +13803,7 @@ function buildCliImportCompanyProfile(resolution, detail, input) {
|
|
|
13780
13803
|
status: "enriched",
|
|
13781
13804
|
error: null,
|
|
13782
13805
|
rawPayload: {
|
|
13806
|
+
resolutionVersion: CLI_IMPORT_COMPANY_RESOLUTION_VERSION,
|
|
13783
13807
|
accountSearchUsed: resolution.accountSearchUsed,
|
|
13784
13808
|
httpStatus: input.status,
|
|
13785
13809
|
detail,
|
|
@@ -13791,6 +13815,12 @@ async function runSalesNavigatorImportEnrichmentCommand(options) {
|
|
|
13791
13815
|
if (options.companiesOnly && options.hunterOnly) {
|
|
13792
13816
|
throw new Error("Use either --companies-only or --hunter-only, not both.");
|
|
13793
13817
|
}
|
|
13818
|
+
if (options.retryCompanies && options.retryNotFoundCompanies) {
|
|
13819
|
+
throw new Error("Use either --retry-companies or --retry-not-found-companies, not both.");
|
|
13820
|
+
}
|
|
13821
|
+
if (options.retryEmails && options.retryFailedEmails) {
|
|
13822
|
+
throw new Error("Use either --retry-emails or --retry-failed-emails, not both.");
|
|
13823
|
+
}
|
|
13794
13824
|
const runIds = Array.from(new Set(options.runId.map((runId) => z.string().uuid().parse(runId))));
|
|
13795
13825
|
const companyTimeoutMs = z.coerce.number().int().min(1000).max(120000).parse(options.companyTimeoutMs);
|
|
13796
13826
|
const companyDelayMinMs = z.coerce.number().int().min(0).parse(options.companyDelayMinMs);
|
|
@@ -13805,13 +13835,24 @@ async function runSalesNavigatorImportEnrichmentCommand(options) {
|
|
|
13805
13835
|
const session = await requireAuthSession();
|
|
13806
13836
|
const startedAt = new Date().toISOString();
|
|
13807
13837
|
const initialStatus = await getCliImportEnrichmentStatusViaApp(session, runIds);
|
|
13838
|
+
const companyRetryMode = options.retryCompanies
|
|
13839
|
+
? "all"
|
|
13840
|
+
: options.retryNotFoundCompanies
|
|
13841
|
+
? "not_found"
|
|
13842
|
+
: "default";
|
|
13843
|
+
const retryStatuses = options.retryEmails
|
|
13844
|
+
? ["not_found", "failed"]
|
|
13845
|
+
: options.retryFailedEmails
|
|
13846
|
+
? ["failed"]
|
|
13847
|
+
: [];
|
|
13808
13848
|
if (options.dryRun) {
|
|
13809
13849
|
const companyCandidates = options.hunterOnly
|
|
13810
13850
|
? []
|
|
13811
13851
|
: (await getCliImportCompanyCandidatesViaApp(session, {
|
|
13812
13852
|
runIds,
|
|
13813
13853
|
limit: 1000,
|
|
13814
|
-
|
|
13854
|
+
retryMode: companyRetryMode,
|
|
13855
|
+
resolutionVersion: CLI_IMPORT_COMPANY_RESOLUTION_VERSION,
|
|
13815
13856
|
})).companies.slice(0, maxCompanies || undefined);
|
|
13816
13857
|
return {
|
|
13817
13858
|
status: "ok",
|
|
@@ -13819,6 +13860,9 @@ async function runSalesNavigatorImportEnrichmentCommand(options) {
|
|
|
13819
13860
|
runIds,
|
|
13820
13861
|
initial: initialStatus,
|
|
13821
13862
|
companyCandidates: companyCandidates.length,
|
|
13863
|
+
companyRetryMode,
|
|
13864
|
+
hunterCompanyFallback: options.hunterCompanyFallback,
|
|
13865
|
+
retryEmailStatuses: retryStatuses,
|
|
13822
13866
|
next: options.companiesOnly
|
|
13823
13867
|
? "company enrichment only"
|
|
13824
13868
|
: options.hunterOnly
|
|
@@ -13838,7 +13882,8 @@ async function runSalesNavigatorImportEnrichmentCommand(options) {
|
|
|
13838
13882
|
const companyCandidates = (await getCliImportCompanyCandidatesViaApp(session, {
|
|
13839
13883
|
runIds,
|
|
13840
13884
|
limit: 1000,
|
|
13841
|
-
|
|
13885
|
+
retryMode: companyRetryMode,
|
|
13886
|
+
resolutionVersion: CLI_IMPORT_COMPANY_RESOLUTION_VERSION,
|
|
13842
13887
|
})).companies.slice(0, maxCompanies || undefined);
|
|
13843
13888
|
companies.selected = companyCandidates.length;
|
|
13844
13889
|
if (companyCandidates.length > 0) {
|
|
@@ -14088,15 +14133,21 @@ async function runSalesNavigatorImportEnrichmentCommand(options) {
|
|
|
14088
14133
|
processed: 0,
|
|
14089
14134
|
found: 0,
|
|
14090
14135
|
notFound: 0,
|
|
14091
|
-
failed: 0
|
|
14136
|
+
failed: 0,
|
|
14137
|
+
domainLookups: 0,
|
|
14138
|
+
companyLookups: 0,
|
|
14092
14139
|
};
|
|
14093
14140
|
if (!options.companiesOnly) {
|
|
14094
|
-
const retryBefore = options.retryEmails
|
|
14141
|
+
const retryBefore = options.retryEmails || options.retryFailedEmails
|
|
14142
|
+
? startedAt
|
|
14143
|
+
: null;
|
|
14095
14144
|
while (maxHunterBatches === 0 || hunter.batches < maxHunterBatches) {
|
|
14096
14145
|
const batch = await runCliImportHunterBatchViaApp(session, {
|
|
14097
14146
|
runIds,
|
|
14098
14147
|
limit: hunterBatchSize,
|
|
14099
|
-
retryBefore
|
|
14148
|
+
retryBefore,
|
|
14149
|
+
allowCompanyFallback: options.hunterCompanyFallback,
|
|
14150
|
+
retryStatuses,
|
|
14100
14151
|
});
|
|
14101
14152
|
if (batch.selected === 0)
|
|
14102
14153
|
break;
|
|
@@ -14106,7 +14157,9 @@ async function runSalesNavigatorImportEnrichmentCommand(options) {
|
|
|
14106
14157
|
processed: hunter.processed + batch.processed,
|
|
14107
14158
|
found: hunter.found + batch.found,
|
|
14108
14159
|
notFound: hunter.notFound + batch.notFound,
|
|
14109
|
-
failed: hunter.failed + batch.failed
|
|
14160
|
+
failed: hunter.failed + batch.failed,
|
|
14161
|
+
domainLookups: hunter.domainLookups + batch.domainLookups,
|
|
14162
|
+
companyLookups: hunter.companyLookups + batch.companyLookups,
|
|
14110
14163
|
};
|
|
14111
14164
|
writeProgress(`Hunter enrichment: ${hunter.processed} checked, ${hunter.found} emails found.`);
|
|
14112
14165
|
if (batch.halted) {
|
|
@@ -14245,9 +14298,12 @@ program
|
|
|
14245
14298
|
.option("--hunter-batch-size <number>", "Hunter contacts checked per request", "100")
|
|
14246
14299
|
.option("--max-hunter-batches <number>", "Maximum Hunter batches; 0 continues until no eligible people remain", "0")
|
|
14247
14300
|
.option("--companies-only", "Stop after company profiles and domains", false)
|
|
14248
|
-
.option("--hunter-only", "Skip company lookup and use
|
|
14249
|
-
.option("--retry-companies", "
|
|
14250
|
-
.option("--retry-
|
|
14301
|
+
.option("--hunter-only", "Skip company lookup and use stored domains or company-name fallback", false)
|
|
14302
|
+
.option("--retry-companies", "Refresh every previously saved company profile", false)
|
|
14303
|
+
.option("--retry-not-found-companies", "Retry only previous exact company misses with the current resolver", false)
|
|
14304
|
+
.option("--retry-emails", "Retry previous Hunter misses and failures once", false)
|
|
14305
|
+
.option("--retry-failed-emails", "Retry only previous Hunter failures once", false)
|
|
14306
|
+
.option("--no-hunter-company-fallback", "Require a verified domain and skip Hunter company-name fallback")
|
|
14251
14307
|
.option("--dry-run", "Show scope without LinkedIn or Hunter requests", false)
|
|
14252
14308
|
.option("--out <path>", "Optional JSON result path")
|
|
14253
14309
|
.action(async (options) => {
|
package/package.json
CHANGED