@signaliz/cli 1.0.44 → 1.0.46

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 +12 -14
  2. package/dist/bin.js +104 -30
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -18,21 +18,18 @@ signaliz find-email --company-domain example.com --full-name "Jane Doe" --skip-c
18
18
  signaliz verify-email jane@example.com
19
19
  # Force a fresh-provider verification instead of reusing cached proof
20
20
  signaliz verify-email jane@example.com --skip-cache
21
+ # Preview any single or batch product request without provider calls or credits
22
+ signaliz verify-email jane@example.com --dry-run --json
21
23
  # Return early when a provider check runs long, then resume the exact run
22
24
  signaliz verify-email jane@example.com --skip-cache --no-wait --json
23
25
  signaliz verify-email --verification-run-id run_... --json
24
26
  signaliz company-signals --domain example.com --research-prompt "expansion priorities"
25
- # Resume a queued run in a later agent/process without duplicate spend
26
- signaliz company-signals --signal-run-id run_...
27
27
  signaliz signal-to-copy \
28
28
  --company-domain example.com \
29
29
  --person-name "Jane Doe" \
30
30
  --title "VP Sales" \
31
31
  --campaign-offer "pipeline intelligence"
32
32
 
33
- # Resume a queued copy request with the returned ID only
34
- signaliz signal-to-copy --signal-run-id copy_... --json
35
-
36
33
  # Force fresh signals or opt into slower deep research only when needed
37
34
  signaliz signal-to-copy --company-domain example.com --person-name "Jane Doe" \
38
35
  --title "VP Sales" --campaign-offer "pipeline intelligence" --skip-cache --deep-search
@@ -70,20 +67,21 @@ JSONL writes one `{ "type": "result", ... }` line per input followed by one
70
67
  Failed result lines preserve `errorCode`, `retryEligible`, and
71
68
  `retryAfterSeconds` when the API supplies recovery guidance.
72
69
 
73
- If a batch submission response is lost, rerun the same command with
74
- `--idempotency-key <key>` to recover the original job without duplicate work.
70
+ If a single request or batch submission response is lost, rerun the same
71
+ command with `--idempotency-key <key>` to recover the original request or supported email job
72
+ without duplicate work. Add `--dry-run` to any product command, including one
73
+ using `--input`, to receive a conservative credit ceiling without provider
74
+ calls, jobs, writes, or spend.
75
75
 
76
76
  Batch input is capped at 5,000 records, concurrency is bounded to `1-50`, input
77
77
  order is preserved, and a failed item does not abort successful items.
78
78
  Exact duplicate tasks are single-flighted across the full input before
79
79
  transport. Find Email and Verify Email inputs larger than 25 use one cache-aware
80
- recoverable REST job with 500-row result pages. Uniform Company Signal
81
- Enrichment inputs larger than 25 use one cache-aware recoverable REST job with
82
- 25-row result pages; heterogeneous, no-wait, and per-run recovery inputs keep
83
- the 25-row request path. Signal to Copy inputs larger than 25 use one
84
- recoverable REST job when they can reuse available signal data; fresh or
85
- deep-search requests keep the 25-row path. Signal to Copy also shares company
86
- research across recipients.
80
+ recoverable REST job with 500-row result pages. Company Signal Enrichment and
81
+ Signal to Copy inputs larger than 25 are chunked client-side into synchronous
82
+ requests of at most 25; the CLI waits for every chunk and emits only complete
83
+ results or terminal per-row errors. Signal to Copy also shares company research
84
+ across recipients.
87
85
 
88
86
  Connection commands are limited to access infrastructure:
89
87
 
