@signaliz/cli 1.0.67 → 1.0.69

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 +18 -20
  2. package/dist/bin.js +92 -254
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -10,10 +10,13 @@ signaliz auth login
10
10
  # Production REST gateway:
11
11
  # https://api.signaliz.com/functions/v1/api/v1/find-email
12
12
  # https://api.signaliz.com/functions/v1/api/v1/verify-email
13
- # https://api.signaliz.com/functions/v1/api/v1/company-signals
13
+ # https://api.signaliz.com/functions/v1/company-signal-enrichment-v2
14
14
  # https://api.signaliz.com/functions/v1/api/v1/signal-to-copy
15
15
  # https://api.signaliz.com/functions/v1/api/v1/signals
16
- # https://api.signaliz.com/functions/v1/api/v1/signal-awareness
16
+ # https://api.signaliz.com/functions/v1/api/v1/signal-awareness/signals
17
+ # https://api.signaliz.com/functions/v1/api/v1/signal-awareness/companies/add
18
+ # https://api.signaliz.com/functions/v1/api/v1/signal-awareness/companies/delete
19
+ # https://api.signaliz.com/functions/v1/api/v1/signal-awareness/companies/schedule
17
20
  # https://api.signaliz.com/functions/v1/api/v1/flow
18
21
  # The same contracts are available under /api/v2/.
19
22
 
@@ -26,12 +29,14 @@ signaliz verify-email jane@example.com --dry-run --json
26
29
  # Return early when a provider check runs long, then resume the exact run
27
30
  signaliz verify-email jane@example.com --no-wait --json
28
31
  signaliz verify-email --verification-run-id run_... --json
29
- signaliz company-signals --domain example.com
32
+ signaliz company-signals --domain example.com \
33
+ --research-prompt "Find recent signals that explain why this company would use Signaliz."
30
34
  signaliz signal-to-copy \
31
35
  --company-domain example.com \
32
36
  --person-name "Jane Doe" \
33
37
  --title "VP Sales" \
34
- --campaign-offer "pipeline intelligence"
38
+ --campaign-offer "pipeline intelligence" \
39
+ --run-without-signal no
35
40
 
36
41
  # Reuse the exact Signals First snapshot, fact, or event instead of rediscovering it.
37
42
  # Keep company/recipient/offer fields so Signaliz can validate identity and write the copy.
@@ -45,22 +50,16 @@ signaliz signal-to-copy --company-domain example.com --person-name "Jane Doe" \
45
50
 
46
51
  # Omit --deep-search for bounded credit-free first-party and Bing grounding.
47
52
 
48
- # Signals Everything returns distinct companies with a source-backed signal.
53
+ # Signals First returns distinct companies with a source-backed signal.
49
54
  # It is asynchronous by default; add --wait or resume the returned run ID.
50
- signaliz signals "companies that just got funded" --limit 100 --sources web,news
51
- signaliz signals "companies showing signals they need account-signal automation" \
52
- --icp-context "B2B SaaS with outbound teams and manual account research" \
53
- --limit 100 --sources web,news
55
+ signaliz signals "companies that just got funded" --limit 100
54
56
  signaliz signals --signal-search-run-id run_... --wait --json
55
57
 
56
58
  # Monitor companies with the fixed Company Signal evidence engine.
57
- signaliz awareness create --company-name "Acme" --domain acme.com --schedule daily
58
- signaliz awareness schedule --monitor-id <uuid> --schedule monthly
59
- signaliz awareness import --input companies.json --schedule weekly
60
- signaliz awareness list --limit 100 --offset 0 --json
61
- signaliz awareness signals --monitor-id <uuid> --limit 100 --offset 0 --json
62
- signaliz awareness set-output --mode webhook --webhook-url https://hooks.example.com/signaliz
63
- signaliz awareness export --monitor-id <uuid> --json
59
+ signaliz awareness add --domain acme.com --schedule daily
60
+ signaliz awareness signals --domain acme.com --json
61
+ signaliz awareness schedule --domain acme.com --schedule monthly
62
+ signaliz awareness delete --domain acme.com
64
63
 
65
64
  # Flow starts and resumes through the versioned REST contract.
66
65
  signaliz flow --signal-query "companies with recent hiring" \
@@ -86,9 +85,8 @@ signaliz signal-to-copy --input copy-requests.jsonl --no-wait --json
86
85
  signaliz signal-to-copy --job-id job_... --idempotency-key key_... --json
