@signaliz/cli 1.0.68 → 1.0.70

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 +16 -18
  2. package/dist/bin.js +86 -224
  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.
@@ -47,20 +52,14 @@ signaliz signal-to-copy --company-domain example.com --person-name "Jane Doe" \
47
52
 
48
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
package/dist/bin.js CHANGED
@@ -24,34 +24,30 @@ 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 "Optional research lens"] [--lookback-days 365]
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>
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 list
43
+ signaliz awareness run --monitor-id <uuid> [--idempotency-key <key>]
44
+ signaliz awareness pause|resume --monitor-id <uuid>
45
+ signaliz awareness signals --domain acme.com
46
+ signaliz awareness signals --monitor-id <uuid>
47
+ signaliz awareness export [--monitor-id <uuid>]
50
48
  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
49
+ signaliz awareness delete --domain acme.com
50
+ signaliz awareness schedule --domain acme.com --schedule daily|weekly|monthly
55
51
  signaliz flow --signal-query "companies with recent hiring" --campaign-offer "..." [--limit 5] [--lookback-days 90] [--people-titles "CEO,VP Sales"]
56
52
  signaliz flow --run-id run_... Read a durable Flow checkpoint without dispatching new work
57
53
 
@@ -75,16 +71,14 @@ Common flags:
75
71
  --concurrency <1-50> Simultaneous API requests for batch input (default: 10)
76
72
  --idempotency-key <key> Reuse after an ambiguous response to recover the same request or job
77
73
  --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
74
+ --run-without-signal yes|no Draft from the offer without researching or claiming a company signal
79
75
  --run-id <run_...> Resume one existing Find Email run without dispatching new work
80
76
  --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
77
  --fact-id <sha256> Pin one active canonical signal fact in Signal to Copy
84
78
  --event-id <sha256> Pin one canonical signal event in Signal to Copy
85
79
  --dry-run Return a no-spend plan without provider calls, jobs, or writes
