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.
Files changed (71) hide show
  1. {qbraid_cli-0.13.0a0/qbraid_cli.egg-info → qbraid_cli-0.13.1}/PKG-INFO +5 -7
  2. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/pyproject.toml +6 -7
  3. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/compute/app.py +26 -35
  4. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/compute/profiles.py +14 -7
  5. qbraid_cli-0.13.1/qbraid_cli/compute/server.py +589 -0
  6. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/compute/ssh.py +72 -35
  7. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/configure/app.py +1 -90
  8. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/activate.py +10 -3
  9. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/app.py +153 -8
  10. qbraid_cli-0.13.1/qbraid_cli/jobs/app.py +406 -0
  11. qbraid_cli-0.13.1/qbraid_cli/jobs/groups.py +351 -0
  12. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/main.py +0 -2
  13. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1/qbraid_cli.egg-info}/PKG-INFO +5 -7
  14. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli.egg-info/SOURCES.txt +1 -4
  15. qbraid_cli-0.13.1/qbraid_cli.egg-info/requires.txt +18 -0
  16. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/tests/test_cli_e2e.py +8 -1
  17. qbraid_cli-0.13.0a0/qbraid_cli/compute/server.py +0 -343
  18. qbraid_cli-0.13.0a0/qbraid_cli/configure/claude_config.py +0 -214
  19. qbraid_cli-0.13.0a0/qbraid_cli/jobs/app.py +0 -182
  20. qbraid_cli-0.13.0a0/qbraid_cli/mcp/__init__.py +0 -11
  21. qbraid_cli-0.13.0a0/qbraid_cli/mcp/app.py +0 -113
  22. qbraid_cli-0.13.0a0/qbraid_cli/mcp/serve.py +0 -320
  23. qbraid_cli-0.13.0a0/qbraid_cli.egg-info/requires.txt +0 -21
  24. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/LICENSE +0 -0
  25. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/README.md +0 -0
  26. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/__init__.py +0 -0
  27. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/_build_info.py +0 -0
  28. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/_version.py +0 -0
  29. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/account/__init__.py +0 -0
  30. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/account/app.py +0 -0
  31. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/admin/__init__.py +0 -0
  32. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/admin/app.py +0 -0
  33. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/admin/headers.py +0 -0
  34. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/admin/validation.py +0 -0
  35. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/agents/__init__.py +0 -0
  36. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/agents/app.py +0 -0
  37. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/compute/__init__.py +0 -0
  38. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/configure/__init__.py +0 -0
  39. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/configure/actions.py +0 -0
  40. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/devices/__init__.py +0 -0
  41. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/devices/app.py +0 -0
  42. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/devices/validation.py +0 -0
  43. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/__init__.py +0 -0
  44. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/create.py +0 -0
  45. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/data_handling.py +0 -0
  46. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/groups.py +0 -0
  47. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/publish.py +0 -0
  48. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/registry.py +0 -0
  49. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/envs/share.py +0 -0
  50. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/exceptions.py +0 -0
  51. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/handlers.py +0 -0
  52. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/jobs/__init__.py +0 -0
  53. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/kernels/__init__.py +0 -0
  54. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/kernels/app.py +0 -0
  55. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/lab/__init__.py +0 -0
  56. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/lab/app.py +0 -0
  57. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/pip/__init__.py +0 -0
  58. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/pip/app.py +0 -0
  59. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/pip/hooks.py +0 -0
  60. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/projects/__init__.py +0 -0
  61. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/projects/app.py +0 -0
  62. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/py.typed +0 -0
  63. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/skills/__init__.py +0 -0
  64. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/skills/app.py +0 -0
  65. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/troubleshoot/__init__.py +0 -0
  66. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli/troubleshoot/app.py +0 -0
  67. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli.egg-info/dependency_links.txt +0 -0
  68. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli.egg-info/entry_points.txt +0 -0
  69. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/qbraid_cli.egg-info/top_level.txt +0 -0
  70. {qbraid_cli-0.13.0a0 → qbraid_cli-0.13.1}/setup.cfg +0 -0
  71. {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.0a0
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.1.8
31
+ Requires-Dist: click<=8.3.3
32
32
  Requires-Dist: questionary>=2.0.0
33
- Requires-Dist: qbraid-core>=0.3.0a1
33
+ Requires-Dist: qbraid-core>=0.3.3
34
34
  Provides-Extra: compute
35
- Requires-Dist: qbraid-core[compute]>=0.3.0a0; extra == "compute"
35
+ Requires-Dist: qbraid-core[compute]>=0.3.3; extra == "compute"
36
36
  Provides-Extra: envs
37
- Requires-Dist: qbraid-core[environments]>=0.3.0a0; extra == "envs"
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.0a0"
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.1.8",
33
+ "click<=8.3.3",
34
34
  "questionary>=2.0.0",
35
- "qbraid-core>=0.3.0a1",
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.0a0"]
47
- envs = ["qbraid-core[environments]>=0.3.0a0"]
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
- # Check if server is running
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("Plan", style="yellow")
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
- profile_type = getattr(profile, "profile_type", "global")
68
- if hasattr(profile_type, "value"):
69
- profile_type = profile_type.value
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
- getattr(profile, "plan", "-") or "-",
75
- profile_type,
82
+ price_str,
76
83
  gpu_str,
77
84
  capacity_str,
78
85
  )