autotouch-cli 0.2.24__tar.gz → 0.2.26__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.24/autotouch_cli.egg-info → autotouch_cli-0.2.26}/PKG-INFO +78 -2
- autotouch_cli-0.2.24/docs/research-table/reference/autotouch-cli.md → autotouch_cli-0.2.26/autotouch_cli.egg-info/PKG-INFO +86 -1
- autotouch_cli-0.2.24/PKG-INFO → autotouch_cli-0.2.26/docs/research-table/reference/autotouch-cli.md +77 -10
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/pyproject.toml +1 -1
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/smart_table_cli.py +398 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/autotouch_cli.egg-info/SOURCES.txt +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/autotouch_cli.egg-info/dependency_links.txt +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/autotouch_cli.egg-info/entry_points.txt +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/autotouch_cli.egg-info/requires.txt +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/autotouch_cli.egg-info/top_level.txt +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/__init__.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/add_column_unique_index.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/attach_csv_import_leads_to_research_table.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/bundle_sequences_backend.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/check_agent_traces.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/check_column_mode.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/exit_terminal_leads_from_sequences.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/fetch_lead.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/fix_lead_titles_from_csv.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250106_add_column_position.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250108_fix_legacy_column_fields.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250109_add_user_fields_to_tables.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250117_add_call_logs_webhook_indexes.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250117_rename_call_logs_collection.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250119_create_leads_unique_email_index.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250123_add_filter_indexes.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250123_add_llm_responses_collection.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250128_migrate_user_ids_to_objectid.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250208_backfill_task_research_values.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250604_add_origin_indexes.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250608_cleanup_agent_metadata.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250608_rename_agent_metadata_to_metadata.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250922_add_activity_indexes.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250926_migrate_single_to_arrays.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250928_add_missing_timestamp_fields.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250929_add_task_join_indexes.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250929_add_task_join_indexes_safe.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250929_create_shared_phone_cache.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20251007_add_rows_position_id_index.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20251109_add_ttl_for_llm_and_preview_traces.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20260113_normalize_table_filter_operators.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20260113_set_user_permissions_user_admin.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20260204_sync_lead_owner_from_tasks.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20260303_add_webhook_subscription_collections.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20260305_force_formatter_autorun_on_source_update.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/migrate_org_user_credits.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/set_default_lead_status.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/update_lead_owner_from_tasks.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/reassign_sequence_owner.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/run_sidecar_orchestrator_demo.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/test_crm_company_policy.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/test_sequences_instantly_e2e.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/test_sequences_personal_e2e.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/test_task_error_logger.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/verify_azurite_voicemail.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/setup.cfg +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/tests/test_contactout_custom.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/tests/test_contactout_integration.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/tests/test_contactout_multi_titles.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/tests/test_contactout_pipeline.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/tests/test_contactout_simple.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/tests/test_contactout_v2_bulk.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/tests/test_lead_required_fields.py +0 -0
- {autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/tests/test_phone_provider_pipeline.py +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.26
|
|
4
4
|
Summary: Autotouch Smart Table CLI
|
|
5
5
|
Requires-Python: >=3.9
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -37,12 +37,13 @@ Use this order when you are orienting in the CLI:
|
|
|
37
37
|
| verify whether a job is really done | `autotouch jobs get --job-id <JOB_ID>` |
|
|
38
38
|
| create projections from JSON output | `autotouch columns projections` |
|
|
39
39
|
| work with sequences/tasks | raw HTTP plus `docs/platform/external-workflows-api.md` |
|
|
40
|
+
| query/filter CRM leads and attached research | `autotouch leads query` then `autotouch leads research` |
|
|
40
41
|
|
|
41
42
|
### Operating model
|
|
42
43
|
|
|
43
44
|
- This file is the full CLI reference and the package readme published to PyPI.
|
|
44
45
|
- The installed package gives you CLI entrypoints and package metadata; do not assume there is a separate installed docs directory.
|
|
45
|
-
- Research-table APIs are the primary CLI surface today; workflow APIs (sequences/tasks) are still HTTP-first.
|
|
46
|
+
- Research-table APIs and read-only leads queries are the primary CLI surface today; workflow APIs (sequences/tasks) are still HTTP-first.
|
|
46
47
|
- For async operations, backend bulk-job state is authoritative; local terminal output is only a convenience layer.
|
|
47
48
|
- For staged or cost-sensitive runs, estimate first and prefer filtered scopes plus `firstN` or `run-next`.
|
|
48
49
|
|
|
@@ -121,17 +122,37 @@ Notes:
|
|
|
121
122
|
| `GET /api/tables/{table_id}/columns` | `autotouch columns list --table-id <TABLE_ID>` |
|
|
122
123
|
| `POST /api/tables/{table_id}/columns` | `autotouch columns create --table-id <TABLE_ID> --data-file column.json` |
|
|
123
124
|
| `PATCH /api/tables/{table_id}/columns/{column_id}` | `autotouch columns update --table-id <TABLE_ID> --column-id <COLUMN_ID> --data-file column-update.json` |
|
|
125
|
+
| `DELETE /api/tables/{table_id}/columns/{column_id}` | `autotouch columns delete --table-id <TABLE_ID> --column-id <COLUMN_ID> --yes` |
|
|
124
126
|
| `POST /api/tables/{table_id}/columns/projections` | `autotouch columns projections --table-id <TABLE_ID> --data-file projections.json` |
|
|
125
127
|
| `POST /api/tables/{table_id}/columns/{column_id}/estimate` | `autotouch columns estimate --table-id <TABLE_ID> --column-id <COLUMN_ID> --scope all` |
|
|
126
128
|
| `POST /api/tables/{table_id}/columns/{column_id}/run` | `autotouch columns run --table-id <TABLE_ID> --column-id <COLUMN_ID> --scope all` |
|
|
127
129
|
| `POST /api/tables/{table_id}/columns/{column_id}/stop` | `autotouch columns stop --table-id <TABLE_ID> --column-id <COLUMN_ID>` |
|
|
128
130
|
| `GET /api/bulk-jobs` | `autotouch jobs list --table-id <TABLE_ID> --column-id <COLUMN_ID> --limit 10` |
|
|
129
131
|
| `GET /api/bulk-jobs/{job_id}` | `autotouch jobs get --job-id <JOB_ID>` |
|
|
132
|
+
| `POST /api/leads/query` | `autotouch leads query --filter-file lead-filter.json --limit 50` |
|
|
133
|
+
| `POST /api/leads/query/count` | `autotouch leads count --filter-file lead-filter.json` |
|
|
134
|
+
| `POST /api/leads/query/stats` | `autotouch leads stats --filter-file lead-filter.json` |
|
|
135
|
+
| `POST /api/leads/query/research` | `autotouch leads research --lead-id <LEAD_ID> --source-table-id <TABLE_ID>` |
|
|
136
|
+
| `GET /api/leads/filters/metadata` | `autotouch leads filters-metadata` |
|
|
137
|
+
| `GET /api/leads/research-tables/available` | `autotouch leads research-tables` |
|
|
130
138
|
| `GET /api/tables/{table_id}/webhook` | `autotouch webhooks get --table-id <TABLE_ID>` |
|
|
131
139
|
| `POST /api/tables/{table_id}/webhook` | `autotouch webhooks rotate --table-id <TABLE_ID>` |
|
|
132
140
|
| `POST /api/webhooks/tables/{table_id}/ingest` | `autotouch webhooks ingest --table-id <TABLE_ID> --records-file records.json --webhook-token <WEBHOOK_TOKEN>` |
|
|
133
141
|
| `POST /api/auth/agent-bootstrap` | HTTP-only bootstrap (no direct CLI wrapper yet) |
|
|
134
142
|
|
|
143
|
+
## Delete column
|
|
144
|
+
|
|
145
|
+
Delete is a hard delete:
|
|
146
|
+
- removes the column definition
|
|
147
|
+
- removes all cells stored under that column
|
|
148
|
+
- requires `columns:write`
|
|
149
|
+
|
|
150
|
+
CLI:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
autotouch columns delete --table-id <TABLE_ID> --column-id <COLUMN_ID> --yes
|
|
154
|
+
```
|
|
155
|
+
|
|
135
156
|
## Workflow API coverage (sequences/tasks)
|
|
136
157
|
|
|
137
158
|
Sequences/tasks APIs are supported by the backend developer-key model but do not yet have dedicated `autotouch` CLI commands.
|
|
@@ -154,6 +175,61 @@ Signature controls for sequence payloads:
|
|
|
154
175
|
- `steps[].appendSignature` (optional, step-level) overrides signature behavior for a specific email step.
|
|
155
176
|
- Signature append is deterministic at send time when enabled for the step.
|
|
156
177
|
|
|
178
|
+
## Leads API coverage
|
|
179
|
+
|
|
180
|
+
The CLI now exposes the public read-only leads endpoints under `autotouch leads`.
|
|
181
|
+
|
|
182
|
+
Use this pattern:
|
|
183
|
+
|
|
184
|
+
1. `autotouch leads query` to page through leads, apply descriptor filters, and inspect `related_tables` / `research_summary`.
|
|
185
|
+
2. `autotouch leads research` when you need actual research field values for specific lead IDs from one source table.
|
|
186
|
+
3. `autotouch leads count` / `autotouch leads stats` when you need sizing before a downstream workflow.
|
|
187
|
+
|
|
188
|
+
Important contract notes:
|
|
189
|
+
- External callers should use `POST /api/leads/query` rather than the older `GET /api/leads` list route.
|
|
190
|
+
- `autotouch leads query` accepts the same descriptor payload shape as the backend:
|
|
191
|
+
- `filter`
|
|
192
|
+
- `search`
|
|
193
|
+
- `sort`
|
|
194
|
+
- `pagination`
|
|
195
|
+
- `scope`
|
|
196
|
+
- optional research context (`source_table_id`, `source_table_scope`, `related_tables_mode`)
|
|
197
|
+
- Research values are best treated as a follow-up call:
|
|
198
|
+
- `query` returns lead rows plus research linkage metadata
|
|
199
|
+
- `research` returns `research_data_by_id` keyed by lead id for one `source_table_id`
|
|
200
|
+
|
|
201
|
+
Examples:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
autotouch leads query \
|
|
205
|
+
--filter-json '{"root":{"kind":"rule","field":"status","operator":"eq","value":"new"}}' \
|
|
206
|
+
--limit 25
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
autotouch leads count \
|
|
211
|
+
--search "fintech" \
|
|
212
|
+
--scope org
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
autotouch leads stats \
|
|
217
|
+
--source-table-id <TABLE_ID> \
|
|
218
|
+
--source-table-scope company
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
autotouch leads research \
|
|
223
|
+
--lead-id <LEAD_ID_1> \
|
|
224
|
+
--lead-id <LEAD_ID_2> \
|
|
225
|
+
--source-table-id <TABLE_ID>
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
autotouch leads filters-metadata
|
|
230
|
+
autotouch leads research-tables
|
|
231
|
+
```
|
|
232
|
+
|
|
157
233
|
## Bulk job status contract (authoritative run state)
|
|
158
234
|
|
|
159
235
|
Use bulk jobs as the source of truth for run lifecycle:
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: autotouch-cli
|
|
3
|
+
Version: 0.2.26
|
|
4
|
+
Summary: Autotouch Smart Table CLI
|
|
5
|
+
Requires-Python: >=3.9
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: requests>=2.31.0
|
|
8
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
9
|
+
|
|
1
10
|
# Autotouch CLI Reference (`autotouch`)
|
|
2
11
|
|
|
3
12
|
This page documents the installable CLI for the Smart Table developer API.
|
|
@@ -28,12 +37,13 @@ Use this order when you are orienting in the CLI:
|
|
|
28
37
|
| verify whether a job is really done | `autotouch jobs get --job-id <JOB_ID>` |
|
|
29
38
|
| create projections from JSON output | `autotouch columns projections` |
|
|
30
39
|
| work with sequences/tasks | raw HTTP plus `docs/platform/external-workflows-api.md` |
|
|
40
|
+
| query/filter CRM leads and attached research | `autotouch leads query` then `autotouch leads research` |
|
|
31
41
|
|
|
32
42
|
### Operating model
|
|
33
43
|
|
|
34
44
|
- This file is the full CLI reference and the package readme published to PyPI.
|
|
35
45
|
- The installed package gives you CLI entrypoints and package metadata; do not assume there is a separate installed docs directory.
|
|
36
|
-
- Research-table APIs are the primary CLI surface today; workflow APIs (sequences/tasks) are still HTTP-first.
|
|
46
|
+
- Research-table APIs and read-only leads queries are the primary CLI surface today; workflow APIs (sequences/tasks) are still HTTP-first.
|
|
37
47
|
- For async operations, backend bulk-job state is authoritative; local terminal output is only a convenience layer.
|
|
38
48
|
- For staged or cost-sensitive runs, estimate first and prefer filtered scopes plus `firstN` or `run-next`.
|
|
39
49
|
|
|
@@ -112,17 +122,37 @@ Notes:
|
|
|
112
122
|
| `GET /api/tables/{table_id}/columns` | `autotouch columns list --table-id <TABLE_ID>` |
|
|
113
123
|
| `POST /api/tables/{table_id}/columns` | `autotouch columns create --table-id <TABLE_ID> --data-file column.json` |
|
|
114
124
|
| `PATCH /api/tables/{table_id}/columns/{column_id}` | `autotouch columns update --table-id <TABLE_ID> --column-id <COLUMN_ID> --data-file column-update.json` |
|
|
125
|
+
| `DELETE /api/tables/{table_id}/columns/{column_id}` | `autotouch columns delete --table-id <TABLE_ID> --column-id <COLUMN_ID> --yes` |
|
|
115
126
|
| `POST /api/tables/{table_id}/columns/projections` | `autotouch columns projections --table-id <TABLE_ID> --data-file projections.json` |
|
|
116
127
|
| `POST /api/tables/{table_id}/columns/{column_id}/estimate` | `autotouch columns estimate --table-id <TABLE_ID> --column-id <COLUMN_ID> --scope all` |
|
|
117
128
|
| `POST /api/tables/{table_id}/columns/{column_id}/run` | `autotouch columns run --table-id <TABLE_ID> --column-id <COLUMN_ID> --scope all` |
|
|
118
129
|
| `POST /api/tables/{table_id}/columns/{column_id}/stop` | `autotouch columns stop --table-id <TABLE_ID> --column-id <COLUMN_ID>` |
|
|
119
130
|
| `GET /api/bulk-jobs` | `autotouch jobs list --table-id <TABLE_ID> --column-id <COLUMN_ID> --limit 10` |
|
|
120
131
|
| `GET /api/bulk-jobs/{job_id}` | `autotouch jobs get --job-id <JOB_ID>` |
|
|
132
|
+
| `POST /api/leads/query` | `autotouch leads query --filter-file lead-filter.json --limit 50` |
|
|
133
|
+
| `POST /api/leads/query/count` | `autotouch leads count --filter-file lead-filter.json` |
|
|
134
|
+
| `POST /api/leads/query/stats` | `autotouch leads stats --filter-file lead-filter.json` |
|
|
135
|
+
| `POST /api/leads/query/research` | `autotouch leads research --lead-id <LEAD_ID> --source-table-id <TABLE_ID>` |
|
|
136
|
+
| `GET /api/leads/filters/metadata` | `autotouch leads filters-metadata` |
|
|
137
|
+
| `GET /api/leads/research-tables/available` | `autotouch leads research-tables` |
|
|
121
138
|
| `GET /api/tables/{table_id}/webhook` | `autotouch webhooks get --table-id <TABLE_ID>` |
|
|
122
139
|
| `POST /api/tables/{table_id}/webhook` | `autotouch webhooks rotate --table-id <TABLE_ID>` |
|
|
123
140
|
| `POST /api/webhooks/tables/{table_id}/ingest` | `autotouch webhooks ingest --table-id <TABLE_ID> --records-file records.json --webhook-token <WEBHOOK_TOKEN>` |
|
|
124
141
|
| `POST /api/auth/agent-bootstrap` | HTTP-only bootstrap (no direct CLI wrapper yet) |
|
|
125
142
|
|
|
143
|
+
## Delete column
|
|
144
|
+
|
|
145
|
+
Delete is a hard delete:
|
|
146
|
+
- removes the column definition
|
|
147
|
+
- removes all cells stored under that column
|
|
148
|
+
- requires `columns:write`
|
|
149
|
+
|
|
150
|
+
CLI:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
autotouch columns delete --table-id <TABLE_ID> --column-id <COLUMN_ID> --yes
|
|
154
|
+
```
|
|
155
|
+
|
|
126
156
|
## Workflow API coverage (sequences/tasks)
|
|
127
157
|
|
|
128
158
|
Sequences/tasks APIs are supported by the backend developer-key model but do not yet have dedicated `autotouch` CLI commands.
|
|
@@ -145,6 +175,61 @@ Signature controls for sequence payloads:
|
|
|
145
175
|
- `steps[].appendSignature` (optional, step-level) overrides signature behavior for a specific email step.
|
|
146
176
|
- Signature append is deterministic at send time when enabled for the step.
|
|
147
177
|
|
|
178
|
+
## Leads API coverage
|
|
179
|
+
|
|
180
|
+
The CLI now exposes the public read-only leads endpoints under `autotouch leads`.
|
|
181
|
+
|
|
182
|
+
Use this pattern:
|
|
183
|
+
|
|
184
|
+
1. `autotouch leads query` to page through leads, apply descriptor filters, and inspect `related_tables` / `research_summary`.
|
|
185
|
+
2. `autotouch leads research` when you need actual research field values for specific lead IDs from one source table.
|
|
186
|
+
3. `autotouch leads count` / `autotouch leads stats` when you need sizing before a downstream workflow.
|
|
187
|
+
|
|
188
|
+
Important contract notes:
|
|
189
|
+
- External callers should use `POST /api/leads/query` rather than the older `GET /api/leads` list route.
|
|
190
|
+
- `autotouch leads query` accepts the same descriptor payload shape as the backend:
|
|
191
|
+
- `filter`
|
|
192
|
+
- `search`
|
|
193
|
+
- `sort`
|
|
194
|
+
- `pagination`
|
|
195
|
+
- `scope`
|
|
196
|
+
- optional research context (`source_table_id`, `source_table_scope`, `related_tables_mode`)
|
|
197
|
+
- Research values are best treated as a follow-up call:
|
|
198
|
+
- `query` returns lead rows plus research linkage metadata
|
|
199
|
+
- `research` returns `research_data_by_id` keyed by lead id for one `source_table_id`
|
|
200
|
+
|
|
201
|
+
Examples:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
autotouch leads query \
|
|
205
|
+
--filter-json '{"root":{"kind":"rule","field":"status","operator":"eq","value":"new"}}' \
|
|
206
|
+
--limit 25
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
autotouch leads count \
|
|
211
|
+
--search "fintech" \
|
|
212
|
+
--scope org
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
autotouch leads stats \
|
|
217
|
+
--source-table-id <TABLE_ID> \
|
|
218
|
+
--source-table-scope company
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
autotouch leads research \
|
|
223
|
+
--lead-id <LEAD_ID_1> \
|
|
224
|
+
--lead-id <LEAD_ID_2> \
|
|
225
|
+
--source-table-id <TABLE_ID>
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
autotouch leads filters-metadata
|
|
230
|
+
autotouch leads research-tables
|
|
231
|
+
```
|
|
232
|
+
|
|
148
233
|
## Bulk job status contract (authoritative run state)
|
|
149
234
|
|
|
150
235
|
Use bulk jobs as the source of truth for run lifecycle:
|
autotouch_cli-0.2.24/PKG-INFO → autotouch_cli-0.2.26/docs/research-table/reference/autotouch-cli.md
RENAMED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: autotouch-cli
|
|
3
|
-
Version: 0.2.24
|
|
4
|
-
Summary: Autotouch Smart Table CLI
|
|
5
|
-
Requires-Python: >=3.9
|
|
6
|
-
Description-Content-Type: text/markdown
|
|
7
|
-
Requires-Dist: requests>=2.31.0
|
|
8
|
-
Requires-Dist: python-dotenv>=1.0.0
|
|
9
|
-
|
|
10
1
|
# Autotouch CLI Reference (`autotouch`)
|
|
11
2
|
|
|
12
3
|
This page documents the installable CLI for the Smart Table developer API.
|
|
@@ -37,12 +28,13 @@ Use this order when you are orienting in the CLI:
|
|
|
37
28
|
| verify whether a job is really done | `autotouch jobs get --job-id <JOB_ID>` |
|
|
38
29
|
| create projections from JSON output | `autotouch columns projections` |
|
|
39
30
|
| work with sequences/tasks | raw HTTP plus `docs/platform/external-workflows-api.md` |
|
|
31
|
+
| query/filter CRM leads and attached research | `autotouch leads query` then `autotouch leads research` |
|
|
40
32
|
|
|
41
33
|
### Operating model
|
|
42
34
|
|
|
43
35
|
- This file is the full CLI reference and the package readme published to PyPI.
|
|
44
36
|
- The installed package gives you CLI entrypoints and package metadata; do not assume there is a separate installed docs directory.
|
|
45
|
-
- Research-table APIs are the primary CLI surface today; workflow APIs (sequences/tasks) are still HTTP-first.
|
|
37
|
+
- Research-table APIs and read-only leads queries are the primary CLI surface today; workflow APIs (sequences/tasks) are still HTTP-first.
|
|
46
38
|
- For async operations, backend bulk-job state is authoritative; local terminal output is only a convenience layer.
|
|
47
39
|
- For staged or cost-sensitive runs, estimate first and prefer filtered scopes plus `firstN` or `run-next`.
|
|
48
40
|
|
|
@@ -121,17 +113,37 @@ Notes:
|
|
|
121
113
|
| `GET /api/tables/{table_id}/columns` | `autotouch columns list --table-id <TABLE_ID>` |
|
|
122
114
|
| `POST /api/tables/{table_id}/columns` | `autotouch columns create --table-id <TABLE_ID> --data-file column.json` |
|
|
123
115
|
| `PATCH /api/tables/{table_id}/columns/{column_id}` | `autotouch columns update --table-id <TABLE_ID> --column-id <COLUMN_ID> --data-file column-update.json` |
|
|
116
|
+
| `DELETE /api/tables/{table_id}/columns/{column_id}` | `autotouch columns delete --table-id <TABLE_ID> --column-id <COLUMN_ID> --yes` |
|
|
124
117
|
| `POST /api/tables/{table_id}/columns/projections` | `autotouch columns projections --table-id <TABLE_ID> --data-file projections.json` |
|
|
125
118
|
| `POST /api/tables/{table_id}/columns/{column_id}/estimate` | `autotouch columns estimate --table-id <TABLE_ID> --column-id <COLUMN_ID> --scope all` |
|
|
126
119
|
| `POST /api/tables/{table_id}/columns/{column_id}/run` | `autotouch columns run --table-id <TABLE_ID> --column-id <COLUMN_ID> --scope all` |
|
|
127
120
|
| `POST /api/tables/{table_id}/columns/{column_id}/stop` | `autotouch columns stop --table-id <TABLE_ID> --column-id <COLUMN_ID>` |
|
|
128
121
|
| `GET /api/bulk-jobs` | `autotouch jobs list --table-id <TABLE_ID> --column-id <COLUMN_ID> --limit 10` |
|
|
129
122
|
| `GET /api/bulk-jobs/{job_id}` | `autotouch jobs get --job-id <JOB_ID>` |
|
|
123
|
+
| `POST /api/leads/query` | `autotouch leads query --filter-file lead-filter.json --limit 50` |
|
|
124
|
+
| `POST /api/leads/query/count` | `autotouch leads count --filter-file lead-filter.json` |
|
|
125
|
+
| `POST /api/leads/query/stats` | `autotouch leads stats --filter-file lead-filter.json` |
|
|
126
|
+
| `POST /api/leads/query/research` | `autotouch leads research --lead-id <LEAD_ID> --source-table-id <TABLE_ID>` |
|
|
127
|
+
| `GET /api/leads/filters/metadata` | `autotouch leads filters-metadata` |
|
|
128
|
+
| `GET /api/leads/research-tables/available` | `autotouch leads research-tables` |
|
|
130
129
|
| `GET /api/tables/{table_id}/webhook` | `autotouch webhooks get --table-id <TABLE_ID>` |
|
|
131
130
|
| `POST /api/tables/{table_id}/webhook` | `autotouch webhooks rotate --table-id <TABLE_ID>` |
|
|
132
131
|
| `POST /api/webhooks/tables/{table_id}/ingest` | `autotouch webhooks ingest --table-id <TABLE_ID> --records-file records.json --webhook-token <WEBHOOK_TOKEN>` |
|
|
133
132
|
| `POST /api/auth/agent-bootstrap` | HTTP-only bootstrap (no direct CLI wrapper yet) |
|
|
134
133
|
|
|
134
|
+
## Delete column
|
|
135
|
+
|
|
136
|
+
Delete is a hard delete:
|
|
137
|
+
- removes the column definition
|
|
138
|
+
- removes all cells stored under that column
|
|
139
|
+
- requires `columns:write`
|
|
140
|
+
|
|
141
|
+
CLI:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
autotouch columns delete --table-id <TABLE_ID> --column-id <COLUMN_ID> --yes
|
|
145
|
+
```
|
|
146
|
+
|
|
135
147
|
## Workflow API coverage (sequences/tasks)
|
|
136
148
|
|
|
137
149
|
Sequences/tasks APIs are supported by the backend developer-key model but do not yet have dedicated `autotouch` CLI commands.
|
|
@@ -154,6 +166,61 @@ Signature controls for sequence payloads:
|
|
|
154
166
|
- `steps[].appendSignature` (optional, step-level) overrides signature behavior for a specific email step.
|
|
155
167
|
- Signature append is deterministic at send time when enabled for the step.
|
|
156
168
|
|
|
169
|
+
## Leads API coverage
|
|
170
|
+
|
|
171
|
+
The CLI now exposes the public read-only leads endpoints under `autotouch leads`.
|
|
172
|
+
|
|
173
|
+
Use this pattern:
|
|
174
|
+
|
|
175
|
+
1. `autotouch leads query` to page through leads, apply descriptor filters, and inspect `related_tables` / `research_summary`.
|
|
176
|
+
2. `autotouch leads research` when you need actual research field values for specific lead IDs from one source table.
|
|
177
|
+
3. `autotouch leads count` / `autotouch leads stats` when you need sizing before a downstream workflow.
|
|
178
|
+
|
|
179
|
+
Important contract notes:
|
|
180
|
+
- External callers should use `POST /api/leads/query` rather than the older `GET /api/leads` list route.
|
|
181
|
+
- `autotouch leads query` accepts the same descriptor payload shape as the backend:
|
|
182
|
+
- `filter`
|
|
183
|
+
- `search`
|
|
184
|
+
- `sort`
|
|
185
|
+
- `pagination`
|
|
186
|
+
- `scope`
|
|
187
|
+
- optional research context (`source_table_id`, `source_table_scope`, `related_tables_mode`)
|
|
188
|
+
- Research values are best treated as a follow-up call:
|
|
189
|
+
- `query` returns lead rows plus research linkage metadata
|
|
190
|
+
- `research` returns `research_data_by_id` keyed by lead id for one `source_table_id`
|
|
191
|
+
|
|
192
|
+
Examples:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
autotouch leads query \
|
|
196
|
+
--filter-json '{"root":{"kind":"rule","field":"status","operator":"eq","value":"new"}}' \
|
|
197
|
+
--limit 25
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
autotouch leads count \
|
|
202
|
+
--search "fintech" \
|
|
203
|
+
--scope org
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
autotouch leads stats \
|
|
208
|
+
--source-table-id <TABLE_ID> \
|
|
209
|
+
--source-table-scope company
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
autotouch leads research \
|
|
214
|
+
--lead-id <LEAD_ID_1> \
|
|
215
|
+
--lead-id <LEAD_ID_2> \
|
|
216
|
+
--source-table-id <TABLE_ID>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
autotouch leads filters-metadata
|
|
221
|
+
autotouch leads research-tables
|
|
222
|
+
```
|
|
223
|
+
|
|
157
224
|
## Bulk job status contract (authoritative run state)
|
|
158
225
|
|
|
159
226
|
Use bulk jobs as the source of truth for run lifecycle:
|
|
@@ -998,6 +998,198 @@ def _normalize_run_payload(args: argparse.Namespace) -> Dict[str, Any]:
|
|
|
998
998
|
return payload
|
|
999
999
|
|
|
1000
1000
|
|
|
1001
|
+
def _normalize_filter_payload(filter_payload: Any) -> Any:
|
|
1002
|
+
if filter_payload is None:
|
|
1003
|
+
return None
|
|
1004
|
+
if isinstance(filter_payload, dict):
|
|
1005
|
+
return filter_payload
|
|
1006
|
+
print("ERROR: leads filter payload must be a JSON object", file=sys.stderr)
|
|
1007
|
+
sys.exit(2)
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
def _normalize_sort_payload(sort_payload: Any) -> Any:
|
|
1011
|
+
if sort_payload is None:
|
|
1012
|
+
return None
|
|
1013
|
+
if isinstance(sort_payload, list):
|
|
1014
|
+
return sort_payload
|
|
1015
|
+
if isinstance(sort_payload, dict):
|
|
1016
|
+
return [sort_payload]
|
|
1017
|
+
print("ERROR: leads sort payload must be a JSON object or array", file=sys.stderr)
|
|
1018
|
+
sys.exit(2)
|
|
1019
|
+
|
|
1020
|
+
|
|
1021
|
+
def _normalize_leads_query_payload(args: argparse.Namespace) -> Dict[str, Any]:
|
|
1022
|
+
explicit_payload = _load_json_input(
|
|
1023
|
+
inline_json=getattr(args, "data_json", None),
|
|
1024
|
+
file_path=getattr(args, "data_file", None),
|
|
1025
|
+
context="data",
|
|
1026
|
+
default=None,
|
|
1027
|
+
)
|
|
1028
|
+
if explicit_payload is not None:
|
|
1029
|
+
if not isinstance(explicit_payload, dict):
|
|
1030
|
+
print("ERROR: leads payload must be a JSON object", file=sys.stderr)
|
|
1031
|
+
sys.exit(2)
|
|
1032
|
+
return explicit_payload
|
|
1033
|
+
|
|
1034
|
+
payload: Dict[str, Any] = {}
|
|
1035
|
+
|
|
1036
|
+
filter_payload = _normalize_filter_payload(
|
|
1037
|
+
_load_json_input(
|
|
1038
|
+
inline_json=getattr(args, "filter_json", None),
|
|
1039
|
+
file_path=getattr(args, "filter_file", None),
|
|
1040
|
+
context="filter",
|
|
1041
|
+
default=None,
|
|
1042
|
+
)
|
|
1043
|
+
)
|
|
1044
|
+
if filter_payload is not None:
|
|
1045
|
+
payload["filter"] = filter_payload
|
|
1046
|
+
|
|
1047
|
+
sort_payload = _normalize_sort_payload(
|
|
1048
|
+
_load_json_input(
|
|
1049
|
+
inline_json=getattr(args, "sort_json", None),
|
|
1050
|
+
file_path=getattr(args, "sort_file", None),
|
|
1051
|
+
context="sort",
|
|
1052
|
+
default=None,
|
|
1053
|
+
)
|
|
1054
|
+
)
|
|
1055
|
+
if sort_payload is not None:
|
|
1056
|
+
payload["sort"] = sort_payload
|
|
1057
|
+
|
|
1058
|
+
search = str(getattr(args, "search", "") or "").strip()
|
|
1059
|
+
if search:
|
|
1060
|
+
payload["search"] = search
|
|
1061
|
+
|
|
1062
|
+
pagination: Dict[str, Any] = {}
|
|
1063
|
+
limit = getattr(args, "limit", None)
|
|
1064
|
+
if limit is not None:
|
|
1065
|
+
pagination["limit"] = int(limit)
|
|
1066
|
+
cursor = str(getattr(args, "cursor", "") or "").strip()
|
|
1067
|
+
if cursor:
|
|
1068
|
+
pagination["cursor"] = cursor
|
|
1069
|
+
if pagination:
|
|
1070
|
+
payload["pagination"] = pagination
|
|
1071
|
+
|
|
1072
|
+
scope = str(getattr(args, "scope", "") or "").strip()
|
|
1073
|
+
if scope:
|
|
1074
|
+
payload["scope"] = scope
|
|
1075
|
+
|
|
1076
|
+
source_table_id = str(getattr(args, "source_table_id", "") or "").strip()
|
|
1077
|
+
if source_table_id:
|
|
1078
|
+
payload["source_table_id"] = source_table_id
|
|
1079
|
+
|
|
1080
|
+
source_table_scope = str(getattr(args, "source_table_scope", "") or "").strip()
|
|
1081
|
+
if source_table_scope:
|
|
1082
|
+
payload["source_table_scope"] = source_table_scope
|
|
1083
|
+
|
|
1084
|
+
related_tables_mode = str(getattr(args, "related_tables_mode", "") or "").strip()
|
|
1085
|
+
if related_tables_mode:
|
|
1086
|
+
payload["related_tables_mode"] = related_tables_mode
|
|
1087
|
+
|
|
1088
|
+
if bool(getattr(args, "include_research_data", False)):
|
|
1089
|
+
payload["include_research_data"] = True
|
|
1090
|
+
|
|
1091
|
+
if bool(getattr(args, "include_placeholder_leads", False)):
|
|
1092
|
+
payload["include_placeholder_leads"] = True
|
|
1093
|
+
|
|
1094
|
+
return payload
|
|
1095
|
+
|
|
1096
|
+
|
|
1097
|
+
def _collect_cli_string_values(raw_values: Optional[List[str]]) -> List[str]:
|
|
1098
|
+
values: List[str] = []
|
|
1099
|
+
for raw in raw_values or []:
|
|
1100
|
+
for piece in str(raw).replace("\n", ",").split(","):
|
|
1101
|
+
normalized = str(piece or "").strip()
|
|
1102
|
+
if normalized:
|
|
1103
|
+
values.append(normalized)
|
|
1104
|
+
return values
|
|
1105
|
+
|
|
1106
|
+
|
|
1107
|
+
def _parse_string_list_payload(payload: Any, *, context: str, key: Optional[str] = None) -> List[str]:
|
|
1108
|
+
raw_values: List[Any]
|
|
1109
|
+
if isinstance(payload, list):
|
|
1110
|
+
raw_values = payload
|
|
1111
|
+
elif isinstance(payload, dict) and key and isinstance(payload.get(key), list):
|
|
1112
|
+
raw_values = payload.get(key) or []
|
|
1113
|
+
else:
|
|
1114
|
+
suffix = f" or object with '{key}' array" if key else ""
|
|
1115
|
+
print(f"ERROR: {context} must be a JSON array{suffix}", file=sys.stderr)
|
|
1116
|
+
sys.exit(2)
|
|
1117
|
+
|
|
1118
|
+
values: List[str] = []
|
|
1119
|
+
for item in raw_values:
|
|
1120
|
+
normalized = str(item or "").strip()
|
|
1121
|
+
if normalized:
|
|
1122
|
+
values.append(normalized)
|
|
1123
|
+
return values
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
def _load_string_list_input(
|
|
1127
|
+
*,
|
|
1128
|
+
cli_values: Optional[List[str]],
|
|
1129
|
+
inline_json: Optional[str],
|
|
1130
|
+
file_path: Optional[str],
|
|
1131
|
+
context: str,
|
|
1132
|
+
key: Optional[str] = None,
|
|
1133
|
+
) -> List[str]:
|
|
1134
|
+
values = _collect_cli_string_values(cli_values)
|
|
1135
|
+
payload = _load_json_input(
|
|
1136
|
+
inline_json=inline_json,
|
|
1137
|
+
file_path=file_path,
|
|
1138
|
+
context=context,
|
|
1139
|
+
default=None,
|
|
1140
|
+
)
|
|
1141
|
+
if payload is not None:
|
|
1142
|
+
values.extend(_parse_string_list_payload(payload, context=context, key=key))
|
|
1143
|
+
return _dedupe_keep_order(values)
|
|
1144
|
+
|
|
1145
|
+
|
|
1146
|
+
def _normalize_leads_research_payload(args: argparse.Namespace) -> Dict[str, Any]:
|
|
1147
|
+
explicit_payload = _load_json_input(
|
|
1148
|
+
inline_json=getattr(args, "data_json", None),
|
|
1149
|
+
file_path=getattr(args, "data_file", None),
|
|
1150
|
+
context="data",
|
|
1151
|
+
default=None,
|
|
1152
|
+
)
|
|
1153
|
+
if explicit_payload is not None:
|
|
1154
|
+
if not isinstance(explicit_payload, dict):
|
|
1155
|
+
print("ERROR: leads research payload must be a JSON object", file=sys.stderr)
|
|
1156
|
+
sys.exit(2)
|
|
1157
|
+
return explicit_payload
|
|
1158
|
+
|
|
1159
|
+
lead_ids = _load_string_list_input(
|
|
1160
|
+
cli_values=getattr(args, "lead_id", None),
|
|
1161
|
+
inline_json=getattr(args, "lead_ids_json", None),
|
|
1162
|
+
file_path=getattr(args, "lead_ids_file", None),
|
|
1163
|
+
context="lead_ids",
|
|
1164
|
+
key="lead_ids",
|
|
1165
|
+
)
|
|
1166
|
+
if not lead_ids:
|
|
1167
|
+
print("ERROR: provide at least one lead id", file=sys.stderr)
|
|
1168
|
+
sys.exit(2)
|
|
1169
|
+
|
|
1170
|
+
source_table_id = str(getattr(args, "source_table_id", "") or "").strip()
|
|
1171
|
+
if not source_table_id:
|
|
1172
|
+
print("ERROR: --source-table-id is required", file=sys.stderr)
|
|
1173
|
+
sys.exit(2)
|
|
1174
|
+
|
|
1175
|
+
payload: Dict[str, Any] = {
|
|
1176
|
+
"lead_ids": lead_ids,
|
|
1177
|
+
"source_table_id": source_table_id,
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
field_ids = _load_string_list_input(
|
|
1181
|
+
cli_values=getattr(args, "field_id", None),
|
|
1182
|
+
inline_json=getattr(args, "field_ids_json", None),
|
|
1183
|
+
file_path=getattr(args, "field_ids_file", None),
|
|
1184
|
+
context="field_ids",
|
|
1185
|
+
key="field_ids",
|
|
1186
|
+
)
|
|
1187
|
+
if field_ids:
|
|
1188
|
+
payload["field_ids"] = field_ids
|
|
1189
|
+
|
|
1190
|
+
return payload
|
|
1191
|
+
|
|
1192
|
+
|
|
1001
1193
|
def _resolve_column_key(
|
|
1002
1194
|
*,
|
|
1003
1195
|
table_id: str,
|
|
@@ -3562,6 +3754,27 @@ def cmd_columns_update(args: argparse.Namespace) -> None:
|
|
|
3562
3754
|
_print_json(data, compact=args.compact)
|
|
3563
3755
|
|
|
3564
3756
|
|
|
3757
|
+
def cmd_columns_delete(args: argparse.Namespace) -> None:
|
|
3758
|
+
if not getattr(args, "yes", False):
|
|
3759
|
+
print(
|
|
3760
|
+
"ERROR: column delete is destructive and also removes all cells for that column. Re-run with --yes to confirm.",
|
|
3761
|
+
file=sys.stderr,
|
|
3762
|
+
)
|
|
3763
|
+
sys.exit(2)
|
|
3764
|
+
|
|
3765
|
+
token = _resolve_token(args.token, required=True)
|
|
3766
|
+
data = _request_api(
|
|
3767
|
+
"DELETE",
|
|
3768
|
+
f"/api/tables/{args.table_id}/columns/{args.column_id}",
|
|
3769
|
+
base_url=args.base_url,
|
|
3770
|
+
token=token,
|
|
3771
|
+
use_x_api_key=args.use_x_api_key,
|
|
3772
|
+
timeout=args.timeout,
|
|
3773
|
+
verbose=args.verbose,
|
|
3774
|
+
)
|
|
3775
|
+
_print_json(data, compact=args.compact)
|
|
3776
|
+
|
|
3777
|
+
|
|
3565
3778
|
def cmd_columns_projections(args: argparse.Namespace) -> None:
|
|
3566
3779
|
token = _resolve_token(args.token, required=True)
|
|
3567
3780
|
payload = _load_json_input(
|
|
@@ -3765,6 +3978,98 @@ def cmd_jobs_watch(args: argparse.Namespace) -> None:
|
|
|
3765
3978
|
sys.exit(1)
|
|
3766
3979
|
|
|
3767
3980
|
|
|
3981
|
+
def cmd_leads_query(args: argparse.Namespace) -> None:
|
|
3982
|
+
token = _resolve_token(args.token, required=True)
|
|
3983
|
+
payload = _normalize_leads_query_payload(args)
|
|
3984
|
+
data = _request_api(
|
|
3985
|
+
"POST",
|
|
3986
|
+
"/api/leads/query",
|
|
3987
|
+
base_url=args.base_url,
|
|
3988
|
+
token=token,
|
|
3989
|
+
use_x_api_key=args.use_x_api_key,
|
|
3990
|
+
payload=payload,
|
|
3991
|
+
timeout=args.timeout,
|
|
3992
|
+
verbose=args.verbose,
|
|
3993
|
+
)
|
|
3994
|
+
_print_json(data, compact=args.compact)
|
|
3995
|
+
|
|
3996
|
+
|
|
3997
|
+
def cmd_leads_count(args: argparse.Namespace) -> None:
|
|
3998
|
+
token = _resolve_token(args.token, required=True)
|
|
3999
|
+
payload = _normalize_leads_query_payload(args)
|
|
4000
|
+
data = _request_api(
|
|
4001
|
+
"POST",
|
|
4002
|
+
"/api/leads/query/count",
|
|
4003
|
+
base_url=args.base_url,
|
|
4004
|
+
token=token,
|
|
4005
|
+
use_x_api_key=args.use_x_api_key,
|
|
4006
|
+
payload=payload,
|
|
4007
|
+
timeout=args.timeout,
|
|
4008
|
+
verbose=args.verbose,
|
|
4009
|
+
)
|
|
4010
|
+
_print_json(data, compact=args.compact)
|
|
4011
|
+
|
|
4012
|
+
|
|
4013
|
+
def cmd_leads_stats(args: argparse.Namespace) -> None:
|
|
4014
|
+
token = _resolve_token(args.token, required=True)
|
|
4015
|
+
payload = _normalize_leads_query_payload(args)
|
|
4016
|
+
data = _request_api(
|
|
4017
|
+
"POST",
|
|
4018
|
+
"/api/leads/query/stats",
|
|
4019
|
+
base_url=args.base_url,
|
|
4020
|
+
token=token,
|
|
4021
|
+
use_x_api_key=args.use_x_api_key,
|
|
4022
|
+
payload=payload,
|
|
4023
|
+
timeout=args.timeout,
|
|
4024
|
+
verbose=args.verbose,
|
|
4025
|
+
)
|
|
4026
|
+
_print_json(data, compact=args.compact)
|
|
4027
|
+
|
|
4028
|
+
|
|
4029
|
+
def cmd_leads_research(args: argparse.Namespace) -> None:
|
|
4030
|
+
token = _resolve_token(args.token, required=True)
|
|
4031
|
+
payload = _normalize_leads_research_payload(args)
|
|
4032
|
+
data = _request_api(
|
|
4033
|
+
"POST",
|
|
4034
|
+
"/api/leads/query/research",
|
|
4035
|
+
base_url=args.base_url,
|
|
4036
|
+
token=token,
|
|
4037
|
+
use_x_api_key=args.use_x_api_key,
|
|
4038
|
+
payload=payload,
|
|
4039
|
+
timeout=args.timeout,
|
|
4040
|
+
verbose=args.verbose,
|
|
4041
|
+
)
|
|
4042
|
+
_print_json(data, compact=args.compact)
|
|
4043
|
+
|
|
4044
|
+
|
|
4045
|
+
def cmd_leads_filters_metadata(args: argparse.Namespace) -> None:
|
|
4046
|
+
token = _resolve_token(args.token, required=True)
|
|
4047
|
+
data = _request_api(
|
|
4048
|
+
"GET",
|
|
4049
|
+
"/api/leads/filters/metadata",
|
|
4050
|
+
base_url=args.base_url,
|
|
4051
|
+
token=token,
|
|
4052
|
+
use_x_api_key=args.use_x_api_key,
|
|
4053
|
+
timeout=args.timeout,
|
|
4054
|
+
verbose=args.verbose,
|
|
4055
|
+
)
|
|
4056
|
+
_print_json(data, compact=args.compact)
|
|
4057
|
+
|
|
4058
|
+
|
|
4059
|
+
def cmd_leads_research_tables(args: argparse.Namespace) -> None:
|
|
4060
|
+
token = _resolve_token(args.token, required=True)
|
|
4061
|
+
data = _request_api(
|
|
4062
|
+
"GET",
|
|
4063
|
+
"/api/leads/research-tables/available",
|
|
4064
|
+
base_url=args.base_url,
|
|
4065
|
+
token=token,
|
|
4066
|
+
use_x_api_key=args.use_x_api_key,
|
|
4067
|
+
timeout=args.timeout,
|
|
4068
|
+
verbose=args.verbose,
|
|
4069
|
+
)
|
|
4070
|
+
_print_json(data, compact=args.compact)
|
|
4071
|
+
|
|
4072
|
+
|
|
3768
4073
|
def cmd_webhooks_get(args: argparse.Namespace) -> None:
|
|
3769
4074
|
token = _resolve_token(args.token, required=True)
|
|
3770
4075
|
data = _request_api(
|
|
@@ -4156,6 +4461,60 @@ def _add_run_execution_arguments(parser: argparse.ArgumentParser) -> None:
|
|
|
4156
4461
|
parser.add_argument("--fail-on-partial", action="store_true", help="Exit non-zero when final status is partial")
|
|
4157
4462
|
|
|
4158
4463
|
|
|
4464
|
+
def _add_leads_query_arguments(parser: argparse.ArgumentParser) -> None:
|
|
4465
|
+
parser.add_argument("--data-json", help="Explicit leads query payload JSON")
|
|
4466
|
+
parser.add_argument("--data-file", help="Path to leads query payload JSON file")
|
|
4467
|
+
parser.add_argument("--filter-json", help="Filter descriptor JSON object")
|
|
4468
|
+
parser.add_argument("--filter-file", help="Path to filter descriptor JSON file")
|
|
4469
|
+
parser.add_argument("--sort-json", help="Sort spec JSON object/array")
|
|
4470
|
+
parser.add_argument("--sort-file", help="Path to sort spec JSON file")
|
|
4471
|
+
parser.add_argument("--search", help="Free-text lead search")
|
|
4472
|
+
parser.add_argument("--limit", type=int, help="Pagination limit")
|
|
4473
|
+
parser.add_argument("--cursor", help="Pagination cursor")
|
|
4474
|
+
parser.add_argument("--scope", choices=["org", "user"], help="Lead scope")
|
|
4475
|
+
parser.add_argument("--source-table-id", help="Research table id used for scope/research context")
|
|
4476
|
+
parser.add_argument(
|
|
4477
|
+
"--source-table-scope",
|
|
4478
|
+
choices=["company", "lead"],
|
|
4479
|
+
help="Research scope resolution mode",
|
|
4480
|
+
)
|
|
4481
|
+
parser.add_argument(
|
|
4482
|
+
"--related-tables-mode",
|
|
4483
|
+
choices=["linked", "direct", "none"],
|
|
4484
|
+
help="How related_tables should be populated",
|
|
4485
|
+
)
|
|
4486
|
+
parser.add_argument(
|
|
4487
|
+
"--include-research-data",
|
|
4488
|
+
action="store_true",
|
|
4489
|
+
help="Inline research_data when --source-table-id is provided",
|
|
4490
|
+
)
|
|
4491
|
+
parser.add_argument(
|
|
4492
|
+
"--include-placeholder-leads",
|
|
4493
|
+
action="store_true",
|
|
4494
|
+
help="Include placeholder/incomplete lead records",
|
|
4495
|
+
)
|
|
4496
|
+
|
|
4497
|
+
|
|
4498
|
+
def _add_leads_research_arguments(parser: argparse.ArgumentParser) -> None:
|
|
4499
|
+
parser.add_argument("--data-json", help="Explicit leads research payload JSON")
|
|
4500
|
+
parser.add_argument("--data-file", help="Path to leads research payload JSON file")
|
|
4501
|
+
parser.add_argument(
|
|
4502
|
+
"--lead-id",
|
|
4503
|
+
action="append",
|
|
4504
|
+
help="Lead id (repeatable; comma-separated also supported)",
|
|
4505
|
+
)
|
|
4506
|
+
parser.add_argument("--lead-ids-json", help="JSON array or object with lead_ids[]")
|
|
4507
|
+
parser.add_argument("--lead-ids-file", help="Path to JSON file with lead_ids[]")
|
|
4508
|
+
parser.add_argument("--source-table-id", help="Research table id")
|
|
4509
|
+
parser.add_argument(
|
|
4510
|
+
"--field-id",
|
|
4511
|
+
action="append",
|
|
4512
|
+
help="Research field/column id to include (repeatable; comma-separated also supported)",
|
|
4513
|
+
)
|
|
4514
|
+
parser.add_argument("--field-ids-json", help="JSON array or object with field_ids[]")
|
|
4515
|
+
parser.add_argument("--field-ids-file", help="Path to JSON file with field_ids[]")
|
|
4516
|
+
|
|
4517
|
+
|
|
4159
4518
|
def build_parser() -> argparse.ArgumentParser:
|
|
4160
4519
|
p = argparse.ArgumentParser(prog="autotouch", description="Smart Table CLI")
|
|
4161
4520
|
sub = p.add_subparsers(dest="cmd", required=True)
|
|
@@ -4461,6 +4820,13 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
4461
4820
|
_add_api_common_arguments(pcu)
|
|
4462
4821
|
pcu.set_defaults(func=cmd_columns_update)
|
|
4463
4822
|
|
|
4823
|
+
pcd = col_sub.add_parser("delete", help="Delete a column and all of its cells")
|
|
4824
|
+
pcd.add_argument("--table-id", required=True)
|
|
4825
|
+
pcd.add_argument("--column-id", required=True)
|
|
4826
|
+
pcd.add_argument("--yes", action="store_true", help="Required confirmation flag for destructive delete")
|
|
4827
|
+
_add_api_common_arguments(pcd)
|
|
4828
|
+
pcd.set_defaults(func=cmd_columns_delete)
|
|
4829
|
+
|
|
4464
4830
|
pcpj = col_sub.add_parser("projections", help="Create JSON projection columns")
|
|
4465
4831
|
pcpj.add_argument("--table-id", required=True)
|
|
4466
4832
|
pcpj.add_argument("--data-json", help="CreateProjectionsRequest payload JSON")
|
|
@@ -4515,6 +4881,38 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
4515
4881
|
pcre.add_argument("--compact", action="store_true", help="Print compact JSON")
|
|
4516
4882
|
pcre.set_defaults(func=cmd_columns_recipe)
|
|
4517
4883
|
|
|
4884
|
+
# leads
|
|
4885
|
+
pl = sub.add_parser("leads", help="Read-only leads query operations")
|
|
4886
|
+
leads_sub = pl.add_subparsers(dest="leads_cmd", required=True)
|
|
4887
|
+
|
|
4888
|
+
plq = leads_sub.add_parser("query", help="Query/filter leads with descriptor payloads")
|
|
4889
|
+
_add_leads_query_arguments(plq)
|
|
4890
|
+
_add_api_common_arguments(plq)
|
|
4891
|
+
plq.set_defaults(func=cmd_leads_query)
|
|
4892
|
+
|
|
4893
|
+
plc = leads_sub.add_parser("count", help="Count leads matching a query payload")
|
|
4894
|
+
_add_leads_query_arguments(plc)
|
|
4895
|
+
_add_api_common_arguments(plc)
|
|
4896
|
+
plc.set_defaults(func=cmd_leads_count)
|
|
4897
|
+
|
|
4898
|
+
pls = leads_sub.add_parser("stats", help="Aggregate stats for leads matching a query payload")
|
|
4899
|
+
_add_leads_query_arguments(pls)
|
|
4900
|
+
_add_api_common_arguments(pls)
|
|
4901
|
+
pls.set_defaults(func=cmd_leads_stats)
|
|
4902
|
+
|
|
4903
|
+
plr = leads_sub.add_parser("research", help="Fetch research row data for specific lead ids")
|
|
4904
|
+
_add_leads_research_arguments(plr)
|
|
4905
|
+
_add_api_common_arguments(plr)
|
|
4906
|
+
plr.set_defaults(func=cmd_leads_research)
|
|
4907
|
+
|
|
4908
|
+
plf = leads_sub.add_parser("filters-metadata", help="List filterable lead fields and research columns")
|
|
4909
|
+
_add_api_common_arguments(plf)
|
|
4910
|
+
plf.set_defaults(func=cmd_leads_filters_metadata)
|
|
4911
|
+
|
|
4912
|
+
plrt = leads_sub.add_parser("research-tables", help="List research tables available for lead lookups")
|
|
4913
|
+
_add_api_common_arguments(plrt)
|
|
4914
|
+
plrt.set_defaults(func=cmd_leads_research_tables)
|
|
4915
|
+
|
|
4518
4916
|
# jobs
|
|
4519
4917
|
pj = sub.add_parser("jobs", help="Bulk job operations")
|
|
4520
4918
|
jobs_sub = pj.add_subparsers(dest="jobs_cmd", required=True)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/attach_csv_import_leads_to_research_table.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250106_add_column_position.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250123_add_filter_indexes.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250604_add_origin_indexes.py
RENAMED
|
File without changes
|
{autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250608_cleanup_agent_metadata.py
RENAMED
|
File without changes
|
|
File without changes
|
{autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250922_add_activity_indexes.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/20250929_add_task_join_indexes.py
RENAMED
|
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
|
{autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/migrate_org_user_credits.py
RENAMED
|
File without changes
|
|
File without changes
|
{autotouch_cli-0.2.24 → autotouch_cli-0.2.26}/scripts/migrations/update_lead_owner_from_tasks.py
RENAMED
|
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
|