package/dist/bin.js CHANGED
@@ -14,12 +14,12 @@ var HELP = `Signaliz CLI
14
14
  Four product commands:
15
15
  signaliz find-email --company-domain example.com --full-name "Jane Doe" [--skip-cache]
16
16
  signaliz verify-email [jane@example.com] [--verification-run-id run_...] [--no-wait] [--max-wait-ms 600000]
17
- signaliz company-signals --domain example.com [--research-prompt "..."] [--no-summary] [--max-wait-ms 1200000]
18
- signaliz company-signals --signal-run-id run_... Resume without duplicate spend
17
+ signaliz company-signals --domain example.com [--research-prompt "..."] [--search-mode fast|balanced|coverage] [--no-summary] [--max-wait-ms 120000]
18
+ signaliz company-signals --signal-run-id run_... Read a completed run without duplicate spend
19
19
  signaliz signal-to-copy --company-domain example.com --person-name "Jane Doe" \\
20
20
  --title "VP Sales" --campaign-offer "pipeline intelligence" [--signal-run-id run_...] \\
21
- [--skip-cache] [--deep-search] [--max-wait-ms 1200000]
22
- signaliz signal-to-copy --signal-run-id copy_... Resume with the returned ID only
21
+ [--skip-cache] [--deep-search] [--max-wait-ms 120000]
22
+ signaliz signal-to-copy --signal-run-id copy_... Reuse a completed signal run
23
23
 
24
24
  Access and connection:
25
25
  signaliz auth login
@@ -39,7 +39,10 @@ Common flags:
39
39
  --input <json-or-jsonl-file> Batch up to 5,000 records with any product command
40
40
  --input - Read a JSON array or JSONL batch from stdin
41
41
  --concurrency <1-50> Simultaneous API requests for batch input (default: 10)
42
- --idempotency-key <key> Reuse after an ambiguous batch submission to recover the same job
42
+ --idempotency-key <key> Reuse after an ambiguous response to recover the same request or job
43
+ --dry-run Return a no-spend plan without provider calls, jobs, or writes
44
+
45
+ Company Signals and Signal to Copy always wait for complete results or terminal errors.
43
46
  `;
