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.
- {autotouch_cli-0.2.45/autotouch_cli.egg-info → autotouch_cli-0.2.46}/PKG-INFO +37 -10
- autotouch_cli-0.2.45/PKG-INFO → autotouch_cli-0.2.46/README.md +20 -18
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/cli.py +1 -1
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/cli_contracts.py +121 -4
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/columns.py +2 -2
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/core/auth.py +4 -3
- autotouch_cli-0.2.46/autotouch_cli/data/CLI_REFERENCE.md +5119 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/data/cli-manifest.json +5444 -484
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/templates.py +3 -3
- autotouch_cli-0.2.45/README.md → autotouch_cli-0.2.46/autotouch_cli.egg-info/PKG-INFO +45 -9
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli.egg-info/requires.txt +3 -0
- autotouch_cli-0.2.46/pyproject.toml +46 -0
- autotouch_cli-0.2.45/autotouch_cli/data/CLI_REFERENCE.md +0 -5118
- autotouch_cli-0.2.45/pyproject.toml +0 -25
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/MANIFEST.in +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/__init__.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/__init__.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/auth.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/cells.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/jobs.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/leads.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/linkedin.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/prompts.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/rows.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/search.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/sequences.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/tables.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/tasks.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/webhooks.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/commands/workspace_secrets.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/core/__init__.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/core/config.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/core/http.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/core/io.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/core/output.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/core/polling.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/mongo_status.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/parser_groups.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli/sequence_support.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli.egg-info/SOURCES.txt +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli.egg-info/dependency_links.txt +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli.egg-info/entry_points.txt +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_cli.egg-info/top_level.txt +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_shared/__init__.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_shared/linkedin_contract.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_shared/provider_registry.py +0 -0
- {autotouch_cli-0.2.45 → autotouch_cli-0.2.46}/autotouch_shared/search_contract.py +0 -0
- {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.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
125
|
-
- Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.
|
|
126
|
-
- Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.
|
|
127
|
-
- Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
125
|
-
- Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.
|
|
126
|
-
- Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.
|
|
127
|
-
- Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.
|
|
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="
|
|
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
|
|
139
|
-
|
|
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"] =
|
|
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
|
|
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="
|
|
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
|
|
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
|
|
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
|
-
|