86
80
 
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 First is asynchronous by default; use --wait to poll until it completes.
81
+ Company Signals requires only --domain; --research-prompt and --lookback-days are optional. 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. Signal to Copy accepts --run-without-signal yes|no. Signals First accepts a query and --limit up to 100, plus recovery, idempotency, and dry-run controls. Signal Awareness supports simple domain commands and the full monitor lifecycle.
88
82
  `;
89
83
  function loadConfig() {
90
84
  if (!(0, import_node_fs.existsSync)(CONFIG_FILE)) return {};
@@ -131,25 +125,6 @@ function requireIntegerInRange(value, name, minimum, maximum) {
131
125
  throw new CliInputError(`${name} must be an integer between ${minimum} and ${maximum}`);
132
126
  }
133
127
  }
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
128
  function requireSignalToCopyIdentity(request) {
154
129
  if (stringValue(request.signalRunId)) return;
155
130
  const missing = [
@@ -436,12 +411,19 @@ function customerEmailResult(value, kind) {
436
411
  const result = record(value);
437
412
  const raw = record(result.raw);
438
413
  if (kind === "verify") {
414
+ const isCatchAll2 = result.isCatchAll === true || raw.is_catch_all === true || raw.email_is_catch_all === true;
415
+ const okToSend = result.okToSend === true || raw.ok_to_send === true;
416
+ const rawStatus = String(result.status || raw.status || "").trim().toLowerCase();
417
+ const legacyVerdict = String(
418
+ raw.verification_status || raw.verification_verdict || raw.deliverability_status || ""
419
+ ).trim().toLowerCase();
420
+ const status = rawStatus && !["completed", "processing"].includes(rawStatus) ? rawStatus : rawStatus === "processing" ? "processing" : legacyVerdict ? legacyVerdict : okToSend ? "valid" : isCatchAll2 ? "catch_all" : "unknown";
439
421
  return {
440
422
  email: typeof result.email === "string" ? result.email : typeof raw.email === "string" ? raw.email : null,
441
- status: result.status || raw.status || "completed",
442
- is_catch_all: result.isCatchAll === true || raw.is_catch_all === true || raw.email_is_catch_all === true,
423
+ status,
424
+ is_catch_all: isCatchAll2,
443
425
  credits_charged: safeNonNegativeNumber(result.creditsCharged ?? raw.credits_charged) ?? 0,
444
- ok_to_send: result.okToSend === true || raw.ok_to_send === true
426
+ ok_to_send: okToSend
445
427
  };
446
428
  }
447
429
  if (String(result.status || "").toLowerCase() === "processing") {
@@ -936,16 +918,10 @@ async function discoverSignalsEverything(request) {
936
918
  const body = request.signalSearchRunId ? {
937
919
  signal_search_run_id: request.signalSearchRunId,
938
920
  ...request.limit === void 0 ? {} : { limit: request.limit },
939
- ...request.dryRun === void 0 ? {} : { dry_run: request.dryRun },
940
- ...request.idempotencyKey ? { idempotency_key: request.idempotencyKey } : {}
921
+ ...request.dryRun === void 0 ? {} : { dry_run: request.dryRun }
941
922
  } : {
942
923
  query: request.query,
943
- ...request.icpContext ? { icp_context: request.icpContext } : {},
944
924
  limit: request.limit ?? 100,
945
- ...request.sources ? { sources: request.sources } : {},
946
- ...request.lookbackDays === void 0 ? {} : { lookback_days: request.lookbackDays },
947
- ...request.afterDate ? { after_date: request.afterDate } : {},
948
- ...request.beforeDate ? { before_date: request.beforeDate } : {},
949
925
  ...request.dryRun === void 0 ? {} : { dry_run: request.dryRun },
950
926
  ...request.idempotencyKey ? { idempotency_key: request.idempotencyKey } : {}
951
927
  };
@@ -1340,7 +1316,7 @@ async function companySignals() {
1340
1316
  ].filter(hasFlag);
1341
1317
  if (removedControlFlags.length > 0) {
1342
1318
  throw new CliInputError(
1343
- `Company Signals manages provider routing, coverage, and classifications internally; ${removedControlFlags.map((name) => `--${name}`).join(", ")} is no longer supported. Use --domain only.`
1319
+ `Company Signals manages provider routing, coverage, and classifications internally; ${removedControlFlags.map((name) => `--${name}`).join(", ")} is no longer supported. Use --domain and --research-prompt.`
1344
1320
  );
1345
1321
  }
1346
1322
  if (jobId) {
@@ -1381,6 +1357,8 @@ async function companySignals() {
1381
1357
  signalRunId: row.signalRunId || row.signal_run_id,
1382
1358
  companyDomain: row.companyDomain || row.company_domain || row.domain,
1383
1359
  domain: row.domain || row.companyDomain || row.company_domain,
1360
+ researchPrompt: row.researchPrompt || row.research_prompt,
1361
+ lookbackDays: row.lookbackDays || row.lookback_days,
1384
1362
  idempotencyKey: row.idempotencyKey || row.idempotency_key
1385
1363
  };
1386
1364
  });
@@ -1390,7 +1368,7 @@ async function companySignals() {
1390
1368
  );
1391
1369
  if (incompatible) {
1392
1370
  throw new CliInputError(
1393
- "Company Signals batches larger than 25 require domain-only rows without per-row controls or recovery IDs."
1371
+ "Company Signals batches larger than 25 require domain rows without per-row controls or recovery IDs."
1394
1372
  );
1395
1373
  }
1396
1374
  } else if (hasFlag("no-wait") && !hasFlag("dry-run")) {
@@ -1425,14 +1403,16 @@ async function companySignals() {
1425
1403
  throw new CliInputError("Company Signals --poll-interval-ms requires --input or --job-id.");
1426
1404
  }
1427
1405
  const companyDomain = flag("domain") || flag("company-domain");
1406
+ const researchPrompt = flag("research-prompt");
1428
1407
  const signalRunId = flag("signal-run-id");
1429
1408
  if (!companyDomain && !signalRunId) {
1430
- throw new CliInputError("Usage: signaliz company-signals --domain example.com");
1409
+ throw new CliInputError('Usage: signaliz company-signals --domain example.com [--research-prompt "Why now?"]');
1431
1410
  }
1432
1411
  const request = {
1433
1412
  signalRunId,
1434
1413
  domain: companyDomain,
1435
- idempotencyKey: flag("idempotency-key")
1414
+ researchPrompt,
1415
+ lookbackDays: numberFlag("lookback-days")
1436
1416
  };
1437
1417
  if (hasFlag("dry-run")) {
1438
1418
  const result2 = await createClient().enrichCompanySignals({ ...request, dryRun: true });
@@ -1492,29 +1472,19 @@ async function signals(args) {
1492
1472
  if (!query && !signalSearchRunId) {
1493
1473
  fail('Usage: signaliz signals "companies that just got funded" [--limit 100] OR signaliz signals --signal-search-run-id run_...');
1494
1474
  }
1495
- const sourceValues = csvFlag("sources");
1496
- if (sourceValues?.some((source) => !["web", "news"].includes(source))) {
1497
- fail("--sources must contain only web or news");
1498
- }
1499
- const icpContext = flag("icp-context");
1500
- if (hasFlag("icp-context") && (typeof icpContext !== "string" || icpContext.trim().length < 2 || icpContext.trim().length > 4e3)) {
1501
- fail("--icp-context must contain between 2 and 4000 characters");
1475
+ const removedControls = ["icp-context", "sources", "lookback-days", "after-date", "before-date"].filter(hasFlag);
1476
+ if (removedControls.length > 0) {
1477
+ fail(`Signals First accepts only query and --limit; ${removedControls.map((name) => `--${name}`).join(", ")} is no longer supported.`);
1502
1478
  }
1503
1479
  const request = {
1504
1480
  query,
1505
- icpContext: icpContext?.trim(),
1506
1481
  signalSearchRunId,
1507
1482
  limit: numberFlag("limit"),
1508
- sources: sourceValues,
1509
- lookbackDays: numberFlag("lookback-days"),
1510
- afterDate: flag("after-date"),
1511
- beforeDate: flag("before-date"),
1512
- idempotencyKey: flag("idempotency-key"),
1513
- dryRun: hasFlag("dry-run")
1483
+ dryRun: hasFlag("dry-run") || void 0,
1484
+ idempotencyKey: flag("idempotency-key")
1514
1485
  };
1515
- validateSignalDateWindow(request.afterDate, request.beforeDate, request.lookbackDays);
1516
1486
  let result = await discoverSignalsEverything(request);
1517
- if (hasFlag("wait") && !request.dryRun) {
1487
+ if (hasFlag("wait")) {
1518
1488
  const maxWaitMs = numberFlag("max-wait-ms") ?? 15 * 6e4;
1519
1489
  const pollIntervalMs = numberFlag("poll-interval-ms");
1520
1490
  const startedAt = Date.now();
@@ -1674,6 +1644,7 @@ async function signalToCopy() {
1674
1644
  "lookback-days",
1675
1645
  "copy-evidence-mode",
1676
1646
  "without-signals",
1647
+ "run-without-signal",
1677
1648
  "signal-run-id",
1678
1649
  "signal-search-run-id",
1679
1650
  "fact-id",
@@ -1708,10 +1679,9 @@ async function signalToCopy() {
1708
1679
  personName: row.personName || row.person_name,
1709
1680
  title: row.title,
1710
1681
  campaignOffer: row.campaignOffer || row.campaign_offer || row.offer,
1711
- copyEvidenceMode: row.copyEvidenceMode || row.copy_evidence_mode || flag("copy-evidence-mode") || (hasFlag("without-signals") ? "firmographic" : void 0),
1682
+ runWithoutSignal: row.runWithoutSignal ?? row.run_without_signal ?? yesNoFlag("run-without-signal"),
1712
1683
  lookbackDays: 365,
1713
1684
  signalRunId: row.signalRunId || row.signal_run_id,
1714
- signalSearchRunId: row.signalSearchRunId || row.signal_search_run_id,
1715
1685
  factId: row.factId || row.fact_id,
1716
1686
  eventId: row.eventId || row.event_id,
1717
1687
  enableDeepSearch: row.enableDeepSearch ?? row.enable_deep_search ?? hasFlag("deep-search"),
@@ -1725,7 +1695,7 @@ async function signalToCopy() {
1725
1695
  }
1726
1696
  if (durableBatch) {
1727
1697
  const invalidIndex = requests.findIndex(
1728
- (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)
1698
+ (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)
1729
1699
  );
1730
1700
  if (invalidIndex >= 0) {
1731
1701
  throw new CliInputError(
@@ -1771,10 +1741,9 @@ async function signalToCopy() {
1771
1741
  personName,
1772
1742
  title,
1773
1743
  campaignOffer,
1774
- copyEvidenceMode: flag("copy-evidence-mode") || (hasFlag("without-signals") ? "firmographic" : void 0),
1744
+ runWithoutSignal: yesNoFlag("run-without-signal"),
1775
1745
  lookbackDays: 365,
1776
1746
  signalRunId,
1777
- signalSearchRunId: flag("signal-search-run-id"),
1778
1747
  factId: flag("fact-id"),
1779
1748
  eventId: flag("event-id"),
1780
1749
  enableDeepSearch: hasFlag("deep-search"),
@@ -1860,102 +1829,51 @@ Import this file into your MCP client.
1860
1829
  });
1861
1830
  }
1862
1831
  function awarenessSchedule() {
1863
- const direct = flag("schedule-cron");
1864
- if (direct) return direct;
1865
1832
  const schedule = flag("schedule");
1866
1833
  if (!schedule) return void 0;
1867
- const schedules = {
1868
- every_6_hours: "0 */6 * * *",
1869
- daily: "0 8 * * *",
1870
- every_2_days: "0 8 */2 * *",
1871
- weekly: "0 8 * * 1",
1872
- monthly: "0 8 1 * *"
1873
- };
1874
- if (!schedules[schedule]) {
1875
- throw new CliInputError("--schedule must be every_6_hours, daily, every_2_days, weekly, or monthly");
1834
+ if (!["daily", "weekly", "monthly"].includes(schedule)) {
1835
+ throw new CliInputError("--schedule must be daily, weekly, or monthly");
1876
1836
  }
1877
- return schedules[schedule];
1837
+ return schedule;
1838
+ }
1839
+ function yesNoFlag(name) {
1840
+ const value = flag(name);
1841
+ if (value === void 0) return void 0;
1842
+ if (value === "yes") return true;
1843
+ if (value === "no") return false;
1844
+ throw new CliInputError(`--${name} must be yes or no`);
1878
1845
  }
1879
1846
  async function awareness(args) {
1880
1847
  const action = args[0];
1881
- const monitorId = flag("monitor-id");
1882
- const actions = [
1883
- "create",
1884
- "import",
1885
- "list",
1886
- "update",
1887
- "schedule",
1888
- "run",
1889
- "signals",
1890
- "pause",
1891
- "resume",
1892
- "delete",
1893
- "settings",
1894
- "set-output",
1895
- "test-webhook",
1896
- "export",
1897
- "send-export"
1898
- ];
1848
+ const actions = ["add", "list", "run", "pause", "resume", "signals", "export", "settings", "delete", "schedule"];
1899
1849
  if (!action || !actions.includes(action)) {
1900
1850
  throw new CliInputError(`Usage: signaliz awareness <${actions.join("|")}>`);
1901
1851
  }
1852
+ const domain = flag("domain");
1853
+ const monitorId = flag("monitor-id");
1902
1854
  const client = createClient();
1903
- if (action === "create") {
1904
- const companyName = flag("company-name");
1905
- const domain = flag("domain");
1906
- if (!companyName || !domain) {
1907
- throw new CliInputError('Usage: signaliz awareness create --company-name "Acme" --domain acme.com');
1908
- }
1909
- const result2 = await client.createSignalMonitor({
1910
- companyName,
1911
- domain,
1912
- scheduleCron: awarenessSchedule(),
1913
- webhookUrl: flag("webhook-url")
1914
- });
1915
- output(result2, () => process.stdout.write(`Monitor created: ${String(result2.monitor?.id || "pending")}
1916
- `));
1855
+ if (action === "list") {
1856
+ const result2 = await client.listSignalMonitors(numberFlag("limit"), numberFlag("offset"));
1857
+ output(result2);
1917
1858
  return;
1918
1859
  }
1919
- if (action === "import") {
1920
- const rows = readBatchInput();
1921
- if (!rows) throw new CliInputError("signaliz awareness import requires --input <json-or-jsonl-file>");
1922
- if (rows.length > 500) throw new CliInputError(`Signal Awareness imports at most 500 companies; received ${rows.length}`);
1923
- const monitors = rows.map((value, index) => {
1924
- const row = record(value);
1925
- const companyName = stringValue(row.company_name ?? row.companyName ?? row.company ?? row.name);
1926
- const domain = stringValue(row.domain ?? row.website);
1927
- if (!companyName || !domain) throw new CliInputError(`Awareness import row ${index + 1} requires company_name and domain`);
1928
- return { companyName, domain };
1929
- });
1930
- const result2 = await client.bulkCreateSignalMonitors(monitors, {
1931
- scheduleCron: awarenessSchedule(),
1932
- webhookUrl: flag("webhook-url")
1933
- });
1934
- output(result2, () => process.stdout.write(`Created: ${result2.created || 0}
1935
- Skipped: ${result2.skipped || 0}
1936
- `));
1860
+ if (action === "settings") {
1861
+ output(await client.getSignalAwarenessSettings());
1937
1862
  return;
1938
1863
  }
1939
- if (action === "list") {
1940
- const offset = numberFlag("offset");
1941
- const limit = numberFlag("limit");
1942
- if (limit !== void 0) requireIntegerInRange(limit, "--limit", 1, 500);
1943
- if (offset !== void 0) requireIntegerInRange(offset, "--offset", 0, 1e4);
1944
- const result2 = await client.listSignalMonitors(limit, offset);
1945
- output(result2, () => {
1946
- for (const monitor of result2.monitors || []) {
1947
- process.stdout.write(`${String(monitor.company_name)} ${String(monitor.status)} ${String(monitor.next_run_at || "not scheduled")} ${String(monitor.id)}
1948
- `);
1949
- }
1950
- });
1864
+ if (action === "run" || action === "pause" || action === "resume") {
1865
+ if (!monitorId) throw new CliInputError(`signaliz awareness ${action} requires --monitor-id <uuid>`);
1866
+ const result2 = action === "run" ? await client.runSignalMonitor(monitorId, flag("idempotency-key")) : action === "pause" ? await client.pauseSignalMonitor(monitorId) : await client.resumeSignalMonitor(monitorId);
1867
+ output(result2);
1868
+ return;
1869
+ }
1870
+ if (action === "export") {
1871
+ output(await client.exportSignalAwareness(monitorId));
1951
1872
  return;
1952
1873
  }
1953
1874
  if (action === "signals") {
1954
- const offset = numberFlag("offset");
1955
- const limit = numberFlag("limit");
1956
- if (limit !== void 0) requireIntegerInRange(limit, "--limit", 1, 500);
1957
- if (offset !== void 0) requireIntegerInRange(offset, "--offset", 0, 1e4);
1958
- const result2 = customerSignalAwarenessResult(await client.listSignalAwarenessSignals(monitorId, limit, offset));
1875
+ if (!domain && !monitorId) throw new CliInputError("signaliz awareness signals requires --domain or --monitor-id");
1876
+ const result2 = customerSignalAwarenessResult(monitorId ? await client.listSignalAwarenessSignals(monitorId, numberFlag("limit"), numberFlag("offset")) : await client.listAllSignalAwarenessSignals(domain));
1959
1877
  output(result2, () => {
1960
1878
  for (const signal of result2.signals || []) {
1961
1879
  process.stdout.write(`${signal.signal_type} ${signal.signal_title} ${signal.signal_summary} ${signal.source} ${signal.date} ${signal.company_name} ${signal.domain}
