discolike-cli 0.4.0__tar.gz → 0.5.0__tar.gz

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 (48) hide show
  1. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/PKG-INFO +27 -7
  2. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/README.md +23 -2
  3. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/pyproject.toml +4 -5
  4. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/_help.py +3 -0
  5. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/_output.py +3 -2
  6. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/auth.py +2 -2
  7. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/bulk.py +2 -2
  8. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/contacts.py +2 -2
  9. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/discogen.py +1 -1
  10. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/email.py +5 -5
  11. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/main.py +3 -1
  12. discolike_cli-0.5.0/src/discolike_cli/prospecting.py +363 -0
  13. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/queries.py +2 -2
  14. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_entrypoint.py +3 -3
  15. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_output.py +3 -3
  16. discolike_cli-0.5.0/tests/test_prospecting_cli.py +457 -0
  17. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_sdk_parity.py +1 -0
  18. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/.gitignore +0 -0
  19. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/LICENSE +0 -0
  20. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/__init__.py +0 -0
  21. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/_inputs.py +0 -0
  22. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/_loopback.py +0 -0
  23. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/account.py +0 -0
  24. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/company.py +0 -0
  25. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/discover.py +0 -0
  26. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/enrich.py +0 -0
  27. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/match.py +0 -0
  28. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/providers.py +0 -0
  29. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/py.typed +0 -0
  30. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/src/discolike_cli/signup.py +0 -0
  31. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/conftest.py +0 -0
  32. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_account.py +0 -0
  33. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_auth.py +0 -0
  34. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_auth_oauth.py +0 -0
  35. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_bulk_cli.py +0 -0
  36. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_company.py +0 -0
  37. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_contacts_cli.py +0 -0
  38. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_discogen_cli.py +0 -0
  39. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_discover.py +0 -0
  40. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_email_cli.py +0 -0
  41. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_enrich_cli.py +0 -0
  42. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_file_inputs_cli.py +0 -0
  43. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_help.py +0 -0
  44. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_inputs.py +0 -0
  45. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_match_cli.py +0 -0
  46. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_providers_cli.py +0 -0
  47. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_queries_cli.py +0 -0
  48. {discolike_cli-0.4.0 → discolike_cli-0.5.0}/tests/test_signup_cli.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: discolike-cli
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: Official CLI for the DiscoLike API
5
5
  Project-URL: Homepage, https://www.discolike.com
6
6
  Project-URL: Documentation, https://docs.discolike.com
@@ -17,17 +17,16 @@ Classifier: Intended Audience :: Developers
17
17
  Classifier: Operating System :: OS Independent
18
18
  Classifier: Programming Language :: Python :: 3
19
19
  Classifier: Programming Language :: Python :: 3 :: Only
20
- Classifier: Programming Language :: Python :: 3.10
21
20
  Classifier: Programming Language :: Python :: 3.11
22
21
  Classifier: Programming Language :: Python :: 3.12
23
22
  Classifier: Programming Language :: Python :: 3.13
24
23
  Classifier: Programming Language :: Python :: 3.14
25
24
  Classifier: Topic :: Utilities
26
25
  Classifier: Typing :: Typed
27
- Requires-Python: >=3.10
28
- Requires-Dist: discolike==0.4.0
26
+ Requires-Python: >=3.11
27
+ Requires-Dist: discolike==0.5.0
29
28
  Requires-Dist: rich>=13.0
30
- Requires-Dist: typer>=0.12
29
+ Requires-Dist: typer<0.28,>=0.26.1
31
30
  Description-Content-Type: text/markdown
32
31
 
33
32
  # discolike-cli
@@ -46,7 +45,7 @@ Or run it without installing:
46
45
  uvx --from discolike-cli discolike --help
47
46
  ```
48
47
 
49
- Requires Python 3.10+. Installing this package gives you the `discolike` command.
48
+ Requires Python 3.11+. Installing this package gives you the `discolike` command.
50
49
 
51
50
  ## Authentication
52
51
 
@@ -67,7 +66,7 @@ discolike company data stripe.com
67
66
  discolike extract https://stripe.com/enterprise
68
67
  ```
69
68
 
