runtime-sdk 0.4.12__tar.gz → 0.4.14__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.
- {runtime_sdk-0.4.12 → runtime_sdk-0.4.14}/PKG-INFO +7 -3
- {runtime_sdk-0.4.12 → runtime_sdk-0.4.14}/README.md +6 -2
- {runtime_sdk-0.4.12 → runtime_sdk-0.4.14}/pyproject.toml +1 -1
- {runtime_sdk-0.4.12 → runtime_sdk-0.4.14}/scripts/runtime_sdk/cli.py +68 -22
- {runtime_sdk-0.4.12 → runtime_sdk-0.4.14}/scripts/runtime_sdk/config.py +13 -4
- {runtime_sdk-0.4.12 → runtime_sdk-0.4.14}/scripts/runtime_sdk.egg-info/PKG-INFO +7 -3
- {runtime_sdk-0.4.12 → runtime_sdk-0.4.14}/scripts/runtime_sdk/__init__.py +0 -0
- {runtime_sdk-0.4.12 → runtime_sdk-0.4.14}/scripts/runtime_sdk/client.py +0 -0
- {runtime_sdk-0.4.12 → runtime_sdk-0.4.14}/scripts/runtime_sdk.egg-info/SOURCES.txt +0 -0
- {runtime_sdk-0.4.12 → runtime_sdk-0.4.14}/scripts/runtime_sdk.egg-info/dependency_links.txt +0 -0
- {runtime_sdk-0.4.12 → runtime_sdk-0.4.14}/scripts/runtime_sdk.egg-info/entry_points.txt +0 -0
- {runtime_sdk-0.4.12 → runtime_sdk-0.4.14}/scripts/runtime_sdk.egg-info/requires.txt +0 -0
- {runtime_sdk-0.4.12 → runtime_sdk-0.4.14}/scripts/runtime_sdk.egg-info/top_level.txt +0 -0
- {runtime_sdk-0.4.12 → runtime_sdk-0.4.14}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: runtime-sdk
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.14
|
|
4
4
|
Summary: Runtime Python SDK and CLI
|
|
5
5
|
Project-URL: Repository, https://github.com/The-Money-Company-Limited/runtimevm
|
|
6
6
|
Project-URL: Issues, https://github.com/The-Money-Company-Limited/runtimevm/issues
|
|
@@ -35,10 +35,12 @@ uv tool upgrade runtime-sdk
|
|
|
35
35
|
|
|
36
36
|
## Configure
|
|
37
37
|
|
|
38
|
-
The CLI talks to `
|
|
38
|
+
The CLI talks to `https://api.runruntime.dev` by default.
|
|
39
|
+
|
|
40
|
+
For local or self-hosted Runtime, override it with:
|
|
39
41
|
|
|
40
42
|
```bash
|
|
41
|
-
export RUNTIME_BASE_URL=
|
|
43
|
+
export RUNTIME_BASE_URL=http://127.0.0.1:8080
|
|
42
44
|
```
|
|
43
45
|
|
|
44
46
|
Or pass `--base-url` per command.
|
|
@@ -47,6 +49,8 @@ Or pass `--base-url` per command.
|
|
|
47
49
|
|
|
48
50
|
```bash
|
|
49
51
|
# Auth
|
|
52
|
+
runtime # first run in a real terminal prompts for email + verification code, then creates your first computer
|
|
53
|
+
runtime login # interactive email + verification code flow
|
|
50
54
|
runtime login you@example.com
|
|
51
55
|
runtime verify 123456
|
|
52
56
|
runtime whoami
|
|
@@ -16,10 +16,12 @@ uv tool upgrade runtime-sdk
|
|
|
16
16
|
|
|
17
17
|
## Configure
|
|
18
18
|
|
|
19
|
-
The CLI talks to `
|
|
19
|
+
The CLI talks to `https://api.runruntime.dev` by default.
|
|
20
|
+
|
|
21
|
+
For local or self-hosted Runtime, override it with:
|
|
20
22
|
|
|
21
23
|
```bash
|
|
22
|
-
export RUNTIME_BASE_URL=
|
|
24
|
+
export RUNTIME_BASE_URL=http://127.0.0.1:8080
|
|
23
25
|
```
|
|
24
26
|
|
|
25
27
|
Or pass `--base-url` per command.
|
|
@@ -28,6 +30,8 @@ Or pass `--base-url` per command.
|
|
|
28
30
|
|
|
29
31
|
```bash
|
|
30
32
|
# Auth
|
|
33
|
+
runtime # first run in a real terminal prompts for email + verification code, then creates your first computer
|
|
34
|
+
runtime login # interactive email + verification code flow
|
|
31
35
|
runtime login you@example.com
|
|
32
36
|
runtime verify 123456
|
|
33
37
|
runtime whoami
|
|
@@ -132,7 +132,7 @@ class _UI:
|
|
|
132
132
|
|
|
133
133
|
def build_parser() -> argparse.ArgumentParser:
|
|
134
134
|
parser = argparse.ArgumentParser(prog="runtime")
|
|
135
|
-
parser.add_argument("--base-url", help="Runtime API base URL")
|
|
135
|
+
parser.add_argument("--base-url", help="Override the Runtime API base URL")
|
|
136
136
|
parser.add_argument("--version", action="version", version=f"runtime-sdk {__version__}")
|
|
137
137
|
|
|
138
138
|
# Subcommand is optional: bare `runtime` defaults to `create`.
|
|
@@ -263,20 +263,21 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
263
263
|
parser = build_parser()
|
|
264
264
|
args = parser.parse_args(argv)
|
|
265
265
|
|
|
266
|
-
# Bare `runtime` → create flow.
|
|
267
|
-
if args.command is None:
|
|
268
|
-
args.command = "create"
|
|
269
|
-
args.name = None
|
|
270
|
-
|
|
271
266
|
try:
|
|
272
267
|
config = load_config()
|
|
273
|
-
base_url
|
|
274
|
-
args.base_url
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
268
|
+
if args.base_url:
|
|
269
|
+
config.base_url = args.base_url
|
|
270
|
+
elif os.environ.get("RUNTIME_BASE_URL"):
|
|
271
|
+
config.base_url = str(os.environ.get("RUNTIME_BASE_URL"))
|
|
272
|
+
else:
|
|
273
|
+
config.base_url = config.configured_base_url or DEFAULT_BASE_URL
|
|
274
|
+
|
|
275
|
+
# Bare `runtime` → first-run onboarding for interactive users, create otherwise.
|
|
276
|
+
if args.command is None:
|
|
277
|
+
if _interactive() and not config.api_key:
|
|
278
|
+
return handle_onboarding(config)
|
|
279
|
+
args.command = "create"
|
|
280
|
+
args.name = None
|
|
280
281
|
|
|
281
282
|
if args.command == "signup":
|
|
282
283
|
return handle_signup(config, args.email, args.name)
|
|
@@ -1181,14 +1182,7 @@ def _looks_like_api_key(value: str | None) -> bool:
|
|
|
1181
1182
|
return candidate.startswith("rt_live_")
|
|
1182
1183
|
|
|
1183
1184
|
|
|
1184
|
-
def
|
|
1185
|
-
if email is None:
|
|
1186
|
-
if not _interactive():
|
|
1187
|
-
return report_error("email is required")
|
|
1188
|
-
email = _prompt_text("Email")
|
|
1189
|
-
if not email:
|
|
1190
|
-
return report_error("email is required")
|
|
1191
|
-
|
|
1185
|
+
def _begin_verification_flow(config: RuntimeConfig, email: str, name: str | None) -> dict[str, Any]:
|
|
1192
1186
|
client = RuntimeClient(base_url=config.base_url)
|
|
1193
1187
|
result = client.start_verification(email, name)
|
|
1194
1188
|
config.pending_signup = PendingSignup(
|
|
@@ -1197,6 +1191,19 @@ def _start_verification_flow(config: RuntimeConfig, email: str | None, name: str
|
|
|
1197
1191
|
expires_at=result.get("expires_at"),
|
|
1198
1192
|
)
|
|
1199
1193
|
save_config(config)
|
|
1194
|
+
return result
|
|
1195
|
+
|
|
1196
|
+
|
|
1197
|
+
|
|
1198
|
+
def _start_verification_flow(config: RuntimeConfig, email: str | None, name: str | None) -> int:
|
|
1199
|
+
if email is None:
|
|
1200
|
+
if not _interactive():
|
|
1201
|
+
return report_error("email is required")
|
|
1202
|
+
email = _prompt_text("Email")
|
|
1203
|
+
if not email:
|
|
1204
|
+
return report_error("email is required")
|
|
1205
|
+
|
|
1206
|
+
result = _begin_verification_flow(config, email, name)
|
|
1200
1207
|
|
|
1201
1208
|
def render(payload: dict[str, Any]) -> None:
|
|
1202
1209
|
_UI.console().print(
|
|
@@ -1209,6 +1216,33 @@ def _start_verification_flow(config: RuntimeConfig, email: str | None, name: str
|
|
|
1209
1216
|
return report_success(result, render)
|
|
1210
1217
|
|
|
1211
1218
|
|
|
1219
|
+
|
|
1220
|
+
def _interactive_email_auth_flow(config: RuntimeConfig, email: str | None, name: str | None) -> int:
|
|
1221
|
+
pending = config.pending_signup
|
|
1222
|
+
if email is None and pending is not None and pending.email:
|
|
1223
|
+
_UI.console().print(
|
|
1224
|
+
f"[green]✓[/green] verification code already sent to [bold]{pending.email}[/bold]"
|
|
1225
|
+
)
|
|
1226
|
+
code = _prompt_text("Verification code")
|
|
1227
|
+
if not code:
|
|
1228
|
+
return report_error("verification code is required")
|
|
1229
|
+
return handle_verify(config, code, pending.flow_id)
|
|
1230
|
+
|
|
1231
|
+
if email is None:
|
|
1232
|
+
email = _prompt_text("Email")
|
|
1233
|
+
if not email:
|
|
1234
|
+
return report_error("email is required")
|
|
1235
|
+
|
|
1236
|
+
_begin_verification_flow(config, email, name)
|
|
1237
|
+
_UI.console().print(
|
|
1238
|
+
f"[green]✓[/green] verification code sent to [bold]{email}[/bold]"
|
|
1239
|
+
)
|
|
1240
|
+
code = _prompt_text("Verification code")
|
|
1241
|
+
if not code:
|
|
1242
|
+
return report_error("verification code is required")
|
|
1243
|
+
return handle_verify(config, code, None)
|
|
1244
|
+
|
|
1245
|
+
|
|
1212
1246
|
def _login_with_api_key(config: RuntimeConfig, api_key: str | None) -> int:
|
|
1213
1247
|
if api_key is None or api_key == "":
|
|
1214
1248
|
if not _interactive():
|
|
@@ -1235,6 +1269,8 @@ def _login_with_api_key(config: RuntimeConfig, api_key: str | None) -> int:
|
|
|
1235
1269
|
|
|
1236
1270
|
|
|
1237
1271
|
def handle_signup(config: RuntimeConfig, email: str | None, name: str | None) -> int:
|
|
1272
|
+
if _interactive():
|
|
1273
|
+
return _interactive_email_auth_flow(config, email, name)
|
|
1238
1274
|
return _start_verification_flow(config, email, name)
|
|
1239
1275
|
|
|
1240
1276
|
|
|
@@ -1284,6 +1320,8 @@ def handle_login(
|
|
|
1284
1320
|
if _looks_like_api_key(identifier):
|
|
1285
1321
|
return _login_with_api_key(config, identifier)
|
|
1286
1322
|
|
|
1323
|
+
if _interactive():
|
|
1324
|
+
return _interactive_email_auth_flow(config, identifier, name)
|
|
1287
1325
|
return _start_verification_flow(config, identifier, name)
|
|
1288
1326
|
|
|
1289
1327
|
|
|
@@ -1369,6 +1407,14 @@ def handle_api_keys_revoke(config: RuntimeConfig, key_id: str | None) -> int:
|
|
|
1369
1407
|
|
|
1370
1408
|
|
|
1371
1409
|
|
|
1410
|
+
def handle_onboarding(config: RuntimeConfig) -> int:
|
|
1411
|
+
code = handle_login(config, None, None, None)
|
|
1412
|
+
if code != 0:
|
|
1413
|
+
return code
|
|
1414
|
+
return handle_create(config, None, None, None, None)
|
|
1415
|
+
|
|
1416
|
+
|
|
1417
|
+
|
|
1372
1418
|
def handle_create(
|
|
1373
1419
|
config: RuntimeConfig,
|
|
1374
1420
|
name: str | None,
|
|
@@ -2141,7 +2187,7 @@ def _strip_terminal_noise(text: str) -> str:
|
|
|
2141
2187
|
filtered: list[str] = []
|
|
2142
2188
|
for line in lines:
|
|
2143
2189
|
stripped = line.rstrip("\r\n")
|
|
2144
|
-
if stripped
|
|
2190
|
+
if stripped.startswith("Running bootstrap command: export PS1='\\[\\033[1;34m\\]runtime@"):
|
|
2145
2191
|
continue
|
|
2146
2192
|
if stripped == "Connected! Press Ctrl+] to exit.":
|
|
2147
2193
|
continue
|
|
@@ -6,7 +6,7 @@ from dataclasses import asdict, dataclass
|
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
DEFAULT_BASE_URL = "
|
|
9
|
+
DEFAULT_BASE_URL = "https://api.runruntime.dev"
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class RuntimeConfigError(RuntimeError):
|
|
@@ -23,6 +23,7 @@ class PendingSignup:
|
|
|
23
23
|
@dataclass(slots=True)
|
|
24
24
|
class RuntimeConfig:
|
|
25
25
|
base_url: str = DEFAULT_BASE_URL
|
|
26
|
+
configured_base_url: str | None = None
|
|
26
27
|
api_key: str | None = None
|
|
27
28
|
pending_signup: PendingSignup | None = None
|
|
28
29
|
|
|
@@ -37,7 +38,7 @@ def config_path() -> Path:
|
|
|
37
38
|
def load_config() -> RuntimeConfig:
|
|
38
39
|
path = config_path()
|
|
39
40
|
if not path.exists():
|
|
40
|
-
return RuntimeConfig(
|
|
41
|
+
return RuntimeConfig()
|
|
41
42
|
|
|
42
43
|
try:
|
|
43
44
|
data = json.loads(path.read_text())
|
|
@@ -48,9 +49,11 @@ def load_config() -> RuntimeConfig:
|
|
|
48
49
|
if not isinstance(data, dict):
|
|
49
50
|
raise RuntimeConfigError("config file must contain a JSON object")
|
|
50
51
|
pending = data.get("pending_signup")
|
|
52
|
+
configured_base_url = data.get("base_url") or None
|
|
51
53
|
try:
|
|
52
54
|
return RuntimeConfig(
|
|
53
|
-
base_url=
|
|
55
|
+
base_url=configured_base_url or DEFAULT_BASE_URL,
|
|
56
|
+
configured_base_url=configured_base_url,
|
|
54
57
|
api_key=data.get("api_key"),
|
|
55
58
|
pending_signup=PendingSignup(**pending) if pending else None,
|
|
56
59
|
)
|
|
@@ -60,7 +63,13 @@ def load_config() -> RuntimeConfig:
|
|
|
60
63
|
|
|
61
64
|
def save_config(config: RuntimeConfig) -> None:
|
|
62
65
|
path = config_path()
|
|
63
|
-
|
|
66
|
+
configured_base_url = config.configured_base_url
|
|
67
|
+
payload = {
|
|
68
|
+
"api_key": config.api_key,
|
|
69
|
+
"pending_signup": asdict(config.pending_signup) if config.pending_signup else None,
|
|
70
|
+
}
|
|
71
|
+
if configured_base_url is not None:
|
|
72
|
+
payload["base_url"] = configured_base_url
|
|
64
73
|
try:
|
|
65
74
|
path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
|
|
66
75
|
path.write_text(json.dumps(payload, indent=2) + "\n")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: runtime-sdk
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.14
|
|
4
4
|
Summary: Runtime Python SDK and CLI
|
|
5
5
|
Project-URL: Repository, https://github.com/The-Money-Company-Limited/runtimevm
|
|
6
6
|
Project-URL: Issues, https://github.com/The-Money-Company-Limited/runtimevm/issues
|
|
@@ -35,10 +35,12 @@ uv tool upgrade runtime-sdk
|
|
|
35
35
|
|
|
36
36
|
## Configure
|
|
37
37
|
|
|
38
|
-
The CLI talks to `
|
|
38
|
+
The CLI talks to `https://api.runruntime.dev` by default.
|
|
39
|
+
|
|
40
|
+
For local or self-hosted Runtime, override it with:
|
|
39
41
|
|
|
40
42
|
```bash
|
|
41
|
-
export RUNTIME_BASE_URL=
|
|
43
|
+
export RUNTIME_BASE_URL=http://127.0.0.1:8080
|
|
42
44
|
```
|
|
43
45
|
|
|
44
46
|
Or pass `--base-url` per command.
|
|
@@ -47,6 +49,8 @@ Or pass `--base-url` per command.
|
|
|
47
49
|
|
|
48
50
|
```bash
|
|
49
51
|
# Auth
|
|
52
|
+
runtime # first run in a real terminal prompts for email + verification code, then creates your first computer
|
|
53
|
+
runtime login # interactive email + verification code flow
|
|
50
54
|
runtime login you@example.com
|
|
51
55
|
runtime verify 123456
|
|
52
56
|
runtime whoami
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|