treadstone-cli 0.2.1__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.
@@ -0,0 +1,34 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ *.egg
8
+
9
+ .venv/
10
+ .env
11
+ .env.test
12
+ .env.local
13
+ .env.demo
14
+ .env.prod
15
+
16
+ .mypy_cache/
17
+ .pytest_cache/
18
+ .ruff_cache/
19
+ .coverage
20
+ htmlcov/
21
+
22
+ *.db
23
+ *.sqlite3
24
+
25
+ openapi.json
26
+ reports/
27
+
28
+ .DS_Store
29
+ Thumbs.db
30
+
31
+ .idea/
32
+ .vscode/
33
+ *.swp
34
+ *.swo
@@ -0,0 +1,222 @@
1
+ Metadata-Version: 2.4
2
+ Name: treadstone-cli
3
+ Version: 0.2.1
4
+ Summary: CLI for the Treadstone sandbox service.
5
+ Requires-Python: >=3.12
6
+ Requires-Dist: click>=8.1
7
+ Requires-Dist: httpx>=0.28.1
8
+ Requires-Dist: rich>=14.0
9
+ Description-Content-Type: text/markdown
10
+
11
+ # Treadstone CLI
12
+
13
+ Command-line interface for the Treadstone sandbox service.
14
+
15
+ ## Installation
16
+
17
+ ### From PyPI
18
+
19
+ ```bash
20
+ pip install treadstone
21
+ ```
22
+
23
+ ### Pre-built binary
24
+
25
+ Download the latest release from [GitHub Releases](https://github.com/earayu/treadstone/releases). The binary is self-contained and does not require Python.
26
+
27
+ ```bash
28
+ # macOS / Linux
29
+ chmod +x treadstone
30
+ sudo mv treadstone /usr/local/bin/
31
+ ```
32
+
33
+ ## Quick start
34
+
35
+ ```bash
36
+ # Check that the server is reachable
37
+ treadstone health
38
+
39
+ # Register an account (first time only)
40
+ treadstone auth register
41
+
42
+ # Log in
43
+ treadstone auth login
44
+
45
+ # Create an API key for non-interactive use
46
+ treadstone api-keys create --name my-key
47
+ # Save the key — it is shown only once
48
+
49
+ # Store the key in config so you don't have to pass it every time
50
+ treadstone config set api_key ts_live_xxxxxxxxxxxx
51
+
52
+ # Create a sandbox
53
+ treadstone sandboxes create --template default --name my-sandbox
54
+
55
+ # List sandboxes
56
+ treadstone sb list
57
+ ```
58
+
59
+ ## Configuration
60
+
61
+ The CLI reads configuration from three sources, in order of priority:
62
+
63
+ | Priority | Source | Example |
64
+ |----------|--------|---------|
65
+ | 1 (highest) | CLI flags | `--base-url https://... --api-key ts_...` |
66
+ | 2 | Environment variables | `TREADSTONE_BASE_URL`, `TREADSTONE_API_KEY` |
67
+ | 3 (lowest) | Config file | `~/.config/treadstone/config.toml` |
68
+
69
+ ### Config file
70
+
71
+ Location: `~/.config/treadstone/config.toml`
72
+
73
+ ```toml
74
+ [default]
75
+ base_url = "https://your-server.example.com"
76
+ api_key = "ts_live_xxxxxxxxxxxx"
77
+ ```
78
+
79
+ You can manage this file with the `config` subcommand:
80
+
81
+ ```bash
82
+ # Set a value
83
+ treadstone config set base_url https://your-server.example.com
84
+ treadstone config set api_key ts_live_xxxxxxxxxxxx
85
+
86
+ # View current settings (api_key is partially masked)
87
+ treadstone config get
88
+
89
+ # View a single key
90
+ treadstone config get base_url
91
+
92
+ # Remove a value
93
+ treadstone config unset api_key
94
+
95
+ # Show config file path
96
+ treadstone config path
97
+ ```
98
+
99
+ ### Environment variables
100
+
101
+ | Variable | Description | Default |
102
+ |----------|-------------|---------|
103
+ | `TREADSTONE_BASE_URL` | Base URL of the Treadstone server | `https://api.treadstone-ai.dev` |
104
+ | `TREADSTONE_API_KEY` | API key for authentication | (none) |
105
+
106
+ ### Global flags
107
+
108
+ | Flag | Description |
109
+ |------|-------------|
110
+ | `--base-url URL` | Override the server URL |
111
+ | `--api-key KEY` | Override the API key |
112
+ | `--json` | Output responses as JSON (useful for scripting) |
113
+ | `--version` | Show CLI version |
114
+ | `--help` | Show help message |
115
+
116
+ ## Commands
117
+
118
+ ### `health`
119
+
120
+ Check if the server is reachable and healthy.
121
+
122
+ ```bash
123
+ treadstone health
124
+ # Server is healthy
125
+ ```
126
+
127
+ ### `auth`
128
+
129
+ Authentication and user management.
130
+
131
+ ```bash
132
+ treadstone auth register # Create a new account
133
+ treadstone auth login # Log in interactively
134
+ treadstone auth logout # Log out
135
+ treadstone auth whoami # Show current user info
136
+ treadstone auth change-password # Change your password
137
+ treadstone auth invite --email user@example.com # Invite a user (admin)
138
+ treadstone auth users # List all users (admin)
139
+ treadstone auth delete-user <user-id> # Delete a user (admin)
140
+ ```
141
+
142
+ ### `sandboxes` (alias: `sb`)
143
+
144
+ Create and manage sandboxes.
145
+
146
+ ```bash
147
+ treadstone sb create --template default --name my-box
148
+ treadstone sb create --template python --label env:dev --persist
149
+ treadstone sb list
150
+ treadstone sb list --label env:prod --limit 10
151
+ treadstone sb get <sandbox-id>
152
+ treadstone sb start <sandbox-id>
153
+ treadstone sb stop <sandbox-id>
154
+ treadstone sb delete <sandbox-id>
155
+ treadstone sb token <sandbox-id> # Get an access token
156
+ treadstone sb token <sandbox-id> --expires-in 7200 # Custom TTL
157
+ ```
158
+
159
+ ### `templates`
160
+
161
+ List available sandbox templates.
162
+
163
+ ```bash
164
+ treadstone templates list
165
+ ```
166
+
167
+ ### `api-keys`
168
+
169
+ Manage long-lived API keys.
170
+
171
+ ```bash
172
+ treadstone api-keys create --name ci-bot
173
+ treadstone api-keys create --name temp --expires-in 86400 # 24h
174
+ treadstone api-keys list
175
+ treadstone api-keys delete <key-id>
176
+ ```
177
+
178
+ ### `config`
179
+
180
+ Manage local CLI configuration.
181
+
182
+ ```bash
183
+ treadstone config set base_url https://...
184
+ treadstone config set api_key ts_...
185
+ treadstone config get
186
+ treadstone config get base_url
187
+ treadstone config unset api_key
188
+ treadstone config path
189
+ ```
190
+
191
+ ## JSON output
192
+
193
+ Pass `--json` before any command to get machine-readable JSON output:
194
+
195
+ ```bash
196
+ treadstone --json sb list
197
+ treadstone --json health
198
+ treadstone --json api-keys list
199
+ ```
200
+
201
+ ## Error handling
202
+
203
+ The CLI displays user-friendly error messages instead of stack traces:
204
+
205
+ ```
206
+ Error: Connection refused.
207
+ Possible causes:
208
+ - The Treadstone server is not running
209
+ - The --base-url or TREADSTONE_BASE_URL is incorrect
210
+ - A firewall or proxy is blocking the connection
211
+ Detail: ...
212
+ ```
213
+
214
+ Common errors:
215
+
216
+ | Error | Cause | Fix |
217
+ |-------|-------|-----|
218
+ | Connection refused | Server not running or wrong URL | Check `treadstone config get base_url` |
219
+ | Request timed out | Server slow or unreachable | Retry, or check network |
220
+ | No API key configured | Missing authentication | `treadstone config set api_key <key>` |
221
+ | HTTP 401 | Invalid or expired API key | Create a new key with `treadstone api-keys create` |
222
+ | HTTP 404 | Resource not found | Verify the ID is correct |
@@ -0,0 +1,212 @@
1
+ # Treadstone CLI
2
+
3
+ Command-line interface for the Treadstone sandbox service.
4
+
5
+ ## Installation
6
+
7
+ ### From PyPI
8
+
9
+ ```bash
10
+ pip install treadstone
11
+ ```
12
+
13
+ ### Pre-built binary
14
+
15
+ Download the latest release from [GitHub Releases](https://github.com/earayu/treadstone/releases). The binary is self-contained and does not require Python.
16
+
17
+ ```bash
18
+ # macOS / Linux
19
+ chmod +x treadstone
20
+ sudo mv treadstone /usr/local/bin/
21
+ ```
22
+
23
+ ## Quick start
24
+
25
+ ```bash
26
+ # Check that the server is reachable
27
+ treadstone health
28
+
29
+ # Register an account (first time only)
30
+ treadstone auth register
31
+
32
+ # Log in
33
+ treadstone auth login
34
+
35
+ # Create an API key for non-interactive use
36
+ treadstone api-keys create --name my-key
37
+ # Save the key — it is shown only once
38
+
39
+ # Store the key in config so you don't have to pass it every time
40
+ treadstone config set api_key ts_live_xxxxxxxxxxxx
41
+
42
+ # Create a sandbox
43
+ treadstone sandboxes create --template default --name my-sandbox
44
+
45
+ # List sandboxes
46
+ treadstone sb list
47
+ ```
48
+
49
+ ## Configuration
50
+
51
+ The CLI reads configuration from three sources, in order of priority:
52
+
53
+ | Priority | Source | Example |
54
+ |----------|--------|---------|
55
+ | 1 (highest) | CLI flags | `--base-url https://... --api-key ts_...` |
56
+ | 2 | Environment variables | `TREADSTONE_BASE_URL`, `TREADSTONE_API_KEY` |
57
+ | 3 (lowest) | Config file | `~/.config/treadstone/config.toml` |
58
+
59
+ ### Config file
60
+
61
+ Location: `~/.config/treadstone/config.toml`
62
+
63
+ ```toml
64
+ [default]
65
+ base_url = "https://your-server.example.com"
66
+ api_key = "ts_live_xxxxxxxxxxxx"
67
+ ```
68
+
69
+ You can manage this file with the `config` subcommand:
70
+
71
+ ```bash
72
+ # Set a value
73
+ treadstone config set base_url https://your-server.example.com
74
+ treadstone config set api_key ts_live_xxxxxxxxxxxx
75
+
76
+ # View current settings (api_key is partially masked)
77
+ treadstone config get
78
+
79
+ # View a single key
80
+ treadstone config get base_url
81
+
82
+ # Remove a value
83
+ treadstone config unset api_key
84
+
85
+ # Show config file path
86
+ treadstone config path
87
+ ```
88
+
89
+ ### Environment variables
90
+
91
+ | Variable | Description | Default |
92
+ |----------|-------------|---------|
93
+ | `TREADSTONE_BASE_URL` | Base URL of the Treadstone server | `https://api.treadstone-ai.dev` |
94
+ | `TREADSTONE_API_KEY` | API key for authentication | (none) |
95
+
96
+ ### Global flags
97
+
98
+ | Flag | Description |
99
+ |------|-------------|
100
+ | `--base-url URL` | Override the server URL |
101
+ | `--api-key KEY` | Override the API key |
102
+ | `--json` | Output responses as JSON (useful for scripting) |
103
+ | `--version` | Show CLI version |
104
+ | `--help` | Show help message |
105
+
106
+ ## Commands
107
+
108
+ ### `health`
109
+
110
+ Check if the server is reachable and healthy.
111
+
112
+ ```bash
113
+ treadstone health
114
+ # Server is healthy
115
+ ```
116
+
117
+ ### `auth`
118
+
119
+ Authentication and user management.
120
+
121
+ ```bash
122
+ treadstone auth register # Create a new account
123
+ treadstone auth login # Log in interactively
124
+ treadstone auth logout # Log out
125
+ treadstone auth whoami # Show current user info
126
+ treadstone auth change-password # Change your password
127
+ treadstone auth invite --email user@example.com # Invite a user (admin)
128
+ treadstone auth users # List all users (admin)
129
+ treadstone auth delete-user <user-id> # Delete a user (admin)
130
+ ```
131
+
132
+ ### `sandboxes` (alias: `sb`)
133
+
134
+ Create and manage sandboxes.
135
+
136
+ ```bash
137
+ treadstone sb create --template default --name my-box
138
+ treadstone sb create --template python --label env:dev --persist
139
+ treadstone sb list
140
+ treadstone sb list --label env:prod --limit 10
141
+ treadstone sb get <sandbox-id>
142
+ treadstone sb start <sandbox-id>
143
+ treadstone sb stop <sandbox-id>
144
+ treadstone sb delete <sandbox-id>
145
+ treadstone sb token <sandbox-id> # Get an access token
146
+ treadstone sb token <sandbox-id> --expires-in 7200 # Custom TTL
147
+ ```
148
+
149
+ ### `templates`
150
+
151
+ List available sandbox templates.
152
+
153
+ ```bash
154
+ treadstone templates list
155
+ ```
156
+
157
+ ### `api-keys`
158
+
159
+ Manage long-lived API keys.
160
+
161
+ ```bash
162
+ treadstone api-keys create --name ci-bot
163
+ treadstone api-keys create --name temp --expires-in 86400 # 24h
164
+ treadstone api-keys list
165
+ treadstone api-keys delete <key-id>
166
+ ```
167
+
168
+ ### `config`
169
+
170
+ Manage local CLI configuration.
171
+
172
+ ```bash
173
+ treadstone config set base_url https://...
174
+ treadstone config set api_key ts_...
175
+ treadstone config get
176
+ treadstone config get base_url
177
+ treadstone config unset api_key
178
+ treadstone config path
179
+ ```
180
+
181
+ ## JSON output
182
+
183
+ Pass `--json` before any command to get machine-readable JSON output:
184
+
185
+ ```bash
186
+ treadstone --json sb list
187
+ treadstone --json health
188
+ treadstone --json api-keys list
189
+ ```
190
+
191
+ ## Error handling
192
+
193
+ The CLI displays user-friendly error messages instead of stack traces:
194
+
195
+ ```
196
+ Error: Connection refused.
197
+ Possible causes:
198
+ - The Treadstone server is not running
199
+ - The --base-url or TREADSTONE_BASE_URL is incorrect
200
+ - A firewall or proxy is blocking the connection
201
+ Detail: ...
202
+ ```
203
+
204
+ Common errors:
205
+
206
+ | Error | Cause | Fix |
207
+ |-------|-------|-----|
208
+ | Connection refused | Server not running or wrong URL | Check `treadstone config get base_url` |
209
+ | Request timed out | Server slow or unreachable | Retry, or check network |
210
+ | No API key configured | Missing authentication | `treadstone config set api_key <key>` |
211
+ | HTTP 401 | Invalid or expired API key | Create a new key with `treadstone api-keys create` |
212
+ | HTTP 404 | Resource not found | Verify the ID is correct |
@@ -0,0 +1,25 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "treadstone-cli"
7
+ version = "0.2.1"
8
+ description = "CLI for the Treadstone sandbox service."
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ dependencies = [
12
+ "click>=8.1",
13
+ "httpx>=0.28.1",
14
+ "rich>=14.0",
15
+ ]
16
+
17
+ [project.scripts]
18
+ treadstone = "treadstone_cli.main:cli"
19
+
20
+ [tool.ruff]
21
+ target-version = "py312"
22
+ line-length = 120
23
+
24
+ [tool.ruff.lint]
25
+ select = ["E", "F", "I", "UP"]
File without changes
@@ -0,0 +1,6 @@
1
+ """Entry point for `python -m treadstone_cli` and PyInstaller builds."""
2
+
3
+ from treadstone_cli.main import cli
4
+
5
+ if __name__ == "__main__":
6
+ cli()
@@ -0,0 +1,77 @@
1
+ """HTTP client factory for CLI commands.
2
+
3
+ Priority: CLI flags > environment variables > config file.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import os
9
+ import sys
10
+ from pathlib import Path
11
+
12
+ import click
13
+ import httpx
14
+
15
+ CONFIG_DIR = Path.home() / ".config" / "treadstone"
16
+ CONFIG_FILE = CONFIG_DIR / "config.toml"
17
+
18
+ _DEFAULT_BASE_URL = "https://api.treadstone-ai.dev"
19
+
20
+
21
+ def _read_config() -> dict[str, str]:
22
+ if not CONFIG_FILE.exists():
23
+ return {}
24
+ try:
25
+ import tomllib
26
+ except ModuleNotFoundError:
27
+ import tomli as tomllib # type: ignore[no-redef]
28
+ with open(CONFIG_FILE, "rb") as f:
29
+ data = tomllib.load(f)
30
+ return data.get("default", {})
31
+
32
+
33
+ def get_base_url(ctx: click.Context) -> str:
34
+ url = ctx.obj.get("base_url") or _read_config().get("base_url") or _DEFAULT_BASE_URL
35
+ return url.rstrip("/")
36
+
37
+
38
+ def get_api_key(ctx: click.Context) -> str | None:
39
+ return ctx.obj.get("api_key") or _read_config().get("api_key")
40
+
41
+
42
+ def effective_base_url() -> tuple[str, str]:
43
+ """Return (url, source) without requiring a Click context.
44
+
45
+ Source is one of: 'env', 'file', 'default'.
46
+ Used for displaying configuration in help text.
47
+ """
48
+ env = os.environ.get("TREADSTONE_BASE_URL")
49
+ if env:
50
+ return env.rstrip("/"), "env"
51
+ cfg = _read_config().get("base_url")
52
+ if cfg:
53
+ return cfg.rstrip("/"), "file"
54
+ return _DEFAULT_BASE_URL, "default"
55
+
56
+
57
+ def effective_api_key() -> str | None:
58
+ """Return API key without requiring a Click context."""
59
+ return os.environ.get("TREADSTONE_API_KEY") or _read_config().get("api_key")
60
+
61
+
62
+ def build_client(ctx: click.Context) -> httpx.Client:
63
+ base_url = get_base_url(ctx)
64
+ api_key = get_api_key(ctx)
65
+ headers: dict[str, str] = {}
66
+ if api_key:
67
+ headers["Authorization"] = f"Bearer {api_key}"
68
+ return httpx.Client(base_url=base_url, headers=headers, timeout=30.0)
69
+
70
+
71
+ def require_auth(ctx: click.Context) -> httpx.Client:
72
+ """Build client and abort if no API key is configured."""
73
+ client = build_client(ctx)
74
+ if "Authorization" not in client.headers:
75
+ click.echo("Error: No API key configured. Set TREADSTONE_API_KEY or use --api-key.", err=True)
76
+ sys.exit(1)
77
+ return client
@@ -0,0 +1,102 @@
1
+ """Output formatting utilities for CLI — table (Rich) or JSON mode."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import sys
7
+ from typing import Any
8
+
9
+ import click
10
+ import httpx
11
+ from rich.console import Console
12
+ from rich.table import Table
13
+
14
+ console = Console()
15
+
16
+
17
+ def friendly_exception_handler(cli_main: click.Group) -> click.Group:
18
+ """Wrap a Click group so unhandled exceptions print user-friendly messages instead of tracebacks."""
19
+ original_main = cli_main.main
20
+
21
+ def _patched_main(*args: Any, **kwargs: Any) -> Any:
22
+ try:
23
+ return original_main(*args, standalone_mode=False, **kwargs)
24
+ except click.exceptions.Abort:
25
+ click.echo("\nAborted.", err=True)
26
+ sys.exit(130)
27
+ except click.exceptions.Exit as exc:
28
+ sys.exit(exc.exit_code)
29
+ except click.UsageError as exc:
30
+ exc.show()
31
+ sys.exit(exc.exit_code if exc.exit_code is not None else 2)
32
+ except SystemExit:
33
+ raise
34
+ except KeyboardInterrupt:
35
+ click.echo("\nInterrupted.", err=True)
36
+ sys.exit(130)
37
+ except httpx.ConnectError as exc:
38
+ _print_network_hint(str(exc), "Connection refused")
39
+ sys.exit(1)
40
+ except httpx.TimeoutException:
41
+ click.echo("Error: Request timed out. The server may be slow or unreachable.", err=True)
42
+ sys.exit(1)
43
+ except httpx.HTTPStatusError as exc:
44
+ click.echo(f"Error: HTTP {exc.response.status_code} — {exc.response.text[:200]}", err=True)
45
+ sys.exit(1)
46
+ except httpx.HTTPError as exc:
47
+ click.echo(f"Error: {type(exc).__name__} — {exc}", err=True)
48
+ sys.exit(1)
49
+ except Exception as exc:
50
+ click.echo(f"Error: {exc}", err=True)
51
+ sys.exit(1)
52
+
53
+ cli_main.main = _patched_main # type: ignore[assignment]
54
+ return cli_main
55
+
56
+
57
+ def _print_network_hint(detail: str, summary: str) -> None:
58
+ click.echo(f"Error: {summary}.", err=True)
59
+ click.echo(" Possible causes:", err=True)
60
+ click.echo(" - The Treadstone server is not running", err=True)
61
+ click.echo(" - The --base-url or TREADSTONE_BASE_URL is incorrect", err=True)
62
+ click.echo(" - A firewall or proxy is blocking the connection", err=True)
63
+ click.echo(f" Detail: {detail}", err=True)
64
+
65
+
66
+ def is_json_mode(ctx: click.Context) -> bool:
67
+ return ctx.obj.get("json_output", False)
68
+
69
+
70
+ def print_json(data: Any) -> None:
71
+ click.echo(json.dumps(data, indent=2, default=str))
72
+
73
+
74
+ def print_table(columns: list[str], rows: list[list[Any]], title: str | None = None) -> None:
75
+ table = Table(title=title, show_header=True, header_style="bold cyan")
76
+ for col in columns:
77
+ table.add_column(col)
78
+ for row in rows:
79
+ table.add_row(*[str(v) if v is not None else "" for v in row])
80
+ console.print(table)
81
+
82
+
83
+ def print_detail(data: dict[str, Any], title: str | None = None) -> None:
84
+ table = Table(title=title, show_header=False)
85
+ table.add_column("Field", style="bold")
86
+ table.add_column("Value")
87
+ for k, v in data.items():
88
+ table.add_row(k, str(v) if v is not None else "")
89
+ console.print(table)
90
+
91
+
92
+ def handle_error(resp: Any) -> None:
93
+ """Print error and exit if response is not 2xx."""
94
+ if resp.status_code >= 400:
95
+ try:
96
+ body = resp.json()
97
+ err = body.get("error", body)
98
+ msg = err.get("message", str(err)) if isinstance(err, dict) else str(err)
99
+ except Exception:
100
+ msg = resp.text
101
+ click.echo(f"Error ({resp.status_code}): {msg}", err=True)
102
+ sys.exit(1)