@signaliz/cli 1.0.56 → 1.0.57

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 +13 -1
  2. package/dist/bin.js +126 -37
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -40,6 +40,9 @@ signaliz signal-to-copy --company-domain example.com --person-name "Jane Doe" \
40
40
  # Signals Everything returns distinct companies with a source-backed signal.
41
41
  # It is asynchronous by default; add --wait or resume the returned run ID.
42
42
  signaliz signals "companies that just got funded" --limit 100 --sources web,news
43
+ signaliz signals "companies showing signals they need account-signal automation" \
44
+ --icp-context "B2B SaaS with outbound teams and manual account research" \
45
+ --limit 100 --sources web,news
43
46
  signaliz signals --signal-search-run-id run_... --wait --json
44
47
  ```
45
48
 
@@ -106,6 +109,14 @@ copy row explicitly requests fresh or deep research, the CLI preserves that
106
109
  behavior with synchronous chunks of at most 25. Signal to Copy also shares
107
110
  company research across recipients.
108
111
 
112
+ Every command uses the authenticated workspace. Find Email and Verify Email
113
+ honor that workspace's configured cache window; eligible hits cost 0 credits,
114
+ while fresh discovery or verification is charged on every plan. Team, Agency,
115
+ and Pay-As-You-Go include fresh Company Signals and Signal to Copy. Those plans
116
+ still check eligible workspace signal data first even when Company Signals is
117
+ set to No cache. `--lookback-days` remains a hard evidence-age bound for both
118
+ cached and fresh Company Signals and Signal to Copy results.
119
+
109
120
  Signals Everything is a query-first company discovery command rather than a
110
121
  row batch. It returns only dated, source-linked signals that contain both a
111
122
  company name and company domain. The default request is 100 companies and the
@@ -113,7 +124,8 @@ maximum is 1,000. It is included on Team and Agency plans, is resumable with
113
124
  `signal_search_run_id`, and reports a strict source-cost guardrail: results are
114
125
  only returned when source cost is below $0.01 per qualified company. A request
115
126
  is a ceiling, not a promise: it can return fewer results when public evidence
116
- cannot verify both a date and company identity.
127
+ cannot verify both a date and company identity. Use `--icp-context` to qualify
128
+ an open-ended signal request against a target market.
117
129
 
118
130
  Connection commands are limited to access infrastructure:
119
131
 
package/dist/bin.js CHANGED
@@ -13,14 +13,15 @@ var HELP = `Signaliz CLI
13
13
 
14
14
  Five product commands:
15
15
  signaliz find-email --company-domain example.com --full-name "Jane Doe" [--skip-cache]
16
+ signaliz find-email --run-id run_... Resume an existing Find Email run without duplicate spend
16
17
  signaliz verify-email [jane@example.com] [--verification-run-id run_...] [--no-wait] [--max-wait-ms 600000]
17
18
  signaliz company-signals --domain example.com [--research-prompt "..."] [--search-mode fast|balanced|coverage] [--include-candidate-evidence] [--no-summary] [--max-wait-ms 120000]
18
19
  signaliz company-signals --signal-run-id run_... Read a completed run without duplicate spend
19
20
  signaliz signal-to-copy --company-domain example.com --person-name "Jane Doe" \\
20
21
  --title "VP Sales" --campaign-offer "pipeline intelligence" [--signal-run-id run_...] \\
21
- [--skip-cache] [--deep-search] [--max-wait-ms 120000]
22
+ [--lookback-days 90] [--skip-cache] [--deep-search] [--max-wait-ms 120000]
22
23
  signaliz signal-to-copy --signal-run-id copy_... Reuse a completed signal run
23
- signaliz signals "companies that just got funded" [--limit 100] [--sources web,news] [--wait]
24
+ signaliz signals "companies that just got funded" [--icp-context "..."] [--limit 100] [--sources web,news] [--wait]
24
25
  signaliz signals --signal-search-run-id run_... Resume an existing company-attributed signal search
25
26
 
26
27
  Access and connection:
