qbraid-cli 0.13.0a0__tar.gz → 0.13.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.
- {qbraid_cli-0.13.0a0/qbraid_cli.egg-info → qbraid_cli-0.13.1}/PKG-INFO +5 -7
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/pyproject.toml +6 -7
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/compute/app.py +26 -35
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/compute/profiles.py +14 -7
- qbraid_cli-0.13.1/qbraid_cli/compute/server.py +589 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/compute/ssh.py +72 -35
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/configure/app.py +1 -90
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/activate.py +10 -3
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/app.py +153 -8
- qbraid_cli-0.13.1/qbraid_cli/jobs/app.py +406 -0
- qbraid_cli-0.13.1/qbraid_cli/jobs/groups.py +351 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/main.py +0 -2
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1/qbraid_cli.egg-info}/PKG-INFO +5 -7
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli.egg-info/SOURCES.txt +1 -4
- qbraid_cli-0.13.1/qbraid_cli.egg-info/requires.txt +18 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/tests/test_cli_e2e.py +8 -1
- qbraid_cli-0.13.0a0/qbraid_cli/compute/server.py +0 -343
- qbraid_cli-0.13.0a0/qbraid_cli/configure/claude_config.py +0 -214
- qbraid_cli-0.13.0a0/qbraid_cli/jobs/app.py +0 -182
- qbraid_cli-0.13.0a0/qbraid_cli/mcp/__init__.py +0 -11
- qbraid_cli-0.13.0a0/qbraid_cli/mcp/app.py +0 -113
- qbraid_cli-0.13.0a0/qbraid_cli/mcp/serve.py +0 -320
- qbraid_cli-0.13.0a0/qbraid_cli.egg-info/requires.txt +0 -21
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/LICENSE +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/README.md +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/__init__.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/_build_info.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/_version.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/account/__init__.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/account/app.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/admin/__init__.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/admin/app.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/admin/headers.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/admin/validation.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/agents/__init__.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/agents/app.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/compute/__init__.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/configure/__init__.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/configure/actions.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/devices/__init__.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/devices/app.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/devices/validation.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/__init__.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/create.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/data_handling.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/groups.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/publish.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/registry.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/share.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/exceptions.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/handlers.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/jobs/__init__.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/kernels/__init__.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/kernels/app.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/lab/__init__.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/lab/app.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/pip/__init__.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/pip/app.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/pip/hooks.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/projects/__init__.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/projects/app.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/py.typed +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/skills/__init__.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/skills/app.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/troubleshoot/__init__.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/troubleshoot/app.py +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli.egg-info/dependency_links.txt +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli.egg-info/entry_points.txt +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli.egg-info/top_level.txt +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/setup.cfg +0 -0
- {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/tests/test_version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qbraid-cli
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.1
|
|
4
4
|
Summary: Command Line Interface for interacting with all parts of the qBraid platform.
|
|
5
5
|
Author-email: qBraid Development Team <contact@qbraid.com>
|
|
6
6
|
License-Expression: LicenseRef-Proprietary
|
|
@@ -28,15 +28,13 @@ Description-Content-Type: text/markdown
|
|
|
28
28
|
License-File: LICENSE
|
|
29
29
|
Requires-Dist: typer>=0.12.1
|
|
30
30
|
Requires-Dist: rich>=10.11.0
|
|
31
|
-
Requires-Dist: click<=8.
|
|
31
|
+
Requires-Dist: click<=8.3.3
|
|
32
32
|
Requires-Dist: questionary>=2.0.0
|
|
33
|
-
Requires-Dist: qbraid-core>=0.3.
|
|
33
|
+
Requires-Dist: qbraid-core>=0.3.3
|
|
34
34
|
Provides-Extra: compute
|
|
35
|
-
Requires-Dist: qbraid-core[compute]>=0.3.
|
|
35
|
+
Requires-Dist: qbraid-core[compute]>=0.3.3; extra == "compute"
|
|
36
36
|
Provides-Extra: envs
|
|
37
|
-
Requires-Dist: qbraid-core[environments]>=0.3.
|
|
38
|
-
Provides-Extra: mcp
|
|
39
|
-
Requires-Dist: qbraid-core[mcp]>=0.3.0a0; extra == "mcp"
|
|
37
|
+
Requires-Dist: qbraid-core[environments]>=0.3.0; extra == "envs"
|
|
40
38
|
Provides-Extra: dev
|
|
41
39
|
Requires-Dist: isort; extra == "dev"
|
|
42
40
|
Requires-Dist: black; extra == "dev"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "qbraid-cli"
|
|
7
|
-
version = "0.13.
|
|
7
|
+
version = "0.13.1"
|
|
8
8
|
description = "Command Line Interface for interacting with all parts of the qBraid platform."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{ name = "qBraid Development Team", email = "contact@qbraid.com" }]
|
|
@@ -30,9 +30,9 @@ classifiers = [
|
|
|
30
30
|
dependencies = [
|
|
31
31
|
"typer>=0.12.1",
|
|
32
32
|
"rich>=10.11.0",
|
|
33
|
-
"click<=8.
|
|
33
|
+
"click<=8.3.3",
|
|
34
34
|
"questionary>=2.0.0",
|
|
35
|
-
"qbraid-core>=0.3.
|
|
35
|
+
"qbraid-core>=0.3.3",
|
|
36
36
|
]
|
|
37
37
|
requires-python = ">= 3.10"
|
|
38
38
|
|
|
@@ -43,9 +43,8 @@ Documentation = "https://docs.qbraid.com/v2/cli/api-reference/qbraid"
|
|
|
43
43
|
Discord = "https://discord.gg/KugF6Cnncm"
|
|
44
44
|
|
|
45
45
|
[project.optional-dependencies]
|
|
46
|
-
compute = ["qbraid-core[compute]>=0.3.
|
|
47
|
-
envs = ["qbraid-core[environments]>=0.3.
|
|
48
|
-
mcp = ["qbraid-core[mcp]>=0.3.0a0"]
|
|
46
|
+
compute = ["qbraid-core[compute]>=0.3.3"]
|
|
47
|
+
envs = ["qbraid-core[environments]>=0.3.0"]
|
|
49
48
|
dev = ["isort", "black", "pytest", "pytest-cov", "pytest-asyncio"]
|
|
50
49
|
|
|
51
50
|
[project.scripts]
|
|
@@ -65,7 +64,7 @@ line_length = 110
|
|
|
65
64
|
|
|
66
65
|
[tool.pylint.'MESSAGES CONTROL']
|
|
67
66
|
max-line-length = 110
|
|
68
|
-
disable = "C0116,C0302,C0415,E1101,R0801,R0903,R0912,R0913,R0914,R0915,R0917,R1702,W0212,W0511,W0621,W0707,W0718"
|
|
67
|
+
disable = "C0116,C0302,C0415,E1101,R0401,R0801,R0903,R0912,R0913,R0914,R0915,R0917,R1702,W0212,W0511,W0621,W0707,W0718"
|
|
69
68
|
|
|
70
69
|
[tool.pylint.MASTER]
|
|
71
70
|
ignore-paths = [
|
|
@@ -13,7 +13,7 @@ from rich.table import Table
|
|
|
13
13
|
from qbraid_cli.handlers import handle_error, run_progress_task
|
|
14
14
|
|
|
15
15
|
from .profiles import profiles_app
|
|
16
|
-
from .server import server_app
|
|
16
|
+
from .server import _print_unified_status_table, _select_bma_instance, server_app
|
|
17
17
|
from .ssh import ssh_app
|
|
18
18
|
|
|
19
19
|
compute_app = typer.Typer(
|
|
@@ -173,7 +173,29 @@ def compute_down(
|
|
|
173
173
|
try:
|
|
174
174
|
client = _get_client()
|
|
175
175
|
|
|
176
|
-
#
|
|
176
|
+
# Route to a BMA instance if an on-demand instance is running.
|
|
177
|
+
target_instance = _select_bma_instance(client, None, "stop")
|
|
178
|
+
if target_instance:
|
|
179
|
+
if not force:
|
|
180
|
+
confirm = typer.confirm(f"Stop instance {target_instance}?")
|
|
181
|
+
if not confirm:
|
|
182
|
+
console.print("Cancelled.")
|
|
183
|
+
raise typer.Exit(code=0)
|
|
184
|
+
|
|
185
|
+
def stop_instance():
|
|
186
|
+
return client.stop_bma_instance(target_instance)
|
|
187
|
+
|
|
188
|
+
inst = run_progress_task(
|
|
189
|
+
stop_instance,
|
|
190
|
+
description=f"Stopping {target_instance}...",
|
|
191
|
+
include_error_traceback=False,
|
|
192
|
+
)
|
|
193
|
+
console.print(f"[green]Stopping instance {inst.instance_id}[/green]")
|
|
194
|
+
console.print(f" Status: {inst.status.value}")
|
|
195
|
+
console.print("[dim]Poll with: qbraid compute status[/dim]")
|
|
196
|
+
return
|
|
197
|
+
|
|
198
|
+
# Check if a legacy server is running
|
|
177
199
|
status = client.get_server_status(cluster_id)
|
|
178
200
|
if not status.server_running and not status.server_starting:
|
|
179
201
|
console.print("[dim]No server is currently running.[/dim]")
|
|
@@ -222,41 +244,10 @@ def compute_status(
|
|
|
222
244
|
"""
|
|
223
245
|
try:
|
|
224
246
|
client = _get_client()
|
|
225
|
-
|
|
226
247
|
status = client.get_server_status(cluster_id)
|
|
248
|
+
instances = _print_unified_status_table(client, status)
|
|
227
249
|
|
|
228
|
-
if status.server_running:
|
|
229
|
-
console.print(f"[green]●[/green] Running: [cyan]{status.current_profile}[/cyan]")
|
|
230
|
-
|
|
231
|
-
# Show clickable URL for non-SSH IDE profiles
|
|
232
|
-
ide = None
|
|
233
|
-
if status.current_profile:
|
|
234
|
-
try:
|
|
235
|
-
profile = client.get_profile(status.current_profile)
|
|
236
|
-
ide = profile.ide
|
|
237
|
-
except Exception:
|
|
238
|
-
pass
|
|
239
|
-
|
|
240
|
-
if ide and ide != "ssh":
|
|
241
|
-
lab_url = status.url if status.url else None
|
|
242
|
-
if not lab_url:
|
|
243
|
-
try:
|
|
244
|
-
token_resp = client.get_session_token(cluster_id)
|
|
245
|
-
hub_domain = f"{token_resp.cluster_id}.qbraid.com"
|
|
246
|
-
username = status.user_info.name if status.user_info else token_resp.token.user
|
|
247
|
-
lab_url = (
|
|
248
|
-
f"https://{hub_domain}/user/{username}" f"/lab?token={token_resp.token.token}"
|
|
249
|
-
)
|
|
250
|
-
except Exception:
|
|
251
|
-
pass
|
|
252
|
-
if lab_url:
|
|
253
|
-
from .server import _mask_url_token
|
|
254
|
-
|
|
255
|
-
console.print(f" [link={lab_url}]{_mask_url_token(lab_url)}[/link]")
|
|
256
|
-
elif status.server_starting:
|
|
257
|
-
console.print("[yellow]●[/yellow] Starting...")
|
|
258
|
-
else:
|
|
259
|
-
console.print("[dim]○[/dim] No server running")
|
|
250
|
+
if not status.server_running and not status.server_starting and not instances:
|
|
260
251
|
console.print()
|
|
261
252
|
console.print("[dim]Start with: qbraid compute up <profile>[/dim]")
|
|
262
253
|
|
|
@@ -56,23 +56,30 @@ def profiles_list(
|
|
|
56
56
|
table = Table(title="Compute Profiles")
|
|
57
57
|
table.add_column("Slug", style="cyan")
|
|
58
58
|
table.add_column("Name", style="white")
|
|
59
|
-
table.add_column("
|
|
60
|
-
table.add_column("Type", style="magenta")
|
|
59
|
+
table.add_column("Price", style="magenta")
|
|
61
60
|
table.add_column("GPU", style="green")
|
|
62
61
|
table.add_column("Capacity", style="blue")
|
|
63
62
|
|
|
64
63
|
for profile in profiles:
|
|
65
64
|
gpu_str = "Yes" if profile.gpu else "No"
|
|
66
65
|
capacity_str = "Yes" if profile.has_capacity else "No"
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
|
|
67
|
+
rate = getattr(profile, "rate_dollar", None)
|
|
68
|
+
try:
|
|
69
|
+
# Defensive: API has occasionally returned rate as a string.
|
|
70
|
+
rate_f = float(rate) if rate is not None else 0.0
|
|
71
|
+
except (TypeError, ValueError):
|
|
72
|
+
rate_f = 0.0
|
|
73
|
+
if not rate_f:
|
|
74
|
+
price_str = "Free"
|
|
75
|
+
else:
|
|
76
|
+
frame = getattr(profile, "rate_time_frame", None) or "hr"
|
|
77
|
+
price_str = f"${rate_f:g}/{frame}"
|
|
70
78
|
|
|
71
79
|
table.add_row(
|
|
72
80
|
profile.slug,
|
|
73
81
|
profile.display_name or profile.slug,
|
|
74
|
-
|
|
75
|
-
profile_type,
|
|
82
|
+
price_str,
|
|
76
83
|
gpu_str,
|
|
77
84
|
capacity_str,
|
|
78
85
|
)
|