70
- Top-level commands: `discover`, `count`, `match`, `extract`, `validate-icp`, `append`, `segment` — plus `auth`, `bulk`, `company`, `contacts`, `discogen`, `queries`, `account`, `search-providers`, and `llm-providers` command groups.
69
+ Top-level commands: `discover`, `count`, `match`, `extract`, `validate-icp`, `append`, `segment` — plus `auth`, `bulk`, `company`, `contacts`, `discogen`, `prospecting`, `queries`, `account`, `search-providers`, and `llm-providers` command groups.
71
70
 
72
71
  ### Volume pulls
73
72
 
@@ -81,6 +80,26 @@ discolike bulk contacts --domains-file companies.csv --per-company 10 --summary
81
80
 
82
81
  `companies` saves each page as an exclusion list (`<run-name>-round-N`) and excludes it from the next page; rerunning with the same `--out` resumes from the CSV. `contacts` slices the domain list at `10000 / per-company` domains per call and records finished slices in `<out>.checkpoint`. Both keep one call in flight under `--rate-limit` (default 10/min, the Pro rate on `/discover` and `/contacts`), retry on 429/5xx, and print a JSON summary at the end. Filters come from `--params-file`, `--param` and the common flags; the paging fields are managed for you.
83
82
 
83
+ ### Managed prospecting
84
+
85
+ ```bash
86
+ discolike prospecting start --brief "Find 100 US logistics companies and 3 operations directors each" --idempotency-key logistics-1
87
+ discolike prospecting start --brief "Find lookalikes of our customers and their CTOs" --customers-file customers.csv --idempotency-key seeded-1
88
+ discolike prospecting wait RUN_ID
89
+ # Review the proposed plan, then approve the exact version you saw:
90
+ discolike prospecting approve RUN_ID --plan-version 1
91
+ discolike prospecting list --limit 20
92
+ discolike prospecting message RUN_ID --text "Make it 250 companies" --idempotency-key logistics-edit-1
93
+ discolike prospecting status RUN_ID --events-after 12 --messages-after 8 --limit 100
94
+ discolike prospecting cancel RUN_ID
95
+ ```
96
+
97
+ `wait` returns on `proposed`, `needs_input`, `completed`, `failed`, or `cancelled`. A timeout stops polling only. Inspect status and stop reason; completion does not guarantee full coverage. Message replies arrive through `status --messages-after`; follow `next_message_seq` and `reply_pending`. A "segment these" request keeps `reply_pending` true until the segments message is posted, which can take more than an hour. If grouping stops without an outcome, the flag clears on its own after about 90 minutes.
98
+
99
+ `start` and `approve` default to pausing at checkpoints, like the web chat: a pilot check on large lists (`pilot`), a search drifting off target (`tail_quality`), candidates running out short of the target (`short`), the target being met (`target_reached`), another round of companies when the ones checked yield too few contacts (`top_up`), and, on wave runs, the researched contacts found before their emails are looked up (`contacts_review`, asked with `--auto` too; contacts already in DiscoLike's database get their lookups during research, which approving the plan starts; picking "Find emails" by number sends the question's `seq`, which the API needs to accept it). Pass `--auto` to never pause (except at a `top_up` round that would pass a spending limit); a poor pilot is then sharpened once and the run continues with a notice, stopping with `pilot_failed` only if the re-pilot fit is still under 20%. If sharpening itself fails, the run continues on the original criteria. On a terminal, `wait` shows the question, any sample companies and numbered replies at a checkpoint, sends your pick or your own text, and keeps waiting. Without a terminal, or with `--no-input`, it prints the run on stdout, a `needs_input` envelope (`message`, `stop_reason`, `suggested_replies`, `sample`) on stderr, and exits 7; answer with `prospecting message --text "<reply>"` (add `--question-seq` with the question's `seq` to answer only that question) and run `wait` again.
100
+
101
+ Omit `--target-companies` and `--contacts-per-company` to infer counts from the brief (fallback 1,000 and 3; up to 10 contacts per company). Explicit values override the text. `--deliverable accounts` returns the checked companies only, with no people; `--goal companies` takes `--target-companies` matching companies and works only those instead of adding rounds until the contact target is met. Both default to `leads`. `--max-candidates` and `--max-actions` are automatic when omitted or `0`; their maxima are 100,000 and 10,000. Targets allow up to 10,000 companies, status pages up to 500 rows, and lists up to 50 runs. Work caps do not cap provider charges.
102
+
84
103
  ### Conventions
85
104
 
86
105
  - Results print as JSON to stdout; errors print as JSON (`error`, `message`, `status_code`) to stderr.
@@ -99,6 +118,7 @@ discolike bulk contacts --domains-file companies.csv --per-company 10 --summary
99
118
  | 4 | Rate limited |
100
119
  | 5 | Network error |
101
120
  | 6 | Not found |
121
+ | 7 | Needs input: `prospecting wait` reached a checkpoint with no terminal to ask (or `--no-input`) |
102
122
 
103
123
  ## Links
104
124
 
@@ -14,7 +14,7 @@ Or run it without installing:
14
14
  uvx --from discolike-cli discolike --help
15
15
  ```
16
16
 
17
- Requires Python 3.10+. Installing this package gives you the `discolike` command.
17
+ Requires Python 3.11+. Installing this package gives you the `discolike` command.
18
18
 
19
19
  ## Authentication
20
20
 
@@ -35,7 +35,7 @@ discolike company data stripe.com
35
35
  discolike extract https://stripe.com/enterprise
36
36
  ```
37
37
 
38
- Top-level commands: `discover`, `count`, `match`, `extract`, `validate-icp`, `append`, `segment` — plus `auth`, `bulk`, `company`, `contacts`, `discogen`, `queries`, `account`, `search-providers`, and `llm-providers` command groups.
38
+ Top-level commands: `discover`, `count`, `match`, `extract`, `validate-icp`, `append`, `segment` — plus `auth`, `bulk`, `company`, `contacts`, `discogen`, `prospecting`, `queries`, `account`, `search-providers`, and `llm-providers` command groups.
39
39
 
40
40
  ### Volume pulls
41
41
 
@@ -49,6 +49,26 @@ discolike bulk contacts --domains-file companies.csv --per-company 10 --summary
49
49
 
50
50
  `companies` saves each page as an exclusion list (`<run-name>-round-N`) and excludes it from the next page; rerunning with the same `--out` resumes from the CSV. `contacts` slices the domain list at `10000 / per-company` domains per call and records finished slices in `<out>.checkpoint`. Both keep one call in flight under `--rate-limit` (default 10/min, the Pro rate on `/discover` and `/contacts`), retry on 429/5xx, and print a JSON summary at the end. Filters come from `--params-file`, `--param` and the common flags; the paging fields are managed for you.
51
51
 
52
+ ### Managed prospecting
53
+
54
+ ```bash
55
+ discolike prospecting start --brief "Find 100 US logistics companies and 3 operations directors each" --idempotency-key logistics-1
56
+ discolike prospecting start --brief "Find lookalikes of our customers and their CTOs" --customers-file customers.csv --idempotency-key seeded-1
57
+ discolike prospecting wait RUN_ID
58
+ # Review the proposed plan, then approve the exact version you saw:
59
+ discolike prospecting approve RUN_ID --plan-version 1
60
+ discolike prospecting list --limit 20
61
+ discolike prospecting message RUN_ID --text "Make it 250 companies" --idempotency-key logistics-edit-1
62
+ discolike prospecting status RUN_ID --events-after 12 --messages-after 8 --limit 100
63
+ discolike prospecting cancel RUN_ID
64
+ ```
65
+
66
+ `wait` returns on `proposed`, `needs_input`, `completed`, `failed`, or `cancelled`. A timeout stops polling only. Inspect status and stop reason; completion does not guarantee full coverage. Message replies arrive through `status --messages-after`; follow `next_message_seq` and `reply_pending`. A "segment these" request keeps `reply_pending` true until the segments message is posted, which can take more than an hour. If grouping stops without an outcome, the flag clears on its own after about 90 minutes.
67
+
68
+ `start` and `approve` default to pausing at checkpoints, like the web chat: a pilot check on large lists (`pilot`), a search drifting off target (`tail_quality`), candidates running out short of the target (`short`), the target being met (`target_reached`), another round of companies when the ones checked yield too few contacts (`top_up`), and, on wave runs, the researched contacts found before their emails are looked up (`contacts_review`, asked with `--auto` too; contacts already in DiscoLike's database get their lookups during research, which approving the plan starts; picking "Find emails" by number sends the question's `seq`, which the API needs to accept it). Pass `--auto` to never pause (except at a `top_up` round that would pass a spending limit); a poor pilot is then sharpened once and the run continues with a notice, stopping with `pilot_failed` only if the re-pilot fit is still under 20%. If sharpening itself fails, the run continues on the original criteria. On a terminal, `wait` shows the question, any sample companies and numbered replies at a checkpoint, sends your pick or your own text, and keeps waiting. Without a terminal, or with `--no-input`, it prints the run on stdout, a `needs_input` envelope (`message`, `stop_reason`, `suggested_replies`, `sample`) on stderr, and exits 7; answer with `prospecting message --text "<reply>"` (add `--question-seq` with the question's `seq` to answer only that question) and run `wait` again.
69
+
70
+ Omit `--target-companies` and `--contacts-per-company` to infer counts from the brief (fallback 1,000 and 3; up to 10 contacts per company). Explicit values override the text. `--deliverable accounts` returns the checked companies only, with no people; `--goal companies` takes `--target-companies` matching companies and works only those instead of adding rounds until the contact target is met. Both default to `leads`. `--max-candidates` and `--max-actions` are automatic when omitted or `0`; their maxima are 100,000 and 10,000. Targets allow up to 10,000 companies, status pages up to 500 rows, and lists up to 50 runs. Work caps do not cap provider charges.
71
+
52
72
  ### Conventions
53
73
 
54
74
  - Results print as JSON to stdout; errors print as JSON (`error`, `message`, `status_code`) to stderr.
@@ -67,6 +87,7 @@ discolike bulk contacts --domains-file companies.csv --per-company 10 --summary
67
87
  | 4 | Rate limited |
68
88
  | 5 | Network error |
69
89
  | 6 | Not found |
90
+ | 7 | Needs input: `prospecting wait` reached a checkpoint with no terminal to ask (or `--no-input`) |
70
91
 
71
92
  ## Links
72
93
 
@@ -4,16 +4,16 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "discolike-cli"
7
- version = "0.4.0"
7
+ version = "0.5.0"
8
8
  description = "Official CLI for the DiscoLike API"
9
9
  readme = "README.md"
10
10
  license = "MIT"
11
11
  license-files = ["LICENSE"]
12
- requires-python = ">=3.10"
12
+ requires-python = ">=3.11"
13
13
  authors = [{ name = "DiscoLike", email = "support@discolike.com" }]
14
14
  dependencies = [
15
- "discolike==0.4.0",
16
- "typer>=0.12",
15
+ "discolike==0.5.0",
16
+ "typer>=0.26.1,<0.28",
17
17
  "rich>=13.0",
18
18
  ]
19
19
  keywords = ["discolike", "cli", "business-data", "enrichment"]
@@ -21,7 +21,6 @@ classifiers = [
21
21
  "Development Status :: 4 - Beta",
22
22
  "Intended Audience :: Developers",
23
23
  "Programming Language :: Python :: 3",
24
- "Programming Language :: Python :: 3.10",
25
24
  "Programming Language :: Python :: 3.11",
26
25
  "Programming Language :: Python :: 3.12",
27
26
  "Programming Language :: Python :: 3.13",
@@ -74,6 +74,9 @@ Exit codes:
74
74
  4 rate_limited HTTP 429; wait "retry_after" seconds, then retry
75
75
  5 network_error could not reach the API
76
76
  6 not_found HTTP 404
77
+ 7 needs_input `prospecting wait` stopped at a checkpoint with no terminal to ask
78
+ (or --no-input): the run is on stdout, the question and
79
+ "suggested_replies" in the stderr envelope
77
80
 
78
81
  Environment:
79
82
  {ENV_API_KEY} API key; overrides the config file written by `discolike auth login`.
@@ -43,6 +43,7 @@ EXIT_CODES: dict[type, int] = {
43
43
  NotFoundError: 6,
44
44
  }
45
45
  DEFAULT_EXIT_CODE = 1
46
+ NEEDS_INPUT_EXIT_CODE = 7
46
47
 
47
48
  # Stable, snake_case error codes for agents and scripts to branch on. The class
48
49
  # name in `error` is kept for backwards compatibility; `code` is the contract.
@@ -82,7 +83,7 @@ class SupportsWait(Protocol):
82
83
  task_id: str
83
84
  task_family: str
84
85
 
85
- def wait(self, *, timeout: float, on_poll: Callable[[_JobStatusLike], None] | None = None) -> _JobStatusLike: ...
86
+ def wait(self, *, max_wait: float, on_poll: Callable[[_JobStatusLike], None] | None = None) -> _JobStatusLike: ...
86
87
 
87
88
 
88
89
  def _normalize(data: Any) -> Any: # noqa: ANN401 -- accepts arbitrary JSON-serializable CLI output data
@@ -203,5 +204,5 @@ def run_job(job: SupportsWait, *, wait: bool, timeout: float, fmt: str | None =
203
204
  def _on_poll(status: _JobStatusLike) -> None:
204
205
  sys.stderr.write(f"progress: {status.progress}%\n")
205
206
 
206
- final = job.wait(timeout=timeout, on_poll=_on_poll)
207
+ final = job.wait(max_wait=timeout, on_poll=_on_poll)
207
208
  emit(final.results if final.results is not None else final.to_dict(), fmt=fmt)
@@ -4,8 +4,8 @@ import json
4
4
  import secrets
5
5
  import sys
6
6
  import webbrowser
7
+ from datetime import UTC
7
8
  from datetime import datetime
8
- from datetime import timezone
9
9
  from typing import Any
10
10
  from typing import NoReturn
11
11
  from urllib.parse import urlparse
@@ -88,7 +88,7 @@ def _offer_signup(ctx: typer.Context) -> None:
88
88
 
89
89
 
90
90
  def _iso(epoch_seconds: float) -> str:
91
- return datetime.fromtimestamp(epoch_seconds, tz=timezone.utc).isoformat()
91
+ return datetime.fromtimestamp(epoch_seconds, tz=UTC).isoformat()
92
92
 
93
93
 
94
94
  def _global_key_source(ctx: typer.Context) -> str:
@@ -382,8 +382,8 @@ def _persona_ids_in(path: pathlib.Path) -> set[str]:
382
382
 
383
383
 
384
384
  ICP_PROMPT_HELP = "Natural-language ICP prompt used to derive contact filters."
385
- SUMMARY_HELP = "Filter by profile summary text (semantic search); ranks who comes back per company."
386
- NEGATE_SUMMARY_HELP = "Exclude contacts matching this summary description."
385
+ SUMMARY_HELP = "Match profile summary text: every word of any one term, in any order. Quote a multi-word term to keep it together, prefix + to require it. Ranks who comes back per company."
386
+ NEGATE_SUMMARY_HELP = "Exclude contacts whose profile summary contains every word of any one term, in any order."
387
387
  HAS_EMAIL_HELP = "Only contacts with an email address (on by default)."
388
388
 
389
389
 
@@ -30,8 +30,8 @@ WAIT_HELP = "Block until the job finishes, streaming progress to stderr."
30
30
  TIMEOUT_HELP = "Max seconds to wait with --wait."
31
31
  PARAM_HELP = "Extra key=value query parameter forwarded to the SDK (repeatable)."
32
32
  JOBSTART_DATE_HELP = "Job start date filter: min date or 'min,max' range, e.g. 2025-01-01 or 2025-01-01,2025-06-30."
33
- SUMMARY_HELP = "Filter by profile summary text (semantic search)."
34
- NEGATE_SUMMARY_HELP = "Exclude contacts matching this summary description."
33
+ SUMMARY_HELP = "Match profile summary text: every word of any one term, in any order. Quote a multi-word term to keep it together, prefix + to require it."
34
+ NEGATE_SUMMARY_HELP = "Exclude contacts whose profile summary contains every word of any one term, in any order."
35
35
  NAME_HELP = "Filter by contact name (partial match supported)."
36
36
  SKILLS_HELP = "Filter by skill (repeatable)."
37
37
  FILTER_STATE_HELP = "Filter by company state/region (repeatable)."
@@ -44,7 +44,7 @@ TASK_ID_HELP = "Task ID returned when the job was started."
44
44
  app = typer.Typer(help="Run DiscoGen research jobs and check status of or cancel any async task (see --family)")
45
45
 
46
46
 
47
- class TaskFamily(str, enum.Enum):
47
+ class TaskFamily(enum.StrEnum):
48
48
  discogen = "discogen"
49
49
  bulkmatch = "bulkmatch"
50
50
  contactmatch = "contactmatch"
@@ -71,7 +71,7 @@ def _fetch_batch_snapshot(batch: EmailBatch) -> EmailBatchResults:
71
71
  """Fetch the batch results once, whether or not the batch has finished."""
72
72
  snapshot: dict[str, EmailBatchResults] = {}
73
73
  try:
74
- return batch.results(timeout=0, on_poll=lambda results: snapshot.update(latest=results))
74
+ return batch.results(max_wait=0, on_poll=lambda results: snapshot.update(latest=results))
75
75
  except JobTimeoutError:
76
76
  return snapshot["latest"]
77
77
 
@@ -101,7 +101,7 @@ def find_command(
101
101
  if not wait:
102
102
  emit({"job_id": job.job_id, "hint": f"poll with: discolike email job {job.job_id}"})
103
103
  return
104
- emit(job.wait(timeout=timeout, on_poll=_job_status_to_stderr), fmt=fmt)
104
+ emit(job.wait(max_wait=timeout, on_poll=_job_status_to_stderr), fmt=fmt)
105
105
 
106
106
 
107
107
  @app.command("find-batch")
@@ -136,7 +136,7 @@ def find_batch_command(
136
136
  if not wait:
137
137
  emit({"batch_id": batch.batch_id, "hint": f"fetch with: discolike email results {batch.batch_id}"})
138
138
  return
139
- emit(batch.results(timeout=timeout, on_poll=_batch_progress_to_stderr), fmt=fmt)
139
+ emit(batch.results(max_wait=timeout, on_poll=_batch_progress_to_stderr), fmt=fmt)
140
140
 
141
141
 
142
142
  @app.command("results")
@@ -156,7 +156,7 @@ def results_command(
156
156
  raise typer.BadParameter(f"--kind must be one of: {', '.join(EMAIL_KINDS)}")
157
157
  batch = get_client(ctx).email.batch(batch_id, kind=kind) # type: ignore[arg-type]
158
158
  if wait:
159
- emit(batch.results(timeout=timeout, on_poll=_batch_progress_to_stderr), fmt=fmt)
159
+ emit(batch.results(max_wait=timeout, on_poll=_batch_progress_to_stderr), fmt=fmt)
160
160
  return
161
161
  emit(_fetch_batch_snapshot(batch), fmt=fmt)
162
162
 
@@ -175,6 +175,6 @@ def job_command(
175
175
 
176
176
  job = get_client(ctx).email.job(job_id)
177
177
  if wait:
178
- emit(job.wait(timeout=timeout, on_poll=_job_status_to_stderr), fmt=fmt)
178
+ emit(job.wait(max_wait=timeout, on_poll=_job_status_to_stderr), fmt=fmt)
179
179
  return
180
180
  emit(job.status(), fmt=fmt)
@@ -5,7 +5,7 @@ from importlib.metadata import version as package_version
5
5
  from typing import Any
6
6
 
7
7
  import typer
8
- from typer._click.exceptions import Abort
8
+ from typer import Abort
9
9
  from typer._click.exceptions import ClickException
10
10
  from typer._click.exceptions import NoArgsIsHelpError
11
11
  from typer._click.exceptions import UsageError
@@ -23,6 +23,7 @@ from discolike_cli import discover
23
23
  from discolike_cli import email
24
24
  from discolike_cli import enrich
25
25
  from discolike_cli import match
26
+ from discolike_cli import prospecting
26
27
  from discolike_cli import providers
27
28
  from discolike_cli import queries
28
29
  from discolike_cli import signup
@@ -85,6 +86,7 @@ app.add_typer(contacts.app, name="contacts")
85
86
  app.add_typer(discogen.app, name="discogen")
86
87
  app.add_typer(email.app, name="email")
87
88
  app.add_typer(queries.app, name="queries")
89
+ app.add_typer(prospecting.app, name="prospecting")
88
90
  app.add_typer(account.app, name="account")
89
91
  app.add_typer(providers.search_providers_app, name="search-providers")
90
92
  app.add_typer(providers.llm_providers_app, name="llm-providers")