@@ -42,6 +43,8 @@ Common flags:
42
43
  --input - Read a JSON array or JSONL batch from stdin
43
44
  --concurrency <1-50> Simultaneous API requests for batch input (default: 10)
44
45
  --idempotency-key <key> Reuse after an ambiguous response to recover the same request or job
46
+ --run-id <run_...> Resume one existing Find Email run without dispatching new work
47
+ --icp-context <text> Optional ICP, product, or pain context that returned signals must support
45
48
  --dry-run Return a no-spend plan without provider calls, jobs, or writes
46
49
 
47
50
  Company Signals and Signal to Copy always wait for complete results or terminal errors. Signals Everything is asynchronous by default; use --wait to poll until it completes.
@@ -126,24 +129,27 @@ function record(value) {
126
129
  }
127
130
  function customerEmailResult(value) {
128
131
  const result = record(value);
129
- if (String(result.status || "").toLowerCase() === "processing") return result;
130
132
  const raw = record(result.raw);
131
- const verifiedForSending = typeof raw.verified_for_sending === "boolean" ? raw.verified_for_sending : typeof raw._verified_for_sending === "boolean" ? raw._verified_for_sending : result.raw === void 0 && typeof result.verifiedForSending === "boolean" ? result.verifiedForSending : result.raw === void 0 && typeof result.isVerifiedForSending === "boolean" ? result.isVerifiedForSending : void 0;
132
- const isCatchAll = typeof result.isCatchAll === "boolean" ? result.isCatchAll : void 0;
133
- const isMalformed = result.isMalformed === true || raw.is_malformed === true;
134
- const verificationStatus = result.verificationStatus || result.verificationVerdict;
133
+ if (String(result.status || "").toLowerCase() === "processing") {
134
+ const verificationRunId = result.verificationRunId ?? raw.verification_run_id;
135
+ const runId = result.runId ?? raw.run_id ?? verificationRunId;
136
+ return {
137
+ success: true,
138
+ status: "processing",
139
+ email: null,
140
+ run_id: runId,
141
+ ...verificationRunId ? { verification_run_id: verificationRunId } : {},
142
+ next_poll_after_seconds: result.nextPollAfterSeconds ?? raw.next_poll_after_seconds,
143
+ suggested_action: result.suggestedAction ?? raw.suggested_action ?? (verificationRunId ? "retry_with_verification_run_id" : "retry_with_run_id")
144
+ };
145
+ }
146
+ const creditsUsed = Number(result.creditsUsed ?? raw.credits_used ?? 0);
135
147
  return {
136
- ...result,
137
148
  email: typeof result.email === "string" && result.email.trim() ? result.email.trim() : null,
138
149
  status: "completed",
139
150
  success: result.success === true,
140
- is_valid: verifiedForSending ?? result.isValid ?? result.isVerified ?? false,
141
- credits_used: Number(result.creditsUsed || 0),
142
- ...verifiedForSending !== void 0 ? { verified_for_sending: verifiedForSending } : {},
143
- ...isCatchAll !== void 0 ? { email_is_catch_all: isCatchAll, is_catch_all: isCatchAll } : {},
144
- ...typeof result.isMalformed === "boolean" || typeof raw.is_malformed === "boolean" ? { is_malformed: isMalformed } : {},
145
- ...verificationStatus ? { verification_status: verificationStatus, verification_verdict: verificationStatus } : {},
146
- ...result.billingMetadata ? { billing_metadata: result.billingMetadata } : {}
151
+ is_valid: typeof raw.is_valid === "boolean" ? raw.is_valid : result.isValid ?? result.isVerified ?? false,
152
+ credits_used: Number.isFinite(creditsUsed) && creditsUsed >= 0 ? creditsUsed : 0
147
153
  };
148
154
  }
149
155
  function customerEmailBatch(value) {
@@ -151,10 +157,19 @@ function customerEmailBatch(value) {
151
157
  ...value,
152
158
  results: value.results.map((item) => {
153
159
  const row = record(item);
154
- return row.data ? { ...row, data: customerEmailResult(row.data) } : row;
160
+ return promoteBatchRecoveryMetadata(row.data ? { ...row, data: customerEmailResult(row.data) } : row);
155
161
  })
156
162
  };
157
163
  }
