runtime-sdk 0.4.17__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runtime-sdk
3
- Version: 0.4.17
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
@@ -10,6 +10,9 @@ Classifier: Programming Language :: Python :: 3.12
10
10
  Classifier: Programming Language :: Python :: 3.13
11
11
  Classifier: Programming Language :: Python :: 3 :: Only
12
12
  Classifier: Environment :: Console
13
+ Classifier: Operating System :: MacOS :: MacOS X
14
+ Classifier: Operating System :: POSIX
15
+ Classifier: Operating System :: POSIX :: Linux
13
16
  Requires-Python: >=3.11
14
17
  Description-Content-Type: text/markdown
15
18
  Requires-Dist: httpx>=0.28.1
@@ -23,6 +26,10 @@ Python SDK and CLI for Runtime.
23
26
 
24
27
  ## Install
25
28
 
29
+ Supported host OS for the CLI: **macOS and Linux only**.
30
+
31
+ Windows is **not supported** at this time.
32
+
26
33
  ```bash
27
34
  uv tool install runtime-sdk
28
35
  ```
@@ -59,8 +66,12 @@ runtime login --api-key rt_live_...
59
66
  runtime api-keys list
60
67
  runtime api-keys create "my laptop"
61
68
  runtime api-keys revoke 123
69
+ runtime integrations connect github
62
70
 
63
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
64
75
  runtime create # creates a computer with the starter app already published
65
76
  runtime create myapp --command "python3 app.py" --cwd /home/ubuntu --port 3000
66
77
  runtime enter <name-or-id> # accepts slug/name like test, or the computer id
@@ -150,6 +161,28 @@ show|clear` expose that same durable app state directly. The low-level
150
161
  `runtime run` stays one-shot: the filesystem is restored after going cold, but
151
162
  that ad-hoc process is not.
152
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
+
153
186
  Run the SDK unit tests through the backend project environment:
154
187
 
155
188
  ```bash
@@ -4,6 +4,10 @@ Python SDK and CLI for Runtime.
4
4
 
5
5
  ## Install
6
6
 
7
+ Supported host OS for the CLI: **macOS and Linux only**.
8
+
9
+ Windows is **not supported** at this time.
10
+
7
11
  ```bash
8
12
  uv tool install runtime-sdk
9
13
  ```
@@ -40,8 +44,12 @@ runtime login --api-key rt_live_...
40
44
  runtime api-keys list
41
45
  runtime api-keys create "my laptop"
42
46
  runtime api-keys revoke 123
47
+ runtime integrations connect github
43
48
 
44
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
45
53
  runtime create # creates a computer with the starter app already published
46
54
  runtime create myapp --command "python3 app.py" --cwd /home/ubuntu --port 3000
47
55
  runtime enter <name-or-id> # accepts slug/name like test, or the computer id
@@ -131,6 +139,28 @@ show|clear` expose that same durable app state directly. The low-level
131
139
  `runtime run` stays one-shot: the filesystem is restored after going cold, but
132
140
  that ad-hoc process is not.
133
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
+
134
164
  Run the SDK unit tests through the backend project environment:
135
165
 
136
166
  ```bash
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "runtime-sdk"
3
- version = "0.4.17"
3
+ version = "0.4.19"
4
4
  description = "Runtime Python SDK and CLI"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -17,6 +17,9 @@ classifiers = [
17
17
  "Programming Language :: Python :: 3.13",
18
18
  "Programming Language :: Python :: 3 :: Only",
19
19
  "Environment :: Console",
20
+ "Operating System :: MacOS :: MacOS X",
21
+ "Operating System :: POSIX",
22
+ "Operating System :: POSIX :: Linux",
20
23
  ]
21
24
 
22
25
  [project.urls]
@@ -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",
@@ -281,10 +292,18 @@ def build_parser() -> argparse.ArgumentParser:
281
292
  return parser
282
293
 
283
294
 
295
+ def _windows_unsupported() -> bool:
296
+ return sys.platform == "win32"
297
+
298
+
299
+
284
300
  def main(argv: list[str] | None = None) -> int:
285
301
  parser = build_parser()
286
302
  args = parser.parse_args(argv)
287
303
 
304
+ if _windows_unsupported():
305
+ return report_error("runtime-sdk supports macOS and Linux only; Windows is not supported")
306
+
288
307
  try:
289
308
  config = load_config()
290
309
  if args.base_url:
@@ -335,6 +354,14 @@ def main(argv: list[str] | None = None) -> int:
335
354
  if args.integrations_action == "connect":
336
355
  return handle_integrations_connect(config, args.provider, args.slug, args.owner, no_open=args.no_open)
337
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
+ )
338
365
  if args.command == "create":
339
366
  return handle_create(
340
367
  config,
@@ -756,6 +783,48 @@ def _resolve_computer_ref(client: RuntimeClient, ref: str) -> str:
756
783
 
757
784
 
758
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
+
759
828
  def _computer_name(c: dict[str, Any]) -> str:
760
829
  return str(c.get("slug") or c.get("id") or "?")
761
830
 
@@ -1678,6 +1747,74 @@ def handle_integrations_connect(
1678
1747
 
1679
1748
 
1680
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
+
1681
1818
  def handle_onboarding(config: RuntimeConfig) -> int:
1682
1819
  code = handle_login(config, None, None, None)
1683
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.17
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
@@ -10,6 +10,9 @@ Classifier: Programming Language :: Python :: 3.12
10
10
  Classifier: Programming Language :: Python :: 3.13
11
11
  Classifier: Programming Language :: Python :: 3 :: Only
12
12
  Classifier: Environment :: Console
13
+ Classifier: Operating System :: MacOS :: MacOS X
14
+ Classifier: Operating System :: POSIX
15
+ Classifier: Operating System :: POSIX :: Linux
13
16
  Requires-Python: >=3.11
14
17
  Description-Content-Type: text/markdown
15
18
  Requires-Dist: httpx>=0.28.1
@@ -23,6 +26,10 @@ Python SDK and CLI for Runtime.
23
26
 
24
27
  ## Install
25
28
 
29
+ Supported host OS for the CLI: **macOS and Linux only**.
30
+
31
+ Windows is **not supported** at this time.
32
+
26
33
  ```bash
27
34
  uv tool install runtime-sdk
28
35
  ```
@@ -59,8 +66,12 @@ runtime login --api-key rt_live_...
59
66
  runtime api-keys list
60
67
  runtime api-keys create "my laptop"
61
68
  runtime api-keys revoke 123
69
+ runtime integrations connect github
62
70
 
63
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
64
75
  runtime create # creates a computer with the starter app already published
65
76
  runtime create myapp --command "python3 app.py" --cwd /home/ubuntu --port 3000
66
77
  runtime enter <name-or-id> # accepts slug/name like test, or the computer id
@@ -150,6 +161,28 @@ show|clear` expose that same durable app state directly. The low-level
150
161
  `runtime run` stays one-shot: the filesystem is restored after going cold, but
151
162
  that ad-hoc process is not.
152
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
+
153
186
  Run the SDK unit tests through the backend project environment:
154
187
 
155
188
  ```bash
File without changes