autotouch-cli 0.2.48__tar.gz → 0.2.50__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/PKG-INFO +5 -5
  2. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/README.md +4 -4
  3. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/cli.py +6 -0
  4. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/commands/columns.py +95 -0
  5. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/data/CLI_REFERENCE.md +54 -9
  6. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/data/cli-manifest.json +291 -5
  7. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli.egg-info/PKG-INFO +5 -5
  8. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_shared/provider_registry.py +52 -13
  9. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/pyproject.toml +1 -1
  10. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/MANIFEST.in +0 -0
  11. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/__init__.py +0 -0
  12. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/cli_contracts.py +0 -0
  13. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/commands/__init__.py +0 -0
  14. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/commands/auth.py +0 -0
  15. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/commands/cells.py +0 -0
  16. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/commands/jobs.py +0 -0
  17. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/commands/leads.py +0 -0
  18. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/commands/linkedin.py +0 -0
  19. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/commands/prompts.py +0 -0
  20. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/commands/rows.py +0 -0
  21. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/commands/search.py +0 -0
  22. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/commands/sequences.py +0 -0
  23. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/commands/tables.py +0 -0
  24. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/commands/tasks.py +0 -0
  25. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/commands/webhooks.py +0 -0
  26. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/commands/workspace_secrets.py +0 -0
  27. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/core/__init__.py +0 -0
  28. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/core/auth.py +0 -0
  29. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/core/config.py +0 -0
  30. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/core/http.py +0 -0
  31. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/core/io.py +0 -0
  32. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/core/output.py +0 -0
  33. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/core/polling.py +0 -0
  34. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/mongo_status.py +0 -0
  35. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/parser_groups.py +0 -0
  36. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/sequence_support.py +0 -0
  37. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli/templates.py +0 -0
  38. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli.egg-info/SOURCES.txt +0 -0
  39. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli.egg-info/dependency_links.txt +0 -0
  40. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli.egg-info/entry_points.txt +0 -0
  41. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli.egg-info/requires.txt +0 -0
  42. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_cli.egg-info/top_level.txt +0 -0
  43. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_shared/__init__.py +0 -0
  44. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_shared/linkedin_contract.py +0 -0
  45. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/autotouch_shared/search_contract.py +0 -0
  46. {autotouch_cli-0.2.48 → autotouch_cli-0.2.50}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autotouch-cli
3
- Version: 0.2.48
3
+ Version: 0.2.50
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
@@ -157,7 +157,7 @@ Only send `user_schema` / `response_schema` when you intentionally want to overr
157
157
 
158
158
  ## Docs
159
159
 
160
- - Full CLI reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/reference/autotouch-cli.md
161
- - Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/guides/autotouch-cli-agent-playbook.md
162
- - Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/reference/tables-api.md
163
- - Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/platform/authentication.md
160
+ - Full CLI reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.50/docs/research-table/reference/autotouch-cli.md
161
+ - Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.50/docs/research-table/guides/autotouch-cli-agent-playbook.md
162
+ - Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.50/docs/research-table/reference/tables-api.md
163
+ - Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.50/docs/platform/authentication.md
@@ -132,7 +132,7 @@ Only send `user_schema` / `response_schema` when you intentionally want to overr
132
132
 
133
133
  ## Docs
134
134
 
