autotouch-cli 0.2.73__tar.gz → 0.2.74__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.
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/PKG-INFO +3 -3
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/README.md +2 -2
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/commands/linkedin.py +66 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/data/CLI_REFERENCE.md +27 -1
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/data/cli-manifest.json +160 -2
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli.egg-info/PKG-INFO +3 -3
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_shared/linkedin_contract.py +11 -5
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_shared/linkedin_filters.py +151 -3
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/pyproject.toml +1 -1
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/MANIFEST.in +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/__init__.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/cli.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/cli_contracts.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/commands/__init__.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/commands/agents.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/commands/auth.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/commands/cells.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/commands/columns.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/commands/jobs.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/commands/leads.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/commands/prompts.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/commands/rows.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/commands/search.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/commands/sequences.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/commands/tables.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/commands/tasks.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/commands/webhooks.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/commands/workspace_secrets.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/core/__init__.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/core/auth.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/core/config.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/core/csv_import.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/core/http.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/core/io.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/core/output.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/core/polling.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/core/run.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/core/validation.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/exceptions.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/mongo_status.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/parser.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/parser_groups.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/sequence_support.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli/templates.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli.egg-info/SOURCES.txt +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli.egg-info/dependency_links.txt +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli.egg-info/entry_points.txt +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli.egg-info/requires.txt +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_cli.egg-info/top_level.txt +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_shared/__init__.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_shared/provider_registry.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/autotouch_shared/search_contract.py +0 -0
- {autotouch_cli-0.2.73 → autotouch_cli-0.2.74}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: autotouch-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.74
|
|
4
4
|
Summary: Autotouch Smart Table CLI
|
|
5
5
|
Project-URL: Homepage, https://app.autotouch.ai
|
|
6
6
|
Project-URL: Documentation, https://github.com/nicolonic/autotouch_main/tree/main/docs/research-table/reference
|
|
@@ -134,7 +134,7 @@ autotouch rows get --table-id "$TABLE_ID" --row-id "$ROW_ID" --output json
|
|
|
134
134
|
- Create a workflow column: `autotouch columns recipe`, `autotouch columns create`
|
|
135
135
|
- Run provider-hidden search: `autotouch search companies`, `autotouch search people`
|
|
136
136
|
- Inspect LinkedIn/Sales Nav filters: `autotouch linkedin filters --api sales_navigator --category people`
|
|
137
|
-
- Build a paced LinkedIn people list: `autotouch linkedin list-build create --company-query 'SaaS startups' --headcount 1-10 --people-query 'Account Executive OR SDR' --num-results 250 --wait`
|
|
137
|
+
- Build a paced LinkedIn people list on Smart Table workers: `autotouch linkedin list-build create --company-query 'SaaS startups' --headcount 1-10 --people-query 'Account Executive OR SDR' --num-results 250 --wait`
|
|
138
138
|
- Run one LinkedIn search page/debug replay: `autotouch linkedin search`
|
|
139
139
|
- Run controlled slices: `autotouch columns run-next`
|
|
140
140
|
- Poll authoritative state: `autotouch jobs get`
|
|
@@ -149,7 +149,7 @@ For automation or agent-driven setup, use:
|
|
|
149
149
|
- `autotouch cli-reference` for the shipped parser-generated reference
|
|
150
150
|
- `autotouch capabilities --output json` for provider/workflow contracts
|
|
151
151
|
- `autotouch linkedin filters --output json` for LinkedIn/Sales Navigator filter tokens such as headcount, industry, location, role, function, and seniority
|
|
152
|
-
- `autotouch linkedin list-build create` for durable LinkedIn/Sales Navigator list building with paced provider requests, visible progress, and cooldown status
|
|
152
|
+
- `autotouch linkedin list-build create` for durable LinkedIn/Sales Navigator list building with Smart Table-owned paced provider requests, visible progress, and cooldown status
|
|
153
153
|
- `autotouch linkedin search` for one-page LinkedIn/Sales Navigator replay/debug searches; it is not the recommended path for large lists
|
|
154
154
|
- `autotouch rows list` / `autotouch rows get` / `autotouch cells get` for read-back and audit
|
|
155
155
|
- `autotouch sequences ...` and `autotouch tasks ...` for sequence/task workflows
|
|
@@ -109,7 +109,7 @@ autotouch rows get --table-id "$TABLE_ID" --row-id "$ROW_ID" --output json
|
|
|
109
109
|
- Create a workflow column: `autotouch columns recipe`, `autotouch columns create`
|
|
110
110
|
- Run provider-hidden search: `autotouch search companies`, `autotouch search people`
|
|
111
111
|
- Inspect LinkedIn/Sales Nav filters: `autotouch linkedin filters --api sales_navigator --category people`
|
|
112
|
-
- Build a paced LinkedIn people list: `autotouch linkedin list-build create --company-query 'SaaS startups' --headcount 1-10 --people-query 'Account Executive OR SDR' --num-results 250 --wait`
|
|
112
|
+
- Build a paced LinkedIn people list on Smart Table workers: `autotouch linkedin list-build create --company-query 'SaaS startups' --headcount 1-10 --people-query 'Account Executive OR SDR' --num-results 250 --wait`
|
|
113
113
|
- Run one LinkedIn search page/debug replay: `autotouch linkedin search`
|
|
114
114
|
- Run controlled slices: `autotouch columns run-next`
|
|
115
115
|
- Poll authoritative state: `autotouch jobs get`
|
|
@@ -124,7 +124,7 @@ For automation or agent-driven setup, use:
|
|
|
124
124
|
- `autotouch cli-reference` for the shipped parser-generated reference
|
|
125
125
|
- `autotouch capabilities --output json` for provider/workflow contracts
|
|
126
126
|
- `autotouch linkedin filters --output json` for LinkedIn/Sales Navigator filter tokens such as headcount, industry, location, role, function, and seniority
|
|
127
|
-
- `autotouch linkedin list-build create` for durable LinkedIn/Sales Navigator list building with paced provider requests, visible progress, and cooldown status
|
|
127
|
+
- `autotouch linkedin list-build create` for durable LinkedIn/Sales Navigator list building with Smart Table-owned paced provider requests, visible progress, and cooldown status
|
|
128
128
|
- `autotouch linkedin search` for one-page LinkedIn/Sales Navigator replay/debug searches; it is not the recommended path for large lists
|
|
129
129
|
- `autotouch rows list` / `autotouch rows get` / `autotouch cells get` for read-back and audit
|
|
130
130
|
- `autotouch sequences ...` and `autotouch tasks ...` for sequence/task workflows
|
|
@@ -141,6 +141,42 @@ def _split_repeated_values(values: Optional[List[str]]) -> List[str]:
|
|
|
141
141
|
return output
|
|
142
142
|
|
|
143
143
|
|
|
144
|
+
def _coerce_filter_arg_value(raw: str) -> Any:
|
|
145
|
+
value = str(raw or "").strip()
|
|
146
|
+
if not value:
|
|
147
|
+
return ""
|
|
148
|
+
if value[0] in "[{\"" or value.lower() in {"true", "false", "null"}:
|
|
149
|
+
try:
|
|
150
|
+
return json.loads(value)
|
|
151
|
+
except Exception:
|
|
152
|
+
pass
|
|
153
|
+
if "," in value:
|
|
154
|
+
return [part.strip() for part in value.split(",") if part.strip()]
|
|
155
|
+
return value
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _parse_filter_pairs(values: Optional[List[str]], *, context: str) -> Dict[str, Any]:
|
|
159
|
+
filters: Dict[str, Any] = {}
|
|
160
|
+
for raw in values or []:
|
|
161
|
+
item = str(raw or "").strip()
|
|
162
|
+
if not item:
|
|
163
|
+
continue
|
|
164
|
+
if "=" not in item:
|
|
165
|
+
raise AutotouchInputError(f"{context} filters must use FIELD=VALUE")
|
|
166
|
+
field, value = item.split("=", 1)
|
|
167
|
+
field = field.strip()
|
|
168
|
+
if not field:
|
|
169
|
+
raise AutotouchInputError(f"{context} filter field is empty")
|
|
170
|
+
filters[field] = _coerce_filter_arg_value(value)
|
|
171
|
+
return filters
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _add_repeated_filter(filters: Dict[str, Any], field: str, values: Optional[List[str]]) -> None:
|
|
175
|
+
parsed = _split_repeated_values(values)
|
|
176
|
+
if parsed:
|
|
177
|
+
filters[field] = parsed
|
|
178
|
+
|
|
179
|
+
|
|
144
180
|
def _normalize_linkedin_list_build_payload(args: argparse.Namespace, *, runtime: LinkedInCommandRuntime) -> Dict[str, Any]:
|
|
145
181
|
explicit = runtime.load_json_input(
|
|
146
182
|
inline_json=getattr(args, "data_json", None),
|
|
@@ -172,6 +208,23 @@ def _normalize_linkedin_list_build_payload(args: argparse.Namespace, *, runtime:
|
|
|
172
208
|
excluded_titles = _split_repeated_values(getattr(args, "excluded_title", None))
|
|
173
209
|
if excluded_titles:
|
|
174
210
|
payload["excluded_titles"] = excluded_titles
|
|
211
|
+
company_filters = _parse_filter_pairs(getattr(args, "company_filter", None), context="company")
|
|
212
|
+
people_filters = _parse_filter_pairs(getattr(args, "people_filter", None), context="people")
|
|
213
|
+
_add_repeated_filter(company_filters, "location", getattr(args, "company_location_id", None) or getattr(args, "location_id", None))
|
|
214
|
+
_add_repeated_filter(people_filters, "location", getattr(args, "people_location_id", None) or getattr(args, "location_id", None))
|
|
215
|
+
_add_repeated_filter(company_filters, "industry", getattr(args, "company_industry_id", None))
|
|
216
|
+
_add_repeated_filter(people_filters, "industry", getattr(args, "people_industry_id", None))
|
|
217
|
+
_add_repeated_filter(people_filters, "role", getattr(args, "role_id", None))
|
|
218
|
+
_add_repeated_filter(people_filters, "function", getattr(args, "function_id", None))
|
|
219
|
+
_add_repeated_filter(people_filters, "seniority", getattr(args, "seniority", None))
|
|
220
|
+
_add_repeated_filter(people_filters, "profile_language", getattr(args, "profile_language", None))
|
|
221
|
+
_add_repeated_filter(company_filters, "technologies", getattr(args, "technology_id", None))
|
|
222
|
+
if getattr(args, "has_job_offers", False):
|
|
223
|
+
company_filters["has_job_offers"] = True
|
|
224
|
+
if company_filters:
|
|
225
|
+
payload["company_filters"] = company_filters
|
|
226
|
+
if people_filters:
|
|
227
|
+
payload["people_filters"] = people_filters
|
|
175
228
|
for arg_name, payload_key, context in (
|
|
176
229
|
("extra_params_json", "extra_params", "extra-params"),
|
|
177
230
|
("company_extra_params_json", "company_extra_params", "company-extra-params"),
|
|
@@ -456,6 +509,19 @@ def register_linkedin_subcommands(
|
|
|
456
509
|
list_build_create.add_argument("--headcount", default="1-10", help="Company headcount range, e.g. 1-10 or 11-50")
|
|
457
510
|
list_build_create.add_argument("--num-results", type=int, default=100, help="Target number of people results, 1-1000")
|
|
458
511
|
list_build_create.add_argument("--excluded-title", action="append", help="Title to exclude after results return; repeat or comma-separate")
|
|
512
|
+
list_build_create.add_argument("--location-id", action="append", help="LinkedIn location/region ID applied to company and people search")
|
|
513
|
+
list_build_create.add_argument("--company-location-id", action="append", help="LinkedIn location/region ID applied only to company search")
|
|
514
|
+
list_build_create.add_argument("--people-location-id", action="append", help="LinkedIn location/region ID applied only to people search")
|
|
515
|
+
list_build_create.add_argument("--company-industry-id", action="append", help="LinkedIn industry ID applied to company search")
|
|
516
|
+
list_build_create.add_argument("--people-industry-id", action="append", help="LinkedIn industry ID applied to people search")
|
|
517
|
+
list_build_create.add_argument("--role-id", action="append", help="Resolved LinkedIn job-title ID for people search; repeat or comma-separate")
|
|
518
|
+
list_build_create.add_argument("--function-id", action="append", help="Resolved LinkedIn department/function ID for Sales Nav people search")
|
|
519
|
+
list_build_create.add_argument("--seniority", action="append", help="Sales Nav seniority filter value; repeat or comma-separate")
|
|
520
|
+
list_build_create.add_argument("--profile-language", action="append", help="Profile language code, e.g. en")
|
|
521
|
+
list_build_create.add_argument("--technology-id", action="append", help="Sales Nav technology ID applied to company search")
|
|
522
|
+
list_build_create.add_argument("--has-job-offers", action="store_true", help="Filter companies currently hiring on LinkedIn")
|
|
523
|
+
list_build_create.add_argument("--company-filter", action="append", help="Catalog company filter as FIELD=VALUE; repeat for multiple filters")
|
|
524
|
+
list_build_create.add_argument("--people-filter", action="append", help="Catalog people filter as FIELD=VALUE; repeat for multiple filters")
|
|
459
525
|
list_build_create.add_argument("--extra-params-json", help="JSON object applied to both company and people searches")
|
|
460
526
|
list_build_create.add_argument("--company-extra-params-json", help="JSON object applied only to company search")
|
|
461
527
|
list_build_create.add_argument("--people-extra-params-json", help="JSON object applied only to people search")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Autotouch CLI Reference
|
|
2
2
|
|
|
3
|
-
Generated from the installed parser for `autotouch-cli` `0.2.
|
|
3
|
+
Generated from the installed parser for `autotouch-cli` `0.2.74`.
|
|
4
4
|
Manifest schema version: `2`.
|
|
5
5
|
|
|
6
6
|
## Output Modes
|
|
@@ -2365,6 +2365,19 @@ Create a paced background LinkedIn list-build job
|
|
|
2365
2365
|
[--headcount HEADCOUNT]
|
|
2366
2366
|
[--num-results NUM_RESULTS]
|
|
2367
2367
|
[--excluded-title EXCLUDED_TITLE]
|
|
2368
|
+
[--location-id LOCATION_ID]
|
|
2369
|
+
[--company-location-id COMPANY_LOCATION_ID]
|
|
2370
|
+
[--people-location-id PEOPLE_LOCATION_ID]
|
|
2371
|
+
[--company-industry-id COMPANY_INDUSTRY_ID]
|
|
2372
|
+
[--people-industry-id PEOPLE_INDUSTRY_ID]
|
|
2373
|
+
[--role-id ROLE_ID]
|
|
2374
|
+
[--function-id FUNCTION_ID]
|
|
2375
|
+
[--seniority SENIORITY]
|
|
2376
|
+
[--profile-language PROFILE_LANGUAGE]
|
|
2377
|
+
[--technology-id TECHNOLOGY_ID]
|
|
2378
|
+
[--has-job-offers]
|
|
2379
|
+
[--company-filter COMPANY_FILTER]
|
|
2380
|
+
[--people-filter PEOPLE_FILTER]
|
|
2368
2381
|
[--extra-params-json EXTRA_PARAMS_JSON]
|
|
2369
2382
|
[--company-extra-params-json COMPANY_EXTRA_PARAMS_JSON]
|
|
2370
2383
|
[--people-extra-params-json PEOPLE_EXTRA_PARAMS_JSON]
|
|
@@ -2388,6 +2401,19 @@ Create a paced background LinkedIn list-build job
|
|
|
2388
2401
|
- `--headcount` (kind=string; default=1-10): Company headcount range, e.g. 1-10 or 11-50
|
|
2389
2402
|
- `--num-results` (kind=integer; default=100): Target number of people results, 1-1000
|
|
2390
2403
|
- `--excluded-title` (kind=string; repeatable): Title to exclude after results return; repeat or comma-separate
|
|
2404
|
+
- `--location-id` (kind=string; repeatable): LinkedIn location/region ID applied to company and people search
|
|
2405
|
+
- `--company-location-id` (kind=string; repeatable): LinkedIn location/region ID applied only to company search
|
|
2406
|
+
- `--people-location-id` (kind=string; repeatable): LinkedIn location/region ID applied only to people search
|
|
2407
|
+
- `--company-industry-id` (kind=string; repeatable): LinkedIn industry ID applied to company search
|
|
2408
|
+
- `--people-industry-id` (kind=string; repeatable): LinkedIn industry ID applied to people search
|
|
2409
|
+
- `--role-id` (kind=string; repeatable): Resolved LinkedIn job-title ID for people search; repeat or comma-separate
|
|
2410
|
+
- `--function-id` (kind=string; repeatable): Resolved LinkedIn department/function ID for Sales Nav people search
|
|
2411
|
+
- `--seniority` (kind=string; repeatable): Sales Nav seniority filter value; repeat or comma-separate
|
|
2412
|
+
- `--profile-language` (kind=string; repeatable): Profile language code, e.g. en
|
|
2413
|
+
- `--technology-id` (kind=string; repeatable): Sales Nav technology ID applied to company search
|
|
2414
|
+
- `--has-job-offers` (kind=boolean; when omitted=False; when present=True): Filter companies currently hiring on LinkedIn
|
|
2415
|
+
- `--company-filter` (kind=string; repeatable): Catalog company filter as FIELD=VALUE; repeat for multiple filters
|
|
2416
|
+
- `--people-filter` (kind=string; repeatable): Catalog people filter as FIELD=VALUE; repeat for multiple filters
|
|
2391
2417
|
- `--extra-params-json` (kind=json; input=json): JSON object applied to both company and people searches
|
|
2392
2418
|
- `--company-extra-params-json` (kind=json; input=json): JSON object applied only to company search
|
|
2393
2419
|
- `--people-extra-params-json` (kind=json; input=json): JSON object applied only to people search
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.2.
|
|
2
|
+
"version": "0.2.74",
|
|
3
3
|
"manifest_schema_version": 2,
|
|
4
4
|
"entry_points": {
|
|
5
5
|
"autotouch": "autotouch_cli.cli:main",
|
|
@@ -33877,6 +33877,164 @@
|
|
|
33877
33877
|
],
|
|
33878
33878
|
"takes_value": true
|
|
33879
33879
|
},
|
|
33880
|
+
{
|
|
33881
|
+
"dest": "location_id",
|
|
33882
|
+
"required": false,
|
|
33883
|
+
"help": "LinkedIn location/region ID applied to company and people search",
|
|
33884
|
+
"kind": "string",
|
|
33885
|
+
"action": "append",
|
|
33886
|
+
"repeatable": true,
|
|
33887
|
+
"flags": [
|
|
33888
|
+
"--location-id"
|
|
33889
|
+
],
|
|
33890
|
+
"takes_value": true
|
|
33891
|
+
},
|
|
33892
|
+
{
|
|
33893
|
+
"dest": "company_location_id",
|
|
33894
|
+
"required": false,
|
|
33895
|
+
"help": "LinkedIn location/region ID applied only to company search",
|
|
33896
|
+
"kind": "string",
|
|
33897
|
+
"action": "append",
|
|
33898
|
+
"repeatable": true,
|
|
33899
|
+
"flags": [
|
|
33900
|
+
"--company-location-id"
|
|
33901
|
+
],
|
|
33902
|
+
"takes_value": true
|
|
33903
|
+
},
|
|
33904
|
+
{
|
|
33905
|
+
"dest": "people_location_id",
|
|
33906
|
+
"required": false,
|
|
33907
|
+
"help": "LinkedIn location/region ID applied only to people search",
|
|
33908
|
+
"kind": "string",
|
|
33909
|
+
"action": "append",
|
|
33910
|
+
"repeatable": true,
|
|
33911
|
+
"flags": [
|
|
33912
|
+
"--people-location-id"
|
|
33913
|
+
],
|
|
33914
|
+
"takes_value": true
|
|
33915
|
+
},
|
|
33916
|
+
{
|
|
33917
|
+
"dest": "company_industry_id",
|
|
33918
|
+
"required": false,
|
|
33919
|
+
"help": "LinkedIn industry ID applied to company search",
|
|
33920
|
+
"kind": "string",
|
|
33921
|
+
"action": "append",
|
|
33922
|
+
"repeatable": true,
|
|
33923
|
+
"flags": [
|
|
33924
|
+
"--company-industry-id"
|
|
33925
|
+
],
|
|
33926
|
+
"takes_value": true
|
|
33927
|
+
},
|
|
33928
|
+
{
|
|
33929
|
+
"dest": "people_industry_id",
|
|
33930
|
+
"required": false,
|
|
33931
|
+
"help": "LinkedIn industry ID applied to people search",
|
|
33932
|
+
"kind": "string",
|
|
33933
|
+
"action": "append",
|
|
33934
|
+
"repeatable": true,
|
|
33935
|
+
"flags": [
|
|
33936
|
+
"--people-industry-id"
|
|
33937
|
+
],
|
|
33938
|
+
"takes_value": true
|
|
33939
|
+
},
|
|
33940
|
+
{
|
|
33941
|
+
"dest": "role_id",
|
|
33942
|
+
"required": false,
|
|
33943
|
+
"help": "Resolved LinkedIn job-title ID for people search; repeat or comma-separate",
|
|
33944
|
+
"kind": "string",
|
|
33945
|
+
"action": "append",
|
|
33946
|
+
"repeatable": true,
|
|
33947
|
+
"flags": [
|
|
33948
|
+
"--role-id"
|
|
33949
|
+
],
|
|
33950
|
+
"takes_value": true
|
|
33951
|
+
},
|
|
33952
|
+
{
|
|
33953
|
+
"dest": "function_id",
|
|
33954
|
+
"required": false,
|
|
33955
|
+
"help": "Resolved LinkedIn department/function ID for Sales Nav people search",
|
|
33956
|
+
"kind": "string",
|
|
33957
|
+
"action": "append",
|
|
33958
|
+
"repeatable": true,
|
|
33959
|
+
"flags": [
|
|
33960
|
+
"--function-id"
|
|
33961
|
+
],
|
|
33962
|
+
"takes_value": true
|
|
33963
|
+
},
|
|
33964
|
+
{
|
|
33965
|
+
"dest": "seniority",
|
|
33966
|
+
"required": false,
|
|
33967
|
+
"help": "Sales Nav seniority filter value; repeat or comma-separate",
|
|
33968
|
+
"kind": "string",
|
|
33969
|
+
"action": "append",
|
|
33970
|
+
"repeatable": true,
|
|
33971
|
+
"flags": [
|
|
33972
|
+
"--seniority"
|
|
33973
|
+
],
|
|
33974
|
+
"takes_value": true
|
|
33975
|
+
},
|
|
33976
|
+
{
|
|
33977
|
+
"dest": "profile_language",
|
|
33978
|
+
"required": false,
|
|
33979
|
+
"help": "Profile language code, e.g. en",
|
|
33980
|
+
"kind": "string",
|
|
33981
|
+
"action": "append",
|
|
33982
|
+
"repeatable": true,
|
|
33983
|
+
"flags": [
|
|
33984
|
+
"--profile-language"
|
|
33985
|
+
],
|
|
33986
|
+
"takes_value": true
|
|
33987
|
+
},
|
|
33988
|
+
{
|
|
33989
|
+
"dest": "technology_id",
|
|
33990
|
+
"required": false,
|
|
33991
|
+
"help": "Sales Nav technology ID applied to company search",
|
|
33992
|
+
"kind": "string",
|
|
33993
|
+
"action": "append",
|
|
33994
|
+
"repeatable": true,
|
|
33995
|
+
"flags": [
|
|
33996
|
+
"--technology-id"
|
|
33997
|
+
],
|
|
33998
|
+
"takes_value": true
|
|
33999
|
+
},
|
|
34000
|
+
{
|
|
34001
|
+
"dest": "has_job_offers",
|
|
34002
|
+
"required": false,
|
|
34003
|
+
"help": "Filter companies currently hiring on LinkedIn",
|
|
34004
|
+
"kind": "boolean",
|
|
34005
|
+
"action": "store_true",
|
|
34006
|
+
"nargs": 0,
|
|
34007
|
+
"default_when_omitted": false,
|
|
34008
|
+
"value_when_present": true,
|
|
34009
|
+
"flags": [
|
|
34010
|
+
"--has-job-offers"
|
|
34011
|
+
],
|
|
34012
|
+
"takes_value": false
|
|
34013
|
+
},
|
|
34014
|
+
{
|
|
34015
|
+
"dest": "company_filter",
|
|
34016
|
+
"required": false,
|
|
34017
|
+
"help": "Catalog company filter as FIELD=VALUE; repeat for multiple filters",
|
|
34018
|
+
"kind": "string",
|
|
34019
|
+
"action": "append",
|
|
34020
|
+
"repeatable": true,
|
|
34021
|
+
"flags": [
|
|
34022
|
+
"--company-filter"
|
|
34023
|
+
],
|
|
34024
|
+
"takes_value": true
|
|
34025
|
+
},
|
|
34026
|
+
{
|
|
34027
|
+
"dest": "people_filter",
|
|
34028
|
+
"required": false,
|
|
34029
|
+
"help": "Catalog people filter as FIELD=VALUE; repeat for multiple filters",
|
|
34030
|
+
"kind": "string",
|
|
34031
|
+
"action": "append",
|
|
34032
|
+
"repeatable": true,
|
|
34033
|
+
"flags": [
|
|
34034
|
+
"--people-filter"
|
|
34035
|
+
],
|
|
34036
|
+
"takes_value": true
|
|
34037
|
+
},
|
|
33880
34038
|
{
|
|
33881
34039
|
"dest": "extra_params_json",
|
|
33882
34040
|
"required": false,
|
|
@@ -34106,7 +34264,7 @@
|
|
|
34106
34264
|
},
|
|
34107
34265
|
"availability": null,
|
|
34108
34266
|
"examples": [
|
|
34109
|
-
"autotouch linkedin list-build create [-h] [--data-json DATA_JSON]\n [--data-file DATA_FILE]\n [--mode {company-first-people}]\n [--linkedin-api {auto,classic,sales_navigator}]\n [--company-query COMPANY_QUERY]\n [--people-query PEOPLE_QUERY]\n [--headcount HEADCOUNT]\n [--num-results NUM_RESULTS]\n [--excluded-title EXCLUDED_TITLE]\n [--extra-params-json EXTRA_PARAMS_JSON]\n [--company-extra-params-json COMPANY_EXTRA_PARAMS_JSON]\n [--people-extra-params-json PEOPLE_EXTRA_PARAMS_JSON]\n [--wait]\n [--poll-interval POLL_INTERVAL]\n [--wait-timeout WAIT_TIMEOUT]\n [--base-url BASE_URL]\n [--token TOKEN] [--use-x-api-key]\n [--timeout TIMEOUT]\n [--output {json,ndjson,human}]\n [--compact] [--select SELECT |\n --json-pointer JSON_POINTER]\n [--verbose]"
|
|
34267
|
+
"autotouch linkedin list-build create [-h] [--data-json DATA_JSON]\n [--data-file DATA_FILE]\n [--mode {company-first-people}]\n [--linkedin-api {auto,classic,sales_navigator}]\n [--company-query COMPANY_QUERY]\n [--people-query PEOPLE_QUERY]\n [--headcount HEADCOUNT]\n [--num-results NUM_RESULTS]\n [--excluded-title EXCLUDED_TITLE]\n [--location-id LOCATION_ID]\n [--company-location-id COMPANY_LOCATION_ID]\n [--people-location-id PEOPLE_LOCATION_ID]\n [--company-industry-id COMPANY_INDUSTRY_ID]\n [--people-industry-id PEOPLE_INDUSTRY_ID]\n [--role-id ROLE_ID]\n [--function-id FUNCTION_ID]\n [--seniority SENIORITY]\n [--profile-language PROFILE_LANGUAGE]\n [--technology-id TECHNOLOGY_ID]\n [--has-job-offers]\n [--company-filter COMPANY_FILTER]\n [--people-filter PEOPLE_FILTER]\n [--extra-params-json EXTRA_PARAMS_JSON]\n [--company-extra-params-json COMPANY_EXTRA_PARAMS_JSON]\n [--people-extra-params-json PEOPLE_EXTRA_PARAMS_JSON]\n [--wait]\n [--poll-interval POLL_INTERVAL]\n [--wait-timeout WAIT_TIMEOUT]\n [--base-url BASE_URL]\n [--token TOKEN] [--use-x-api-key]\n [--timeout TIMEOUT]\n [--output {json,ndjson,human}]\n [--compact] [--select SELECT |\n --json-pointer JSON_POINTER]\n [--verbose]"
|
|
34110
34268
|
],
|
|
34111
34269
|
"stability": "stable",
|
|
34112
34270
|
"handler": "_fn"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: autotouch-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.74
|
|
4
4
|
Summary: Autotouch Smart Table CLI
|
|
5
5
|
Project-URL: Homepage, https://app.autotouch.ai
|
|
6
6
|
Project-URL: Documentation, https://github.com/nicolonic/autotouch_main/tree/main/docs/research-table/reference
|
|
@@ -134,7 +134,7 @@ autotouch rows get --table-id "$TABLE_ID" --row-id "$ROW_ID" --output json
|
|
|
134
134
|
- Create a workflow column: `autotouch columns recipe`, `autotouch columns create`
|
|
135
135
|
- Run provider-hidden search: `autotouch search companies`, `autotouch search people`
|
|
136
136
|
- Inspect LinkedIn/Sales Nav filters: `autotouch linkedin filters --api sales_navigator --category people`
|
|
137
|
-
- Build a paced LinkedIn people list: `autotouch linkedin list-build create --company-query 'SaaS startups' --headcount 1-10 --people-query 'Account Executive OR SDR' --num-results 250 --wait`
|
|
137
|
+
- Build a paced LinkedIn people list on Smart Table workers: `autotouch linkedin list-build create --company-query 'SaaS startups' --headcount 1-10 --people-query 'Account Executive OR SDR' --num-results 250 --wait`
|
|
138
138
|
- Run one LinkedIn search page/debug replay: `autotouch linkedin search`
|
|
139
139
|
- Run controlled slices: `autotouch columns run-next`
|
|
140
140
|
- Poll authoritative state: `autotouch jobs get`
|
|
@@ -149,7 +149,7 @@ For automation or agent-driven setup, use:
|
|
|
149
149
|
- `autotouch cli-reference` for the shipped parser-generated reference
|
|
150
150
|
- `autotouch capabilities --output json` for provider/workflow contracts
|
|
151
151
|
- `autotouch linkedin filters --output json` for LinkedIn/Sales Navigator filter tokens such as headcount, industry, location, role, function, and seniority
|
|
152
|
-
- `autotouch linkedin list-build create` for durable LinkedIn/Sales Navigator list building with paced provider requests, visible progress, and cooldown status
|
|
152
|
+
- `autotouch linkedin list-build create` for durable LinkedIn/Sales Navigator list building with Smart Table-owned paced provider requests, visible progress, and cooldown status
|
|
153
153
|
- `autotouch linkedin search` for one-page LinkedIn/Sales Navigator replay/debug searches; it is not the recommended path for large lists
|
|
154
154
|
- `autotouch rows list` / `autotouch rows get` / `autotouch cells get` for read-back and audit
|
|
155
155
|
- `autotouch sequences ...` and `autotouch tasks ...` for sequence/task workflows
|
|
@@ -68,11 +68,14 @@ _LINKEDIN_ENDPOINTS: Dict[str, Dict[str, Any]] = {
|
|
|
68
68
|
"headcount": "optional range such as 1-10 or {'min':1,'max':10}",
|
|
69
69
|
"num_results": "optional 1-1000 target people results",
|
|
70
70
|
"excluded_titles": "optional array of titles to exclude after people results return",
|
|
71
|
+
"filters": "optional catalog filters applied to company and people searches",
|
|
72
|
+
"company_filters": "optional catalog filters applied to company search; compiled by API mode",
|
|
73
|
+
"people_filters": "optional catalog filters applied to people search; compiled by API mode",
|
|
71
74
|
"extra_params": "optional object applied to company and people searches",
|
|
72
75
|
"company_extra_params": "optional object applied only to company search",
|
|
73
|
-
"people_extra_params": "optional object applied only to people search",
|
|
76
|
+
"people_extra_params": "optional object applied only to people search; structured title filters should use provider IDs",
|
|
74
77
|
},
|
|
75
|
-
"notes": "Recommended path for large LinkedIn/Sales Navigator lists. Runs as a paced background job with durable progress and cooldown state.",
|
|
78
|
+
"notes": "Recommended path for large LinkedIn/Sales Navigator lists. Runs as a Smart Table-owned paced background job with durable progress and cooldown state.",
|
|
76
79
|
},
|
|
77
80
|
"linkedin_list_build_status": {
|
|
78
81
|
"method": "GET",
|
|
@@ -196,13 +199,16 @@ _LINKEDIN_RECIPES: Dict[str, Dict[str, Any]] = {
|
|
|
196
199
|
"headcount": "1-10",
|
|
197
200
|
"num_results": 250,
|
|
198
201
|
"excluded_titles": ["founder", "owner", "ceo", "chief", "president"],
|
|
199
|
-
"
|
|
200
|
-
"
|
|
202
|
+
"company_filters": {"location": ["103644278"], "industry": ["6"]},
|
|
203
|
+
"people_filters": {"location": ["103644278"], "profile_language": ["en"]},
|
|
201
204
|
},
|
|
202
205
|
"usage": "autotouch linkedin list-build create --data-file <payload.json> --wait",
|
|
203
206
|
"notes": [
|
|
204
207
|
"Recommended path for larger LinkedIn/Sales Navigator lists.",
|
|
205
|
-
"
|
|
208
|
+
"Execution is owned by Smart Table workers; the retired standalone List Builder worker is not required.",
|
|
209
|
+
"The worker sends headcount to company search, validates returned headcount locally, then searches people at matched companies.",
|
|
210
|
+
"Catalog filters compile to classic or Sales Navigator shapes after the connected account mode is resolved.",
|
|
211
|
+
"Use title text in people_query; only use structured role/job-title params after resolving provider IDs.",
|
|
206
212
|
"No provider-hidden fallback is used when LinkedIn is disconnected, cooled down, or rate limited.",
|
|
207
213
|
"Use 'autotouch linkedin filters' and 'autotouch linkedin search-params' to discover structured filter fields and IDs.",
|
|
208
214
|
],
|
|
@@ -280,12 +280,13 @@ _FILTERS: List[Dict[str, Any]] = [
|
|
|
280
280
|
provider_field="role",
|
|
281
281
|
api_modes=["sales_navigator"],
|
|
282
282
|
categories=["people"],
|
|
283
|
-
value_kind="
|
|
283
|
+
value_kind="id",
|
|
284
284
|
resolver_type="JOB_TITLE",
|
|
285
285
|
supports_include_exclude=True,
|
|
286
|
-
shape='{"include":["
|
|
287
|
-
examples=[{"include": ["
|
|
286
|
+
shape='{"include":["1234"],"exclude":["5678"]}',
|
|
287
|
+
examples=[{"include": ["1234"], "exclude": ["5678"]}],
|
|
288
288
|
aliases=["job_title", "title"],
|
|
289
|
+
notes=["Resolve human title text with /linkedin/search/parameters before using this structured filter."],
|
|
289
290
|
),
|
|
290
291
|
_entry(
|
|
291
292
|
"past_role",
|
|
@@ -633,6 +634,152 @@ def linkedin_parameter_types(*, service: Optional[str] = None) -> List[Dict[str,
|
|
|
633
634
|
return [deepcopy(entry) for entry in _PARAMETER_TYPES if target in entry.get("services", [])]
|
|
634
635
|
|
|
635
636
|
|
|
637
|
+
def _find_filter_entry(field: str, *, api_mode: str, category: str) -> Optional[Dict[str, Any]]:
|
|
638
|
+
target = str(field or "").strip().lower()
|
|
639
|
+
api = str(api_mode or "").strip().lower()
|
|
640
|
+
cat = str(category or "").strip().lower()
|
|
641
|
+
for entry in _FILTERS:
|
|
642
|
+
aliases = [str(alias).lower() for alias in entry.get("aliases", [])]
|
|
643
|
+
if target not in {str(entry.get("field", "")).lower(), *aliases}:
|
|
644
|
+
continue
|
|
645
|
+
if api not in entry.get("api_modes", []):
|
|
646
|
+
continue
|
|
647
|
+
if cat not in entry.get("categories", []):
|
|
648
|
+
continue
|
|
649
|
+
return entry
|
|
650
|
+
return None
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
def _list_values(value: Any) -> List[Any]:
|
|
654
|
+
if value is None or value == "":
|
|
655
|
+
return []
|
|
656
|
+
if isinstance(value, list):
|
|
657
|
+
values = value
|
|
658
|
+
elif isinstance(value, tuple):
|
|
659
|
+
values = list(value)
|
|
660
|
+
else:
|
|
661
|
+
values = [value]
|
|
662
|
+
return [item for item in values if item not in (None, "")]
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
def _include_exclude(value: Any) -> Dict[str, List[Any]]:
|
|
666
|
+
if isinstance(value, dict):
|
|
667
|
+
return {
|
|
668
|
+
"include": _list_values(value.get("include") or value.get("includes") or value.get("values")),
|
|
669
|
+
"exclude": _list_values(value.get("exclude") or value.get("excludes")),
|
|
670
|
+
}
|
|
671
|
+
return {"include": _list_values(value), "exclude": []}
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
def _parse_range_filter(value: Any) -> List[Dict[str, int]]:
|
|
675
|
+
if value is None or value == "":
|
|
676
|
+
return []
|
|
677
|
+
if isinstance(value, list):
|
|
678
|
+
output: List[Dict[str, int]] = []
|
|
679
|
+
for item in value:
|
|
680
|
+
output.extend(_parse_range_filter(item))
|
|
681
|
+
return output
|
|
682
|
+
if isinstance(value, dict):
|
|
683
|
+
try:
|
|
684
|
+
minimum = int(value.get("min"))
|
|
685
|
+
except Exception:
|
|
686
|
+
return []
|
|
687
|
+
parsed: Dict[str, int] = {"min": minimum}
|
|
688
|
+
maximum = value.get("max")
|
|
689
|
+
if maximum not in (None, ""):
|
|
690
|
+
try:
|
|
691
|
+
parsed["max"] = int(maximum)
|
|
692
|
+
except Exception:
|
|
693
|
+
pass
|
|
694
|
+
return [parsed]
|
|
695
|
+
|
|
696
|
+
raw = str(value).strip().lower().replace(",", "")
|
|
697
|
+
for bucket in HEADCOUNT_BUCKETS:
|
|
698
|
+
if raw == str(bucket["label"]).lower().replace(",", ""):
|
|
699
|
+
parsed = {"min": int(bucket["min"])}
|
|
700
|
+
if bucket.get("max") is not None:
|
|
701
|
+
parsed["max"] = int(bucket["max"])
|
|
702
|
+
return [parsed]
|
|
703
|
+
numbers: List[int] = []
|
|
704
|
+
current = ""
|
|
705
|
+
for char in raw:
|
|
706
|
+
if char.isdigit():
|
|
707
|
+
current += char
|
|
708
|
+
elif current:
|
|
709
|
+
numbers.append(int(current))
|
|
710
|
+
current = ""
|
|
711
|
+
if current:
|
|
712
|
+
numbers.append(int(current))
|
|
713
|
+
if not numbers:
|
|
714
|
+
return []
|
|
715
|
+
parsed = {"min": numbers[0]}
|
|
716
|
+
if "+" not in raw and len(numbers) > 1:
|
|
717
|
+
parsed["max"] = numbers[1]
|
|
718
|
+
return [parsed]
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
def _coerce_filter_value(entry: Dict[str, Any], value: Any) -> Any:
|
|
722
|
+
field = str(entry.get("field") or "")
|
|
723
|
+
kind = str(entry.get("value_kind") or "")
|
|
724
|
+
shape = str(entry.get("shape") or "")
|
|
725
|
+
|
|
726
|
+
if kind in {"range_bucket", "numeric_range"}:
|
|
727
|
+
if kind == "numeric_range" and isinstance(value, dict):
|
|
728
|
+
return value
|
|
729
|
+
return _parse_range_filter(value)
|
|
730
|
+
if kind == "boolean":
|
|
731
|
+
if isinstance(value, bool):
|
|
732
|
+
return value
|
|
733
|
+
return str(value).strip().lower() in {"1", "true", "yes", "y", "on"}
|
|
734
|
+
if kind == "object":
|
|
735
|
+
return value if isinstance(value, dict) else {}
|
|
736
|
+
if kind in {"enum", "iso_639_1", "enum_or_number"}:
|
|
737
|
+
if shape.startswith("["):
|
|
738
|
+
return _list_values(value)
|
|
739
|
+
return value
|
|
740
|
+
if field in {"saved_search_id", "recent_search_id"}:
|
|
741
|
+
values = _list_values(value)
|
|
742
|
+
return str(values[0]) if values else ""
|
|
743
|
+
if entry.get("supports_include_exclude"):
|
|
744
|
+
parts = _include_exclude(value)
|
|
745
|
+
payload: Dict[str, Any] = {}
|
|
746
|
+
if parts["include"]:
|
|
747
|
+
payload["include"] = parts["include"]
|
|
748
|
+
if parts["exclude"]:
|
|
749
|
+
payload["exclude"] = parts["exclude"]
|
|
750
|
+
return payload
|
|
751
|
+
return _list_values(value) if shape.startswith("[") else value
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
def compile_linkedin_search_filters(
|
|
755
|
+
filters: Optional[Dict[str, Any]],
|
|
756
|
+
*,
|
|
757
|
+
api_mode: str,
|
|
758
|
+
category: str,
|
|
759
|
+
) -> Dict[str, Any]:
|
|
760
|
+
"""Compile catalog-level filter values into Unipile search extra_params.
|
|
761
|
+
|
|
762
|
+
The caller should pass the already resolved LinkedIn API mode. This keeps
|
|
763
|
+
CLI clients mode-neutral while still emitting classic vs Sales Navigator
|
|
764
|
+
shapes correctly after account capability resolution.
|
|
765
|
+
"""
|
|
766
|
+
if not isinstance(filters, dict):
|
|
767
|
+
return {}
|
|
768
|
+
compiled: Dict[str, Any] = {}
|
|
769
|
+
for raw_field, raw_value in filters.items():
|
|
770
|
+
field = str(raw_field or "").strip()
|
|
771
|
+
if not field:
|
|
772
|
+
continue
|
|
773
|
+
entry = _find_filter_entry(field, api_mode=api_mode, category=category)
|
|
774
|
+
if entry is None:
|
|
775
|
+
raise ValueError(f"LinkedIn filter '{field}' is not supported for {api_mode}/{category}")
|
|
776
|
+
value = _coerce_filter_value(entry, raw_value)
|
|
777
|
+
if value in (None, "", [], {}):
|
|
778
|
+
continue
|
|
779
|
+
compiled[str(entry.get("provider_field") or field)] = value
|
|
780
|
+
return compiled
|
|
781
|
+
|
|
782
|
+
|
|
636
783
|
def linkedin_filter_catalog(
|
|
637
784
|
*,
|
|
638
785
|
api_mode: Optional[str] = None,
|
|
@@ -654,6 +801,7 @@ def linkedin_filter_catalog(
|
|
|
654
801
|
|
|
655
802
|
__all__ = [
|
|
656
803
|
"HEADCOUNT_BUCKETS",
|
|
804
|
+
"compile_linkedin_search_filters",
|
|
657
805
|
"linkedin_filter_catalog",
|
|
658
806
|
"linkedin_filter_entries",
|
|
659
807
|
"linkedin_parameter_types",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|