87
86
  ```
88
87
 
89
- Signal to Copy accepts `signal_search_run_id`, `fact_id`, or `event_id` in
90
- JSON/JSONL rows, and the equivalent `--signal-search-run-id`, `--fact-id`, or
91
- `--event-id` flags for one request. These references reuse canonical evidence
88
+ Signal to Copy accepts `fact_id` or `event_id` in JSON/JSONL rows, and the
89
+ equivalent `--fact-id` or `--event-id` flags for one request. These references reuse canonical evidence
92
90
  in single calls and synchronous batches of at most 25. Durable batches of
93
91
  26-5,000 reject canonical references instead of silently rediscovering them.
94
92
  JSON output exposes the normalized customer-facing signal fields; human output
@@ -161,7 +159,7 @@ Company Signals. Signal to Copy costs 1 credit per successful result on Free and
161
159
  Builder, and is unlimited on Team and Agency. `--lookback-days` remains a hard
162
160
  evidence-age bound.
163
161
 
164
- Signals Everything is a query-first company discovery command rather than a
162
+ Signals First is a query-first company discovery command rather than a
165
163
  row batch. It returns only dated, source-linked signals that contain both a
166
164
  company name and company domain. The default request is 100 companies and the
167
165
  maximum is 1,000. It is included on Builder, Team, and Agency plans, is resumable with
package/dist/bin.js CHANGED
@@ -24,34 +24,24 @@ Six product commands:
24
24
  signaliz find-email --job-id job_... Resume an existing Find Email batch without redispatch
25
25
  signaliz verify-email [jane@example.com] [--verification-run-id run_...] [--no-wait] [--max-wait-ms 600000]
26
26
  signaliz verify-email --job-id job_... Resume an existing Verify Email batch without redispatch
27
- signaliz company-signals --domain example.com
27
+ signaliz company-signals --domain example.com --research-prompt "Why would this company use Signaliz?"
28
28
  signaliz company-signals --input companies.json --no-wait Submit a durable >25-row batch and return its job
29
29
  signaliz company-signals --job-id job_... Resume an existing Company Signals batch without redispatch
30
30
  signaliz company-signals --signal-run-id run_... Read a completed run without duplicate spend
31
31
  signaliz signal-to-copy --company-domain example.com --person-name "Jane Doe" \\
32
32
  --title "VP Sales" --campaign-offer "pipeline intelligence" [--signal-run-id run_...] \\
33
- [--signal-search-run-id run_... | --fact-id <sha256> | --event-id <sha256>] \\
34
- [--copy-evidence-mode signal_led|firmographic] [--deep-search] [--max-wait-ms 120000]
33
+ [--fact-id <sha256> | --event-id <sha256>] \\
34
+ [--run-without-signal yes|no] [--deep-search] [--max-wait-ms 120000]
35
35
  signaliz signal-to-copy --signal-run-id copy_... Reuse a completed signal run
36
36
  signaliz signal-to-copy --fact-id <sha256> --company-domain example.com --person-name "Jane Doe" --title "VP Sales" --campaign-offer "pipeline intelligence" Reuse one canonical signal without rediscovery
37
37
  signaliz signal-to-copy --input recipients.json --no-wait Submit a durable >25-row batch
38
38
  signaliz signal-to-copy --job-id job_... Resume an existing Signal to Copy batch without redispatch
39
- signaliz signals "companies that just got funded" [--icp-context "..."] [--limit 100] [--sources web,news] [--after-date YYYY-MM-DD --before-date YYYY-MM-DD] [--wait]
40
- signaliz signals-first "companies that just got funded" [--limit 100] [--lookback-days 30] [--wait]
41
- signaliz signals --signal-search-run-id run_... Resume an existing company-attributed signal search
42
- signaliz awareness create --company-name "Acme" --domain acme.com [--schedule daily|weekly|monthly | --schedule-cron "0 8 * * *"]
43
- signaliz awareness import --input companies.json [--schedule daily]
44
- signaliz awareness list [--limit 100] [--offset 0]
45
- signaliz awareness update --monitor-id <uuid> [--company-name "Acme"] [--schedule weekly] [--webhook-url https://...]
46
- signaliz awareness schedule --monitor-id <uuid> --schedule monthly
47
- signaliz awareness run --monitor-id <uuid> --idempotency-key <key>
48
- signaliz awareness signals [--monitor-id <uuid>]
49
- signaliz awareness pause|resume|delete --monitor-id <uuid>
50
- signaliz awareness settings
51
- signaliz awareness set-output --mode csv|webhook [--webhook-url https://...]
52
- signaliz awareness test-webhook --webhook-url https://...
53
- signaliz awareness export [--monitor-id <uuid>] --json
54
- signaliz awareness send-export --input signals.jsonl
39
+ signaliz signals "companies that just got funded" [--limit 100] [--wait]
40
+ signaliz signals-first "companies that just got funded" [--limit 100] [--wait]
41
+ signaliz awareness add --domain acme.com [--schedule daily|weekly|monthly]
42
+ signaliz awareness signals --domain acme.com
43
+ signaliz awareness delete --domain acme.com
44
+ signaliz awareness schedule --domain acme.com --schedule daily|weekly|monthly
55
45
  signaliz flow --signal-query "companies with recent hiring" --campaign-offer "..." [--limit 5] [--lookback-days 90] [--people-titles "CEO,VP Sales"]
56
46
  signaliz flow --run-id run_... Read a durable Flow checkpoint without dispatching new work
57
47
 
@@ -75,16 +65,14 @@ Common flags:
75
65
  --concurrency <1-50> Simultaneous API requests for batch input (default: 10)
76
66
  --idempotency-key <key> Reuse after an ambiguous response to recover the same request or job
77
67
  --no-wait Return the durable Find Email run ID immediately; resume with --run-id
78
- --copy-evidence-mode <mode> Use signals, or draft from offer and research context without signal claims
68
+ --run-without-signal yes|no Draft from the offer without researching or claiming a company signal
79
69
  --run-id <run_...> Resume one existing Find Email run without dispatching new work
80
70
  --job-id <job_...> Resume an existing core-product batch without dispatching new work
81
- --icp-context <text> Optional ICP, product, or pain context that returned signals must support
82
- --signal-search-run-id <id> Resume Signals First, or pin its immutable snapshot in Signal to Copy
83
71
  --fact-id <sha256> Pin one active canonical signal fact in Signal to Copy
84
72
  --event-id <sha256> Pin one canonical signal event in Signal to Copy
85
73
  --dry-run Return a no-spend plan without provider calls, jobs, or writes
86
74
 
87
- Company Signals accepts only --domain. Signaliz checks its cache, runs one type-agnostic Parallel Advanced search plus at most one first-party hub Extract, and returns the newest distinct events that pass its deterministic date, source, company, evidence, and duplicate gates. For a durable batch larger than 25 rows, provide domain-only rows with --no-wait and resume with --job-id. Signal to Copy canonical references remain separate. Signals Everything is asynchronous by default; use --wait to poll until it completes.
75
+ Company Signals requires --domain and --research-prompt. Signaliz checks its cache and returns the newest distinct events that pass its deterministic date, source, company, evidence, and duplicate gates. Durable batch rows require domain and research_prompt. Signal to Copy accepts --run-without-signal yes|no. Signals First accepts only a query and --limit up to 100. Signal Awareness management uses only a company domain and, for schedule changes, daily, weekly, or monthly.
88
76
  `;