@@ -1964,81 +1882,25 @@ Skipped: ${result2.skipped || 0}
1964
1882
  });
1965
1883
  return;
1966
1884
  }
1967
- if (action === "settings") {
1968
- const result2 = await client.getSignalAwarenessSettings();
1969
- output(result2, () => process.stdout.write(`Output: ${result2.outputMode || "csv"}
1970
- Webhook: ${result2.webhookUrl || "not configured"}
1971
- `));
1972
- return;
1973
- }
1974
- if (action === "set-output") {
1975
- const mode = flag("mode");
1976
- if (mode !== "csv" && mode !== "webhook") throw new CliInputError("signaliz awareness set-output requires --mode csv|webhook");
1977
- const webhookUrl = flag("webhook-url");
1978
- if (mode === "webhook" && !webhookUrl) throw new CliInputError("--webhook-url is required when --mode webhook");
1979
- const result2 = await client.setSignalAwarenessOutput(mode, webhookUrl);
1980
- output(result2, () => process.stdout.write(`Signal Awareness output set to ${mode}
1981
- `));
1982
- return;
1983
- }
1984
- if (action === "test-webhook") {
1985
- const webhookUrl = flag("webhook-url");
1986
- if (!webhookUrl) throw new CliInputError("signaliz awareness test-webhook requires --webhook-url https://...");
1987
- const result2 = await client.testSignalAwarenessWebhook(webhookUrl);
1988
- output(result2, () => process.stdout.write(`Webhook returned HTTP ${result2.webhookStatus || "unknown"}
1989
- `));
1990
- return;
1991
- }
1992
- if (action === "export") {
1993
- const result2 = customerSignalAwarenessResult(await client.exportSignalAwareness(monitorId));
1994
- output(result2, () => process.stdout.write(`Companies: ${result2.monitors?.length || 0}
1995
- Signals: ${result2.signals?.length || 0}
1996
- `));
1997
- return;
1998
- }
1999
- if (action === "send-export") {
2000
- const rows = readBatchInput();
2001
- if (!rows) throw new CliInputError("signaliz awareness send-export requires --input <json-or-jsonl-file>");
2002
- if (rows.length > 2e3) throw new CliInputError(`Signal Awareness sends at most 2,000 signals per call; received ${rows.length}`);
2003
- const signals2 = publicSignalRows(rows);
2004
- if (signals2.length !== rows.length) throw new CliInputError("Every send-export row must contain signal_type, source, date, company_name, and domain");
2005
- const result2 = await client.sendSignalAwarenessExport(signals2);
2006
- output(result2, () => process.stdout.write(`Delivered: ${result2.delivered || 0}
2007
- Webhook: HTTP ${result2.webhookStatus || "unknown"}
1885
+ if (action === "add") {
1886
+ if (!domain) throw new CliInputError("signaliz awareness add requires --domain <company-domain>");
1887
+ const result2 = await client.addSignalAwarenessCompany(domain, awarenessSchedule() ?? "daily");
1888
+ output(result2, () => process.stdout.write(`Company added: ${domain}
2008
1889
  `));
2009
1890
  return;
2010
1891
  }
2011
- if (!monitorId) throw new CliInputError(`signaliz awareness ${action} requires --monitor-id <uuid>`);
2012
- if (action === "update" || action === "schedule") {
2013
- const scheduleCron = awarenessSchedule();
2014
- const companyName = flag("company-name");
2015
- const webhookUrl = hasFlag("clear-webhook") ? null : flag("webhook-url");
2016
- if (action === "schedule" && !scheduleCron) throw new CliInputError("signaliz awareness schedule requires --schedule or --schedule-cron");
2017
- if (!companyName && !scheduleCron && webhookUrl === void 0) {
2018
- throw new CliInputError("signaliz awareness update requires --company-name, --schedule/--schedule-cron, --webhook-url, or --clear-webhook");
2019
- }
2020
- const result2 = await client.updateSignalMonitor(monitorId, { companyName, scheduleCron, webhookUrl });
2021
- output(result2, () => process.stdout.write(`Monitor updated: ${monitorId}
1892
+ if (action === "schedule") {
1893
+ if (!domain) throw new CliInputError("signaliz awareness schedule requires --domain <company-domain>");
1894
+ const schedule = awarenessSchedule();
1895
+ if (!schedule) throw new CliInputError("signaliz awareness schedule requires --schedule daily|weekly|monthly");
1896
+ const result2 = await client.changeSignalAwarenessSchedule(domain, schedule);
1897
+ output(result2, () => process.stdout.write(`Schedule updated: ${domain} (${schedule})
2022
1898
  `));
2023
1899
  return;
2024
1900
  }
2025
- if (action === "run") {
2026
- if (hasFlag("dry-run")) {
2027
- const result3 = await client.signalAwareness({ action: "manual_run", monitorId, idempotencyKey: flag("idempotency-key"), dryRun: true });
2028
- output(result3);
2029
- return;
2030
- }
2031
- const result2 = await client.runSignalMonitor(monitorId, flag("idempotency-key"));
2032
- output(result2, () => {
2033
- process.stdout.write(`Run: ${String(result2.run?.id || result2.runId || "pending")}
2034
- Signals: ${String(result2.run?.signals_found || 0)}
2035
- Credits used: ${result2.creditsUsed || 0}
2036
- `);
2037
- });
2038
- return;
2039
- }
2040
- const result = action === "delete" ? await client.deleteSignalMonitor(monitorId) : action === "resume" ? await client.resumeSignalMonitor(monitorId) : await client.pauseSignalMonitor(monitorId);
2041
- output(result, () => process.stdout.write(`Monitor ${action === "delete" ? "deleted" : action === "resume" ? "resumed" : "paused"}: ${monitorId}
1901
+ if (!domain && !monitorId) throw new CliInputError("signaliz awareness delete requires --domain or --monitor-id");
1902
+ const result = monitorId ? await client.deleteSignalMonitor(monitorId) : await client.deleteSignalAwarenessCompany(domain);
1903
+ output(result, () => process.stdout.write(`Monitor deleted: ${monitorId || domain}
2042
1904
  `));
2043
1905
  }
2044
1906
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signaliz/cli",
3
- "version": "1.0.68",
3
+ "version": "1.0.70",
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.75"
33
33
  },
34
34
  "devDependencies": {
35
35
  "tsup": "^8.0.0",