runtime-sdk 0.4.18__tar.gz → 0.4.19__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.18 → runtime_sdk-0.4.19}/PKG-INFO +27 -1
- {runtime_sdk-0.4.18 → runtime_sdk-0.4.19}/README.md +26 -0
- {runtime_sdk-0.4.18 → runtime_sdk-0.4.19}/pyproject.toml +1 -1
- {runtime_sdk-0.4.18 → runtime_sdk-0.4.19}/scripts/runtime_sdk/cli.py +129 -0
- {runtime_sdk-0.4.18 → runtime_sdk-0.4.19}/scripts/runtime_sdk/client.py +19 -0
- {runtime_sdk-0.4.18 → runtime_sdk-0.4.19}/scripts/runtime_sdk.egg-info/PKG-INFO +27 -1
- {runtime_sdk-0.4.18 → runtime_sdk-0.4.19}/scripts/runtime_sdk/__init__.py +0 -0
- {runtime_sdk-0.4.18 → runtime_sdk-0.4.19}/scripts/runtime_sdk/config.py +0 -0
- {runtime_sdk-0.4.18 → runtime_sdk-0.4.19}/scripts/runtime_sdk.egg-info/SOURCES.txt +0 -0
- {runtime_sdk-0.4.18 → runtime_sdk-0.4.19}/scripts/runtime_sdk.egg-info/dependency_links.txt +0 -0
- {runtime_sdk-0.4.18 → runtime_sdk-0.4.19}/scripts/runtime_sdk.egg-info/entry_points.txt +0 -0
- {runtime_sdk-0.4.18 → runtime_sdk-0.4.19}/scripts/runtime_sdk.egg-info/requires.txt +0 -0
- {runtime_sdk-0.4.18 → runtime_sdk-0.4.19}/scripts/runtime_sdk.egg-info/top_level.txt +0 -0
- {runtime_sdk-0.4.18 → runtime_sdk-0.4.19}/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.19
|
|
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
|
|
@@ -66,8 +66,12 @@ runtime login --api-key rt_live_...
|
|
|
66
66
|
runtime api-keys list
|
|
67
67
|
runtime api-keys create "my laptop"
|
|
68
68
|
runtime api-keys revoke 123
|
|
69
|
+
runtime integrations connect github
|
|
69
70
|
|
|
70
71
|
# Computers
|
|
72
|
+
runtime switch --repo owner/repo feature/login # open or create the branch workspace computer
|
|
73
|
+
runtime switch -c feature/login --repo owner/repo # create a new branch workspace from the repo default branch
|
|
74
|
+
runtime checkout --repo owner/repo feature/login # alias for switch
|
|
71
75
|
runtime create # creates a computer with the starter app already published
|
|
72
76
|
runtime create myapp --command "python3 app.py" --cwd /home/ubuntu --port 3000
|
|
73
77
|
runtime enter <name-or-id> # accepts slug/name like test, or the computer id
|
|
@@ -157,6 +161,28 @@ show|clear` expose that same durable app state directly. The low-level
|
|
|
157
161
|
`runtime run` stays one-shot: the filesystem is restored after going cold, but
|
|
158
162
|
that ad-hoc process is not.
|
|
159
163
|
|
|
164
|
+
## GitHub branch workspaces
|
|
165
|
+
|
|
166
|
+
`runtime switch` gives a repo branch its own Runtime computer so you can jump
|
|
167
|
+
between parallel tasks without local worktrees.
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
runtime integrations connect github
|
|
171
|
+
runtime switch --repo owner/repo feature/login
|
|
172
|
+
runtime switch -c feature/search --repo owner/repo --from main
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Rules:
|
|
176
|
+
- GitHub must already be connected with `runtime integrations connect github`.
|
|
177
|
+
- `runtime switch` opens an existing branch workspace, or creates the computer if
|
|
178
|
+
the branch exists but the workspace does not yet.
|
|
179
|
+
- `runtime switch -c` creates a new branch first, then opens that branch's
|
|
180
|
+
workspace.
|
|
181
|
+
- Each `repo + branch` maps to one dedicated computer.
|
|
182
|
+
- The repo is cloned into `/home/ubuntu/<repo>` and new shells in that computer
|
|
183
|
+
start there automatically.
|
|
184
|
+
- `runtime checkout ...` is an alias for `runtime switch ...`.
|
|
185
|
+
|
|
160
186
|
Run the SDK unit tests through the backend project environment:
|
|
161
187
|
|
|
162
188
|
```bash
|
|
@@ -44,8 +44,12 @@ runtime login --api-key rt_live_...
|
|
|
44
44
|
runtime api-keys list
|
|
45
45
|
runtime api-keys create "my laptop"
|
|
46
46
|
runtime api-keys revoke 123
|
|
47
|
+
runtime integrations connect github
|
|
47
48
|
|
|
48
49
|
# Computers
|
|
50
|
+
runtime switch --repo owner/repo feature/login # open or create the branch workspace computer
|
|
51
|
+
runtime switch -c feature/login --repo owner/repo # create a new branch workspace from the repo default branch
|
|
52
|
+
runtime checkout --repo owner/repo feature/login # alias for switch
|
|
49
53
|
runtime create # creates a computer with the starter app already published
|
|
50
54
|
runtime create myapp --command "python3 app.py" --cwd /home/ubuntu --port 3000
|
|
51
55
|
runtime enter <name-or-id> # accepts slug/name like test, or the computer id
|
|
@@ -135,6 +139,28 @@ show|clear` expose that same durable app state directly. The low-level
|
|
|
135
139
|
`runtime run` stays one-shot: the filesystem is restored after going cold, but
|
|
136
140
|
that ad-hoc process is not.
|
|
137
141
|
|
|
142
|
+
## GitHub branch workspaces
|
|
143
|
+
|
|
144
|
+
`runtime switch` gives a repo branch its own Runtime computer so you can jump
|
|
145
|
+
between parallel tasks without local worktrees.
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
runtime integrations connect github
|
|
149
|
+
runtime switch --repo owner/repo feature/login
|
|
150
|
+
runtime switch -c feature/search --repo owner/repo --from main
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Rules:
|
|
154
|
+
- GitHub must already be connected with `runtime integrations connect github`.
|
|
155
|
+
- `runtime switch` opens an existing branch workspace, or creates the computer if
|
|
156
|
+
the branch exists but the workspace does not yet.
|
|
157
|
+
- `runtime switch -c` creates a new branch first, then opens that branch's
|
|
158
|
+
workspace.
|
|
159
|
+
- Each `repo + branch` maps to one dedicated computer.
|
|
160
|
+
- The repo is cloned into `/home/ubuntu/<repo>` and new shells in that computer
|
|
161
|
+
start there automatically.
|
|
162
|
+
- `runtime checkout ...` is an alias for `runtime switch ...`.
|
|
163
|
+
|
|
138
164
|
Run the SDK unit tests through the backend project environment:
|
|
139
165
|
|
|
140
166
|
```bash
|
|
@@ -5,6 +5,7 @@ import contextlib
|
|
|
5
5
|
import importlib
|
|
6
6
|
import json
|
|
7
7
|
import os
|
|
8
|
+
import re
|
|
8
9
|
import select
|
|
9
10
|
import shlex
|
|
10
11
|
import shutil
|
|
@@ -195,6 +196,16 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
195
196
|
integrations_connect.add_argument("--owner", default=None, help="GitHub username or org where the app is installed")
|
|
196
197
|
integrations_connect.add_argument("--no-open", action="store_true", help="Print the install URL instead of opening a browser")
|
|
197
198
|
|
|
199
|
+
switch_cmd = subparsers.add_parser(
|
|
200
|
+
"switch",
|
|
201
|
+
aliases=["checkout"],
|
|
202
|
+
help="Open a GitHub branch workspace in its own computer",
|
|
203
|
+
)
|
|
204
|
+
switch_cmd.add_argument("branch", nargs="?", default=None, help="Git branch to open")
|
|
205
|
+
switch_cmd.add_argument("--repo", default=None, help="GitHub repository in owner/name format")
|
|
206
|
+
switch_cmd.add_argument("-c", "--create", action="store_true", help="Create a new branch before opening it")
|
|
207
|
+
switch_cmd.add_argument("--from", dest="base_branch", default=None, help="Base branch for -c (defaults to the repo default branch)")
|
|
208
|
+
|
|
198
209
|
create_cmd = subparsers.add_parser("create", help="Create a new computer with the starter app published by default")
|
|
199
210
|
create_cmd.add_argument(
|
|
200
211
|
"name",
|
|
@@ -343,6 +354,14 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
343
354
|
if args.integrations_action == "connect":
|
|
344
355
|
return handle_integrations_connect(config, args.provider, args.slug, args.owner, no_open=args.no_open)
|
|
345
356
|
return report_error("unknown integrations command")
|
|
357
|
+
if args.command in ("switch", "checkout"):
|
|
358
|
+
return handle_switch(
|
|
359
|
+
config,
|
|
360
|
+
getattr(args, "repo", None),
|
|
361
|
+
getattr(args, "branch", None),
|
|
362
|
+
create_branch=getattr(args, "create", False),
|
|
363
|
+
base_branch=getattr(args, "base_branch", None),
|
|
364
|
+
)
|
|
346
365
|
if args.command == "create":
|
|
347
366
|
return handle_create(
|
|
348
367
|
config,
|
|
@@ -764,6 +783,48 @@ def _resolve_computer_ref(client: RuntimeClient, ref: str) -> str:
|
|
|
764
783
|
|
|
765
784
|
|
|
766
785
|
|
|
786
|
+
def _coerce_github_repo(repo: str | None) -> str | None:
|
|
787
|
+
text = str(repo or "").strip()
|
|
788
|
+
if not text:
|
|
789
|
+
return None
|
|
790
|
+
if not re.fullmatch(r"[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+", text):
|
|
791
|
+
raise RuntimeAPIError("repo must be in owner/name format")
|
|
792
|
+
owner, name = text.split("/", 1)
|
|
793
|
+
return f"{owner}/{name}"
|
|
794
|
+
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
def _coerce_git_branch(branch: str | None) -> str | None:
|
|
798
|
+
text = str(branch or "").strip()
|
|
799
|
+
if not text:
|
|
800
|
+
return None
|
|
801
|
+
if text == "@":
|
|
802
|
+
raise RuntimeAPIError("branch name is invalid")
|
|
803
|
+
if text.startswith("-") or text.endswith("/") or text.endswith(".") or text.endswith(".lock"):
|
|
804
|
+
raise RuntimeAPIError("branch name is invalid")
|
|
805
|
+
if ".." in text or "//" in text or "@{" in text:
|
|
806
|
+
raise RuntimeAPIError("branch name is invalid")
|
|
807
|
+
if any(ch in text for ch in (" ", "~", "^", ":", "?", "*", "[", "\\")):
|
|
808
|
+
raise RuntimeAPIError("branch name is invalid")
|
|
809
|
+
if any(ord(ch) < 32 or ord(ch) == 127 for ch in text):
|
|
810
|
+
raise RuntimeAPIError("branch name is invalid")
|
|
811
|
+
return text
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
def _render_branch_workspace(payload: dict[str, Any]) -> None:
|
|
816
|
+
computer = payload.get("computer") or {}
|
|
817
|
+
repo = str(payload.get("repo") or "")
|
|
818
|
+
branch = str(payload.get("branch") or "")
|
|
819
|
+
action = "created branch" if payload.get("create_branch") else "opened branch"
|
|
820
|
+
_render_computer_panel(computer, title="workspace")
|
|
821
|
+
_UI.console().print(f"[green]✓[/green] {action} [bold]{repo}#{branch}[/bold]")
|
|
822
|
+
url = computer.get("public_url")
|
|
823
|
+
if url:
|
|
824
|
+
_UI.console().print(f"[bold green]→[/bold green] [cyan]{url}[/cyan]")
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
|
|
767
828
|
def _computer_name(c: dict[str, Any]) -> str:
|
|
768
829
|
return str(c.get("slug") or c.get("id") or "?")
|
|
769
830
|
|
|
@@ -1686,6 +1747,74 @@ def handle_integrations_connect(
|
|
|
1686
1747
|
|
|
1687
1748
|
|
|
1688
1749
|
|
|
1750
|
+
def handle_switch(
|
|
1751
|
+
config: RuntimeConfig,
|
|
1752
|
+
repo: str | None,
|
|
1753
|
+
branch: str | None,
|
|
1754
|
+
*,
|
|
1755
|
+
create_branch: bool = False,
|
|
1756
|
+
base_branch: str | None = None,
|
|
1757
|
+
) -> int:
|
|
1758
|
+
if (err := _require_api_key(config)) is not None:
|
|
1759
|
+
return err
|
|
1760
|
+
if base_branch is not None and not create_branch:
|
|
1761
|
+
return report_error("--from can only be used together with -c")
|
|
1762
|
+
|
|
1763
|
+
try:
|
|
1764
|
+
resolved_repo = _coerce_github_repo(repo)
|
|
1765
|
+
resolved_branch = _coerce_git_branch(branch)
|
|
1766
|
+
except RuntimeAPIError as exc:
|
|
1767
|
+
return report_error(str(exc), status_code=exc.status_code)
|
|
1768
|
+
|
|
1769
|
+
if resolved_repo is None:
|
|
1770
|
+
if not _interactive():
|
|
1771
|
+
return report_error("--repo is required")
|
|
1772
|
+
resolved_repo = _prompt_text("GitHub repo (owner/name)")
|
|
1773
|
+
try:
|
|
1774
|
+
resolved_repo = _coerce_github_repo(resolved_repo)
|
|
1775
|
+
except RuntimeAPIError as exc:
|
|
1776
|
+
return report_error(str(exc), status_code=exc.status_code)
|
|
1777
|
+
if resolved_repo is None:
|
|
1778
|
+
return report_error("repo is required")
|
|
1779
|
+
|
|
1780
|
+
if resolved_branch is None:
|
|
1781
|
+
if not _interactive():
|
|
1782
|
+
return report_error("branch is required")
|
|
1783
|
+
prompt = "New branch name" if create_branch else "Branch name"
|
|
1784
|
+
resolved_branch = _prompt_text(prompt)
|
|
1785
|
+
try:
|
|
1786
|
+
resolved_branch = _coerce_git_branch(resolved_branch)
|
|
1787
|
+
except RuntimeAPIError as exc:
|
|
1788
|
+
return report_error(str(exc), status_code=exc.status_code)
|
|
1789
|
+
if resolved_branch is None:
|
|
1790
|
+
return report_error("branch is required")
|
|
1791
|
+
|
|
1792
|
+
client = RuntimeClient(base_url=config.base_url, api_key=config.api_key)
|
|
1793
|
+
try:
|
|
1794
|
+
payload = _with_spinner(
|
|
1795
|
+
"opening branch workspace…",
|
|
1796
|
+
lambda: client.switch_workspace(
|
|
1797
|
+
repo=resolved_repo,
|
|
1798
|
+
branch=resolved_branch,
|
|
1799
|
+
create=create_branch,
|
|
1800
|
+
base_branch=base_branch,
|
|
1801
|
+
),
|
|
1802
|
+
)
|
|
1803
|
+
except RuntimeAPIError as exc:
|
|
1804
|
+
return report_error(str(exc), status_code=exc.status_code)
|
|
1805
|
+
|
|
1806
|
+
computer = payload.get("computer") or {}
|
|
1807
|
+
computer_id = str(computer.get("id") or "").strip()
|
|
1808
|
+
if not computer_id:
|
|
1809
|
+
return report_error("server did not return a computer id")
|
|
1810
|
+
|
|
1811
|
+
code = report_success(payload, _render_branch_workspace)
|
|
1812
|
+
if code != 0 or not _interactive():
|
|
1813
|
+
return code
|
|
1814
|
+
return _enter_computer(config, computer_id)
|
|
1815
|
+
|
|
1816
|
+
|
|
1817
|
+
|
|
1689
1818
|
def handle_onboarding(config: RuntimeConfig) -> int:
|
|
1690
1819
|
code = handle_login(config, None, None, None)
|
|
1691
1820
|
if code != 0:
|
|
@@ -96,6 +96,25 @@ class RuntimeClient:
|
|
|
96
96
|
|
|
97
97
|
# --- Computers ---
|
|
98
98
|
|
|
99
|
+
def switch_workspace(
|
|
100
|
+
self,
|
|
101
|
+
*,
|
|
102
|
+
repo: str,
|
|
103
|
+
branch: str,
|
|
104
|
+
create: bool = False,
|
|
105
|
+
base_branch: str | None = None,
|
|
106
|
+
) -> dict[str, Any]:
|
|
107
|
+
body: dict[str, Any] = {"repo": repo, "branch": branch, "create": create}
|
|
108
|
+
if base_branch is not None:
|
|
109
|
+
body["from"] = base_branch
|
|
110
|
+
return self._request(
|
|
111
|
+
"POST",
|
|
112
|
+
"/api/workspaces/switch",
|
|
113
|
+
json=body,
|
|
114
|
+
auth_required=True,
|
|
115
|
+
timeout=max(self.timeout, DEFAULT_WARMUP_TIMEOUT),
|
|
116
|
+
)
|
|
117
|
+
|
|
99
118
|
def create_computer(
|
|
100
119
|
self,
|
|
101
120
|
*,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: runtime-sdk
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.19
|
|
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
|
|
@@ -66,8 +66,12 @@ runtime login --api-key rt_live_...
|
|
|
66
66
|
runtime api-keys list
|
|
67
67
|
runtime api-keys create "my laptop"
|
|
68
68
|
runtime api-keys revoke 123
|
|
69
|
+
runtime integrations connect github
|
|
69
70
|
|
|
70
71
|
# Computers
|
|
72
|
+
runtime switch --repo owner/repo feature/login # open or create the branch workspace computer
|
|
73
|
+
runtime switch -c feature/login --repo owner/repo # create a new branch workspace from the repo default branch
|
|
74
|
+
runtime checkout --repo owner/repo feature/login # alias for switch
|
|
71
75
|
runtime create # creates a computer with the starter app already published
|
|
72
76
|
runtime create myapp --command "python3 app.py" --cwd /home/ubuntu --port 3000
|
|
73
77
|
runtime enter <name-or-id> # accepts slug/name like test, or the computer id
|
|
@@ -157,6 +161,28 @@ show|clear` expose that same durable app state directly. The low-level
|
|
|
157
161
|
`runtime run` stays one-shot: the filesystem is restored after going cold, but
|
|
158
162
|
that ad-hoc process is not.
|
|
159
163
|
|
|
164
|
+
## GitHub branch workspaces
|
|
165
|
+
|
|
166
|
+
`runtime switch` gives a repo branch its own Runtime computer so you can jump
|
|
167
|
+
between parallel tasks without local worktrees.
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
runtime integrations connect github
|
|
171
|
+
runtime switch --repo owner/repo feature/login
|
|
172
|
+
runtime switch -c feature/search --repo owner/repo --from main
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Rules:
|
|
176
|
+
- GitHub must already be connected with `runtime integrations connect github`.
|
|
177
|
+
- `runtime switch` opens an existing branch workspace, or creates the computer if
|
|
178
|
+
the branch exists but the workspace does not yet.
|
|
179
|
+
- `runtime switch -c` creates a new branch first, then opens that branch's
|
|
180
|
+
workspace.
|
|
181
|
+
- Each `repo + branch` maps to one dedicated computer.
|
|
182
|
+
- The repo is cloned into `/home/ubuntu/<repo>` and new shells in that computer
|
|
183
|
+
start there automatically.
|
|
184
|
+
- `runtime checkout ...` is an alias for `runtime switch ...`.
|
|
185
|
+
|
|
160
186
|
Run the SDK unit tests through the backend project environment:
|
|
161
187
|
|
|
162
188
|
```bash
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|