qbraid-cli 0.16.4__tar.gz → 0.16.6__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.16.4/qbraid_cli.egg-info → qbraid_cli-0.16.6}/PKG-INFO +4 -4
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/pyproject.toml +4 -4
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/agents/app.py +113 -40
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6/qbraid_cli.egg-info}/PKG-INFO +4 -4
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli.egg-info/requires.txt +3 -3
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/LICENSE +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/README.md +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/_build_info.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/_version.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/account/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/account/app.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/admin/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/admin/app.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/admin/headers.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/admin/validation.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/agents/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/agents/permission_response.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/ai/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/ai/app.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/ai/token.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/comms/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/comms/app.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/compute/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/compute/app.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/compute/instances.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/compute/profiles.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/compute/server.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/compute/ssh.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/configure/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/configure/actions.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/configure/app.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/devices/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/devices/app.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/devices/validation.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/envs/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/envs/activate.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/envs/app.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/envs/create.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/envs/data_handling.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/envs/groups.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/envs/publish.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/envs/registry.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/envs/share.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/exceptions.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/handlers.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/jobs/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/jobs/app.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/jobs/groups.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/kernels/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/kernels/app.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/lab/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/lab/app.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/main.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/pip/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/pip/app.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/pip/hooks.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/projects/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/projects/app.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/py.typed +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/skills/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/skills/app.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/troubleshoot/__init__.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli/troubleshoot/app.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli.egg-info/SOURCES.txt +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli.egg-info/dependency_links.txt +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli.egg-info/entry_points.txt +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/qbraid_cli.egg-info/top_level.txt +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/setup.cfg +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/tests/test_cli_e2e.py +0 -0
- {qbraid_cli-0.16.4 → qbraid_cli-0.16.6}/tests/test_version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qbraid-cli
|
|
3
|
-
Version: 0.16.
|
|
3
|
+
Version: 0.16.6
|
|
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
|
|
@@ -30,11 +30,11 @@ Requires-Dist: typer>=0.12.1
|
|
|
30
30
|
Requires-Dist: rich>=10.11.0
|
|
31
31
|
Requires-Dist: click<=8.5.0
|
|
32
32
|
Requires-Dist: questionary>=2.0.0
|
|
33
|
-
Requires-Dist: qbraid-core>=0.6.
|
|
33
|
+
Requires-Dist: qbraid-core>=0.6.15
|
|
34
34
|
Provides-Extra: compute
|
|
35
|
-
Requires-Dist: qbraid-core[compute]>=0.6.
|
|
35
|
+
Requires-Dist: qbraid-core[compute]>=0.6.15; extra == "compute"
|
|
36
36
|
Provides-Extra: envs
|
|
37
|
-
Requires-Dist: qbraid-core[environments]>=0.6.
|
|
37
|
+
Requires-Dist: qbraid-core[environments]>=0.6.15; extra == "envs"
|
|
38
38
|
Provides-Extra: dev
|
|
39
39
|
Requires-Dist: isort; extra == "dev"
|
|
40
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.16.
|
|
7
|
+
version = "0.16.6"
|
|
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" }]
|
|
@@ -32,7 +32,7 @@ dependencies = [
|
|
|
32
32
|
"rich>=10.11.0",
|
|
33
33
|
"click<=8.5.0",
|
|
34
34
|
"questionary>=2.0.0",
|
|
35
|
-
"qbraid-core>=0.6.
|
|
35
|
+
"qbraid-core>=0.6.15",
|
|
36
36
|
]
|
|
37
37
|
requires-python = ">= 3.10"
|
|
38
38
|
|
|
@@ -43,8 +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.6.
|
|
47
|
-
envs = ["qbraid-core[environments]>=0.6.
|
|
46
|
+
compute = ["qbraid-core[compute]>=0.6.15"]
|
|
47
|
+
envs = ["qbraid-core[environments]>=0.6.15"]
|
|
48
48
|
dev = ["isort", "black", "pytest", "pytest-cov", "pytest-asyncio"]
|
|
49
49
|
|
|
50
50
|
[project.scripts]
|
|
@@ -985,6 +985,13 @@ def agents_kill(
|
|
|
985
985
|
session = matches[0]
|
|
986
986
|
pid = session.pid
|
|
987
987
|
|
|
988
|
+
if session.metadata.get("terminal_backend") == "jupyter":
|
|
989
|
+
from qbraid_core.services.agents import AgentLauncher
|
|
990
|
+
|
|
991
|
+
AgentLauncher().kill_bound(session.session_id)
|
|
992
|
+
console.print("[green]Stopped native Lab agent.[/green]")
|
|
993
|
+
return
|
|
994
|
+
|
|
988
995
|
# For tmux-managed sessions, kill the tmux window
|
|
989
996
|
if session.tmux_session and session.tmux_window:
|
|
990
997
|
try:
|
|
@@ -1155,7 +1162,11 @@ def _interactive_attach(console_: Console) -> str:
|
|
|
1155
1162
|
sessions = registry.get_active_sessions()
|
|
1156
1163
|
|
|
1157
1164
|
# Only show sessions with tmux info (attachable)
|
|
1158
|
-
tmux_sessions = [
|
|
1165
|
+
tmux_sessions = [
|
|
1166
|
+
s
|
|
1167
|
+
for s in sessions
|
|
1168
|
+
if (s.tmux_session and s.tmux_window) or s.metadata.get("terminal_backend") == "jupyter"
|
|
1169
|
+
]
|
|
1159
1170
|
|
|
1160
1171
|
if not tmux_sessions:
|
|
1161
1172
|
non_tmux_count = len(sessions) - len(tmux_sessions)
|
|
@@ -1189,14 +1200,31 @@ def _interactive_attach(console_: Console) -> str:
|
|
|
1189
1200
|
|
|
1190
1201
|
|
|
1191
1202
|
class ApprovalMode(str, Enum):
|
|
1192
|
-
"""
|
|
1193
|
-
|
|
1194
|
-
A launched agent is detached, so a confirmation prompt has nobody to
|
|
1195
|
-
answer it — ``auto`` is the mode for anything you intend to leave running.
|
|
1196
|
-
"""
|
|
1203
|
+
"""Explicit native presets and backwards-compatible ask/auto policies."""
|
|
1197
1204
|
|
|
1198
1205
|
ASK = "ask"
|
|
1199
1206
|
AUTO = "auto"
|
|
1207
|
+
MANUAL = "manual"
|
|
1208
|
+
AUTO_REVIEW = "auto-review"
|
|
1209
|
+
YOLO = "yolo"
|
|
1210
|
+
|
|
1211
|
+
|
|
1212
|
+
class TerminalBackend(str, Enum):
|
|
1213
|
+
"""Terminal transport used to host an agent session."""
|
|
1214
|
+
|
|
1215
|
+
AUTO = "auto"
|
|
1216
|
+
JUPYTER = "jupyter"
|
|
1217
|
+
TMUX = "tmux"
|
|
1218
|
+
|
|
1219
|
+
|
|
1220
|
+
def _backend_launcher(backend):
|
|
1221
|
+
from qbraid_core.services.agents import AgentLauncher, AgentLauncherError
|
|
1222
|
+
|
|
1223
|
+
if backend == TerminalBackend.AUTO:
|
|
1224
|
+
return AgentLauncher()
|
|
1225
|
+
if "backend" not in inspect.signature(AgentLauncher).parameters:
|
|
1226
|
+
raise AgentLauncherError("Explicit terminal backends require a newer qbraid-core.")
|
|
1227
|
+
return AgentLauncher(backend=backend.value)
|
|
1200
1228
|
|
|
1201
1229
|
|
|
1202
1230
|
class ExecutionMode(str, Enum):
|
|
@@ -1399,6 +1427,11 @@ def agents_settings(
|
|
|
1399
1427
|
|
|
1400
1428
|
@agents_app.command("launch")
|
|
1401
1429
|
def agents_launch(
|
|
1430
|
+
backend: TerminalBackend = typer.Option(
|
|
1431
|
+
TerminalBackend.AUTO,
|
|
1432
|
+
"--backend",
|
|
1433
|
+
help="auto: prefer the owning Lab terminal; jupyter: require Lab; tmux: run independently.",
|
|
1434
|
+
),
|
|
1402
1435
|
tool: Optional[str] = typer.Option(
|
|
1403
1436
|
None, "--tool", "-t", help="Agent tool (claude, codeq, codex; claude-auto = claude --approval auto)"
|
|
1404
1437
|
),
|
|
@@ -1432,12 +1465,18 @@ def agents_launch(
|
|
|
1432
1465
|
approval: Optional[ApprovalMode] = typer.Option(
|
|
1433
1466
|
None,
|
|
1434
1467
|
"--approval",
|
|
1435
|
-
help=
|
|
1468
|
+
help=(
|
|
1469
|
+
"manual: the agent asks you. auto-review: the tool's own automatic reviewer "
|
|
1470
|
+
"decides. yolo: no permission checks. ask/auto: legacy modes, unchanged."
|
|
1471
|
+
),
|
|
1472
|
+
),
|
|
1473
|
+
yolo: bool = typer.Option(
|
|
1474
|
+
False, "--yolo", help="Claude: skip permissions. Codex: bypass approvals and its sandbox."
|
|
1436
1475
|
),
|
|
1437
1476
|
):
|
|
1438
1477
|
"""Launch an AI coding agent.
|
|
1439
1478
|
|
|
1440
|
-
|
|
1479
|
+
Uses the owning Lab terminal when available; otherwise starts in tmux.
|
|
1441
1480
|
|
|
1442
1481
|
Detached agents may wait for approval until you open their terminal or dashboard.
|
|
1443
1482
|
Approval and execution mode are independent and remembered for resume.
|
|
@@ -1446,7 +1485,7 @@ def agents_launch(
|
|
|
1446
1485
|
Choose it only where you trust the surrounding machine/container isolation.
|
|
1447
1486
|
"""
|
|
1448
1487
|
try:
|
|
1449
|
-
from qbraid_core.services.agents import
|
|
1488
|
+
from qbraid_core.services.agents import AgentLauncherError
|
|
1450
1489
|
|
|
1451
1490
|
# Interactive mode if no tool specified
|
|
1452
1491
|
if tool is None:
|
|
@@ -1459,13 +1498,29 @@ def agents_launch(
|
|
|
1459
1498
|
tag = tag or result.get("tags")
|
|
1460
1499
|
repo = repo or result.get("repo")
|
|
1461
1500
|
|
|
1501
|
+
if yolo:
|
|
1502
|
+
if tool not in ("claude", "claude-auto", "codex"):
|
|
1503
|
+
raise AgentLauncherError("--yolo is supported only for Claude and Codex.")
|
|
1504
|
+
# Only an explicit --approval yolo agrees with --yolo. "auto" used to
|
|
1505
|
+
# be accepted and silently upgraded, which for Codex drops the
|
|
1506
|
+
# workspace sandbox the user may have meant to keep.
|
|
1507
|
+
if approval not in (None, ApprovalMode.YOLO) or (
|
|
1508
|
+
execution_mode and execution_mode != ExecutionMode.CONTAINER
|
|
1509
|
+
):
|
|
1510
|
+
raise AgentLauncherError("--yolo conflicts with the selected approval or execution mode.")
|
|
1511
|
+
approval = ApprovalMode.YOLO
|
|
1512
|
+
if tool == "codex":
|
|
1513
|
+
execution_mode = ExecutionMode.CONTAINER
|
|
1514
|
+
|
|
1462
1515
|
if request_id is not None:
|
|
1463
1516
|
import uuid
|
|
1464
1517
|
|
|
1465
1518
|
if not compute or str(uuid.UUID(request_id)) != request_id:
|
|
1466
1519
|
raise AgentLauncherError("--request-id requires --compute and a canonical UUID.")
|
|
1467
1520
|
|
|
1468
|
-
|
|
1521
|
+
if compute and backend != TerminalBackend.AUTO:
|
|
1522
|
+
raise AgentLauncherError("Remote launches select the backend on the destination; omit --backend.")
|
|
1523
|
+
launcher = _backend_launcher(backend)
|
|
1469
1524
|
|
|
1470
1525
|
# Remote launch via SSH
|
|
1471
1526
|
if compute:
|
|
@@ -1511,6 +1566,8 @@ def agents_launch(
|
|
|
1511
1566
|
lines.append(f"[bold]Status:[/bold] [{style}]{status_val}[/{style}]")
|
|
1512
1567
|
if session.compute_id:
|
|
1513
1568
|
lines.append(f"[bold]Compute:[/bold] {session.compute_id}")
|
|
1569
|
+
if session.metadata.get("terminal_backend") == "jupyter":
|
|
1570
|
+
lines.append("[bold]Backend:[/bold] Jupyter (lifetime of the owning Lab server)")
|
|
1514
1571
|
lines.append(f"[bold]Tmux Session:[/bold] {session.tmux_session or '-'}")
|
|
1515
1572
|
lines.append(f"[bold]Tmux Window:[/bold] {session.tmux_window or '-'}")
|
|
1516
1573
|
lines.append(f"[bold]PID:[/bold] {session.pid or '-'}")
|
|
@@ -1525,8 +1582,8 @@ def agents_launch(
|
|
|
1525
1582
|
)
|
|
1526
1583
|
console.print(panel)
|
|
1527
1584
|
console.print()
|
|
1528
|
-
console.print("[dim]
|
|
1529
|
-
console.print(f"
|
|
1585
|
+
console.print("[dim]Open from the Agent Dashboard or attach with:[/dim]")
|
|
1586
|
+
console.print(f" qbraid agents attach {session.session_id}")
|
|
1530
1587
|
|
|
1531
1588
|
except AgentLauncherError as e:
|
|
1532
1589
|
console.print(
|
|
@@ -1614,6 +1671,11 @@ def _interactive_resume(console_: Console) -> str:
|
|
|
1614
1671
|
|
|
1615
1672
|
@agents_app.command("resume")
|
|
1616
1673
|
def agents_resume(
|
|
1674
|
+
backend: TerminalBackend = typer.Option(
|
|
1675
|
+
TerminalBackend.AUTO,
|
|
1676
|
+
"--backend",
|
|
1677
|
+
help="auto: prefer the owning Lab terminal; jupyter: require Lab; tmux: run independently.",
|
|
1678
|
+
),
|
|
1617
1679
|
session_id: Optional[str] = typer.Argument(
|
|
1618
1680
|
None, help="Session ID, prefix, or name. Omit for interactive picker."
|
|
1619
1681
|
),
|
|
@@ -1621,17 +1683,22 @@ def agents_resume(
|
|
|
1621
1683
|
execution_mode: Optional[ExecutionMode] = typer.Option(
|
|
1622
1684
|
None, "--execution-mode", help="Override the recorded Codex execution mode for this resume."
|
|
1623
1685
|
),
|
|
1686
|
+
approval: Optional[ApprovalMode] = typer.Option(
|
|
1687
|
+
None, "--approval", help="Override recorded permissions for this resume. Omit to preserve them."
|
|
1688
|
+
),
|
|
1624
1689
|
compute: Optional[str] = typer.Option(None, "--compute", "-c", help="SSH alias for remote compute"),
|
|
1625
1690
|
):
|
|
1626
1691
|
"""Resume a previous agent session.
|
|
1627
1692
|
|
|
1628
|
-
Resumes
|
|
1693
|
+
Resumes with the selected terminal backend. With ``--compute`` the session is resumed
|
|
1629
1694
|
on that machine, and a session id is required -- the interactive picker
|
|
1630
1695
|
reads the local registry and cannot see another host's sessions.
|
|
1631
1696
|
"""
|
|
1632
1697
|
try:
|
|
1633
|
-
from qbraid_core.services.agents import
|
|
1698
|
+
from qbraid_core.services.agents import AgentLauncherError
|
|
1634
1699
|
|
|
1700
|
+
if compute and backend != TerminalBackend.AUTO:
|
|
1701
|
+
raise AgentLauncherError("Remote resumes select the backend on the destination; omit --backend.")
|
|
1635
1702
|
if compute:
|
|
1636
1703
|
if session_id is None:
|
|
1637
1704
|
console.print(
|
|
@@ -1647,6 +1714,8 @@ def agents_resume(
|
|
|
1647
1714
|
flags += f" --name {shlex.quote(name)}"
|
|
1648
1715
|
if execution_mode:
|
|
1649
1716
|
flags += f" --execution-mode {shlex.quote(execution_mode.value)}"
|
|
1717
|
+
if approval:
|
|
1718
|
+
flags += f" --approval {shlex.quote(approval.value)}"
|
|
1650
1719
|
# markup=False -- see agents_status.
|
|
1651
1720
|
console.print(
|
|
1652
1721
|
_ssh_cmd(compute, f"qbraid agents resume {shlex.quote(session_id)}{flags}"),
|
|
@@ -1658,13 +1727,14 @@ def agents_resume(
|
|
|
1658
1727
|
if session_id is None:
|
|
1659
1728
|
session_id = _interactive_resume(console)
|
|
1660
1729
|
|
|
1661
|
-
launcher =
|
|
1730
|
+
launcher = _backend_launcher(backend)
|
|
1662
1731
|
|
|
1663
1732
|
# Try resume — handle active session and ambiguous matches
|
|
1664
1733
|
try:
|
|
1665
1734
|
session = launcher.resume(
|
|
1666
1735
|
session_id=session_id,
|
|
1667
1736
|
name=name,
|
|
1737
|
+
**(_approval_kwargs(launcher.resume, approval.value) if approval else {}),
|
|
1668
1738
|
**_execution_kwargs(launcher.resume, execution_mode.value if execution_mode else None),
|
|
1669
1739
|
)
|
|
1670
1740
|
except AgentLauncherError as e:
|
|
@@ -1711,7 +1781,10 @@ def agents_resume(
|
|
|
1711
1781
|
instructions=None,
|
|
1712
1782
|
# A fork of a detached agent must not quietly
|
|
1713
1783
|
# become one that waits for a human.
|
|
1714
|
-
**_approval_kwargs(
|
|
1784
|
+
**_approval_kwargs(
|
|
1785
|
+
launcher.launch,
|
|
1786
|
+
approval.value if approval else getattr(original, "approval", None),
|
|
1787
|
+
),
|
|
1715
1788
|
**_execution_kwargs(
|
|
1716
1789
|
launcher.launch,
|
|
1717
1790
|
(
|
|
@@ -1782,6 +1855,7 @@ def agents_resume(
|
|
|
1782
1855
|
session = launcher.resume(
|
|
1783
1856
|
session_id=selected,
|
|
1784
1857
|
name=name,
|
|
1858
|
+
**(_approval_kwargs(launcher.resume, approval.value) if approval else {}),
|
|
1785
1859
|
**_execution_kwargs(launcher.resume, execution_mode.value if execution_mode else None),
|
|
1786
1860
|
)
|
|
1787
1861
|
|
|
@@ -1792,6 +1866,8 @@ def agents_resume(
|
|
|
1792
1866
|
lines.append(f"[bold]Session ID:[/bold] {session.session_id}")
|
|
1793
1867
|
lines.append(f"[bold]Tool:[/bold] {session.tool.value if session.tool else '-'}")
|
|
1794
1868
|
lines.append(f"[bold]Status:[/bold] [{style}]{status_val}[/{style}]")
|
|
1869
|
+
if session.metadata.get("terminal_backend") == "jupyter":
|
|
1870
|
+
lines.append("[bold]Backend:[/bold] Jupyter (lifetime of the owning Lab server)")
|
|
1795
1871
|
lines.append(f"[bold]Tmux Session:[/bold] {session.tmux_session or '-'}")
|
|
1796
1872
|
lines.append(f"[bold]Tmux Window:[/bold] {session.tmux_window or '-'}")
|
|
1797
1873
|
lines.append(f"[bold]CWD:[/bold] {session.cwd or '-'}")
|
|
@@ -2485,29 +2561,14 @@ def agents_attach(
|
|
|
2485
2561
|
):
|
|
2486
2562
|
"""Attach to an agent's terminal.
|
|
2487
2563
|
|
|
2488
|
-
|
|
2564
|
+
Reconnects to its recorded native terminal or tmux window.
|
|
2489
2565
|
"""
|
|
2490
2566
|
try:
|
|
2491
|
-
# Remote attach: SSH + tmux attach
|
|
2492
2567
|
if compute:
|
|
2493
2568
|
import shlex
|
|
2494
2569
|
|
|
2495
|
-
if session_id
|
|
2496
|
-
|
|
2497
|
-
console.print(f"[dim]Attaching to {session_id} on {compute}... (Ctrl+b d to detach)[/dim]")
|
|
2498
|
-
os.execvp(
|
|
2499
|
-
"ssh",
|
|
2500
|
-
[
|
|
2501
|
-
"ssh",
|
|
2502
|
-
"-t",
|
|
2503
|
-
compute,
|
|
2504
|
-
f"tmux attach -t qbraid-agents:{shlex.quote(session_id)}",
|
|
2505
|
-
],
|
|
2506
|
-
)
|
|
2507
|
-
else:
|
|
2508
|
-
# Attach to the tmux session (user picks window)
|
|
2509
|
-
console.print(f"[dim]Attaching to qbraid-agents on {compute}... (Ctrl+b d to detach)[/dim]")
|
|
2510
|
-
os.execvp("ssh", ["ssh", "-t", compute, "tmux attach -t qbraid-agents"])
|
|
2570
|
+
command = "qbraid agents attach" + (" -- " + shlex.quote(session_id) if session_id else "")
|
|
2571
|
+
os.execvp("ssh", ["ssh", "-t", "--", compute, command])
|
|
2511
2572
|
return
|
|
2512
2573
|
|
|
2513
2574
|
# Interactive mode if no session_id provided
|
|
@@ -2522,6 +2583,23 @@ def agents_attach(
|
|
|
2522
2583
|
console.print("[dim]Use 'qbraid agents list' to see active sessions.[/dim]")
|
|
2523
2584
|
raise typer.Exit(code=1)
|
|
2524
2585
|
|
|
2586
|
+
if session.compute_id:
|
|
2587
|
+
import shlex
|
|
2588
|
+
|
|
2589
|
+
remote_id = session.metadata.get("remote_session_id") or session.session_id
|
|
2590
|
+
command = "qbraid agents attach -- " + shlex.quote(remote_id)
|
|
2591
|
+
os.execvp("ssh", ["ssh", "-t", "--", session.compute_id, command])
|
|
2592
|
+
return
|
|
2593
|
+
if session.machine_id:
|
|
2594
|
+
raise ValueError("Attach on the recorded machine; no SSH alias was recorded.")
|
|
2595
|
+
|
|
2596
|
+
if session.metadata.get("terminal_backend") == "jupyter":
|
|
2597
|
+
from qbraid_core.services.agents.jupyter_runtime import JupyterRuntimeClient
|
|
2598
|
+
|
|
2599
|
+
console.print("[dim]Attaching to native Lab terminal. Ctrl-] detaches.[/dim]")
|
|
2600
|
+
JupyterRuntimeClient(session.metadata["jupyter_server_id"]).attach(session)
|
|
2601
|
+
return
|
|
2602
|
+
|
|
2525
2603
|
tmux_session = session.tmux_session
|
|
2526
2604
|
tmux_window = session.tmux_window
|
|
2527
2605
|
|
|
@@ -2549,12 +2627,7 @@ def agents_attach(
|
|
|
2549
2627
|
|
|
2550
2628
|
console.print(f"[dim]Attaching to {target}... (Ctrl+b d to detach)[/dim]")
|
|
2551
2629
|
|
|
2552
|
-
|
|
2553
|
-
if session.compute_id:
|
|
2554
|
-
alias = session.compute_id
|
|
2555
|
-
os.execvp("ssh", ["ssh", "-t", alias, f"tmux attach -t {target}"])
|
|
2556
|
-
else:
|
|
2557
|
-
os.execvp("tmux", ["tmux", "attach", "-t", target])
|
|
2630
|
+
os.execvp("tmux", ["tmux", "attach", "-t", target])
|
|
2558
2631
|
|
|
2559
2632
|
except (typer.Exit, SystemExit):
|
|
2560
2633
|
raise
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qbraid-cli
|
|
3
|
-
Version: 0.16.
|
|
3
|
+
Version: 0.16.6
|
|
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
|
|
@@ -30,11 +30,11 @@ Requires-Dist: typer>=0.12.1
|
|
|
30
30
|
Requires-Dist: rich>=10.11.0
|
|
31
31
|
Requires-Dist: click<=8.5.0
|
|
32
32
|
Requires-Dist: questionary>=2.0.0
|
|
33
|
-
Requires-Dist: qbraid-core>=0.6.
|
|
33
|
+
Requires-Dist: qbraid-core>=0.6.15
|
|
34
34
|
Provides-Extra: compute
|
|
35
|
-
Requires-Dist: qbraid-core[compute]>=0.6.
|
|
35
|
+
Requires-Dist: qbraid-core[compute]>=0.6.15; extra == "compute"
|
|
36
36
|
Provides-Extra: envs
|
|
37
|
-
Requires-Dist: qbraid-core[environments]>=0.6.
|
|
37
|
+
Requires-Dist: qbraid-core[environments]>=0.6.15; extra == "envs"
|
|
38
38
|
Provides-Extra: dev
|
|
39
39
|
Requires-Dist: isort; extra == "dev"
|
|
40
40
|
Requires-Dist: black; extra == "dev"
|
|
@@ -2,10 +2,10 @@ typer>=0.12.1
|
|
|
2
2
|
rich>=10.11.0
|
|
3
3
|
click<=8.5.0
|
|
4
4
|
questionary>=2.0.0
|
|
5
|
-
qbraid-core>=0.6.
|
|
5
|
+
qbraid-core>=0.6.15
|
|
6
6
|
|
|
7
7
|
[compute]
|
|
8
|
-
qbraid-core[compute]>=0.6.
|
|
8
|
+
qbraid-core[compute]>=0.6.15
|
|
9
9
|
|
|
10
10
|
[dev]
|
|
11
11
|
isort
|
|
@@ -15,4 +15,4 @@ pytest-cov
|
|
|
15
15
|
pytest-asyncio
|
|
16
16
|
|
|
17
17
|
[envs]
|
|
18
|
-
qbraid-core[environments]>=0.6.
|
|
18
|
+
qbraid-core[environments]>=0.6.15
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|