164
+ function promoteBatchRecoveryMetadata(row) {
165
+ return {
166
+ ...row,
167
+ ...typeof row.runId === "string" ? { run_id: row.runId } : {},
168
+ ...typeof row.verificationRunId === "string" ? { verification_run_id: row.verificationRunId } : {},
169
+ ...typeof row.jobId === "string" ? { job_id: row.jobId } : {},
170
+ ...typeof row.suggestedAction === "string" ? { suggested_action: row.suggestedAction } : {}
171
+ };
172
+ }
158
173
  function customerSignalResult(value) {
159
174
  const result = record(value);
160
175
  const raw = record(result.raw);
@@ -176,7 +191,7 @@ function customerSignalBatch(value) {
176
191
  ...value,
177
192
  results: value.results.map((item) => {
178
193
  const row = record(item);
179
- return row.data ? { ...row, data: customerSignalResult(row.data) } : row;
194
+ return promoteBatchRecoveryMetadata(row.data ? { ...row, data: customerSignalResult(row.data) } : row);
180
195
  })
181
196
  };
182
197
  }
@@ -256,6 +271,9 @@ function numberValue(value) {
256
271
  const number = Number(value);
257
272
  return Number.isFinite(number) ? number : void 0;
258
273
  }
274
+ function nullableNumberValue(value) {
275
+ return value === null ? null : numberValue(value);
276
+ }
259
277
  function stringValue(value) {
260
278
  return typeof value === "string" ? value.trim() : "";
261
279
  }
