autotouch-cli 0.2.45__tar.gz → 0.2.46__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. {autotouch_cli-0.2.45/autotouch_cli.egg-info → autotouch_cli-0.2.46}/PKG-INFO +37 -10
  2. autotouch_cli-0.2.45/PKG-INFO → autotouch_cli-0.2.46/README.md +20 -18
  3. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/cli.py +1 -1
  4. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/cli_contracts.py +121 -4
  5. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/columns.py +2 -2
  6. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/core/auth.py +4 -3
  7. autotouch_cli-0.2.46/autotouch_cli/data/CLI_REFERENCE.md +5119 -0
  8. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/data/cli-manifest.json +5444 -484
  9. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/templates.py +3 -3
  10. autotouch_cli-0.2.45/README.md → autotouch_cli-0.2.46/autotouch_cli.egg-info/PKG-INFO +45 -9
  11. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli.egg-info/requires.txt +3 -0
  12. autotouch_cli-0.2.46/pyproject.toml +46 -0
  13. autotouch_cli-0.2.45/autotouch_cli/data/CLI_REFERENCE.md +0 -5118
  14. autotouch_cli-0.2.45/pyproject.toml +0 -25
  15. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/MANIFEST.in +0 -0
  16. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/__init__.py +0 -0
  17. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/__init__.py +0 -0
  18. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/auth.py +0 -0
  19. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/cells.py +0 -0
  20. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/jobs.py +0 -0
  21. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/leads.py +0 -0
  22. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/linkedin.py +0 -0
  23. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/prompts.py +0 -0
  24. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/rows.py +0 -0
  25. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/search.py +0 -0
  26. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/sequences.py +0 -0
  27. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/tables.py +0 -0
  28. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/tasks.py +0 -0
  29. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/webhooks.py +0 -0
  30. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/workspace_secrets.py +0 -0
  31. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/core/__init__.py +0 -0
  32. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/core/config.py +0 -0
  33. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/core/http.py +0 -0
  34. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/core/io.py +0 -0
  35. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/core/output.py +0 -0
  36. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/core/polling.py +0 -0
  37. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/mongo_status.py +0 -0
  38. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/parser_groups.py +0 -0
  39. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/sequence_support.py +0 -0
  40. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli.egg-info/SOURCES.txt +0 -0
  41. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli.egg-info/dependency_links.txt +0 -0
  42. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli.egg-info/entry_points.txt +0 -0
  43. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli.egg-info/top_level.txt +0 -0
  44. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_shared/__init__.py +0 -0
  45. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_shared/linkedin_contract.py +0 -0
  46. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_shared/provider_registry.py +0 -0
  47. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_shared/search_contract.py +0 -0
  48. {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/setup.cfg +0 -0
@@ -1,11 +1,27 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autotouch-cli
3
- Version: 0.2.45
3
+ Version: 0.2.46
4
4
  Summary: Autotouch Smart Table CLI
5
+ Project-URL: Homepage, https://app.autotouch.ai
6
+ Project-URL: Documentation, https://github.com/nicolonic/autotouch_main/tree/main/docs/research-table/reference
7
+ Project-URL: Source, https://github.com/nicolonic/autotouch_main
8
+ Keywords: autotouch,smart-table,cli,automation,api
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Classifier: Topic :: Utilities
5
19
  Requires-Python: >=3.9
6
20
  Description-Content-Type: text/markdown
7
21
  Requires-Dist: requests>=2.31.0
8
22
  Requires-Dist: python-dotenv>=1.0.0
23
+ Provides-Extra: mongo
24
+ Requires-Dist: pymongo>=4.7; extra == "mongo"
9
25
 
10
26
  # Autotouch CLI
11
27
 
@@ -31,13 +47,15 @@ pip install autotouch-cli
31
47
  Existing developer key:
32
48
 
33
49
  ```bash
34
- autotouch setup --api-key stk_... --base-url https://app.autotouch.ai
50
+ read -s AUTOTOUCH_API_KEY
51
+ export AUTOTOUCH_API_KEY
52
+ autotouch setup --api-key "$AUTOTOUCH_API_KEY" --base-url https://app.autotouch.ai
35
53
  ```
36
54
 
37
55
  Equivalent manual steps:
38
56
 
39
57
  ```bash
40
- autotouch auth set-key --api-key stk_... --base-url https://app.autotouch.ai
58
+ autotouch auth set-key --api-key "$AUTOTOUCH_API_KEY" --base-url https://app.autotouch.ai
41
59
  autotouch auth check --base-url https://app.autotouch.ai
42
60
  ```
43
61
 
@@ -45,23 +63,31 @@ Fresh account:
45
63
 
46
64
  ```bash
47
65
  export AUTOTOUCH_CONFIG_PATH=/tmp/autotouch-audit.json
66
+ read -s AUTOTOUCH_BOOTSTRAP_PASSWORD
67
+ export AUTOTOUCH_BOOTSTRAP_PASSWORD
48
68
 
49
69
  autotouch auth bootstrap \
50
70
  --first-name Ada \
51
71
  --last-name Lovelace \
52
72
  --email ada+audit@example.com \
53
- --password 'use-a-strong-random-password' \
73
+ --password "$AUTOTOUCH_BOOTSTRAP_PASSWORD" \
54
74
  --organization-name "Audit Org" \
55
75
  --save-key
56
76
 
57
77
  autotouch auth check
58
78
  ```
59
79
 
80
+ Config precedence:
81
+ - Explicit flags win over environment variables.
82
+ - Environment variables win over saved config.
83
+ - Saved config wins over built-in defaults.
84
+ - For JSON payload inputs, pass either `--data-json` or `--data-file`, not both.
85
+
60
86
  ## 5-Minute Flow
61
87
 
62
88
  ```bash
63
89
  # 0) First-run setup
64
- autotouch setup --api-key stk_... --base-url https://app.autotouch.ai
90
+ autotouch setup --api-key "$AUTOTOUCH_API_KEY" --base-url https://app.autotouch.ai
65
91
 
66
92
  # 1) Inspect machine-readable contract
67
93
  autotouch capabilities --output json
@@ -85,7 +111,7 @@ COLUMN_ID=$(autotouch columns create --table-id "$TABLE_ID" --data-file column.j
85
111
  JOB_ID=$(autotouch columns run-next \
86
112
  --table-id "$TABLE_ID" \
87
113
  --column-id "$COLUMN_ID" \
88
- --count 10 \
114
+ --count 2 \
89
115
  --show-estimate \
90
116
  --wait \
91
117
  --output json --select job_id)
@@ -118,10 +144,11 @@ For automation or agent-driven setup, use:
118
144
  - `autotouch capabilities --output json` for provider/workflow contracts
119
145
  - `autotouch rows list` / `autotouch rows get` / `autotouch cells get` for read-back and audit
120
146
  - `autotouch sequences ...` and `autotouch tasks ...` for sequence/task workflows
147
+ - `pip install 'autotouch-cli[mongo]'` if you need the Mongo-backed `status` / `watch` commands
121
148
 
122
149
  ## Docs
123
150
 
124
- - Full CLI reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.45/docs/research-table/reference/autotouch-cli.md
125
- - Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.45/docs/research-table/guides/autotouch-cli-agent-playbook.md
126
- - Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.45/docs/research-table/reference/tables-api.md
127
- - Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.45/docs/platform/authentication.md
151
+ - Full CLI reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/research-table/reference/autotouch-cli.md
152
+ - Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/research-table/guides/autotouch-cli-agent-playbook.md
153
+ - Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/research-table/reference/tables-api.md
154
+ - Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/platform/authentication.md
@@ -1,12 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: autotouch-cli
3
- Version: 0.2.45
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
11
2
 
12
3
  Installable CLI for the Smart Table developer API.
@@ -31,13 +22,15 @@ pip install autotouch-cli
31
22
  Existing developer key:
32
23
 
33
24
  ```bash
34
- autotouch setup --api-key stk_... --base-url https://app.autotouch.ai
25
+ read -s AUTOTOUCH_API_KEY
26
+ export AUTOTOUCH_API_KEY
27
+ autotouch setup --api-key "$AUTOTOUCH_API_KEY" --base-url https://app.autotouch.ai
35
28
  ```
36
29
 
37
30
  Equivalent manual steps:
38
31
 
39
32
  ```bash
40
- autotouch auth set-key --api-key stk_... --base-url https://app.autotouch.ai
33
+ autotouch auth set-key --api-key "$AUTOTOUCH_API_KEY" --base-url https://app.autotouch.ai
41
34
  autotouch auth check --base-url https://app.autotouch.ai
42
35
  ```
43
36
 
@@ -45,23 +38,31 @@ Fresh account:
45
38
 
46
39
  ```bash
47
40
  export AUTOTOUCH_CONFIG_PATH=/tmp/autotouch-audit.json
41
+ read -s AUTOTOUCH_BOOTSTRAP_PASSWORD
42
+ export AUTOTOUCH_BOOTSTRAP_PASSWORD
48
43
 
49
44
  autotouch auth bootstrap \
50
45
  --first-name Ada \
51
46
  --last-name Lovelace \
52
47
  --email ada+audit@example.com \
53
- --password 'use-a-strong-random-password' \
48
+ --password "$AUTOTOUCH_BOOTSTRAP_PASSWORD" \
54
49
  --organization-name "Audit Org" \
55
50
  --save-key
56
51
 
57
52
  autotouch auth check
58
53
  ```
59
54
 
55
+ Config precedence:
56
+ - Explicit flags win over environment variables.
57
+ - Environment variables win over saved config.
58
+ - Saved config wins over built-in defaults.
59
+ - For JSON payload inputs, pass either `--data-json` or `--data-file`, not both.
60
+
60
61
  ## 5-Minute Flow
61
62
 
62
63
  ```bash
63
64
  # 0) First-run setup
64
- autotouch setup --api-key stk_... --base-url https://app.autotouch.ai
65
+ autotouch setup --api-key "$AUTOTOUCH_API_KEY" --base-url https://app.autotouch.ai
65
66
 
66
67
  # 1) Inspect machine-readable contract
67
68
  autotouch capabilities --output json
@@ -85,7 +86,7 @@ COLUMN_ID=$(autotouch columns create --table-id "$TABLE_ID" --data-file column.j
85
86
  JOB_ID=$(autotouch columns run-next \
86
87
  --table-id "$TABLE_ID" \
87
88
  --column-id "$COLUMN_ID" \
88
- --count 10 \
89
+ --count 2 \
89
90
  --show-estimate \
90
91
  --wait \
91
92
  --output json --select job_id)
@@ -118,10 +119,11 @@ For automation or agent-driven setup, use:
118
119
  - `autotouch capabilities --output json` for provider/workflow contracts
119
120
  - `autotouch rows list` / `autotouch rows get` / `autotouch cells get` for read-back and audit
120
121
  - `autotouch sequences ...` and `autotouch tasks ...` for sequence/task workflows
122
+ - `pip install 'autotouch-cli[mongo]'` if you need the Mongo-backed `status` / `watch` commands
121
123
 
122
124
  ## Docs
123
125
 
124
- - Full CLI reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.45/docs/research-table/reference/autotouch-cli.md
125
- - Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.45/docs/research-table/guides/autotouch-cli-agent-playbook.md
126
- - Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.45/docs/research-table/reference/tables-api.md
127
- - Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.45/docs/platform/authentication.md
126
+ - Full CLI reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/research-table/reference/autotouch-cli.md
127
+ - Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/research-table/guides/autotouch-cli-agent-playbook.md
128
+ - Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/research-table/reference/tables-api.md
129
+ - Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/platform/authentication.md
@@ -4218,7 +4218,7 @@ def build_parser() -> argparse.ArgumentParser:
4218
4218
  palias_run_next = sub.add_parser("run-next", help="Alias for: columns run-next")
4219
4219
  palias_run_next.add_argument("--table-id", required=True)
4220
4220
  palias_run_next.add_argument("--column-id", required=True)
4221
- palias_run_next.add_argument("--count", type=int, required=True, help="Exact number of rows to queue")
4221
+ palias_run_next.add_argument("--count", type=int, required=True, help="Maximum number of rows to queue")
4222
4222
  palias_run_next.add_argument("--filters-json", help="Optional JSON object to select from filtered rows")
4223
4223
  palias_run_next.add_argument("--filters-file", help="Optional JSON file to select from filtered rows")
4224
4224
  palias_run_next.add_argument("--page-size", type=int, default=200, help="Rows page size while selecting candidates (max 1000)")
@@ -1,9 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import argparse
4
+ import json
4
5
  from typing import Any, Dict, List, Optional, Tuple
5
6
 
6
7
 
8
+ _CLI_MANIFEST_SCHEMA_VERSION = 2
9
+
10
+
7
11
  _AUTH_MODE_EXACT: Dict[str, str] = {
8
12
  "setup": "none",
9
13
  "auth.bootstrap": "none",
@@ -79,6 +83,80 @@ _OPTIONAL_DEPENDENCY_COMMANDS: Dict[str, Dict[str, Any]] = {
79
83
  },
80
84
  }
81
85
 
86
+ _SENSITIVE_OPTION_TERMS = ("token", "api-key", "api_key", "password", "secret")
87
+
88
+
89
+ def _json_safe_value(value: Any) -> Any:
90
+ try:
91
+ json.dumps(value)
92
+ except (TypeError, ValueError):
93
+ return str(value)
94
+ return value
95
+
96
+
97
+ def _option_input_kind(action: argparse.Action) -> Optional[str]:
98
+ flags = [flag.lower() for flag in getattr(action, "option_strings", []) or []]
99
+ dest = str(getattr(action, "dest", "") or "").lower()
100
+ if any(flag.endswith("-file") or flag == "--file" for flag in flags) or dest.endswith("_file"):
101
+ return "file"
102
+ if any(flag.endswith("-json") for flag in flags) or dest.endswith("_json"):
103
+ return "json"
104
+ if dest in {"out_file", "checkpoint_file"}:
105
+ return "file"
106
+ return None
107
+
108
+
109
+ def _option_kind(action: argparse.Action, *, input_kind: Optional[str]) -> str:
110
+ if isinstance(action, (argparse._StoreTrueAction, argparse._StoreFalseAction)):
111
+ return "boolean"
112
+ if isinstance(action, argparse._CountAction):
113
+ return "integer"
114
+ if input_kind:
115
+ return input_kind
116
+ if getattr(action, "type", None) is int:
117
+ return "integer"
118
+ if getattr(action, "type", None) is float:
119
+ return "number"
120
+ if getattr(action, "nargs", None) in ("*", "+"):
121
+ return "list"
122
+ return "string"
123
+
124
+
125
+ def _option_action_kind(action: argparse.Action) -> str:
126
+ if isinstance(action, argparse._StoreTrueAction):
127
+ return "store_true"
128
+ if isinstance(action, argparse._StoreFalseAction):
129
+ return "store_false"
130
+ if isinstance(action, argparse._AppendAction):
131
+ return "append"
132
+ if isinstance(action, argparse._AppendConstAction):
133
+ return "append_const"
134
+ if isinstance(action, argparse._CountAction):
135
+ return "count"
136
+ if isinstance(action, argparse._StoreConstAction):
137
+ return "store_const"
138
+ return "store"
139
+
140
+
141
+ def _option_is_sensitive(action: argparse.Action) -> bool:
142
+ option_strings = [flag.lower() for flag in getattr(action, "option_strings", []) or []]
143
+ dest = str(getattr(action, "dest", "") or "").lower()
144
+ if isinstance(action, (argparse._StoreTrueAction, argparse._StoreFalseAction, argparse._StoreConstAction, argparse._AppendConstAction)):
145
+ return False
146
+ if dest == "value" or "--value" in option_strings:
147
+ return True
148
+ searchable = " ".join([dest, *option_strings])
149
+ return any(term in searchable for term in _SENSITIVE_OPTION_TERMS)
150
+
151
+
152
+ def _option_accepts_comma_separated(action: argparse.Action) -> bool:
153
+ help_text = str(getattr(action, "help", "") or "").lower()
154
+ return "comma-separated" in help_text
155
+
156
+
157
+ def _option_repeatable(action: argparse.Action) -> bool:
158
+ return isinstance(action, (argparse._AppendAction, argparse._AppendConstAction, argparse._CountAction))
159
+
82
160
 
83
161
  def canonical_subparser_entries(
84
162
  action: argparse._SubParsersAction,
@@ -123,10 +201,14 @@ def action_descriptor(action: argparse.Action) -> Optional[Dict[str, Any]]:
123
201
  if isinstance(action, argparse._SubParsersAction):
124
202
  return None
125
203
 
204
+ input_kind = _option_input_kind(action)
205
+ action_kind = _option_action_kind(action)
126
206
  payload: Dict[str, Any] = {
127
207
  "dest": action.dest,
128
208
  "required": bool(getattr(action, "required", False)),
129
209
  "help": action.help,
210
+ "kind": _option_kind(action, input_kind=input_kind),
211
+ "action": action_kind,
130
212
  }
131
213
  if getattr(action, "choices", None) is not None:
132
214
  payload["choices"] = list(action.choices)
@@ -135,11 +217,29 @@ def action_descriptor(action: argparse.Action) -> Optional[Dict[str, Any]]:
135
217
  if getattr(action, "metavar", None) is not None:
136
218
  payload["metavar"] = action.metavar
137
219
  default_value = getattr(action, "default", argparse.SUPPRESS)
138
- if default_value is not argparse.SUPPRESS and default_value is not None:
139
- payload["default"] = default_value
220
+ if default_value is not argparse.SUPPRESS:
221
+ if default_value is not None or isinstance(action, (argparse._StoreTrueAction, argparse._StoreFalseAction)):
222
+ payload["default_when_omitted"] = _json_safe_value(default_value)
223
+ if default_value is not None and not isinstance(action, (argparse._StoreTrueAction, argparse._StoreFalseAction)):
224
+ payload["default"] = _json_safe_value(default_value)
225
+ if isinstance(action, argparse._StoreTrueAction):
226
+ payload["value_when_present"] = True
227
+ elif isinstance(action, argparse._StoreFalseAction):
228
+ payload["value_when_present"] = False
229
+ if input_kind:
230
+ payload["input_kind"] = input_kind
231
+ if _option_repeatable(action):
232
+ payload["repeatable"] = True
233
+ if _option_accepts_comma_separated(action):
234
+ payload["accepts_comma_separated"] = True
235
+ if _option_is_sensitive(action):
236
+ payload["sensitive"] = True
140
237
  if action.option_strings:
141
238
  payload["flags"] = list(action.option_strings)
142
- payload["takes_value"] = getattr(action, "nargs", None) != 0
239
+ payload["takes_value"] = not isinstance(
240
+ action,
241
+ (argparse._StoreTrueAction, argparse._StoreFalseAction, argparse._StoreConstAction, argparse._AppendConstAction),
242
+ ) and getattr(action, "nargs", None) != 0
143
243
  else:
144
244
  payload["name"] = action.dest
145
245
  payload["positional"] = True
@@ -301,6 +401,7 @@ def collect_cli_command_manifest(
301
401
  def build_cli_manifest(version: str, parser: argparse.ArgumentParser) -> Dict[str, Any]:
302
402
  return {
303
403
  "version": version,
404
+ "manifest_schema_version": _CLI_MANIFEST_SCHEMA_VERSION,
304
405
  "entry_points": {
305
406
  "autotouch": "autotouch_cli.cli:main",
306
407
  "smart-table": "autotouch_cli.cli:main",
@@ -311,11 +412,13 @@ def build_cli_manifest(version: str, parser: argparse.ArgumentParser) -> Dict[st
311
412
 
312
413
  def build_cli_reference_markdown(manifest: Dict[str, Any]) -> str:
313
414
  version = str(manifest.get("version") or "unknown")
415
+ manifest_schema_version = str(manifest.get("manifest_schema_version") or "unknown")
314
416
  commands = manifest.get("commands") if isinstance(manifest.get("commands"), dict) else {}
315
417
  lines: List[str] = [
316
418
  "# Autotouch CLI Reference",
317
419
  "",
318
420
  f"Generated from the installed parser for `autotouch-cli` `{version}`.",
421
+ f"Manifest schema version: `{manifest_schema_version}`.",
319
422
  "",
320
423
  "## Output Modes",
321
424
  "",
@@ -394,9 +497,23 @@ def build_cli_reference_markdown(manifest: Dict[str, Any]) -> str:
394
497
  note_parts: List[str] = []
395
498
  if option.get("required"):
396
499
  note_parts.append("required")
500
+ if option.get("kind"):
501
+ note_parts.append(f"kind={option.get('kind')}")
502
+ if option.get("input_kind"):
503
+ note_parts.append(f"input={option.get('input_kind')}")
504
+ if option.get("repeatable"):
505
+ note_parts.append("repeatable")
506
+ if option.get("accepts_comma_separated"):
507
+ note_parts.append("comma-separated")
508
+ if option.get("sensitive"):
509
+ note_parts.append("sensitive")
510
+ if option.get("action") in {"store_true", "store_false"}:
511
+ note_parts.append(
512
+ f"when omitted={option.get('default_when_omitted')}; when present={option.get('value_when_present')}"
513
+ )
397
514
  if option.get("choices"):
398
515
  note_parts.append(f"choices={','.join(str(v) for v in option.get('choices') or [])}")
399
- if option.get("default") is not None:
516
+ if option.get("default") is not None and option.get("action") not in {"store_true", "store_false"}:
400
517
  note_parts.append(f"default={option.get('default')}")
401
518
  help_value = str(option.get("help") or "").strip()
402
519
  note_text = f" ({'; '.join(note_parts)})" if note_parts else ""
@@ -415,10 +415,10 @@ def register_columns_subcommands(
415
415
  add_api_common_arguments(pcs)
416
416
  pcs.set_defaults(func=handlers["stop"])
417
417
 
418
- pcrn = col_sub.add_parser("run-next", help="Run exactly N selected rows using subset scope")
418
+ pcrn = col_sub.add_parser("run-next", help="Run up to N selected rows using subset scope")
419
419
  pcrn.add_argument("--table-id", required=True)
420
420
  pcrn.add_argument("--column-id", required=True)
421
- pcrn.add_argument("--count", type=int, required=True, help="Exact number of rows to queue")
421
+ pcrn.add_argument("--count", type=int, required=True, help="Maximum number of rows to queue")
422
422
  pcrn.add_argument("--filters-json", help="Optional JSON object to select from filtered rows")
423
423
  pcrn.add_argument("--filters-file", help="Optional JSON file to select from filtered rows")
424
424
  pcrn.add_argument("--page-size", type=int, default=200, help="Rows page size while selecting candidates (max 1000)")
@@ -68,8 +68,9 @@ def print_missing_developer_auth_help() -> None:
68
68
  print(
69
69
  "Fresh-account / isolated audit pattern: "
70
70
  "`export AUTOTOUCH_CONFIG_PATH=/tmp/autotouch-audit.json && "
71
+ "read -s AUTOTOUCH_BOOTSTRAP_PASSWORD && export AUTOTOUCH_BOOTSTRAP_PASSWORD && "
71
72
  "autotouch auth bootstrap --first-name Ada --last-name Lovelace "
72
- "--email ada+audit@example.com --password 'use-a-strong-random-password' "
73
+ "--email ada+audit@example.com --password \"$AUTOTOUCH_BOOTSTRAP_PASSWORD\" "
73
74
  "--organization-name \"Audit Org\" --save-key`",
74
75
  file=sys.stderr,
75
76
  )
@@ -89,8 +90,9 @@ def print_missing_user_session_help() -> None:
89
90
  print(
90
91
  "Fresh-account / isolated audit pattern: "
91
92
  "`export AUTOTOUCH_CONFIG_PATH=/tmp/autotouch-audit.json && "
93
+ "read -s AUTOTOUCH_BOOTSTRAP_PASSWORD && export AUTOTOUCH_BOOTSTRAP_PASSWORD && "
92
94
  "autotouch auth bootstrap --first-name Ada --last-name Lovelace "
93
- "--email ada+audit@example.com --password 'use-a-strong-random-password' "
95
+ "--email ada+audit@example.com --password \"$AUTOTOUCH_BOOTSTRAP_PASSWORD\" "
94
96
  "--organization-name \"Audit Org\" --save-key`",
95
97
  file=sys.stderr,
96
98
  )
@@ -157,4 +159,3 @@ def auth_headers(token: Optional[str], *, use_x_api_key: bool = False) -> Dict[s
157
159
  if use_x_api_key:
158
160
  return {"X-API-Key": token}
159
161
  return {"Authorization": f"Bearer {token}"}
160
-