salesprompter-cli 0.1.54 → 0.1.55

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 +11 -0
  2. package/dist/cli.js +66 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -110,6 +110,17 @@ salesprompter packs:list
110
110
  salesprompter --help
111
111
  ```
112
112
 
113
+ Download stored workspace leads without starting a new Sales Navigator scrape:
114
+
115
+ ```bash
116
+ salesprompter leads:download --out ./salesprompter-leads.csv
117
+ salesprompter leads:download --run-id <uuid> --emails-only --out ./run-leads.csv
118
+ ```
119
+
120
+ Use `--search <value>` to match a person, title, or company. The command uses the
121
+ active Salesprompter workspace and downloads the same filtered data available in
122
+ the app's CLI imports view.
123
+
113
124
  ## Output modes
114
125
 
115
126
  - `--json` for machine-readable output
package/dist/cli.js CHANGED
@@ -526,6 +526,7 @@ const cliPacks = [
526
526
  commands: [
527
527
  "leads:discover",
528
528
  "leads:collect",
529
+ "leads:download",
529
530
  "leads:enrich-import",
530
531
  "search:run",
531
532
  "search:status",
@@ -587,6 +588,7 @@ const helpVisibleCommandNames = new Set([
587
588
  "wizard",
588
589
  "auth:whoami",
589
590
  "llm:ready",
591
+ "leads:download",
590
592
  "contacts:find-linkedin-urls",
591
593
  "companies:find-linkedin-urls",
592
594
  "contacts:process-emails",
@@ -6757,6 +6759,59 @@ async function runCliImportEnrichmentAction(session, body, schema) {
6757
6759
  }), schema);
6758
6760
  return value;
6759
6761
  }
6762
+ function parseDownloadFilename(contentDisposition) {
6763
+ const match = contentDisposition?.match(/filename="?([^";]+)"?/i);
6764
+ return match?.[1]?.trim() || `salesprompter-leads-${new Date().toISOString().slice(0, 10)}.csv`;
6765
+ }
6766
+ async function runLeadsDownloadCommand(options) {
6767
+ const session = await requireAuthSession();
6768
+ const runId = options.runId ? z.string().uuid().parse(options.runId) : null;
6769
+ const search = options.search?.trim() || null;
6770
+ const { value } = await withRefreshableAuthSession(session, async (currentSession) => {
6771
+ const url = new URL('/api/cli/leads/imports/export', currentSession.apiBaseUrl);
6772
+ if (runId)
6773
+ url.searchParams.set('runId', runId);
6774
+ if (search)
6775
+ url.searchParams.set('q', search);
6776
+ if (options.emailsOnly)
6777
+ url.searchParams.set('emailsOnly', '1');
6778
+ const response = await fetch(url, {
6779
+ headers: { Authorization: `Bearer ${currentSession.accessToken}` },
6780
+ });
6781
+ if (!response.ok) {
6782
+ const raw = await response.text();
6783
+ let message = `lead download failed (${response.status})`;
6784
+ try {
6785
+ const payload = JSON.parse(raw);
6786
+ if (typeof payload.error === 'string')
6787
+ message = payload.error;
6788
+ }
6789
+ catch {
6790
+ if (raw.trim())
6791
+ message = raw.trim();
6792
+ }
6793
+ throw new CliApiRequestError(message, { statusCode: response.status });
6794
+ }
6795
+ const countHeader = response.headers.get('x-salesprompter-lead-count');
6796
+ return {
6797
+ bytes: Buffer.from(await response.arrayBuffer()),
6798
+ count: countHeader == null ? null : Number.parseInt(countHeader, 10),
6799
+ filename: parseDownloadFilename(response.headers.get('content-disposition')),
6800
+ };
6801
+ });
6802
+ const outputPath = path.resolve(options.out?.trim() || value.filename);
6803
+ await mkdir(path.dirname(outputPath), { recursive: true });
6804
+ await writeFile(outputPath, value.bytes);
6805
+ return {
6806
+ status: 'ok',
6807
+ output: outputPath,
6808
+ leads: Number.isFinite(value.count) ? value.count : null,
6809
+ bytes: value.bytes.length,
6810
+ runId,
6811
+ search,
6812
+ emailsOnly: options.emailsOnly,
6813
+ };
6814
+ }
6760
6815
  async function getCliImportCompanyCandidatesViaApp(session, input) {
6761
6816
  return runCliImportEnrichmentAction(session, {
6762
6817
  action: "company-candidates",
@@ -14284,6 +14339,17 @@ program
14284
14339
  .action(async (options) => {
14285
14340
  printOutput(await runSalesNavigatorPeopleCollectCommand(options));
14286
14341
  });
14342
+ program
14343
+ .command("leads:download")
14344
+ .alias("leads:export-csv")
14345
+ .description("Download stored leads from the active Salesprompter workspace as CSV.")
14346
+ .option("--run-id <uuid>", "Limit the CSV to one CLI import run")
14347
+ .option("--search <value>", "Filter by person, title, or company")
14348
+ .option("--emails-only", "Include only leads with a found email", false)
14349
+ .option("--out <path>", "CSV output path; defaults to a dated filename")
14350
+ .action(async (options) => {
14351
+ printOutput(await runLeadsDownloadCommand(options));
14352
+ });
14287
14353
  program
14288
14354
  .command("salesnav:people:enrich")
14289
14355
  .alias("leads:enrich-import")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "salesprompter-cli",
3
- "version": "0.1.54",
3
+ "version": "0.1.55",
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",