135
- - Full CLI reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/reference/autotouch-cli.md
136
- - Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/guides/autotouch-cli-agent-playbook.md
137
- - Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/reference/tables-api.md
138
- - Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/platform/authentication.md
135
+ - Full CLI reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.50/docs/research-table/reference/autotouch-cli.md
136
+ - Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.50/docs/research-table/guides/autotouch-cli-agent-playbook.md
137
+ - Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.50/docs/research-table/reference/tables-api.md
138
+ - Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.50/docs/platform/authentication.md
@@ -45,6 +45,7 @@ from autotouch_cli.commands.columns import (
45
45
  cmd_columns_delete as cmd_columns_delete_impl,
46
46
  cmd_columns_estimate as cmd_columns_estimate_impl,
47
47
  cmd_columns_list as cmd_columns_list_impl,
48
+ cmd_columns_move as cmd_columns_move_impl,
48
49
  cmd_columns_projections as cmd_columns_projections_impl,
49
50
  cmd_columns_run as cmd_columns_run_impl,
50
51
  cmd_columns_run_next as cmd_columns_run_next_impl,
@@ -3282,6 +3283,10 @@ def cmd_columns_update(args: argparse.Namespace) -> None:
3282
3283
  cmd_columns_update_impl(args, runtime=_column_command_runtime())
3283
3284
 
3284
3285
 
3286
+ def cmd_columns_move(args: argparse.Namespace) -> None:
3287
+ cmd_columns_move_impl(args, runtime=_column_command_runtime())
3288
+
3289
+
3285
3290
  def cmd_columns_delete(args: argparse.Namespace) -> None:
3286
3291
  cmd_columns_delete_impl(args, runtime=_column_command_runtime())
3287
3292
 
@@ -4077,6 +4082,7 @@ def build_parser() -> argparse.ArgumentParser:
4077
4082
  "list": cmd_columns_list,
4078
4083
  "create": cmd_columns_create,
4079
4084
  "update": cmd_columns_update,
4085
+ "move": cmd_columns_move,
4080
4086
  "delete": cmd_columns_delete,
4081
4087
  "projections": cmd_columns_projections,
4082
4088
  "test_http_request": cmd_columns_test_http_request,
@@ -22,6 +22,39 @@ class ColumnCommandRuntime:
22
22
  select_next_row_ids: Callable[..., Dict[str, Any]]
23
23
 
24
24
 
25
+ def _validate_position_flags(args: argparse.Namespace, *, allow_position: bool) -> None:
26
+ if allow_position and getattr(args, "position", None) is not None:
27
+ if getattr(args, "after_column_id", None) or getattr(args, "before_column_id", None):
28
+ print(
29
+ "ERROR: --position cannot be combined with --after-column-id/--before-column-id",
30
+ file=sys.stderr,
31
+ )
32
+ sys.exit(2)
33
+
34
+
35
+ def _apply_column_position_overrides(
36
+ payload: Dict[str, Any],
37
+ args: argparse.Namespace,
38
+ *,
39
+ allow_position: bool,
40
+ allow_neighbors: bool,
41
+ ) -> Dict[str, Any]:
42
+ merged = dict(payload)
43
+ _validate_position_flags(args, allow_position=allow_position)
44
+ if allow_position and getattr(args, "position", None) is not None:
45
+ merged["position"] = float(args.position)
46
+ merged.pop("afterColumnId", None)
47
+ merged.pop("after_column_id", None)
48
+ merged.pop("beforeColumnId", None)
49
+ merged.pop("before_column_id", None)
50
+ if allow_neighbors:
51
+ if getattr(args, "after_column_id", None):
52
+ merged["afterColumnId"] = args.after_column_id
53
+ if getattr(args, "before_column_id", None):
54
+ merged["beforeColumnId"] = args.before_column_id
55
+ return merged
56
+
57
+
25
58
  def _normalize_http_request_test_payload(payload: Dict[str, Any]) -> Dict[str, Any]:
26
59
  candidate = payload
27
60
  config = payload.get("config")
@@ -79,6 +112,12 @@ def cmd_columns_create(args: argparse.Namespace, *, runtime: ColumnCommandRuntim
79
112
  if not isinstance(payload, dict):
80
113
  print("ERROR: column create requires --data-json/--data-file with a JSON object", file=sys.stderr)
81
114
  sys.exit(2)
115
+ payload = _apply_column_position_overrides(
116
+ payload,
117
+ args,
118
+ allow_position=True,
119
+ allow_neighbors=True,
120
+ )
82
121
  runtime.validate_column_contract_payload_or_exit(payload)
83
122
  runtime.validate_add_to_crm_create_payload(payload)
84
123
  data = runtime.request_api(
@@ -119,6 +158,12 @@ def cmd_columns_update(args: argparse.Namespace, *, runtime: ColumnCommandRuntim
119
158
  if not isinstance(payload, dict):
120
159
  print("ERROR: column update requires --data-json/--data-file with a JSON object", file=sys.stderr)
121
160
  sys.exit(2)
161
+ payload = _apply_column_position_overrides(
162
+ payload,
163
+ args,
164
+ allow_position=True,
165
+ allow_neighbors=False,
166
+ )
122
167
  runtime.validate_column_contract_payload_or_exit(payload)
123
168
  data = runtime.request_api(
124
169
  "PATCH",
@@ -165,6 +210,12 @@ def cmd_columns_projections(args: argparse.Namespace, *, runtime: ColumnCommandR
165
210
  if not isinstance(payload, dict):
166
211
  print("ERROR: projection create requires --data-json/--data-file with a JSON object", file=sys.stderr)
167
212
  sys.exit(2)
213
+ payload = _apply_column_position_overrides(
214
+ payload,
215
+ args,
216
+ allow_position=False,
217
+ allow_neighbors=True,
218
+ )
168
219
 
169
220
  preflight_warnings = runtime.build_projection_preflight_warnings(
170
221
  table_id=args.table_id,
@@ -200,6 +251,29 @@ def cmd_columns_projections(args: argparse.Namespace, *, runtime: ColumnCommandR
200
251
  runtime.print_json(data, args.compact)
201
252
 
202
253
 
254
+ def cmd_columns_move(args: argparse.Namespace, *, runtime: ColumnCommandRuntime) -> None:
255
+ token = runtime.resolve_token(args.token, required=True)
256
+ if not args.after_column_id and not args.before_column_id:
257
+ print("ERROR: columns move requires --after-column-id and/or --before-column-id", file=sys.stderr)
258
+ sys.exit(2)
259
+ payload: Dict[str, Any] = {}
260
+ if args.after_column_id:
261
+ payload["after_column_id"] = args.after_column_id
262
+ if args.before_column_id:
263
+ payload["before_column_id"] = args.before_column_id
264
+ data = runtime.request_api(
265
+ "PATCH",
266
+ f"/api/tables/{args.table_id}/columns/{args.column_id}/position",
267
+ base_url=args.base_url,
268
+ token=token,
269
+ use_x_api_key=args.use_x_api_key,
270
+ payload=payload,
271
+ timeout=args.timeout,
272
+ verbose=args.verbose,
273
+ )
274
+ runtime.print_json(data, args.compact)
275
+
276
+
203
277
  def cmd_columns_test_http_request(args: argparse.Namespace, *, runtime: ColumnCommandRuntime) -> None:
204
278
  token = runtime.resolve_token(args.token, required=True)
205
279
  payload = runtime.load_json_input(
@@ -326,6 +400,9 @@ def register_columns_subcommands(
326
400
  pcc.add_argument("--table-id", required=True)
327
401
  pcc.add_argument("--data-json", help="ColumnCreate payload JSON")
328
402
  pcc.add_argument("--data-file", help="ColumnCreate payload file path")
403
+ pcc.add_argument("--position", type=float, help="Explicit numeric position override")
404
+ pcc.add_argument("--after-column-id", help="Place the new column after this existing column id")
405
+ pcc.add_argument("--before-column-id", help="Place the new column before this existing column id")
329
406
  add_api_common_arguments(pcc)
330
407
  pcc.set_defaults(func=handlers["create"])
331
408
 
@@ -341,9 +418,25 @@ def register_columns_subcommands(
341
418
  pcu.add_argument("--column-id", required=True)
342
419
  pcu.add_argument("--data-json", help="ColumnUpdate payload JSON")
343
420
  pcu.add_argument("--data-file", help="ColumnUpdate payload file path")
421
+ pcu.add_argument("--position", type=float, help="Explicit numeric position override")
344
422
  add_api_common_arguments(pcu)
345
423
  pcu.set_defaults(func=handlers["update"])
346
424
 
425
+ pcm = col_sub.add_parser(
426
+ "move",
427
+ help="Reorder an existing column relative to neighbors",
428
+ description=(
429
+ "Move an existing column by supplying neighbor column ids. "
430
+ "Prefer sending both neighbors when possible for stable placement."
431
+ ),
432
+ )
433
+ pcm.add_argument("--table-id", required=True)
434
+ pcm.add_argument("--column-id", required=True)
435
+ pcm.add_argument("--after-column-id", help="Place the column after this existing column id")
436
+ pcm.add_argument("--before-column-id", help="Place the column before this existing column id")
437
+ add_api_common_arguments(pcm)
438
+ pcm.set_defaults(func=handlers["move"])
439
+
347
440
  pcd = col_sub.add_parser("delete", help="Delete a column and all of its cells")
348
441
  pcd.add_argument("--table-id", required=True)
349
442
  pcd.add_argument("--column-id", required=True)
@@ -379,6 +472,8 @@ def register_columns_subcommands(
379
472
  pcpj.add_argument("--table-id", required=True)
380
473
  pcpj.add_argument("--data-json", help="CreateProjectionsRequest payload JSON")
381
474
  pcpj.add_argument("--data-file", help="CreateProjectionsRequest payload file path")
475
+ pcpj.add_argument("--after-column-id", help="Place the new projection group after this existing column id")
476
+ pcpj.add_argument("--before-column-id", help="Place the new projection group before this existing column id")
382
477
  add_api_common_arguments(pcpj)
383
478
  pcpj.set_defaults(func=handlers["projections"])
384
479
 
@@ -1,6 +1,6 @@
1
1
  # Autotouch CLI Reference
2
2
 
3
- Generated from the installed parser for `autotouch-cli` `0.2.48`.
3
+ Generated from the installed parser for `autotouch-cli` `0.2.50`.
4
4
  Manifest schema version: `2`.
5
5
 
6
6
  ## Output Modes
@@ -614,10 +614,10 @@ Column operations
614
614
  - Auth: `varies_by_subcommand`
615
615
  - Stability: `stable`
616
616
  - Destructive: `no`
617
- - Subcommands: `list, create, update, delete, projections, test-http-request, run, stop, run-next, estimate, recipe`
617
+ - Subcommands: `list, create, update, move, delete, projections, test-http-request, run, stop, run-next, estimate, recipe`
618
618
  - Example:
619
619
  - `autotouch columns [-h]
620
- {list,create,update,delete,projections,test-http-request,run,stop,run-next,estimate,recipe} ...`
620
+ {list,create,update,move,delete,projections,test-http-request,run,stop,run-next,estimate,recipe} ...`
621
621
 
622
622
  #### `autotouch columns create`
623
623
 
@@ -631,9 +631,11 @@ Create a column
631
631
  - Example:
632
632
  - `autotouch columns create [-h] --table-id TABLE_ID
633
633
  [--data-json DATA_JSON]
634
- [--data-file DATA_FILE] [--base-url BASE_URL]
635
- [--token TOKEN] [--use-x-api-key]
636
- [--timeout TIMEOUT]
634
+ [--data-file DATA_FILE] [--position POSITION]
635
+ [--after-column-id AFTER_COLUMN_ID]
636
+ [--before-column-id BEFORE_COLUMN_ID]
637
+ [--base-url BASE_URL] [--token TOKEN]
638
+ [--use-x-api-key] [--timeout TIMEOUT]
637
639
  [--output {json,ndjson,human}] [--compact]
638
640
  [--select SELECT |
639
641
  --json-pointer JSON_POINTER] [--verbose]`
@@ -641,6 +643,9 @@ Create a column
641
643
  - `--table-id` (required; kind=string)
642
644
  - `--data-json` (kind=json; input=json): ColumnCreate payload JSON
643
645
  - `--data-file` (kind=file; input=file): ColumnCreate payload file path
646
+ - `--position` (kind=number): Explicit numeric position override
647
+ - `--after-column-id` (kind=string): Place the new column after this existing column id
648
+ - `--before-column-id` (kind=string): Place the new column before this existing column id
644
649
  - `--base-url` (kind=string; default=https://app.autotouch.ai): API base URL (default: https://app.autotouch.ai)
645
650
  - `--token` (kind=string; sensitive): Developer API key / JWT token
646
651
  - `--use-x-api-key` (kind=boolean; when omitted=False; when present=True): Send token via X-API-Key header
@@ -757,6 +762,41 @@ List table columns
757
762
  - `--json-pointer` (kind=string): Extract a JSON pointer from the final result (for example: /id)
758
763
  - `--verbose` (kind=boolean; when omitted=False; when present=True): Print request metadata to stderr
759
764
 
765
+ #### `autotouch columns move`
766
+
767
+ Reorder an existing column relative to neighbors
768
+
769
+ Move an existing column by supplying neighbor column ids. Prefer sending both neighbors when possible for stable placement.
770
+
771
+ - Auth: `developer_key_or_user_session`
772
+ - Stability: `stable`
773
+ - Destructive: `no`
774
+ - Required flags: `--table-id, --column-id`
775
+ - Output modes: `json, ndjson, human`
776
+ - Example:
777
+ - `autotouch columns move [-h] --table-id TABLE_ID --column-id COLUMN_ID
778
+ [--after-column-id AFTER_COLUMN_ID]
779
+ [--before-column-id BEFORE_COLUMN_ID]
780
+ [--base-url BASE_URL] [--token TOKEN]
781
+ [--use-x-api-key] [--timeout TIMEOUT]
782
+ [--output {json,ndjson,human}] [--compact]
783
+ [--select SELECT | --json-pointer JSON_POINTER]
784
+ [--verbose]`
785
+ - Options:
786
+ - `--table-id` (required; kind=string)
787
+ - `--column-id` (required; kind=string)
788
+ - `--after-column-id` (kind=string): Place the column after this existing column id
789
+ - `--before-column-id` (kind=string): Place the column before this existing column id
790
+ - `--base-url` (kind=string; default=https://app.autotouch.ai): API base URL (default: https://app.autotouch.ai)
791
+ - `--token` (kind=string; sensitive): Developer API key / JWT token
792
+ - `--use-x-api-key` (kind=boolean; when omitted=False; when present=True): Send token via X-API-Key header
793
+ - `--timeout` (kind=integer; default=30): HTTP timeout in seconds
794
+ - `--output` (kind=string; choices=json,ndjson,human; default=json): Output mode
795
+ - `--compact` (kind=boolean; when omitted=False; when present=True): Print compact JSON
796
+ - `--select` (kind=string): Extract a dotted field path from the final result (for example: id or items.0.id)
797
+ - `--json-pointer` (kind=string): Extract a JSON pointer from the final result (for example: /id)
798
+ - `--verbose` (kind=boolean; when omitted=False; when present=True): Print request metadata to stderr
799
+
760
800
  #### `autotouch columns projections`
761
801
 
762
802
  Create JSON projection columns
@@ -774,6 +814,8 @@ Do not use `autotouch columns create` with `kind: "projection"` and empty `confi
774
814
  - `autotouch columns projections [-h] --table-id TABLE_ID
775
815
  [--data-json DATA_JSON]
776
816
  [--data-file DATA_FILE]
817
+ [--after-column-id AFTER_COLUMN_ID]
818
+ [--before-column-id BEFORE_COLUMN_ID]
777
819
  [--base-url BASE_URL] [--token TOKEN]
778
820
  [--use-x-api-key] [--timeout TIMEOUT]
779
821
  [--output {json,ndjson,human}]
@@ -802,6 +844,8 @@ Each item must include `key`, `label`, `sourceColumnId`, and `path`.
802
844
  - `--table-id` (required; kind=string)
803
845
  - `--data-json` (kind=json; input=json): CreateProjectionsRequest payload JSON
804
846
  - `--data-file` (kind=file; input=file): CreateProjectionsRequest payload file path
847
+ - `--after-column-id` (kind=string): Place the new projection group after this existing column id
848
+ - `--before-column-id` (kind=string): Place the new projection group before this existing column id
805
849
  - `--base-url` (kind=string; default=https://app.autotouch.ai): API base URL (default: https://app.autotouch.ai)
806
850
  - `--token` (kind=string; sensitive): Developer API key / JWT token
807
851
  - `--use-x-api-key` (kind=boolean; when omitted=False; when present=True): Send token via X-API-Key header
@@ -1039,9 +1083,9 @@ Update a column definition. Nested config keys merge into the existing config, s
1039
1083
  - Example:
1040
1084
  - `autotouch columns update [-h] --table-id TABLE_ID --column-id COLUMN_ID
1041
1085
  [--data-json DATA_JSON]
1042
- [--data-file DATA_FILE] [--base-url BASE_URL]
1043
- [--token TOKEN] [--use-x-api-key]
1044
- [--timeout TIMEOUT]
1086
+ [--data-file DATA_FILE] [--position POSITION]
1087
+ [--base-url BASE_URL] [--token TOKEN]
1088
+ [--use-x-api-key] [--timeout TIMEOUT]
1045
1089
  [--output {json,ndjson,human}] [--compact]
1046
1090
  [--select SELECT |
1047
1091
  --json-pointer JSON_POINTER] [--verbose]`
@@ -1050,6 +1094,7 @@ Update a column definition. Nested config keys merge into the existing config, s
1050
1094
  - `--column-id` (required; kind=string)
1051
1095
  - `--data-json` (kind=json; input=json): ColumnUpdate payload JSON
1052
1096
  - `--data-file` (kind=file; input=file): ColumnUpdate payload file path
1097
+ - `--position` (kind=number): Explicit numeric position override
1053
1098
  - `--base-url` (kind=string; default=https://app.autotouch.ai): API base URL (default: https://app.autotouch.ai)
1054
1099
  - `--token` (kind=string; sensitive): Developer API key / JWT token
1055
1100
  - `--use-x-api-key` (kind=boolean; when omitted=False; when present=True): Send token via X-API-Key header
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.2.48",
2
+ "version": "0.2.50",
3
3
  "manifest_schema_version": 2,
4
4
  "entry_points": {
5
5
  "autotouch": "autotouch_cli.cli:main",
@@ -12980,6 +12980,7 @@
12980
12980
  "list",
12981
12981
  "create",
12982
12982
  "update",
12983
+ "move",
12983
12984
  "delete",
12984
12985
  "projections",
12985
12986
  "test-http-request",
@@ -12995,7 +12996,7 @@
12995
12996
  "output_contract": null,
12996
12997
  "availability": null,
12997
12998
  "examples": [
12998
- "autotouch columns [-h]\n {list,create,update,delete,projections,test-http-request,run,stop,run-next,estimate,recipe} ..."
12999
+ "autotouch columns [-h]\n {list,create,update,move,delete,projections,test-http-request,run,stop,run-next,estimate,recipe} ..."
12999
13000
  ],
13000
13001
  "stability": "stable",
13001
13002
  "handler": null
@@ -13236,6 +13237,39 @@
13236
13237
  ],
13237
13238
  "takes_value": true
13238
13239
  },
13240
+ {
13241
+ "dest": "position",
13242
+ "required": false,
13243
+ "help": "Explicit numeric position override",
13244
+ "kind": "number",
13245
+ "action": "store",
13246
+ "flags": [
13247
+ "--position"
13248
+ ],
13249
+ "takes_value": true
13250
+ },
13251
+ {
13252
+ "dest": "after_column_id",
13253
+ "required": false,
13254
+ "help": "Place the new column after this existing column id",
13255
+ "kind": "string",
13256
+ "action": "store",
13257
+ "flags": [
13258
+ "--after-column-id"
13259
+ ],
13260
+ "takes_value": true
13261
+ },
13262
+ {
13263
+ "dest": "before_column_id",
13264
+ "required": false,
13265
+ "help": "Place the new column before this existing column id",
13266
+ "kind": "string",
13267
+ "action": "store",
13268
+ "flags": [
13269
+ "--before-column-id"
13270
+ ],
13271
+ "takes_value": true
13272
+ },
13239
13273
  {
13240
13274
  "dest": "base_url",
13241
13275
  "required": false,
@@ -13389,7 +13423,7 @@
13389
13423
  },
13390
13424
  "availability": null,
13391
13425
  "examples": [
13392
- "autotouch columns create [-h] --table-id TABLE_ID\n [--data-json DATA_JSON]\n [--data-file DATA_FILE] [--base-url BASE_URL]\n [--token TOKEN] [--use-x-api-key]\n [--timeout TIMEOUT]\n [--output {json,ndjson,human}] [--compact]\n [--select SELECT |\n --json-pointer JSON_POINTER] [--verbose]"
13426
+ "autotouch columns create [-h] --table-id TABLE_ID\n [--data-json DATA_JSON]\n [--data-file DATA_FILE] [--position POSITION]\n [--after-column-id AFTER_COLUMN_ID]\n [--before-column-id BEFORE_COLUMN_ID]\n [--base-url BASE_URL] [--token TOKEN]\n [--use-x-api-key] [--timeout TIMEOUT]\n [--output {json,ndjson,human}] [--compact]\n [--select SELECT |\n --json-pointer JSON_POINTER] [--verbose]"
13393
13427
  ],
13394
13428
  "stability": "stable",
13395
13429
  "handler": "cmd_columns_create"
@@ -13457,6 +13491,17 @@
13457
13491
  ],
13458
13492
  "takes_value": true
13459
13493
  },
13494
+ {
13495
+ "dest": "position",
13496
+ "required": false,
13497
+ "help": "Explicit numeric position override",
13498
+ "kind": "number",
13499
+ "action": "store",
13500
+ "flags": [
13501
+ "--position"
13502
+ ],
13503
+ "takes_value": true
13504
+ },
13460
13505
  {
13461
13506
  "dest": "base_url",
13462
13507
  "required": false,
@@ -13610,11 +13655,230 @@
13610
13655
  },
13611
13656
  "availability": null,
13612
13657
  "examples": [
13613
- "autotouch columns update [-h] --table-id TABLE_ID --column-id COLUMN_ID\n [--data-json DATA_JSON]\n [--data-file DATA_FILE] [--base-url BASE_URL]\n [--token TOKEN] [--use-x-api-key]\n [--timeout TIMEOUT]\n [--output {json,ndjson,human}] [--compact]\n [--select SELECT |\n --json-pointer JSON_POINTER] [--verbose]"
13658
+ "autotouch columns update [-h] --table-id TABLE_ID --column-id COLUMN_ID\n [--data-json DATA_JSON]\n [--data-file DATA_FILE] [--position POSITION]\n [--base-url BASE_URL] [--token TOKEN]\n [--use-x-api-key] [--timeout TIMEOUT]\n [--output {json,ndjson,human}] [--compact]\n [--select SELECT |\n --json-pointer JSON_POINTER] [--verbose]"
13614
13659
  ],
13615
13660
  "stability": "stable",
13616
13661
  "handler": "cmd_columns_update"
13617
13662
  },
13663
+ "columns.move": {
13664
+ "canonical": [
13665
+ "autotouch",
13666
+ "columns",
13667
+ "move"
13668
+ ],
13669
+ "aliases": [],
13670
+ "group": "columns",
13671
+ "help": "Reorder an existing column relative to neighbors",
13672
+ "description": "Move an existing column by supplying neighbor column ids. Prefer sending both neighbors when possible for stable placement.",
13673
+ "notes": null,
13674
+ "required_flags": [
13675
+ "--table-id",
13676
+ "--column-id"
13677
+ ],
13678
+ "positionals": [],
13679
+ "options": [
13680
+ {
13681
+ "dest": "table_id",
13682
+ "required": true,
13683
+ "help": null,
13684
+ "kind": "string",
13685
+ "action": "store",
13686
+ "flags": [
13687
+ "--table-id"
13688
+ ],
13689
+ "takes_value": true
13690
+ },
13691
+ {
13692
+ "dest": "column_id",
13693
+ "required": true,
13694
+ "help": null,
13695
+ "kind": "string",
13696
+ "action": "store",
13697
+ "flags": [
13698
+ "--column-id"
13699
+ ],
13700
+ "takes_value": true
13701
+ },
13702
+ {
13703
+ "dest": "after_column_id",
13704
+ "required": false,
13705
+ "help": "Place the column after this existing column id",
13706
+ "kind": "string",
13707
+ "action": "store",
13708
+ "flags": [
13709
+ "--after-column-id"
13710
+ ],
13711
+ "takes_value": true
13712
+ },
13713
+ {
13714
+ "dest": "before_column_id",
13715
+ "required": false,
13716
+ "help": "Place the column before this existing column id",
13717
+ "kind": "string",
13718
+ "action": "store",
13719
+ "flags": [
13720
+ "--before-column-id"
13721
+ ],
13722
+ "takes_value": true
13723
+ },
13724
+ {
13725
+ "dest": "base_url",
13726
+ "required": false,
13727
+ "help": "API base URL (default: https://app.autotouch.ai)",
13728
+ "kind": "string",
13729
+ "action": "store",
13730
+ "default_when_omitted": "https://app.autotouch.ai",
13731
+ "default": "https://app.autotouch.ai",
13732
+ "flags": [
13733
+ "--base-url"
13734
+ ],
13735
+ "takes_value": true
13736
+ },
13737
+ {
13738
+ "dest": "token",
13739
+ "required": false,
13740
+ "help": "Developer API key / JWT token",
13741
+ "kind": "string",
13742
+ "action": "store",
13743
+ "sensitive": true,
13744
+ "flags": [
13745
+ "--token"
13746
+ ],
13747
+ "takes_value": true
13748
+ },
13749
+ {
13750
+ "dest": "use_x_api_key",
13751
+ "required": false,
13752
+ "help": "Send token via X-API-Key header",
13753
+ "kind": "boolean",
13754
+ "action": "store_true",
13755
+ "nargs": 0,
13756
+ "default_when_omitted": false,
13757
+ "value_when_present": true,
13758
+ "flags": [
13759
+ "--use-x-api-key"
13760
+ ],
13761
+ "takes_value": false
13762
+ },
13763
+ {
13764
+ "dest": "timeout",
13765
+ "required": false,
13766
+ "help": "HTTP timeout in seconds",
13767
+ "kind": "integer",
13768
+ "action": "store",
13769
+ "default_when_omitted": 30,
13770
+ "default": 30,
13771
+ "flags": [
13772
+ "--timeout"
13773
+ ],
13774
+ "takes_value": true
13775
+ },
13776
+ {
13777
+ "dest": "output",
13778
+ "required": false,
13779
+ "help": "Output mode",
13780
+ "kind": "string",
13781
+ "action": "store",
13782
+ "choices": [
13783
+ "json",
13784
+ "ndjson",
13785
+ "human"
13786
+ ],
13787
+ "default_when_omitted": "json",
13788
+ "default": "json",
13789
+ "flags": [
13790
+ "--output"
13791
+ ],
13792
+ "takes_value": true
13793
+ },
13794
+ {
13795
+ "dest": "compact",
13796
+ "required": false,
13797
+ "help": "Print compact JSON",
13798
+ "kind": "boolean",
13799
+ "action": "store_true",
13800
+ "nargs": 0,
13801
+ "default_when_omitted": false,
13802
+ "value_when_present": true,
13803
+ "flags": [
13804
+ "--compact"
13805
+ ],
13806
+ "takes_value": false
13807
+ },
13808
+ {
13809
+ "dest": "select",
13810
+ "required": false,
13811
+ "help": "Extract a dotted field path from the final result (for example: id or items.0.id)",
13812
+ "kind": "string",
13813
+ "action": "store",
13814
+ "flags": [
13815
+ "--select"
13816
+ ],
13817
+ "takes_value": true
13818
+ },
13819
+ {
13820
+ "dest": "json_pointer",
13821
+ "required": false,
13822
+ "help": "Extract a JSON pointer from the final result (for example: /id)",
13823
+ "kind": "string",
13824
+ "action": "store",
13825
+ "flags": [
13826
+ "--json-pointer"
13827
+ ],
13828
+ "takes_value": true
13829
+ },
13830
+ {
13831
+ "dest": "verbose",
13832
+ "required": false,
13833
+ "help": "Print request metadata to stderr",
13834
+ "kind": "boolean",
13835
+ "action": "store_true",
13836
+ "nargs": 0,
13837
+ "default_when_omitted": false,
13838
+ "value_when_present": true,
13839
+ "flags": [
13840
+ "--verbose"
13841
+ ],
13842
+ "takes_value": false
13843
+ }
13844
+ ],
13845
+ "mutually_exclusive_groups": [
13846
+ {
13847
+ "required": false,
13848
+ "options": [
13849
+ "--select",
13850
+ "--json-pointer"
13851
+ ]
13852
+ }
13853
+ ],
13854
+ "subcommands": [],
13855
+ "leaf_command": true,
13856
+ "auth_mode": "developer_key_or_user_session",
13857
+ "destructive": false,
13858
+ "output_contract": {
13859
+ "modes": [
13860
+ "json",
13861
+ "ndjson",
13862
+ "human"
13863
+ ],
13864
+ "json": {
13865
+ "single_document": true
13866
+ },
13867
+ "ndjson": {
13868
+ "streaming": true,
13869
+ "recommended_for": "progress updates / watch flows"
13870
+ },
13871
+ "human": {
13872
+ "interactive": true
13873
+ }
13874
+ },
13875
+ "availability": null,
13876
+ "examples": [
13877
+ "autotouch columns move [-h] --table-id TABLE_ID --column-id COLUMN_ID\n [--after-column-id AFTER_COLUMN_ID]\n [--before-column-id BEFORE_COLUMN_ID]\n [--base-url BASE_URL] [--token TOKEN]\n [--use-x-api-key] [--timeout TIMEOUT]\n [--output {json,ndjson,human}] [--compact]\n [--select SELECT | --json-pointer JSON_POINTER]\n [--verbose]"
13878
+ ],
13879
+ "stability": "stable",
13880
+ "handler": "cmd_columns_move"
13881
+ },
13618
13882
  "columns.delete": {
13619
13883
  "canonical": [
13620
13884
  "autotouch",
@@ -13877,6 +14141,28 @@
13877
14141
  ],
13878
14142
  "takes_value": true
13879
14143
  },
14144
+ {
14145
+ "dest": "after_column_id",
14146
+ "required": false,
14147
+ "help": "Place the new projection group after this existing column id",
14148
+ "kind": "string",
14149
+ "action": "store",
14150
+ "flags": [
14151
+ "--after-column-id"
14152
+ ],
14153
+ "takes_value": true
14154
+ },
14155
+ {
14156
+ "dest": "before_column_id",
14157
+ "required": false,
14158
+ "help": "Place the new projection group before this existing column id",
14159
+ "kind": "string",
14160
+ "action": "store",
14161
+ "flags": [
14162
+ "--before-column-id"
14163
+ ],
14164
+ "takes_value": true
14165
+ },
13880
14166
  {
13881
14167
  "dest": "base_url",
13882
14168
  "required": false,
@@ -14030,7 +14316,7 @@
14030
14316
  },
14031
14317
  "availability": null,
14032
14318
  "examples": [
14033
- "autotouch columns projections [-h] --table-id TABLE_ID\n [--data-json DATA_JSON]\n [--data-file DATA_FILE]\n [--base-url BASE_URL] [--token TOKEN]\n [--use-x-api-key] [--timeout TIMEOUT]\n [--output {json,ndjson,human}]\n [--compact] [--select SELECT |\n --json-pointer JSON_POINTER] [--verbose]"
14319
+ "autotouch columns projections [-h] --table-id TABLE_ID\n [--data-json DATA_JSON]\n [--data-file DATA_FILE]\n [--after-column-id AFTER_COLUMN_ID]\n [--before-column-id BEFORE_COLUMN_ID]\n [--base-url BASE_URL] [--token TOKEN]\n [--use-x-api-key] [--timeout TIMEOUT]\n [--output {json,ndjson,human}]\n [--compact] [--select SELECT |\n --json-pointer JSON_POINTER] [--verbose]"
14034
14320
  ],
14035
14321
  "stability": "stable",
14036
14322
  "handler": "cmd_columns_projections"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autotouch-cli
3
- Version: 0.2.48
3
+ Version: 0.2.50
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
@@ -157,7 +157,7 @@ Only send `user_schema` / `response_schema` when you intentionally want to overr
157
157
 
158
158
  ## Docs
159
159
 
160
- - Full CLI reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/reference/autotouch-cli.md
161
- - Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/guides/autotouch-cli-agent-playbook.md
162
- - Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/reference/tables-api.md
163
- - Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/platform/authentication.md
160
+ - Full CLI reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.50/docs/research-table/reference/autotouch-cli.md
161
+ - Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.50/docs/research-table/guides/autotouch-cli-agent-playbook.md
162
+ - Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.50/docs/research-table/reference/tables-api.md
163
+ - Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.50/docs/platform/authentication.md
@@ -151,6 +151,12 @@ def _text(value: Any) -> str:
151
151
  return str(value or "").strip()
152
152
 
153
153
 
154
+ def _mapping_text(value: Any) -> str:
155
+ if isinstance(value, dict):
156
+ return _text(value.get("column"))
157
+ return _text(value)
158
+
159
+
154
160
  def _llm_provider_values() -> Tuple[str, ...]:
155
161
  return ("gemini", "xai", "openai", "anthropic", "groq")
156
162
 
@@ -515,6 +521,7 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
515
521
  },
516
522
  recipe_notes=(
517
523
  "For non-LinkedIn lookup, use lookupStrategy=domain/company with firstName+lastName+domain/company fields.",
524
+ "Primitive source columns map directly. If an upstream source column stores structured JSON, map it as an object with column + path, for example {\"column\": \"linkedin_lookup\", \"path\": \"linkedin_url\"}.",
518
525
  ),
519
526
  column_type={
520
527
  "type": "email_finder",
@@ -541,6 +548,13 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
541
548
  "strategy_field": "config.strategy",
542
549
  "lookup_strategy_field": "config.lookupStrategy",
543
550
  "input_fields": ["config.linkedinUrl", "config.firstName", "config.lastName", "config.company", "config.domain"],
551
+ "structured_source_mapping": {
552
+ "rule": "primitive columns map directly; structured columns use {column, path}",
553
+ "examples": [
554
+ {"linkedinUrl": {"column": "linkedin_lookup", "path": "linkedin_url"}},
555
+ {"emailColumn": {"column": "email_validation", "path": "response"}},
556
+ ],
557
+ },
544
558
  },
545
559
  composition_contract={
546
560
  "consumes": {
@@ -583,6 +597,7 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
583
597
  },
584
598
  recipe_notes=(
585
599
  "You can use linkedinUrl or email/workEmail/personalEmail inputs.",
600
+ "Primitive source columns map directly. If an upstream source column stores structured JSON, map it as an object with column + path, for example {\"column\": \"linkedin_lookup\", \"path\": \"linkedin_url\"}.",
586
601
  ),
587
602
  column_type={
588
603
  "type": "phone_finder",
@@ -616,6 +631,13 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
616
631
  "config.lastName",
617
632
  "config.company",
618
633
  ],
634
+ "structured_source_mapping": {
635
+ "rule": "primitive columns map directly; structured columns use {column, path}",
636
+ "examples": [
637
+ {"linkedinUrl": {"column": "linkedin_lookup", "path": "linkedin_url"}},
638
+ {"phoneColumn": {"column": "mobile_phone", "path": "mobile_number"}},
639
+ ],
640
+ },
619
641
  },
620
642
  composition_contract={
621
643
  "consumes": {
@@ -662,6 +684,7 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
662
684
  },
663
685
  recipe_notes=(
664
686
  "Add more targeting keys as needed (jobFunctions, seniorities, keywords, excludeKeywords, skills).",
687
+ "Primitive source columns map directly. If companyDomain or other mapped inputs come from structured JSON, use {\"column\": \"...\", \"path\": \"...\"} instead of a plain string column key.",
665
688
  ),
666
689
  column_type={
667
690
  "type": "lead_finder",
@@ -687,6 +710,12 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
687
710
  "source_mode_field": "config.sourceMode",
688
711
  "company_domain_field": "config.companyDomain",
689
712
  "max_results_field": "config.maxResults",
713
+ "structured_source_mapping": {
714
+ "rule": "primitive columns map directly; structured columns use {column, path}",
715
+ "examples": [
716
+ {"companyDomain": {"column": "company_lookup", "path": "domain"}},
717
+ ],
718
+ },
690
719
  },
691
720
  composition_contract={
692
721
  "consumes": {
@@ -758,7 +787,7 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
758
787
  "companyDomain is required; LinkedIn is optional.",
759
788
  "Include at least one usable hard-identity mapping such as LinkedIn, email, or phone.",
760
789
  "If companyDomain is missing in the table, derive or enrich that domain column first.",
761
- "Primitive source columns map directly. Structured JSON columns must specify an explicit path such as work_email.response or mobile_phone.mobile_number.",
790
+ "Primitive source columns map directly. If a mapped source column stores structured JSON, send an object with column + path, for example {\"column\": \"work_email\", \"path\": \"response\"} or {\"column\": \"mobile_phone\", \"path\": \"mobile_number\"}.",
762
791
  "Add to CRM is optional and non-billable.",
763
792
  "Creating add_to_crm after upstream email/phone/lead columns already finished does not replay those older source updates; run add_to_crm explicitly or rerun the upstream source column.",
764
793
  ),
@@ -785,18 +814,19 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
785
814
  "eligibility": "company domain plus at least one valid LinkedIn URL, email, or phone must resolve from mapped source columns",
786
815
  "replay_behavior": "source updates only; explicit run required to backfill older upstream results",
787
816
  "structured_source_mapping": {
788
- "rule": "primitive columns map directly; structured columns require explicit path",
789
- "field": "config.fieldMappings.*.path",
817
+ "rule": "primitive columns map directly; structured columns use {column, path}",
818
+ "field": "config.fieldMappings.*",
790
819
  "examples": [
791
- "emailAddresses[].path = response",
792
- "phoneNumbers[].path = mobile_number",
820
+ {"emailAddresses": [{"column": "work_email", "path": "response", "type": "work"}]},
821
+ {"phoneNumbers": [{"column": "mobile_phone", "path": "mobile_number", "type": "mobile"}]},
822
+ {"linkedinUrl": {"column": "linkedin_lookup", "path": "linkedin_url"}},
793
823
  ],
794
824
  },
795
825
  },
796
826
  composition_contract={
797
827
  "consumes": {
798
828
  "kind": "crm_export_inputs",
799
- "shape": "mapped source row values including company domain plus LinkedIn/email/phone identity; structured source columns must identify the exact JSON key via path",
829
+ "shape": "mapped source row values including company domain plus LinkedIn/email/phone identity; structured source columns use explicit {column, path} mappings to identify the exact field",
800
830
  },
801
831
  "produces": {
802
832
  "kind": "lead_ids",
@@ -1276,30 +1306,39 @@ def validate_column_provider_contract(
1276
1306
 
1277
1307
  if contract.key == "email_finder":
1278
1308
  if not any(
1279
- _text(cfg.get(field_name))
1280
- for field_name in ("linkedinUrl", "firstName", "lastName", "company", "domain")
1309
+ _mapping_text(cfg.get(field_name))
1310
+ for field_name in ("linkedinUrl", "firstName", "lastName", "company", "domain", "emailColumn")
1281
1311
  ):
1282
1312
  raise ProviderContractValidationError(
1283
1313
  "missing_required_field",
1284
- "email_finder requires at least one lookup input such as config.linkedinUrl, config.domain, or name/company fields.",
1314
+ "email_finder requires at least one lookup input such as config.linkedinUrl, config.domain, config.emailColumn, or name/company fields.",
1285
1315
  hint="Use `autotouch columns recipe --type email_finder`.",
1286
1316
  )
1287
1317
  return contract
1288
1318
 
1289
1319
  if contract.key == "phone_finder":
1290
1320
  if not any(
1291
- _text(cfg.get(field_name))
1292
- for field_name in ("linkedinUrl", "email", "workEmail", "personalEmail", "firstName", "lastName", "company")
1321
+ _mapping_text(cfg.get(field_name))
1322
+ for field_name in (
1323
+ "linkedinUrl",
1324
+ "email",
1325
+ "workEmail",
1326
+ "personalEmail",
1327
+ "firstName",
1328
+ "lastName",
1329
+ "company",
1330
+ "phoneColumn",
1331
+ )
1293
1332
  ):
1294
1333
  raise ProviderContractValidationError(
1295
1334
  "missing_required_field",
1296
- "phone_finder requires at least one lookup input such as config.linkedinUrl or config.email/workEmail.",
1335
+ "phone_finder requires at least one lookup input such as config.linkedinUrl, config.email/workEmail, or config.phoneColumn.",
1297
1336
  hint="Use `autotouch columns recipe --type phone_finder`.",
1298
1337
  )
1299
1338
  return contract
1300
1339
 
1301
1340
  if contract.key == "lead_finder":
1302
- if not _text(cfg.get("companyDomain")):
1341
+ if not _mapping_text(cfg.get("companyDomain")):
1303
1342
  raise ProviderContractValidationError(
1304
1343
  "missing_required_field",
1305
1344
  "lead_finder requires config.companyDomain.",
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "autotouch-cli"
7
- version = "0.2.48"
7
+ version = "0.2.50"
8
8
  description = "Autotouch Smart Table CLI"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
File without changes