salesprompter-cli 0.1.36 → 0.1.37
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/dist/cli.js +101 -6
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
|
-
import { access, appendFile, mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import { access, appendFile, mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import os from "node:os";
|
|
6
6
|
import path from "node:path";
|
|
@@ -136,7 +136,13 @@ const PhantombusterContainersSyncResponseSchema = z.object({
|
|
|
136
136
|
resultsSynced: z.number().int().nonnegative(),
|
|
137
137
|
outputsStored: z.number().int().nonnegative(),
|
|
138
138
|
resultObjectsStored: z.number().int().nonnegative(),
|
|
139
|
-
resultRowsStored: z.number().int().nonnegative()
|
|
139
|
+
resultRowsStored: z.number().int().nonnegative(),
|
|
140
|
+
leadListsProjected: z.number().int().nonnegative().optional(),
|
|
141
|
+
leadListContactsProjected: z.number().int().nonnegative().optional(),
|
|
142
|
+
contactsProjected: z.number().int().nonnegative().optional(),
|
|
143
|
+
leadPoolRows: z.number().int().nonnegative().nullable().optional(),
|
|
144
|
+
qualifiedContacts: z.number().int().nonnegative().nullable().optional(),
|
|
145
|
+
qualifiedCompanies: z.number().int().nonnegative().nullable().optional()
|
|
140
146
|
});
|
|
141
147
|
const CliEmailEnrichmentCompaniesResponseSchema = z.object({
|
|
142
148
|
clientId: z.number().int().positive(),
|
|
@@ -4834,19 +4840,29 @@ function buildLinkedInProductCategorySalesNavigatorOutputPath(categorySlug) {
|
|
|
4834
4840
|
return `./data/salesnav-product-category-${categorySlug}.json`;
|
|
4835
4841
|
}
|
|
4836
4842
|
const SALES_NAVIGATOR_TERMINAL_JOB_STATUSES = new Set(["completed", "completed_with_failures"]);
|
|
4843
|
+
const WORKFLOW_LOCAL_LOG_MAX_FILE_BYTES = 10 * 1024 * 1024;
|
|
4844
|
+
const WORKFLOW_LOCAL_LOG_MAX_LINE_BYTES = 32 * 1024;
|
|
4845
|
+
const WORKFLOW_LOCAL_LOG_MAX_STRING_CHARS = 4000;
|
|
4846
|
+
const WORKFLOW_LOCAL_LOG_MAX_ARRAY_ITEMS = 50;
|
|
4847
|
+
const WORKFLOW_LOCAL_LOG_MAX_OBJECT_KEYS = 50;
|
|
4848
|
+
const WORKFLOW_LOCAL_LOG_MAX_DEPTH = 5;
|
|
4837
4849
|
function isSalesNavigatorCrawlJobTerminal(status) {
|
|
4838
4850
|
return SALES_NAVIGATOR_TERMINAL_JOB_STATUSES.has(status);
|
|
4839
4851
|
}
|
|
4840
4852
|
function buildWorkflowTraceId(prefix) {
|
|
4841
4853
|
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
4842
4854
|
}
|
|
4855
|
+
function buildWorkflowLogRunSuffix() {
|
|
4856
|
+
const timestamp = new Date().toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
4857
|
+
return `${timestamp}-${Math.random().toString(36).slice(2, 8)}`;
|
|
4858
|
+
}
|
|
4843
4859
|
function buildSalesNavigatorWorkflowLogPath(input) {
|
|
4844
4860
|
const slug = slugify(input) || "salesnav-product-category";
|
|
4845
|
-
return `./data/${slug}-salesnav.log.jsonl`;
|
|
4861
|
+
return `./data/${slug}-${buildWorkflowLogRunSuffix()}-salesnav.log.jsonl`;
|
|
4846
4862
|
}
|
|
4847
4863
|
function buildSalesNavigatorCrawlLogPath(input) {
|
|
4848
4864
|
const slug = slugify(input) || "salesnav-crawl";
|
|
4849
|
-
return `./data/${slug}-crawl.log.jsonl`;
|
|
4865
|
+
return `./data/${slug}-${buildWorkflowLogRunSuffix()}-crawl.log.jsonl`;
|
|
4850
4866
|
}
|
|
4851
4867
|
function buildSalesNavigatorCrawlOutputPath(input) {
|
|
4852
4868
|
const slug = slugify(input) || "salesnav-crawl";
|
|
@@ -4878,6 +4894,83 @@ function decodeSalesNavigatorQueryParam(url) {
|
|
|
4878
4894
|
return null;
|
|
4879
4895
|
}
|
|
4880
4896
|
}
|
|
4897
|
+
function sanitizeWorkflowLogValue(value, depth = 0, seen = new WeakSet()) {
|
|
4898
|
+
if (typeof value === "string") {
|
|
4899
|
+
if (value.length <= WORKFLOW_LOCAL_LOG_MAX_STRING_CHARS) {
|
|
4900
|
+
return value;
|
|
4901
|
+
}
|
|
4902
|
+
return `${value.slice(0, WORKFLOW_LOCAL_LOG_MAX_STRING_CHARS)}... [truncated ${value.length - WORKFLOW_LOCAL_LOG_MAX_STRING_CHARS} chars]`;
|
|
4903
|
+
}
|
|
4904
|
+
if (typeof value !== "object" || value === null) {
|
|
4905
|
+
return value;
|
|
4906
|
+
}
|
|
4907
|
+
if (seen.has(value)) {
|
|
4908
|
+
return "[Circular]";
|
|
4909
|
+
}
|
|
4910
|
+
if (depth >= WORKFLOW_LOCAL_LOG_MAX_DEPTH) {
|
|
4911
|
+
return "[MaxDepth]";
|
|
4912
|
+
}
|
|
4913
|
+
seen.add(value);
|
|
4914
|
+
if (Array.isArray(value)) {
|
|
4915
|
+
const items = value
|
|
4916
|
+
.slice(0, WORKFLOW_LOCAL_LOG_MAX_ARRAY_ITEMS)
|
|
4917
|
+
.map((item) => sanitizeWorkflowLogValue(item, depth + 1, seen));
|
|
4918
|
+
if (value.length > WORKFLOW_LOCAL_LOG_MAX_ARRAY_ITEMS) {
|
|
4919
|
+
items.push({ truncatedItems: value.length - WORKFLOW_LOCAL_LOG_MAX_ARRAY_ITEMS });
|
|
4920
|
+
}
|
|
4921
|
+
return items;
|
|
4922
|
+
}
|
|
4923
|
+
const entries = Object.entries(value);
|
|
4924
|
+
const sanitized = {};
|
|
4925
|
+
for (const [key, entryValue] of entries.slice(0, WORKFLOW_LOCAL_LOG_MAX_OBJECT_KEYS)) {
|
|
4926
|
+
sanitized[key] = sanitizeWorkflowLogValue(entryValue, depth + 1, seen);
|
|
4927
|
+
}
|
|
4928
|
+
if (entries.length > WORKFLOW_LOCAL_LOG_MAX_OBJECT_KEYS) {
|
|
4929
|
+
sanitized.truncatedKeys = entries.length - WORKFLOW_LOCAL_LOG_MAX_OBJECT_KEYS;
|
|
4930
|
+
}
|
|
4931
|
+
return sanitized;
|
|
4932
|
+
}
|
|
4933
|
+
function serializeWorkflowLogEntry(entry) {
|
|
4934
|
+
const sanitizedEntry = {
|
|
4935
|
+
...entry,
|
|
4936
|
+
metadata: sanitizeWorkflowLogValue(entry.metadata)
|
|
4937
|
+
};
|
|
4938
|
+
let line = JSON.stringify(sanitizedEntry);
|
|
4939
|
+
if (Buffer.byteLength(line, "utf8") <= WORKFLOW_LOCAL_LOG_MAX_LINE_BYTES) {
|
|
4940
|
+
return `${line}\n`;
|
|
4941
|
+
}
|
|
4942
|
+
const originalMetadata = entry.metadata ?? {};
|
|
4943
|
+
const metadataKeys = Object.keys(originalMetadata);
|
|
4944
|
+
line = JSON.stringify({
|
|
4945
|
+
...entry,
|
|
4946
|
+
metadata: {
|
|
4947
|
+
localLogTruncated: true,
|
|
4948
|
+
originalMetadataKeys: metadataKeys.slice(0, WORKFLOW_LOCAL_LOG_MAX_OBJECT_KEYS),
|
|
4949
|
+
truncatedKeys: Math.max(0, metadataKeys.length - WORKFLOW_LOCAL_LOG_MAX_OBJECT_KEYS),
|
|
4950
|
+
originalMetadataBytes: Buffer.byteLength(JSON.stringify(sanitizeWorkflowLogValue(originalMetadata)), "utf8")
|
|
4951
|
+
}
|
|
4952
|
+
});
|
|
4953
|
+
return `${line}\n`;
|
|
4954
|
+
}
|
|
4955
|
+
async function appendWorkflowLocalLog(logPath, entry) {
|
|
4956
|
+
try {
|
|
4957
|
+
const current = await stat(logPath).catch((error) => {
|
|
4958
|
+
if (error.code === "ENOENT") {
|
|
4959
|
+
return null;
|
|
4960
|
+
}
|
|
4961
|
+
throw error;
|
|
4962
|
+
});
|
|
4963
|
+
if (current && current.size >= WORKFLOW_LOCAL_LOG_MAX_FILE_BYTES) {
|
|
4964
|
+
writeProgress(`[${entry.timestamp}] ${entry.event} (local log skipped because ${logPath} is already over 10 MB; durable event storage still runs when configured)`);
|
|
4965
|
+
return;
|
|
4966
|
+
}
|
|
4967
|
+
await appendFile(logPath, serializeWorkflowLogEntry(entry), "utf8");
|
|
4968
|
+
}
|
|
4969
|
+
catch (error) {
|
|
4970
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4971
|
+
writeProgress(`[${entry.timestamp}] workflow.local_log.write_failed: ${message}`);
|
|
4972
|
+
}
|
|
4973
|
+
}
|
|
4881
4974
|
async function createWorkflowLogger(options) {
|
|
4882
4975
|
const traceId = options.traceId ?? buildWorkflowTraceId("salesprompter-cli");
|
|
4883
4976
|
const logPath = options.logPath;
|
|
@@ -4896,7 +4989,7 @@ async function createWorkflowLogger(options) {
|
|
|
4896
4989
|
event,
|
|
4897
4990
|
metadata
|
|
4898
4991
|
};
|
|
4899
|
-
await
|
|
4992
|
+
await appendWorkflowLocalLog(logPath, entry);
|
|
4900
4993
|
if (eventStore) {
|
|
4901
4994
|
try {
|
|
4902
4995
|
await eventStore.append({
|
|
@@ -9811,6 +9904,7 @@ program
|
|
|
9811
9904
|
.option("--mode <mode>", "Phantombuster container mode: all or finalized", "all")
|
|
9812
9905
|
.option("--before-ended-at <iso>", "Only fetch containers that ended before this ISO timestamp")
|
|
9813
9906
|
.option("--metadata-only", "Store container metadata without fetching output and result objects", false)
|
|
9907
|
+
.option("--refresh-lead-pool", "After syncing results, rebuild the Neon lead_pool_new reporting table. This can take several minutes.", false)
|
|
9814
9908
|
.option("--out <path>", "Optional local JSON output path")
|
|
9815
9909
|
.action(async (options) => {
|
|
9816
9910
|
const agentIds = z.array(z.string().min(1)).parse(options.agentId);
|
|
@@ -9827,7 +9921,8 @@ program
|
|
|
9827
9921
|
maxPages,
|
|
9828
9922
|
mode,
|
|
9829
9923
|
beforeEndedAt,
|
|
9830
|
-
includeResults: !options.metadataOnly
|
|
9924
|
+
includeResults: !options.metadataOnly,
|
|
9925
|
+
refreshLeadPool: Boolean(options.refreshLeadPool)
|
|
9831
9926
|
});
|
|
9832
9927
|
const payload = {
|
|
9833
9928
|
...result,
|
package/package.json
CHANGED