44
47
  function loadConfig() {
45
48
  if (!(0, import_node_fs.existsSync)(CONFIG_FILE)) return {};
@@ -84,6 +87,11 @@ function csvFlag(name) {
84
87
  const value = flag(name);
85
88
  return value?.split(",").map((item) => item.trim()).filter(Boolean);
86
89
  }
90
+ function companySignalSearchMode(value) {
91
+ if (value === void 0 || value === null || value === "") return void 0;
92
+ if (value === "fast" || value === "balanced" || value === "coverage") return value;
93
+ fail("--search-mode must be fast, balanced, or coverage");
94
+ }
87
95
  function readBatchInput() {
88
96
  const path = flag("input");
89
97
  if (!path) return null;
@@ -121,6 +129,11 @@ function batchOptions() {
121
129
  compactDuplicates: !hasFlag("expand-duplicates")
122
130
  };
123
131
  }
132
+ function rejectAsyncSignalFlags() {
133
+ if (hasFlag("no-wait") || hasFlag("poll-interval-ms")) {
134
+ fail("Company Signals and Signal to Copy are always synchronous; --no-wait and --poll-interval-ms are not supported.");
135
+ }
136
+ }
124
137
  function batchOutput(value) {
125
138
  if (hasFlag("jsonl")) {
126
139
  for (const result of value.results) {
@@ -143,6 +156,15 @@ function batchOutput(value) {
143
156
  if (value.failed > 0) process.stdout.write("Use --json to inspect per-record errors.\n");
144
157
  });
145
158
  }
159
+ function dryRunOutput(value) {
160
+ output(value, () => {
161
+ process.stdout.write(`Planned ${value.inputCount} ${value.capability} request(s).
162
+ `);
163
+ process.stdout.write(`Maximum estimated credits: ${value.estimatedCredits.max}
164
+ `);
165
+ process.stdout.write("No provider calls, jobs, writes, or credits were used.\n");
166
+ });
167
+ }
146
168
  function resolveApiKey() {
147
169
  const key = process.env.SIGNALIZ_API_KEY || loadConfig().apiKey;
148
170
  if (!key) fail("No API key configured. Run: signaliz auth login");
@@ -238,7 +260,7 @@ async function auth(args) {
238
260
  async function findEmail() {
239
261
  const rows = readBatchInput();
240
262
  if (rows) {
241
- const result2 = await createClient().findEmails(rows.map((value) => {
263
+ const requests = rows.map((value) => {
242
264
  const row = record(value);
243
265
  return {
244
266
  companyDomain: row.companyDomain || row.company_domain || row.domain,
@@ -249,7 +271,13 @@ async function findEmail() {
249
271
  companyName: row.companyName || row.company_name,
250
272
  skipCache: row.skipCache ?? row.skip_cache ?? hasFlag("skip-cache")
251
273
  };
252
- }), batchOptions());
274
+ });
275
+ if (hasFlag("dry-run")) {
276
+ const result3 = await createClient().findEmails(requests, { ...batchOptions(), dryRun: true });
277
+ dryRunOutput(result3);
278
+ return;
279
+ }
280
+ const result2 = await createClient().findEmails(requests, batchOptions());
253
281
  batchOutput(result2);
254
282
  return;
255
283
  }
@@ -261,15 +289,22 @@ async function findEmail() {
261
289
  if (!companyDomain || !fullName && !(firstName && lastName)) {
262
290
  fail('Usage: signaliz find-email --company-domain example.com --full-name "Jane Doe"');
263
291
  }
264
- const result = await createClient().findEmail({
292
+ const request = {
265
293
  companyDomain,
266
294
  fullName,
267
295
  firstName,
268
296
  lastName,
269
297
  linkedinUrl,
270
298
  companyName: flag("company-name"),
271
- skipCache: hasFlag("skip-cache")
272
- });
299
+ skipCache: hasFlag("skip-cache"),
300
+ idempotencyKey: flag("idempotency-key")
301
+ };
302
+ if (hasFlag("dry-run")) {
303
+ const result2 = await createClient().findEmail({ ...request, dryRun: true });
304
+ dryRunOutput(result2);
305
+ return;
306
+ }
307
+ const result = await createClient().findEmail(request);
273
308
  output(result, () => {
274
309
  process.stdout.write(`${result.email || "No email found"} (${result.verificationStatus})
275
310
  `);
@@ -286,6 +321,15 @@ async function verifyEmail(args) {
286
321
  const rows = readBatchInput();
287
322
  if (rows) {
288
323
  const emails = rows.map((value) => typeof value === "string" ? value : String(record(value).email || ""));
324
+ if (hasFlag("dry-run")) {
325
+ const result3 = await createClient().verifyEmails(emails, {
326
+ ...batchOptions(),
327
+ skipCache: hasFlag("skip-cache"),
328
+ dryRun: true
329
+ });
330
+ dryRunOutput(result3);
331
+ return;
332
+ }
289
333
  const result2 = await createClient().verifyEmails(emails, {
290
334
  ...batchOptions(),
291
335
  skipCache: hasFlag("skip-cache")
@@ -296,13 +340,20 @@ async function verifyEmail(args) {
296
340
  const email = args[0] && !args[0].startsWith("--") ? args[0] : flag("email");
297
341
  const verificationRunId = flag("verification-run-id");
298
342
  if (!email && !verificationRunId) fail("Usage: signaliz verify-email [jane@example.com] [--verification-run-id run_...]");
299
- const result = await createClient().verifyEmail(email, {
343
+ const options = {
300
344
  skipCache: hasFlag("skip-cache"),
301
345
  verificationRunId,
302
346
  waitForResult: !hasFlag("no-wait"),
303
347
  maxWaitMs: numberFlag("max-wait-ms"),
304
- pollIntervalMs: numberFlag("poll-interval-ms")
305
- });
348
+ pollIntervalMs: numberFlag("poll-interval-ms"),
349
+ idempotencyKey: flag("idempotency-key")
350
+ };
351
+ if (hasFlag("dry-run")) {
352
+ const result2 = await createClient().verifyEmail(email, { ...options, dryRun: true });
353
+ dryRunOutput(result2);
354
+ return;
355
+ }
356
+ const result = await createClient().verifyEmail(email, options);
306
357
  output(result, () => {
307
358
  if (result.status === "processing") {
308
359
  process.stdout.write(`Verification processing: ${result.verificationRunId}
@@ -319,9 +370,10 @@ Catch-all: ${result.isCatchAll}
319
370
  });
320
371
  }
321
372
  async function companySignals() {
373
+ rejectAsyncSignalFlags();
322
374
  const rows = readBatchInput();
323
375
  if (rows) {
324
- const result2 = await createClient().enrichCompanies(rows.map((value) => {
376
+ const requests = rows.map((value) => {
325
377
  const row = record(value);
326
378
  const online = row.online ?? !hasFlag("offline");
327
379
  return {
@@ -334,15 +386,20 @@ async function companySignals() {
334
386
  lookbackDays: row.lookbackDays || row.lookback_days || numberFlag("lookback-days"),
335
387
  online,
336
388
  enableDeepSearch: row.enableDeepSearch ?? row.enable_deep_search ?? (online && !hasFlag("shallow")),
389
+ searchMode: companySignalSearchMode(row.searchMode ?? row.search_mode ?? flag("search-mode")),
337
390
  includeSummary: row.includeSummary ?? row.include_summary ?? !hasFlag("no-summary"),
338
391
  enableOutreachIntelligence: row.enableOutreachIntelligence ?? row.enable_outreach_intelligence,
339
392
  enablePredictiveIntelligence: row.enablePredictiveIntelligence ?? row.enable_predictive_intelligence,
340
393
  skipCache: row.skipCache ?? row.skip_cache ?? hasFlag("skip-cache"),
341
- waitForResult: row.waitForResult ?? row.wait_for_result ?? !hasFlag("no-wait"),
342
- maxWaitMs: row.maxWaitMs || row.max_wait_ms || numberFlag("max-wait-ms"),
343
- pollIntervalMs: row.pollIntervalMs || row.poll_interval_ms || numberFlag("poll-interval-ms")
394
+ maxWaitMs: row.maxWaitMs || row.max_wait_ms || numberFlag("max-wait-ms")
344
395
  };
345
- }), batchOptions());
396
+ });
397
+ if (hasFlag("dry-run")) {
398
+ const result3 = await createClient().enrichCompanies(requests, { ...batchOptions(), dryRun: true });
399
+ dryRunOutput(result3);
400
+ return;
401
+ }
402
+ const result2 = await createClient().enrichCompanies(requests, batchOptions());
346
403
  batchOutput(result2);
347
404
  return;
348
405
  }
@@ -350,7 +407,7 @@ async function companySignals() {
350
407
  const companyName = flag("company-name");
351
408
  const signalRunId = flag("signal-run-id");
352
409
  if (!companyDomain && !companyName && !signalRunId) fail("Usage: signaliz company-signals --domain example.com");
353
- const result = await createClient().enrichCompanySignals({
410
+ const request = {
354
411
  signalRunId,
355
412
  companyDomain,
356
413
  companyName,
@@ -360,14 +417,20 @@ async function companySignals() {
360
417
  lookbackDays: numberFlag("lookback-days"),
361
418
  online: !hasFlag("offline"),
362
419
  enableDeepSearch: !hasFlag("offline") && !hasFlag("shallow"),
420
+ searchMode: companySignalSearchMode(flag("search-mode")),
363
421
  includeSummary: !hasFlag("no-summary"),
364
422
  enableOutreachIntelligence: hasFlag("outreach-intelligence") || void 0,
365
423
  enablePredictiveIntelligence: hasFlag("predictive-intelligence") || void 0,
366
424
  skipCache: hasFlag("skip-cache"),
367
- waitForResult: !hasFlag("no-wait"),
368
425
  maxWaitMs: numberFlag("max-wait-ms"),
369
- pollIntervalMs: numberFlag("poll-interval-ms")
370
- });
426
+ idempotencyKey: flag("idempotency-key")
427
+ };
428
+ if (hasFlag("dry-run")) {
429
+ const result2 = await createClient().enrichCompanySignals({ ...request, dryRun: true });
430
+ dryRunOutput(result2);
431
+ return;
432
+ }
433
+ const result = await createClient().enrichCompanySignals(request);
371
434
  output(result, () => {
372
435
  process.stdout.write(`Company: ${result.company.name || result.company.domain}
373
436
  Signals: ${result.signalCount}
@@ -379,9 +442,10 @@ Signals: ${result.signalCount}
379
442
  });
380
443
  }
381
444
  async function signalToCopy() {
445
+ rejectAsyncSignalFlags();
382
446
  const rows = readBatchInput();
383
447
  if (rows) {
384
- const result2 = await createClient().createSignalCopyBatch(rows.map((value) => {
448
+ const requests = rows.map((value) => {
385
449
  const row = record(value);
386
450
  return {
387
451
  companyDomain: row.companyDomain || row.company_domain || row.domain,
@@ -392,11 +456,15 @@ async function signalToCopy() {
392
456
  signalRunId: row.signalRunId || row.signal_run_id,
393
457
  skipCache: row.skipCache ?? row.skip_cache ?? hasFlag("skip-cache"),
394
458
  enableDeepSearch: row.enableDeepSearch ?? row.enable_deep_search ?? hasFlag("deep-search"),
395
- waitForResult: row.waitForResult ?? row.wait_for_result ?? !hasFlag("no-wait"),
396
- maxWaitMs: row.maxWaitMs || row.max_wait_ms || numberFlag("max-wait-ms"),
397
- pollIntervalMs: row.pollIntervalMs || row.poll_interval_ms || numberFlag("poll-interval-ms")
459
+ maxWaitMs: row.maxWaitMs || row.max_wait_ms || numberFlag("max-wait-ms")
398
460
  };
399
- }), batchOptions());
461
+ });
462
+ if (hasFlag("dry-run")) {
463
+ const result3 = await createClient().createSignalCopyBatch(requests, { ...batchOptions(), dryRun: true });
464
+ dryRunOutput(result3);
465
+ return;
466
+ }
467
+ const result2 = await createClient().createSignalCopyBatch(requests, batchOptions());
400
468
  batchOutput(result2);
401
469
  return;
402
470
  }
@@ -408,7 +476,7 @@ async function signalToCopy() {
408
476
  if (!signalRunId && (!companyDomain || !personName || !title || !campaignOffer)) {
409
477
  fail('Usage: signaliz signal-to-copy --company-domain example.com --person-name "Jane Doe" --title "VP Sales" --campaign-offer "pipeline intelligence" OR signaliz signal-to-copy --signal-run-id copy_...');
410
478
  }
411
- const result = await createClient().signalToCopy({
479
+ const request = {
412
480
  companyDomain,
413
481
  personName,
414
482
  title,
@@ -418,8 +486,14 @@ async function signalToCopy() {
418
486
  skipCache: hasFlag("skip-cache"),
419
487
  enableDeepSearch: hasFlag("deep-search"),
420
488
  maxWaitMs: numberFlag("max-wait-ms"),
421
- pollIntervalMs: numberFlag("poll-interval-ms")
422
- });
489
+ idempotencyKey: flag("idempotency-key")
490
+ };
491
+ if (hasFlag("dry-run")) {
492
+ const result2 = await createClient().signalToCopy({ ...request, dryRun: true });
493
+ dryRunOutput(result2);
494
+ return;
495
+ }
496
+ const result = await createClient().signalToCopy(request);
423
497
  output(result, () => {
424
498
  if (result.variations.length === 0) {
425
499
  process.stdout.write(`${String(result.raw.message || "Signal research completed without supported evidence.")}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signaliz/cli",
3
- "version": "1.0.44",
3
+ "version": "1.0.46",
4
4
  "description": "Signaliz CLI for Find Email, Verify Email, Company Signal Enrichment, and Signal to Copy AI.",
5
5
  "bin": {
6
6
  "signaliz": "dist/bin.js"
@@ -28,7 +28,7 @@
28
28
  "node": ">=18"
29
29
  },
30
30
  "dependencies": {
31
- "@signaliz/sdk": "^1.0.46"
31
+ "@signaliz/sdk": "^1.0.47"
32
32
  },
33
33
  "devDependencies": {
34
34
  "tsup": "^8.0.0",