89
77
  function loadConfig() {
90
78
  if (!(0, import_node_fs.existsSync)(CONFIG_FILE)) return {};
@@ -131,25 +119,6 @@ function requireIntegerInRange(value, name, minimum, maximum) {
131
119
  throw new CliInputError(`${name} must be an integer between ${minimum} and ${maximum}`);
132
120
  }
133
121
  }
134
- function validateSignalDateWindow(afterDate, beforeDate, lookbackDays, flagPrefix = "--") {
135
- if ((afterDate || beforeDate) && lookbackDays !== void 0) {
136
- throw new CliInputError(`${flagPrefix}after-date/--before-date cannot be combined with --lookback-days`);
137
- }
138
- const parseDate = (value, name) => {
139
- if (value === void 0) return void 0;
140
- if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) throw new CliInputError(`${name} must use YYYY-MM-DD format`);
141
- const timestamp = Date.parse(`${value}T00:00:00Z`);
142
- if (!Number.isFinite(timestamp) || new Date(timestamp).toISOString().slice(0, 10) !== value) {
143
- throw new CliInputError(`${name} must be a valid calendar date`);
144
- }
145
- return timestamp;
146
- };
147
- const afterTimestamp = parseDate(afterDate, `${flagPrefix}after-date`);
148
- const beforeTimestamp = parseDate(beforeDate, `${flagPrefix}before-date`);
149
- if (afterTimestamp !== void 0 && beforeTimestamp !== void 0 && beforeTimestamp < afterTimestamp) {
150
- throw new CliInputError(`${flagPrefix}before-date must be on or after ${flagPrefix}after-date`);
151
- }
152
- }
153
122
  function requireSignalToCopyIdentity(request) {
154
123
  if (stringValue(request.signalRunId)) return;
155
124
  const missing = [
@@ -435,6 +404,15 @@ function customerEmailBillingMetadata(value) {
435
404
  function customerEmailResult(value, kind) {
436
405
  const result = record(value);
437
406
  const raw = record(result.raw);
407
+ if (kind === "verify") {
408
+ return {
409
+ email: typeof result.email === "string" ? result.email : typeof raw.email === "string" ? raw.email : null,
410
+ status: result.status || raw.status || "completed",
411
+ is_catch_all: result.isCatchAll === true || raw.is_catch_all === true || raw.email_is_catch_all === true,
412
+ credits_charged: safeNonNegativeNumber(result.creditsCharged ?? raw.credits_charged) ?? 0,
413
+ ok_to_send: result.okToSend === true || raw.ok_to_send === true
414
+ };
415
+ }
438
416
  if (String(result.status || "").toLowerCase() === "processing") {
439
417
  const verificationRunId2 = result.verificationRunId ?? raw.verification_run_id;
440
418
  const runId2 = result.runId ?? raw.run_id ?? verificationRunId2;
@@ -467,6 +445,7 @@ function customerEmailResult(value, kind) {
467
445
  const creditsCharged = Number(result.creditsCharged ?? raw.credits_charged ?? creditsUsed);
468
446
  const base = {
469
447
  email: typeof result.email === "string" && result.email.trim() ? result.email.trim() : null,
448
+ ...typeof result.checkedEmail === "string" || typeof raw.checked_email === "string" ? { checked_email: result.checkedEmail ?? raw.checked_email } : {},
470
449
  status: "completed",
471
450
  success: result.success === true,
472
451
  is_valid: typeof result.isValid === "boolean" ? result.isValid : typeof raw.is_valid === "boolean" ? raw.is_valid : result.isVerified ?? false,
@@ -527,6 +506,15 @@ function customerEmailResult(value, kind) {
527
506
  email_is_catch_all: isCatchAll2,
528
507
  is_catch_all: isCatchAll2,
529
508
  verification_source: result.verificationSource ?? raw.verification_source ?? result.providerUsed ?? "email_finder",
509
+ ...typeof raw.candidate_source === "string" ? { candidate_source: raw.candidate_source } : {},
510
+ ...typeof raw.primary_verifier === "string" ? { primary_verifier: raw.primary_verifier } : {},
511
+ ...typeof raw.primary_verdict === "string" ? { primary_verdict: raw.primary_verdict } : {},
512
+ ...typeof raw.terminal_verifier === "string" ? { terminal_verifier: raw.terminal_verifier } : {},
513
+ ...typeof raw.terminal_verdict === "string" ? { terminal_verdict: raw.terminal_verdict } : {},
514
+ ...typeof raw.terminal_result === "string" ? { terminal_result: raw.terminal_result } : {},
515
+ ...typeof raw.terminal_is_catch_all === "boolean" ? { terminal_is_catch_all: raw.terminal_is_catch_all } : {},
516
+ ...typeof raw.terminal_is_accept_all === "boolean" ? { terminal_is_accept_all: raw.terminal_is_accept_all } : {},
517
+ ...typeof raw.bounceban_id === "string" ? { bounceban_id: raw.bounceban_id } : {},
530
518
  ...result.verificationObservedAt ?? raw.verification_observed_at ? { verification_observed_at: result.verificationObservedAt ?? raw.verification_observed_at } : {},
531
519
  failure_reason: result.failureReason ?? raw.failure_reason ?? (verifiedForSending2 ? "none" : "no_verified_email_found"),
532
520
  billing_replayed: typeof raw.billing_replayed === "boolean" ? raw.billing_replayed : result.billingReplayed === true,
@@ -602,6 +590,15 @@ function customerEmailResult(value, kind) {
602
590
  smtp_status: result.smtpStatus ?? raw.smtp_status ?? (isCatchAll ? "accept_all" : verifiedForSending ? "accepted" : "not_checked"),
603
591
  provider_status: result.providerStatus ?? raw.provider_status ?? verificationStatus,
604
592
  verification_source: result.verificationSource ?? raw.verification_source ?? "email_verification",
593
+ ...typeof raw.checked_email === "string" ? { checked_email: raw.checked_email } : {},
594
+ ...typeof raw.primary_verifier === "string" ? { primary_verifier: raw.primary_verifier } : {},
595
+ ...typeof raw.primary_verdict === "string" ? { primary_verdict: raw.primary_verdict } : {},
596
+ ...typeof raw.terminal_verifier === "string" ? { terminal_verifier: raw.terminal_verifier } : {},
597
+ ...typeof raw.terminal_verdict === "string" ? { terminal_verdict: raw.terminal_verdict } : {},
598
+ ...typeof raw.terminal_result === "string" ? { terminal_result: raw.terminal_result } : {},
599
+ ...typeof raw.terminal_is_catch_all === "boolean" ? { terminal_is_catch_all: raw.terminal_is_catch_all } : {},
600
+ ...typeof raw.terminal_is_accept_all === "boolean" ? { terminal_is_accept_all: raw.terminal_is_accept_all } : {},
601
+ ...typeof raw.bounceban_id === "string" ? { bounceban_id: raw.bounceban_id } : {},
605
602
  ...result.verificationObservedAt ?? raw.verification_observed_at ? { verification_observed_at: result.verificationObservedAt ?? raw.verification_observed_at } : {},
606
603
  failure_reason: result.failureReason ?? raw.failure_reason ?? (verifiedForSending ? "none" : isCatchAll ? "catch_all_domain_not_send_safe" : "verification_not_send_safe"),
607
604
  billing_replayed: typeof raw.billing_replayed === "boolean" ? raw.billing_replayed : result.billingReplayed === true,
@@ -832,7 +829,7 @@ function publicSignalDiscoveryFailure(value) {
832
829
  if (requestedCode === "IDEMPOTENCY_CONFLICT") {
833
830
  return {
834
831
  errorCode: requestedCode,
835
- error: "This recovery key belongs to a different Signals Everything request."
832
+ error: "This recovery key belongs to a different Signals First request."
836
833
  };
837
834
  }
838
835
  if (requestedCode === "PERSISTENCE_UNAVAILABLE") {
@@ -843,7 +840,7 @@ function publicSignalDiscoveryFailure(value) {
843
840
  }
844
841
  return {
845
842
  errorCode: "SOURCE_UNAVAILABLE",
846
- error: "Signals Everything could not complete this search."
843
+ error: "Signals First could not complete this search."
847
844
  };
848
845
  }
849
846
  function hasFindEmailLinkedInIdentity(value) {
@@ -907,26 +904,16 @@ function normalizeSignalsEverythingResult(request, value) {
907
904
  async function discoverSignalsEverything(request) {
908
905
  const body = request.signalSearchRunId ? {
909
906
  signal_search_run_id: request.signalSearchRunId,
910
- ...request.limit === void 0 ? {} : { limit: request.limit },
911
- ...request.dryRun === void 0 ? {} : { dry_run: request.dryRun },
912
- ...request.idempotencyKey ? { idempotency_key: request.idempotencyKey } : {}
907
+ ...request.limit === void 0 ? {} : { limit: request.limit }
913
908
  } : {
914
909
  query: request.query,
915
- ...request.icpContext ? { icp_context: request.icpContext } : {},
916
- limit: request.limit ?? 100,
917
- ...request.sources ? { sources: request.sources } : {},
918
- ...request.lookbackDays === void 0 ? {} : { lookback_days: request.lookbackDays },
919
- ...request.afterDate ? { after_date: request.afterDate } : {},
920
- ...request.beforeDate ? { before_date: request.beforeDate } : {},
921
- ...request.dryRun === void 0 ? {} : { dry_run: request.dryRun },
922
- ...request.idempotencyKey ? { idempotency_key: request.idempotencyKey } : {}
910
+ limit: request.limit ?? 100
923
911
  };
924
912
  const response = await fetch(`${resolveBaseUrl()}/api/v1/signals`, {
925
913
  method: "POST",
926
914
  headers: {
927
915
  "Content-Type": "application/json",
928
- Authorization: `Bearer ${resolveApiKey()}`,
929
- ...request.idempotencyKey ? { "Idempotency-Key": request.idempotencyKey } : {}
916
+ Authorization: `Bearer ${resolveApiKey()}`
930
917
  },
931
918
  body: JSON.stringify(body)
932
919
  });
@@ -1272,19 +1259,11 @@ async function verifyEmail(args) {
1272
1259
  `);
1273
1260
  process.stdout.write(`Status: ${publicResult.status}
1274
1261
  `);
1275
- process.stdout.write(`Success: ${publicResult.success}
1276
- `);
1277
- process.stdout.write(`Valid: ${publicResult.is_valid}
1278
- `);
1279
- process.stdout.write(`Verdict: ${publicResult.verification_status}
1262
+ process.stdout.write(`Catch-all: ${publicResult.is_catch_all}
1280
1263
  `);
1281
- process.stdout.write(`Recommendation: ${publicResult.recommendation}
1264
+ process.stdout.write(`Credits charged: ${publicResult.credits_charged}
1282
1265
  `);
1283
- process.stdout.write(`Source: ${String(publicResult.verification_source || "email_verification").toLowerCase().includes("cache") ? "email_verification" : publicResult.verification_source}
1284
- `);
1285
- if (publicResult.run_id) process.stdout.write(`Run ID: ${publicResult.run_id}
1286
- `);
1287
- process.stdout.write(`Credits used: ${publicResult.credits_used}
1266
+ process.stdout.write(`OK to send: ${publicResult.ok_to_send ? "Yes" : "No"}
1288
1267
  `);
1289
1268
  });
1290
1269
  }
@@ -1320,7 +1299,7 @@ async function companySignals() {
1320
1299
  ].filter(hasFlag);
1321
1300
  if (removedControlFlags.length > 0) {
1322
1301
  throw new CliInputError(
1323
- `Company Signals manages provider routing, coverage, and classifications internally; ${removedControlFlags.map((name) => `--${name}`).join(", ")} is no longer supported. Use --domain only.`
1302
+ `Company Signals manages provider routing, coverage, and classifications internally; ${removedControlFlags.map((name) => `--${name}`).join(", ")} is no longer supported. Use --domain and --research-prompt.`
1324
1303
  );
1325
1304
  }
1326
1305
  if (jobId) {
@@ -1361,16 +1340,17 @@ async function companySignals() {
1361
1340
  signalRunId: row.signalRunId || row.signal_run_id,
1362
1341
  companyDomain: row.companyDomain || row.company_domain || row.domain,
1363
1342
  domain: row.domain || row.companyDomain || row.company_domain,
1343
+ researchPrompt: row.researchPrompt || row.research_prompt,
1364
1344
  idempotencyKey: row.idempotencyKey || row.idempotency_key
1365
1345
  };
1366
1346
  });
1367
1347
  if (durableBatch) {
1368
1348
  const incompatible = requests.some(
1369
- (request2) => Boolean(stringValue(request2.signalRunId)) || Boolean(stringValue(request2.idempotencyKey)) || !stringValue(request2.domain)
1349
+ (request2) => Boolean(stringValue(request2.signalRunId)) || Boolean(stringValue(request2.idempotencyKey)) || !stringValue(request2.domain) || !stringValue(request2.researchPrompt)
1370
1350
  );
1371
1351
  if (incompatible) {
1372
1352
  throw new CliInputError(
1373
- "Company Signals batches larger than 25 require domain-only rows without per-row controls or recovery IDs."
1353
+ "Company Signals batches larger than 25 require domain and research_prompt rows without per-row controls or recovery IDs."
1374
1354
  );
1375
1355
  }
1376
1356
  } else if (hasFlag("no-wait") && !hasFlag("dry-run")) {
@@ -1405,14 +1385,15 @@ async function companySignals() {
1405
1385
  throw new CliInputError("Company Signals --poll-interval-ms requires --input or --job-id.");
1406
1386
  }
1407
1387
  const companyDomain = flag("domain") || flag("company-domain");
1388
+ const researchPrompt = flag("research-prompt");
1408
1389
  const signalRunId = flag("signal-run-id");
1409
- if (!companyDomain && !signalRunId) {
1410
- throw new CliInputError("Usage: signaliz company-signals --domain example.com");
1390
+ if ((!companyDomain || !researchPrompt) && !signalRunId) {
1391
+ throw new CliInputError('Usage: signaliz company-signals --domain example.com --research-prompt "Why now?"');
1411
1392
  }
1412
1393
  const request = {
1413
1394
  signalRunId,
1414
1395
  domain: companyDomain,
1415
- idempotencyKey: flag("idempotency-key")
1396
+ researchPrompt
1416
1397
  };
1417
1398
  if (hasFlag("dry-run")) {
1418
1399
  const result2 = await createClient().enrichCompanySignals({ ...request, dryRun: true });
@@ -1466,35 +1447,23 @@ function sleep(milliseconds) {
1466
1447
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
1467
1448
  }
1468
1449
  async function signals(args) {
1469
- if (flag("input")) fail("Signals Everything accepts one natural-language query at a time; do not pass --input.");
1450
+ if (flag("input")) fail("Signals First accepts one natural-language query at a time; do not pass --input.");
1470
1451
  const signalSearchRunId = flag("signal-search-run-id");
1471
1452
  const query = signalQueryFromArgs(args);
1472
1453
  if (!query && !signalSearchRunId) {
1473
1454
  fail('Usage: signaliz signals "companies that just got funded" [--limit 100] OR signaliz signals --signal-search-run-id run_...');
1474
1455
  }
1475
- const sourceValues = csvFlag("sources");
1476
- if (sourceValues?.some((source) => !["web", "news"].includes(source))) {
1477
- fail("--sources must contain only web or news");
1478
- }
1479
- const icpContext = flag("icp-context");
1480
- if (hasFlag("icp-context") && (typeof icpContext !== "string" || icpContext.trim().length < 2 || icpContext.trim().length > 4e3)) {
1481
- fail("--icp-context must contain between 2 and 4000 characters");
1456
+ const removedControls = ["icp-context", "sources", "lookback-days", "after-date", "before-date"].filter(hasFlag);
1457
+ if (removedControls.length > 0) {
1458
+ fail(`Signals First accepts only query and --limit; ${removedControls.map((name) => `--${name}`).join(", ")} is no longer supported.`);
1482
1459
  }
1483
1460
  const request = {
1484
1461
  query,
1485
- icpContext: icpContext?.trim(),
1486
1462
  signalSearchRunId,
1487
- limit: numberFlag("limit"),
1488
- sources: sourceValues,
1489
- lookbackDays: numberFlag("lookback-days"),
1490
- afterDate: flag("after-date"),
1491
- beforeDate: flag("before-date"),
1492
- idempotencyKey: flag("idempotency-key"),
1493
- dryRun: hasFlag("dry-run")
1463
+ limit: numberFlag("limit")
1494
1464
  };
1495
- validateSignalDateWindow(request.afterDate, request.beforeDate, request.lookbackDays);
1496
1465
  let result = await discoverSignalsEverything(request);
1497
- if (hasFlag("wait") && !request.dryRun) {
1466
+ if (hasFlag("wait")) {
1498
1467
  const maxWaitMs = numberFlag("max-wait-ms") ?? 15 * 6e4;
1499
1468
  const pollIntervalMs = numberFlag("poll-interval-ms");
1500
1469
  const startedAt = Date.now();
@@ -1508,12 +1477,12 @@ async function signals(args) {
1508
1477
  }
1509
1478
  output(result, () => {
1510
1479
  if (result.status === "planned") {
1511
- process.stdout.write(`Signals Everything plan: ${result.requestedCount} distinct companies. No source acquisition was launched. Included on plan; 0 Signaliz credits charged.
1480
+ process.stdout.write(`Signals First plan: ${result.requestedCount} distinct companies. No source acquisition was launched. Included on plan; 0 Signaliz credits charged.
1512
1481
  `);
1513
1482
  return;
1514
1483
  }
1515
1484
  if (signalDiscoveryIsPending(result.status)) {
1516
- process.stdout.write(`Signals Everything ${result.status}: ${result.signalSearchRunId}
1485
+ process.stdout.write(`Signals First ${result.status}: ${result.signalSearchRunId}
1517
1486
  `);
1518
1487
  process.stdout.write(`Billing: included on plan \xB7 ${result.creditsCharged} Signaliz credits charged.
1519
1488
  `);
@@ -1522,7 +1491,7 @@ async function signals(args) {
1522
1491
  return;
1523
1492
  }
1524
1493
  if (!result.success || result.status === "failed") {
1525
- process.stdout.write(`${result.error || "Signals Everything failed."}
1494
+ process.stdout.write(`${result.error || "Signals First failed."}
1526
1495
  `);
1527
1496
  return;
1528
1497
  }
@@ -1654,6 +1623,7 @@ async function signalToCopy() {
1654
1623
  "lookback-days",
1655
1624
  "copy-evidence-mode",
1656
1625
  "without-signals",
1626
+ "run-without-signal",
1657
1627
  "signal-run-id",
1658
1628
  "signal-search-run-id",
1659
1629
  "fact-id",
@@ -1688,10 +1658,9 @@ async function signalToCopy() {
1688
1658
  personName: row.personName || row.person_name,
1689
1659
  title: row.title,
1690
1660
  campaignOffer: row.campaignOffer || row.campaign_offer || row.offer,
1691
- copyEvidenceMode: row.copyEvidenceMode || row.copy_evidence_mode || flag("copy-evidence-mode") || (hasFlag("without-signals") ? "firmographic" : void 0),
1661
+ runWithoutSignal: row.runWithoutSignal ?? row.run_without_signal ?? yesNoFlag("run-without-signal"),
1692
1662
  lookbackDays: 365,
1693
1663
  signalRunId: row.signalRunId || row.signal_run_id,
1694
- signalSearchRunId: row.signalSearchRunId || row.signal_search_run_id,
1695
1664
  factId: row.factId || row.fact_id,
1696
1665
  eventId: row.eventId || row.event_id,
1697
1666
  enableDeepSearch: row.enableDeepSearch ?? row.enable_deep_search ?? hasFlag("deep-search"),
@@ -1705,7 +1674,7 @@ async function signalToCopy() {
1705
1674
  }
1706
1675
  if (durableBatch) {
1707
1676
  const invalidIndex = requests.findIndex(
1708
- (request2) => Boolean(stringValue(request2.idempotencyKey)) || request2.maxWaitMs !== void 0 || Boolean(stringValue(request2.signalSearchRunId)) || Boolean(stringValue(request2.factId)) || Boolean(stringValue(request2.eventId)) || !stringValue(request2.companyDomain) || !stringValue(request2.personName) || !stringValue(request2.title) || !stringValue(request2.campaignOffer)
1677
+ (request2) => Boolean(stringValue(request2.idempotencyKey)) || request2.maxWaitMs !== void 0 || Boolean(stringValue(request2.factId)) || Boolean(stringValue(request2.eventId)) || !stringValue(request2.companyDomain) || !stringValue(request2.personName) || !stringValue(request2.title) || !stringValue(request2.campaignOffer)
1709
1678
  );
1710
1679
  if (invalidIndex >= 0) {
1711
1680
  throw new CliInputError(
@@ -1751,10 +1720,9 @@ async function signalToCopy() {
1751
1720
  personName,
1752
1721
  title,
1753
1722
  campaignOffer,
1754
- copyEvidenceMode: flag("copy-evidence-mode") || (hasFlag("without-signals") ? "firmographic" : void 0),
1723
+ runWithoutSignal: yesNoFlag("run-without-signal"),
1755
1724
  lookbackDays: 365,
1756
1725
  signalRunId,
1757
- signalSearchRunId: flag("signal-search-run-id"),
1758
1726
  factId: flag("fact-id"),
1759
1727
  eventId: flag("event-id"),
1760
1728
  enableDeepSearch: hasFlag("deep-search"),
@@ -1840,102 +1808,31 @@ Import this file into your MCP client.
1840
1808
  });
1841
1809
  }
1842
1810
  function awarenessSchedule() {
1843
- const direct = flag("schedule-cron");
1844
- if (direct) return direct;
1845
1811
  const schedule = flag("schedule");
1846
1812
  if (!schedule) return void 0;
1847
- const schedules = {
1848
- every_6_hours: "0 */6 * * *",
1849
- daily: "0 8 * * *",
1850
- every_2_days: "0 8 */2 * *",
1851
- weekly: "0 8 * * 1",
1852
- monthly: "0 8 1 * *"
1853
- };
1854
- if (!schedules[schedule]) {
1855
- throw new CliInputError("--schedule must be every_6_hours, daily, every_2_days, weekly, or monthly");
1813
+ if (!["daily", "weekly", "monthly"].includes(schedule)) {
1814
+ throw new CliInputError("--schedule must be daily, weekly, or monthly");
1856
1815
  }
1857
- return schedules[schedule];
1816
+ return schedule;
1817
+ }
1818
+ function yesNoFlag(name) {
1819
+ const value = flag(name);
1820
+ if (value === void 0) return void 0;
1821
+ if (value === "yes") return true;
1822
+ if (value === "no") return false;
1823
+ throw new CliInputError(`--${name} must be yes or no`);
1858
1824
  }
1859
1825
  async function awareness(args) {
1860
1826
  const action = args[0];
1861
- const monitorId = flag("monitor-id");
1862
- const actions = [
1863
- "create",
1864
- "import",
1865
- "list",
1866
- "update",
1867
- "schedule",
1868
- "run",
1869
- "signals",
1870
- "pause",
1871
- "resume",
1872
- "delete",
1873
- "settings",
1874
- "set-output",
1875
- "test-webhook",
1876
- "export",
1877
- "send-export"
1878
- ];
1827
+ const actions = ["add", "signals", "delete", "schedule"];
1879
1828
  if (!action || !actions.includes(action)) {
1880
1829
  throw new CliInputError(`Usage: signaliz awareness <${actions.join("|")}>`);
1881
1830
  }
1831
+ const domain = flag("domain");
1832
+ if (!domain) throw new CliInputError(`signaliz awareness ${action} requires --domain <company-domain>`);
1882
1833
  const client = createClient();
1883
- if (action === "create") {
1884
- const companyName = flag("company-name");
1885
- const domain = flag("domain");
1886
- if (!companyName || !domain) {
1887
- throw new CliInputError('Usage: signaliz awareness create --company-name "Acme" --domain acme.com');
1888
- }
1889
- const result2 = await client.createSignalMonitor({
1890
- companyName,
1891
- domain,
1892
- scheduleCron: awarenessSchedule(),
1893
- webhookUrl: flag("webhook-url")
1894
- });
1895
- output(result2, () => process.stdout.write(`Monitor created: ${String(result2.monitor?.id || "pending")}
1896
- `));
1897
- return;
1898
- }
1899
- if (action === "import") {
1900
- const rows = readBatchInput();
1901
- if (!rows) throw new CliInputError("signaliz awareness import requires --input <json-or-jsonl-file>");
1902
- if (rows.length > 500) throw new CliInputError(`Signal Awareness imports at most 500 companies; received ${rows.length}`);
1903
- const monitors = rows.map((value, index) => {
1904
- const row = record(value);
1905
- const companyName = stringValue(row.company_name ?? row.companyName ?? row.company ?? row.name);
1906
- const domain = stringValue(row.domain ?? row.website);
1907
- if (!companyName || !domain) throw new CliInputError(`Awareness import row ${index + 1} requires company_name and domain`);
1908
- return { companyName, domain };
1909
- });
1910
- const result2 = await client.bulkCreateSignalMonitors(monitors, {
1911
- scheduleCron: awarenessSchedule(),
1912
- webhookUrl: flag("webhook-url")
1913
- });
1914
- output(result2, () => process.stdout.write(`Created: ${result2.created || 0}
1915
- Skipped: ${result2.skipped || 0}
1916
- `));
1917
- return;
1918
- }
1919
- if (action === "list") {
1920
- const offset = numberFlag("offset");
1921
- const limit = numberFlag("limit");
1922
- if (limit !== void 0) requireIntegerInRange(limit, "--limit", 1, 500);
1923
- if (offset !== void 0) requireIntegerInRange(offset, "--offset", 0, 1e4);
1924
- const result2 = await client.listSignalMonitors(limit, offset);
1925
- output(result2, () => {
1926
- for (const monitor of result2.monitors || []) {
1927
- process.stdout.write(`${String(monitor.company_name)} ${String(monitor.status)} ${String(monitor.next_run_at || "not scheduled")} ${String(monitor.id)}
1928
- `);
1929
- }
1930
- });
1931
- return;
1932
- }
1933
1834
  if (action === "signals") {
1934
- const offset = numberFlag("offset");
1935
- const limit = numberFlag("limit");
1936
- if (limit !== void 0) requireIntegerInRange(limit, "--limit", 1, 500);
1937
- if (offset !== void 0) requireIntegerInRange(offset, "--offset", 0, 1e4);
1938
- const result2 = customerSignalAwarenessResult(await client.listSignalAwarenessSignals(monitorId, limit, offset));
1835
+ const result2 = customerSignalAwarenessResult(await client.listAllSignalAwarenessSignals(domain));
1939
1836
  output(result2, () => {
1940
1837
  for (const signal of result2.signals || []) {
1941
1838
  process.stdout.write(`${signal.signal_type} ${signal.signal_title} ${signal.signal_summary} ${signal.source} ${signal.date} ${signal.company_name} ${signal.domain}
@@ -1944,81 +1841,22 @@ Skipped: ${result2.skipped || 0}
1944
1841
  });
1945
1842
  return;
1946
1843
  }
1947
- if (action === "settings") {
1948
- const result2 = await client.getSignalAwarenessSettings();
1949
- output(result2, () => process.stdout.write(`Output: ${result2.outputMode || "csv"}
1950
- Webhook: ${result2.webhookUrl || "not configured"}
1951
- `));
1952
- return;
1953
- }
1954
- if (action === "set-output") {
1955
- const mode = flag("mode");
1956
- if (mode !== "csv" && mode !== "webhook") throw new CliInputError("signaliz awareness set-output requires --mode csv|webhook");
1957
- const webhookUrl = flag("webhook-url");
1958
- if (mode === "webhook" && !webhookUrl) throw new CliInputError("--webhook-url is required when --mode webhook");
1959
- const result2 = await client.setSignalAwarenessOutput(mode, webhookUrl);
1960
- output(result2, () => process.stdout.write(`Signal Awareness output set to ${mode}
1961
- `));
1962
- return;
1963
- }
1964
- if (action === "test-webhook") {
1965
- const webhookUrl = flag("webhook-url");
1966
- if (!webhookUrl) throw new CliInputError("signaliz awareness test-webhook requires --webhook-url https://...");
1967
- const result2 = await client.testSignalAwarenessWebhook(webhookUrl);
1968
- output(result2, () => process.stdout.write(`Webhook returned HTTP ${result2.webhookStatus || "unknown"}
1844
+ if (action === "add") {
1845
+ const result2 = await client.addSignalAwarenessCompany(domain, awarenessSchedule() ?? "daily");
1846
+ output(result2, () => process.stdout.write(`Company added: ${domain}
1969
1847
  `));
1970
1848
  return;
1971
1849
  }
1972
- if (action === "export") {
1973
- const result2 = customerSignalAwarenessResult(await client.exportSignalAwareness(monitorId));
1974
- output(result2, () => process.stdout.write(`Companies: ${result2.monitors?.length || 0}
1975
- Signals: ${result2.signals?.length || 0}
1850
+ if (action === "schedule") {
1851
+ const schedule = awarenessSchedule();
1852
+ if (!schedule) throw new CliInputError("signaliz awareness schedule requires --schedule daily|weekly|monthly");
1853
+ const result2 = await client.changeSignalAwarenessSchedule(domain, schedule);
1854
+ output(result2, () => process.stdout.write(`Schedule updated: ${domain} (${schedule})
1976
1855
  `));
1977
1856
  return;
1978
1857
  }
1979
- if (action === "send-export") {
1980
- const rows = readBatchInput();
1981
- if (!rows) throw new CliInputError("signaliz awareness send-export requires --input <json-or-jsonl-file>");
1982
- if (rows.length > 2e3) throw new CliInputError(`Signal Awareness sends at most 2,000 signals per call; received ${rows.length}`);
1983
- const signals2 = publicSignalRows(rows);
1984
- if (signals2.length !== rows.length) throw new CliInputError("Every send-export row must contain signal_type, source, date, company_name, and domain");
1985
- const result2 = await client.sendSignalAwarenessExport(signals2);
1986
- output(result2, () => process.stdout.write(`Delivered: ${result2.delivered || 0}
1987
- Webhook: HTTP ${result2.webhookStatus || "unknown"}
1988
- `));
1989
- return;
1990
- }
1991
- if (!monitorId) throw new CliInputError(`signaliz awareness ${action} requires --monitor-id <uuid>`);
1992
- if (action === "update" || action === "schedule") {
1993
- const scheduleCron = awarenessSchedule();
1994
- const companyName = flag("company-name");
1995
- const webhookUrl = hasFlag("clear-webhook") ? null : flag("webhook-url");
1996
- if (action === "schedule" && !scheduleCron) throw new CliInputError("signaliz awareness schedule requires --schedule or --schedule-cron");
1997
- if (!companyName && !scheduleCron && webhookUrl === void 0) {
1998
- throw new CliInputError("signaliz awareness update requires --company-name, --schedule/--schedule-cron, --webhook-url, or --clear-webhook");
1999
- }
2000
- const result2 = await client.updateSignalMonitor(monitorId, { companyName, scheduleCron, webhookUrl });
2001
- output(result2, () => process.stdout.write(`Monitor updated: ${monitorId}
2002
- `));
2003
- return;
2004
- }
2005
- if (action === "run") {
2006
- if (hasFlag("dry-run")) {
2007
- const result3 = await client.signalAwareness({ action: "manual_run", monitorId, idempotencyKey: flag("idempotency-key"), dryRun: true });
2008
- output(result3);
2009
- return;
2010
- }
2011
- const result2 = await client.runSignalMonitor(monitorId, flag("idempotency-key"));
2012
- output(result2, () => {
2013
- process.stdout.write(`Run: ${String(result2.run?.id || result2.runId || "pending")}
2014
- Signals: ${String(result2.run?.signals_found || 0)}
2015
- Credits used: ${result2.creditsUsed || 0}
2016
- `);
2017
- });
2018
- return;
2019
- }
2020
- const result = action === "delete" ? await client.deleteSignalMonitor(monitorId) : action === "resume" ? await client.resumeSignalMonitor(monitorId) : await client.pauseSignalMonitor(monitorId);
2021
- output(result, () => process.stdout.write(`Monitor ${action === "delete" ? "deleted" : action === "resume" ? "resumed" : "paused"}: ${monitorId}
1858
+ const result = await client.deleteSignalAwarenessCompany(domain);
1859
+ output(result, () => process.stdout.write(`Company deleted: ${domain}
2022
1860
  `));
2023
1861
  }
2024
1862
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signaliz/cli",
3
- "version": "1.0.67",
3
+ "version": "1.0.69",
4
4
  "description": "Signaliz CLI for Company Signal Enrichment, Signals First, Signal Awareness, Signal to Copy AI, and Signaliz Flow.",
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.72"
32
+ "@signaliz/sdk": "^1.0.74"
33
33
  },
34
34
  "devDependencies": {
35
35
  "tsup": "^8.0.0",