@@ -311,6 +329,7 @@ function normalizeSignalsEverythingResult(request, value) {
311
329
  const status = statuses.has(statusValue) ? statusValue : signals2.length > 0 ? "completed" : "failed";
312
330
  const guardrail = record(value.cost_guardrail);
313
331
  const maxCost = numberValue(guardrail.max_cost_per_qualified_signal_usd);
332
+ const identityCostSource = stringValue(guardrail.identity_cost_source);
314
333
  const warnings = Array.isArray(value.warnings) ? value.warnings.filter((warning) => typeof warning === "string") : void 0;
315
334
  return {
316
335
  success: value.success !== false,
@@ -327,7 +346,15 @@ function normalizeSignalsEverythingResult(request, value) {
327
346
  ...maxCost === void 0 ? {} : {
328
347
  costGuardrail: {
329
348
  maxCostPerQualifiedSignalUsd: maxCost,
330
- costPerQualifiedSignalUsd: value.cost_guardrail && typeof value.cost_guardrail === "object" ? numberValue(guardrail.cost_per_qualified_signal_usd) ?? (guardrail.cost_per_qualified_signal_usd === null ? null : void 0) : void 0
349
+ costPerQualifiedSignalUsd: nullableNumberValue(guardrail.cost_per_qualified_signal_usd),
350
+ identityResolutionCostUsd: nullableNumberValue(guardrail.identity_resolution_cost_usd),
351
+ identityCostSource: [
352
+ "observed_zero_credit_receipts",
353
+ "contractual_zero_cost",
354
+ "not_used",
355
+ "unavailable"
356
+ ].includes(identityCostSource) ? identityCostSource : void 0,
357
+ identityProviderRequests: numberValue(guardrail.identity_provider_requests)
331
358
  }
332
359
  },
333
360
  ...warnings?.length ? { warnings } : {},
@@ -342,6 +369,7 @@ async function discoverSignalsEverything(request) {
342
369
  ...request.idempotencyKey ? { idempotency_key: request.idempotencyKey } : {}
343
370
  } : {
344
371
  query: request.query,
372
+ ...request.icpContext ? { icp_context: request.icpContext } : {},
345
373
  limit: request.limit ?? 100,
346
374
  ...request.sources ? { sources: request.sources } : {},
347
375
  ...request.lookbackDays === void 0 ? {} : { lookback_days: request.lookbackDays },
@@ -469,6 +497,8 @@ async function findEmail() {
469
497
  if (rows) {
470
498
  const requests = rows.map((value) => {
471
499
  const row = record(value);
500
+ const runId2 = row.runId || row.run_id;
501
+ if (runId2) return { runId: runId2 };
472
502
  return {
473
503
  companyDomain: row.companyDomain || row.company_domain || row.domain,
474
504
  fullName: row.fullName || row.full_name || row.name,
@@ -489,14 +519,15 @@ async function findEmail() {
489
519
  return;
490
520
  }
491
521
  const companyDomain = flag("company-domain") || flag("domain");
522
+ const runId = flag("run-id");
492
523
  const fullName = flag("full-name");
493
524
  const firstName = flag("first-name");
494
525
  const lastName = flag("last-name");
495
526
  const linkedinUrl = flag("linkedin-url");
496
- if (!companyDomain || !fullName && !(firstName && lastName)) {
497
- fail('Usage: signaliz find-email --company-domain example.com --full-name "Jane Doe"');
527
+ if (!runId && (!companyDomain || !fullName && !(firstName && lastName))) {
528
+ fail('Usage: signaliz find-email --company-domain example.com --full-name "Jane Doe", or signaliz find-email --run-id run_...');
498
529
  }
499
- const request = {
530
+ const request = runId ? { runId } : {
500
531
  companyDomain,
501
532
  fullName,
502
533
  firstName,
@@ -515,21 +546,23 @@ async function findEmail() {
515
546
  const publicResult = customerEmailResult(result);
516
547
  if (outputFailedCoreProduct(publicResult, "No verified email found")) return;
517
548
  output(publicResult, () => {
518
- process.stdout.write(`${result.email || "No email found"} (${result.verificationStatus})
549
+ if (result.status === "processing" && result.runId) {
550
+ process.stdout.write(`Find Email processing: ${result.runId}
519
551
  `);
520
- process.stdout.write(`Verified for sending: ${result.isVerifiedForSending}
552
+ process.stdout.write(`Retry after ${result.nextPollAfterSeconds || 3} seconds with --run-id ${result.runId}
521
553
  `);
522
- process.stdout.write(`Catch-all: ${result.isCatchAll}
554
+ return;
555
+ }
556
+ process.stdout.write(`Email: ${publicResult.email ?? "Not found"}
523
557
  `);
524
- process.stdout.write(`Confidence: ${result.confidence}
558
+ process.stdout.write(`Status: ${publicResult.status}
525
559
  `);
526
- process.stdout.write(`Provider: ${result.providerUsed}
560
+ process.stdout.write(`Success: ${publicResult.success}
527
561
  `);
528
- process.stdout.write(`Credits used: ${result.creditsUsed || 0}
562
+ process.stdout.write(`Valid: ${publicResult.is_valid}
563
+ `);
564
+ process.stdout.write(`Credits used: ${publicResult.credits_used}
529
565
  `);
530
- if (result.needsReverification) {
531
- process.stdout.write("Send safety: stale verification; rerun with --skip-cache before sending\n");
532
- }
533
566
  });
534
567
  }
535
568
  async function verifyEmail(args) {
@@ -579,15 +612,15 @@ async function verifyEmail(args) {
579
612
  `);
580
613
  return;
581
614
  }
582
- process.stdout.write(`${result.email}: ${result.verifiedForSending ? "verified for sending" : "not verified for sending"}
615
+ process.stdout.write(`Email: ${publicResult.email ?? "Not found"}
616
+ `);
617
+ process.stdout.write(`Status: ${publicResult.status}
618
+ `);
619
+ process.stdout.write(`Success: ${publicResult.success}
583
620
  `);
584
- process.stdout.write(`Valid: ${result.isValid}
585
- Deliverable: ${result.isDeliverable}
586
- Catch-all: ${result.isCatchAll}
587
- Verdict: ${result.verificationVerdict}
621
+ process.stdout.write(`Valid: ${publicResult.is_valid}
588
622
  `);
589
- if (result.isMalformed) process.stdout.write("Malformed: true (rejected before provider call)\n");
590
- process.stdout.write(`Credits used: ${result.creditsUsed || 0}
623
+ process.stdout.write(`Credits used: ${publicResult.credits_used}
591
624
  `);
592
625
  });
593
626
  }
@@ -676,6 +709,7 @@ function signalQueryFromArgs(args) {
676
709
  "--limit",
677
710
  "--sources",
678
711
  "--lookback-days",
712
+ "--icp-context",
679
713
  "--signal-search-run-id",
680
714
  "--idempotency-key",
681
715
  "--max-wait-ms",
@@ -709,8 +743,13 @@ async function signals(args) {
709
743
  if (sourceValues?.some((source) => !["web", "news"].includes(source))) {
710
744
  fail("--sources must contain only web or news");
711
745
  }
746
+ const icpContext = flag("icp-context");
747
+ if (hasFlag("icp-context") && (typeof icpContext !== "string" || icpContext.trim().length < 2 || icpContext.trim().length > 4e3)) {
748
+ fail("--icp-context must contain between 2 and 4000 characters");
749
+ }
712
750
  const request = {
713
751
  query,
752
+ icpContext: icpContext?.trim(),
714
753
  signalSearchRunId,
715
754
  limit: numberFlag("limit"),
716
755
  sources: sourceValues,
@@ -764,6 +803,14 @@ async function signals(args) {
764
803
  `Source cost per qualified company: ${guardrail.costPerQualifiedSignalUsd ?? "n/a"} (must be < $${guardrail.maxCostPerQualifiedSignalUsd})
765
804
  `
766
805
  );
806
+ if (guardrail.identityResolutionCostUsd !== void 0) {
807
+ const identityCost = guardrail.identityResolutionCostUsd === null ? "unavailable" : `$${guardrail.identityResolutionCostUsd}`;
808
+ const identityRequests = guardrail.identityProviderRequests;
809
+ process.stdout.write(
810
+ `Identity resolution cost: ${identityCost}${identityRequests === void 0 ? "" : ` across ${identityRequests} fallback provider request${identityRequests === 1 ? "" : "s"}`}${guardrail.identityCostSource ? ` (${guardrail.identityCostSource})` : ""}.
811
+ `
812
+ );
813
+ }
767
814
  }
768
815
  for (const signal of result.signals.slice(0, 20)) {
769
816
  process.stdout.write(`- ${signal.company.name} (${signal.company.domain}) \u2014 ${signal.eventDate} \u2014 ${signal.title}
@@ -788,6 +835,7 @@ async function signalToCopy() {
788
835
  title: row.title,
789
836
  campaignOffer: row.campaignOffer || row.campaign_offer || row.offer,
790
837
  researchPrompt: row.researchPrompt || row.research_prompt || flag("research-prompt") || flag("prompt"),
838
+ lookbackDays: row.lookbackDays || row.lookback_days || numberFlag("lookback-days"),
791
839
  signalRunId: row.signalRunId || row.signal_run_id,
792
840
  skipCache: row.skipCache ?? row.skip_cache ?? hasFlag("skip-cache"),
793
841
  enableDeepSearch: row.enableDeepSearch ?? row.enable_deep_search ?? hasFlag("deep-search"),
@@ -814,6 +862,7 @@ async function signalToCopy() {
814
862
  title,
815
863
  campaignOffer,
816
864
  researchPrompt: flag("research-prompt") || flag("prompt"),
865
+ lookbackDays: numberFlag("lookback-days"),
817
866
  signalRunId,
818
867
  skipCache: hasFlag("skip-cache"),
819
868
  enableDeepSearch: hasFlag("deep-search"),
@@ -933,6 +982,13 @@ main().catch((error) => {
933
982
  retry_after: signalizError.retryAfter,
934
983
  retry_after_seconds: signalizError.retryAfter
935
984
  } : {},
985
+ ...signalizError?.details?.retry_strategy === "new_idempotency_key" ? { retry_strategy: "new_idempotency_key" } : {},
986
+ ...signalizError?.details?.credits_used === 0 ? { credits_used: 0 } : {},
987
+ ...signalizError?.details?.credits_charged === 0 ? { credits_charged: 0 } : {},
988
+ ...typeof signalizError?.details?.run_id === "string" ? { run_id: signalizError.details.run_id } : {},
989
+ ...typeof signalizError?.details?.verification_run_id === "string" ? { verification_run_id: signalizError.details.verification_run_id } : {},
990
+ ...typeof signalizError?.details?.job_id === "string" ? { job_id: signalizError.details.job_id } : {},
991
+ ...typeof signalizError?.details?.suggested_action === "string" ? { suggested_action: signalizError.details.suggested_action } : {},
936
992
  ...signalizError?.errorType ? { error_type: signalizError.errorType } : {},
937
993
  ...signalizError?.details ? { details: signalizError.details } : {}
938
994
  }, hasFlag("json") ? 2 : void 0)}
@@ -946,6 +1002,39 @@ main().catch((error) => {
946
1002
  fail(`${message}
947
1003
  Recoverable signal run: ${signalRunId}
948
1004
  Retry the same signaliz ${command} command with --signal-run-id ${signalRunId}, or use --json for structured recovery metadata.`);
1005
+ }
1006
+ if (error instanceof import_sdk.SignalizError && typeof error.details?.verification_run_id === "string") {
1007
+ const verificationRunId = error.details.verification_run_id;
1008
+ if (error.details.suggested_action === "retry_with_verification_run_id") {
1009
+ fail(`${message}
1010
+ Recoverable verification run: ${verificationRunId}
1011
+ Retry with: signaliz verify-email --verification-run-id ${verificationRunId}`);
1012
+ }
1013
+ fail(`${message}
1014
+ Terminal verification run: ${verificationRunId}
1015
+ No automatic retry is recommended; review the provider outcome or contact support.`);
1016
+ }
1017
+ if (error instanceof import_sdk.SignalizError && typeof error.details?.run_id === "string" && process.argv[2] === "find-email") {
1018
+ const runId = error.details.run_id;
1019
+ if (error.details.suggested_action === "retry_with_run_id") {
1020
+ fail(`${message}
1021
+ Recoverable Find Email run: ${runId}
1022
+ Retry with: signaliz find-email --run-id ${runId}`);
1023
+ }
1024
+ fail(`${message}
1025
+ Terminal Find Email run: ${runId}
1026
+ No automatic retry is recommended; review the provider outcome or contact support.`);
1027
+ }
1028
+ if (error instanceof import_sdk.SignalizError && typeof error.details?.job_id === "string") {
1029
+ const jobId = error.details.job_id;
1030
+ if (error.details.suggested_action === "check_job_status") {
1031
+ fail(`${message}
1032
+ Recoverable job: ${jobId}
1033
+ Resume this job through the REST API or SDK using job_id ${jobId}, or use --json for structured recovery metadata.`);
1034
+ }
1035
+ fail(`${message}
1036
+ Terminal job: ${jobId}
1037
+ No automatic retry is recommended; review the provider outcome or contact support.`);
949
1038
  }
950
1039
  fail(message);
951
1040
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signaliz/cli",
3
- "version": "1.0.56",
3
+ "version": "1.0.57",
4
4
  "description": "Signaliz CLI for Signals Everything, Find Email, Verify Email, Company Signal Enrichment, and Signal to Copy AI.",
5
5
  "bin": {
6
6
  "signaliz": "dist/bin.js"
@@ -29,7 +29,7 @@
29
29
  "node": ">=18"
30
30
  },
31
31
  "dependencies": {
32
- "@signaliz/sdk": "^1.0.60"
32
+ "@signaliz/sdk": "^1.0.61"
33
33
  },
34
34
  "devDependencies": {
35
35
  "tsup": "^8.0.0",