qbraid-cli 0.15.2__tar.gz → 0.15.3__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 (69) hide show
  1. {qbraid_cli-0.15.2/qbraid_cli.egg-info → qbraid_cli-0.15.3}/PKG-INFO +4 -4
  2. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/pyproject.toml +4 -4
  3. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/agents/app.py +223 -19
  4. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3/qbraid_cli.egg-info}/PKG-INFO +4 -4
  5. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli.egg-info/requires.txt +3 -3
  6. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/LICENSE +0 -0
  7. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/README.md +0 -0
  8. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/__init__.py +0 -0
  9. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/_build_info.py +0 -0
  10. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/_version.py +0 -0
  11. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/account/__init__.py +0 -0
  12. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/account/app.py +0 -0
  13. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/admin/__init__.py +0 -0
  14. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/admin/app.py +0 -0
  15. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/admin/headers.py +0 -0
  16. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/admin/validation.py +0 -0
  17. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/agents/__init__.py +0 -0
  18. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/agents/permission_response.py +0 -0
  19. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/ai/__init__.py +0 -0
  20. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/ai/app.py +0 -0
  21. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/ai/token.py +0 -0
  22. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/compute/__init__.py +0 -0
  23. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/compute/app.py +0 -0
  24. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/compute/instances.py +0 -0
  25. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/compute/profiles.py +0 -0
  26. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/compute/server.py +0 -0
  27. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/compute/ssh.py +0 -0
  28. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/configure/__init__.py +0 -0
  29. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/configure/actions.py +0 -0
  30. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/configure/app.py +0 -0
  31. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/devices/__init__.py +0 -0
  32. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/devices/app.py +0 -0
  33. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/devices/validation.py +0 -0
  34. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/envs/__init__.py +0 -0
  35. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/envs/activate.py +0 -0
  36. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/envs/app.py +0 -0
  37. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/envs/create.py +0 -0
  38. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/envs/data_handling.py +0 -0
  39. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/envs/groups.py +0 -0
  40. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/envs/publish.py +0 -0
  41. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/envs/registry.py +0 -0
  42. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/envs/share.py +0 -0
  43. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/exceptions.py +0 -0
  44. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/handlers.py +0 -0
  45. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/jobs/__init__.py +0 -0
  46. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/jobs/app.py +0 -0
  47. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/jobs/groups.py +0 -0
  48. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/kernels/__init__.py +0 -0
  49. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/kernels/app.py +0 -0
  50. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/lab/__init__.py +0 -0
  51. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/lab/app.py +0 -0
  52. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/main.py +0 -0
  53. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/pip/__init__.py +0 -0
  54. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/pip/app.py +0 -0
  55. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/pip/hooks.py +0 -0
  56. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/projects/__init__.py +0 -0
  57. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/projects/app.py +0 -0
  58. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/py.typed +0 -0
  59. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/skills/__init__.py +0 -0
  60. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/skills/app.py +0 -0
  61. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/troubleshoot/__init__.py +0 -0
  62. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli/troubleshoot/app.py +0 -0
  63. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli.egg-info/SOURCES.txt +0 -0
  64. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli.egg-info/dependency_links.txt +0 -0
  65. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli.egg-info/entry_points.txt +0 -0
  66. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/qbraid_cli.egg-info/top_level.txt +0 -0
  67. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/setup.cfg +0 -0
  68. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/tests/test_cli_e2e.py +0 -0
  69. {qbraid_cli-0.15.2 → qbraid_cli-0.15.3}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qbraid-cli
3
- Version: 0.15.2
3
+ Version: 0.15.3
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.3.3
32
32
  Requires-Dist: questionary>=2.0.0
33
- Requires-Dist: qbraid-core>=0.5.0
33
+ Requires-Dist: qbraid-core>=0.6.5
34
34
  Provides-Extra: compute
35
- Requires-Dist: qbraid-core[compute]>=0.5.0; extra == "compute"
35
+ Requires-Dist: qbraid-core[compute]>=0.6.5; extra == "compute"
36
36
  Provides-Extra: envs
37
- Requires-Dist: qbraid-core[environments]>=0.5.0; extra == "envs"
37
+ Requires-Dist: qbraid-core[environments]>=0.6.5; 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.15.2"
7
+ version = "0.15.3"
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.3.3",
34
34
  "questionary>=2.0.0",
35
- "qbraid-core>=0.5.0",
35
+ "qbraid-core>=0.6.5",
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.5.0"]
47
- envs = ["qbraid-core[environments]>=0.5.0"]
46
+ compute = ["qbraid-core[compute]>=0.6.5"]
47
+ envs = ["qbraid-core[environments]>=0.6.5"]
48
48
  dev = ["isort", "black", "pytest", "pytest-cov", "pytest-asyncio"]
49
49
 
50
50
  [project.scripts]
@@ -4,6 +4,7 @@
4
4
  """Agents CLI - Monitor and manage AI coding agent sessions."""
5
5
 
6
6
  import inspect
7
+ import json
7
8
  import os
8
9
  import re
9
10
  import signal
@@ -207,7 +208,6 @@ def agents_register():
207
208
 
208
209
  Reads session data from stdin JSON (used by hooks).
209
210
  """
210
- import json
211
211
  import sys
212
212
 
213
213
  try:
@@ -237,7 +237,6 @@ def agents_deregister():
237
237
 
238
238
  Reads session data from stdin JSON (used by hooks).
239
239
  """
240
- import json
241
240
  import sys
242
241
 
243
242
  try:
@@ -381,10 +380,9 @@ def agents_list(
381
380
 
382
381
  # JSON output mode
383
382
  if json_output:
384
- import json as _json
385
383
 
386
384
  output = [s.model_dump(mode="json", by_alias=True, exclude_none=True) for s in sessions]
387
- print(_json.dumps(output, indent=2))
385
+ print(json.dumps(output, indent=2))
388
386
  return
389
387
 
390
388
  # Sort
@@ -1109,6 +1107,57 @@ class ApprovalMode(str, Enum):
1109
1107
  AUTO = "auto"
1110
1108
 
1111
1109
 
1110
+ class ExecutionMode(str, Enum):
1111
+ """Codex command isolation, independent of approval prompts."""
1112
+
1113
+ NATIVE = "native"
1114
+ WORKSPACE = "workspace"
1115
+ CONTAINER = "container"
1116
+
1117
+
1118
+ def _execution_kwargs(method: Callable[..., Any], mode: Optional[str]) -> Dict[str, Any]:
1119
+ """Never silently discard an explicitly selected execution policy."""
1120
+ if mode is None:
1121
+ return {}
1122
+ try:
1123
+ params = inspect.signature(method).parameters
1124
+ supported = "execution_mode" in params or any(
1125
+ param.kind is inspect.Parameter.VAR_KEYWORD for param in params.values()
1126
+ )
1127
+ except (TypeError, ValueError):
1128
+ supported = False
1129
+ if not supported:
1130
+ handle_error(
1131
+ error_type="UnsupportedOptionError",
1132
+ message="--execution-mode requires a newer qbraid-core. Upgrade qbraid-core first.",
1133
+ include_traceback=False,
1134
+ )
1135
+ return {"execution_mode": mode}
1136
+
1137
+
1138
+ def _request_id_kwargs(method: Callable[..., Any], request_id: Optional[str]) -> Dict[str, Any]:
1139
+ """Require explicit Core support before promising remote replay protection."""
1140
+ if request_id is None:
1141
+ return {}
1142
+ try:
1143
+ params = inspect.signature(method).parameters
1144
+ supported = "request_id" in params or any(
1145
+ param.kind is inspect.Parameter.VAR_KEYWORD for param in params.values()
1146
+ )
1147
+ except (TypeError, ValueError):
1148
+ supported = False
1149
+ if not supported:
1150
+ handle_error(
1151
+ error_type="UnsupportedOptionError",
1152
+ message=(
1153
+ "--request-id requires a newer qbraid-core. "
1154
+ "Upgrade Core on this machine and the destination before launching."
1155
+ ),
1156
+ include_traceback=False,
1157
+ )
1158
+ return {"request_id": request_id}
1159
+
1160
+
1112
1161
  def _approval_kwargs(method: Callable[..., Any], approval: Optional[str]) -> Dict[str, Any]:
1113
1162
  """Forward ``approval`` only to a qbraid-core new enough to accept it.
1114
1163
 
@@ -1147,6 +1196,115 @@ def _approval_kwargs(method: Callable[..., Any], approval: Optional[str]) -> Dic
1147
1196
  return {}
1148
1197
 
1149
1198
 
1199
+ @agents_app.command("readiness")
1200
+ def agents_readiness(
1201
+ tool: str = typer.Option(..., "--tool", help="Provider to inspect: claude, codex, or codeq."),
1202
+ cwd: Optional[str] = typer.Option(None, "--cwd", help="Working directory on this machine."),
1203
+ approval: Optional[ApprovalMode] = typer.Option(None, "--approval"),
1204
+ execution_mode: Optional[ExecutionMode] = typer.Option(None, "--execution-mode"),
1205
+ json_output: bool = typer.Option(False, "--json", help="Print structured checks and recovery actions."),
1206
+ verify_auth: bool = typer.Option(
1207
+ False,
1208
+ "--verify-auth",
1209
+ help="Explicitly check provider authentication; does not sign in or transfer credentials.",
1210
+ ),
1211
+ ):
1212
+ """Check this destination before launch.
1213
+
1214
+ Known blockers exit with status 1.
1215
+ """
1216
+ try:
1217
+ from qbraid_core.services.agents.readiness import agent_readiness
1218
+ except ImportError:
1219
+ typer.echo("Destination readiness requires a newer qbraid-core.", err=True)
1220
+ raise typer.Exit(2) from None
1221
+ report = agent_readiness(
1222
+ tool,
1223
+ cwd=cwd,
1224
+ approval=approval.value if approval else None,
1225
+ execution_mode=execution_mode.value if execution_mode else None,
1226
+ verify_auth=verify_auth,
1227
+ )
1228
+ if json_output:
1229
+ print(json.dumps(report))
1230
+ else:
1231
+ for check in report["checks"]:
1232
+ console.print(f"{check['id']}: {check['state']} — {check['message']}", markup=False)
1233
+ for action in report.get("auth", {}).get("actions", []):
1234
+ if action.get("command"):
1235
+ console.print(str(action["command"]), markup=False)
1236
+ console.print("Unknown checks are not proof of readiness. Use --json for recovery actions.")
1237
+ if not report["ready"]:
1238
+ raise typer.Exit(1)
1239
+
1240
+
1241
+ @agents_app.command("machine")
1242
+ def agents_machine(
1243
+ serve: bool = typer.Option(
1244
+ False, "--serve", help="Serve JSON lines over authenticated SSH stdin/stdout."
1245
+ ),
1246
+ once: bool = typer.Option(
1247
+ False, "--once", help="Read one JSON request from stdin and return one response."
1248
+ ),
1249
+ ):
1250
+ """Serve the fleet machine protocol.
1251
+
1252
+ Protocol v1 writes only JSON frames to stdout.
1253
+ """
1254
+ if serve == once:
1255
+ raise typer.BadParameter("Choose exactly one of --serve or --once.")
1256
+ try:
1257
+ from qbraid_core.services.agents.machine_protocol import serve_machine
1258
+ except ImportError:
1259
+ typer.echo("Machine protocol requires a newer qbraid-core.", err=True)
1260
+ raise typer.Exit(2) from None
1261
+ serve_machine(once=once)
1262
+
1263
+
1264
+ @agents_app.command("settings")
1265
+ def agents_settings(
1266
+ execution_mode: Optional[ExecutionMode] = typer.Option(
1267
+ None, "--execution-mode", help="Save the Codex execution default for this machine."
1268
+ ),
1269
+ reset: bool = typer.Option(False, "--reset", help="Remove this machine's execution preference."),
1270
+ json_output: bool = typer.Option(
1271
+ False, "--json", help="Print structured settings and sandbox readiness."
1272
+ ),
1273
+ ):
1274
+ """Inspect or configure agent execution.
1275
+
1276
+ Defaults are shared by the CLI and dashboard on this machine.
1277
+ """
1278
+ try:
1279
+ from qbraid_core.services.agents.execution import execution_settings, set_execution_default
1280
+
1281
+ if reset and execution_mode is not None:
1282
+ raise ValueError("Choose --reset or --execution-mode, not both.")
1283
+ if reset:
1284
+ settings = set_execution_default(None)
1285
+ elif execution_mode is not None:
1286
+ settings = set_execution_default(execution_mode.value)
1287
+ else:
1288
+ settings = execution_settings()
1289
+ if json_output:
1290
+ print(json.dumps(settings))
1291
+ else:
1292
+ console.print(
1293
+ "Codex execution default: " + (settings["execution_mode"] or "not set (legacy defaults)")
1294
+ )
1295
+ console.print("Scope: this machine; applies to new CLI and dashboard launches.")
1296
+ console.print(settings["workspace"]["detail"])
1297
+ console.print("Override one launch with --execution-mode native|workspace|container.")
1298
+ except ImportError:
1299
+ handle_error(
1300
+ error_type="UnsupportedOptionError",
1301
+ message="Agent execution settings require a newer qbraid-core.",
1302
+ include_traceback=False,
1303
+ )
1304
+ except Exception as error:
1305
+ handle_error(error_type=type(error).__name__, message=str(error), include_traceback=False)
1306
+
1307
+
1150
1308
  @agents_app.command("launch")
1151
1309
  def agents_launch(
1152
1310
  tool: Optional[str] = typer.Option(
@@ -1167,6 +1325,18 @@ def agents_launch(
1167
1325
  compute: Optional[str] = typer.Option(
1168
1326
  None, "--compute", "-c", help="SSH alias for remote compute server"
1169
1327
  ),
1328
+ request_id: Optional[str] = typer.Option(
1329
+ None, "--request-id", help="Remote launch UUID retained for reconciling an interrupted request."
1330
+ ),
1331
+ execution_mode: Optional[ExecutionMode] = typer.Option(
1332
+ None,
1333
+ "--execution-mode",
1334
+ help=(
1335
+ "Codex only: native uses Codex defaults; workspace adds its workspace sandbox; "
1336
+ "container uses current user access without an extra Codex sandbox (no sudo). "
1337
+ "Omitted preserves existing behavior. Independent of --approval."
1338
+ ),
1339
+ ),
1170
1340
  approval: Optional[ApprovalMode] = typer.Option(
1171
1341
  None,
1172
1342
  "--approval",
@@ -1177,11 +1347,11 @@ def agents_launch(
1177
1347
 
1178
1348
  Starts the agent in a managed tmux session.
1179
1349
 
1180
- The agent runs detached, so nothing is watching its confirmation prompts.
1181
- Pass --approval auto for an agent you intend to leave running: it starts
1182
- the tool in its own non-interactive mode instead of parking on a prompt
1183
- until you come back. Approval mode is remembered, so `qbraid agents
1184
- resume` restores it.
1350
+ Detached agents may wait for approval until you open their terminal or dashboard.
1351
+ Approval and execution mode are independent and remembered for resume.
1352
+ --approval auto disables approval prompts; --execution-mode container
1353
+ explicitly uses the current user's access without an extra Codex sandbox.
1354
+ Choose it only where you trust the surrounding machine/container isolation.
1185
1355
  """
1186
1356
  try:
1187
1357
  from qbraid_core.services.agents import AgentLauncher, AgentLauncherError
@@ -1197,6 +1367,12 @@ def agents_launch(
1197
1367
  tag = tag or result.get("tags")
1198
1368
  repo = repo or result.get("repo")
1199
1369
 
1370
+ if request_id is not None:
1371
+ import uuid
1372
+
1373
+ if not compute or str(uuid.UUID(request_id)) != request_id:
1374
+ raise AgentLauncherError("--request-id requires --compute and a canonical UUID.")
1375
+
1200
1376
  launcher = AgentLauncher()
1201
1377
 
1202
1378
  # Remote launch via SSH
@@ -1210,7 +1386,9 @@ def agents_launch(
1210
1386
  instructions=instructions,
1211
1387
  agent_type=agent_type,
1212
1388
  tags=tag,
1389
+ **_request_id_kwargs(launcher.remote_launch, request_id),
1213
1390
  **_approval_kwargs(launcher.remote_launch, approval.value if approval else None),
1391
+ **_execution_kwargs(launcher.remote_launch, execution_mode.value if execution_mode else None),
1214
1392
  )
1215
1393
  else:
1216
1394
 
@@ -1228,6 +1406,7 @@ def agents_launch(
1228
1406
  team_id=team,
1229
1407
  tags=tag,
1230
1408
  **_approval_kwargs(launcher.launch, approval.value if approval else None),
1409
+ **_execution_kwargs(launcher.launch, execution_mode.value if execution_mode else None),
1231
1410
  progress_callback=_clone_progress if repo else None,
1232
1411
  )
1233
1412
 
@@ -1287,7 +1466,9 @@ def _interactive_resume(console_: Console) -> str:
1287
1466
  import questionary
1288
1467
 
1289
1468
  registry = _get_registry()
1290
- all_sessions = registry.load_registry().sessions
1469
+ # Use the display enumeration so retained transcript aliases do not appear
1470
+ # as duplicate choices. Stopped sessions remain available for resuming.
1471
+ all_sessions = registry.search_sessions(include_stopped=True)
1291
1472
 
1292
1473
  # Show sessions that could be resumed (have a session_id, prefer recent)
1293
1474
  resumable = sorted(
@@ -1345,6 +1526,9 @@ def agents_resume(
1345
1526
  None, help="Session ID, prefix, or name. Omit for interactive picker."
1346
1527
  ),
1347
1528
  name: Optional[str] = typer.Option(None, "--name", "-n", help="Agent name for the resumed session"),
1529
+ execution_mode: Optional[ExecutionMode] = typer.Option(
1530
+ None, "--execution-mode", help="Override the recorded Codex execution mode for this resume."
1531
+ ),
1348
1532
  ):
1349
1533
  """Resume a previous agent session.
1350
1534
 
@@ -1361,7 +1545,11 @@ def agents_resume(
1361
1545
 
1362
1546
  # Try resume — handle active session and ambiguous matches
1363
1547
  try:
1364
- session = launcher.resume(session_id=session_id, name=name)
1548
+ session = launcher.resume(
1549
+ session_id=session_id,
1550
+ name=name,
1551
+ **_execution_kwargs(launcher.resume, execution_mode.value if execution_mode else None),
1552
+ )
1365
1553
  except AgentLauncherError as e:
1366
1554
  err_msg = str(e)
1367
1555
 
@@ -1407,6 +1595,14 @@ def agents_resume(
1407
1595
  # A fork of a detached agent must not quietly
1408
1596
  # become one that waits for a human.
1409
1597
  **_approval_kwargs(launcher.launch, getattr(original, "approval", None)),
1598
+ **_execution_kwargs(
1599
+ launcher.launch,
1600
+ (
1601
+ execution_mode.value
1602
+ if execution_mode
1603
+ else getattr(original, "execution_mode", None)
1604
+ ),
1605
+ ),
1410
1606
  )
1411
1607
  else:
1412
1608
  console.print("[red]Could not find original session to fork.[/red]")
@@ -1425,7 +1621,7 @@ def agents_resume(
1425
1621
  import questionary
1426
1622
 
1427
1623
  registry = _get_registry()
1428
- all_sessions = registry.load_registry().sessions
1624
+ all_sessions = registry.search_sessions(include_stopped=True)
1429
1625
  matches = [
1430
1626
  s
1431
1627
  for s in all_sessions
@@ -1438,6 +1634,13 @@ def agents_resume(
1438
1634
  ]
1439
1635
  matches.sort(key=lambda s: s.last_activity or s.started_at or 0, reverse=True)
1440
1636
 
1637
+ if not matches:
1638
+ console.print(
1639
+ "[yellow]No visible sessions match this prefix. "
1640
+ "Use a full session ID to resume a retained record.[/yellow]"
1641
+ )
1642
+ raise typer.Exit(code=1)
1643
+
1441
1644
  choices = []
1442
1645
  for s in matches:
1443
1646
  sid = s.session_id[:8]
@@ -1459,7 +1662,11 @@ def agents_resume(
1459
1662
  if selected is None:
1460
1663
  raise typer.Exit()
1461
1664
 
1462
- session = launcher.resume(session_id=selected, name=name)
1665
+ session = launcher.resume(
1666
+ session_id=selected,
1667
+ name=name,
1668
+ **_execution_kwargs(launcher.resume, execution_mode.value if execution_mode else None),
1669
+ )
1463
1670
 
1464
1671
  status_val = session.status.value if session.status else "idle"
1465
1672
  style = _status_style(status_val)
@@ -1718,9 +1925,8 @@ def agents_watch(
1718
1925
  else:
1719
1926
  # Parse and render
1720
1927
  try:
1721
- import json as _json
1722
1928
 
1723
- event = _json.loads(line)
1929
+ event = json.loads(line)
1724
1930
  entry_type = event.get("type", "unknown")
1725
1931
  content = event.get("content", "")
1726
1932
  ts = event.get("timestamp")
@@ -1904,7 +2110,6 @@ def agents_watch(
1904
2110
  perm_pending.set()
1905
2111
 
1906
2112
  if can_notify:
1907
- import json as _json
1908
2113
 
1909
2114
  notification = {
1910
2115
  "type": "permission_required",
@@ -1918,7 +2123,7 @@ def agents_watch(
1918
2123
  if request.get("opencode_request_id"):
1919
2124
  notification["opencode_request_id"] = request["opencode_request_id"]
1920
2125
  notification["opencode_port"] = oc_port
1921
- print(_json.dumps(notification), flush=True)
2126
+ print(json.dumps(notification), flush=True)
1922
2127
 
1923
2128
  if not can_prompt:
1924
2129
  perm_data.clear()
@@ -2049,7 +2254,6 @@ def agents_watch(
2049
2254
  tool_info = f" ({entry.tool_name})"
2050
2255
 
2051
2256
  if stream:
2052
- import json as _json
2053
2257
 
2054
2258
  event = {
2055
2259
  "type": entry_type,
@@ -2060,7 +2264,7 @@ def agents_watch(
2060
2264
  "cost_usd": entry.cost_usd,
2061
2265
  "token_count": entry.token_count,
2062
2266
  }
2063
- print(_json.dumps({k: v for k, v in event.items() if v is not None}), flush=True)
2267
+ print(json.dumps({k: v for k, v in event.items() if v is not None}), flush=True)
2064
2268
  else:
2065
2269
  line = f"{prefix}{type_label}{tool_info}: [{style}]{content}[/{style}]"
2066
2270
  console.print(line, highlight=False)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qbraid-cli
3
- Version: 0.15.2
3
+ Version: 0.15.3
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.3.3
32
32
  Requires-Dist: questionary>=2.0.0
33
- Requires-Dist: qbraid-core>=0.5.0
33
+ Requires-Dist: qbraid-core>=0.6.5
34
34
  Provides-Extra: compute
35
- Requires-Dist: qbraid-core[compute]>=0.5.0; extra == "compute"
35
+ Requires-Dist: qbraid-core[compute]>=0.6.5; extra == "compute"
36
36
  Provides-Extra: envs
37
- Requires-Dist: qbraid-core[environments]>=0.5.0; extra == "envs"
37
+ Requires-Dist: qbraid-core[environments]>=0.6.5; 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.3.3
4
4
  questionary>=2.0.0
5
- qbraid-core>=0.5.0
5
+ qbraid-core>=0.6.5
6
6
 
7
7
  [compute]
8
- qbraid-core[compute]>=0.5.0
8
+ qbraid-core[compute]>=0.6.5
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.5.0
18
+ qbraid-core[environments]>=0.6.5
File without changes
File without changes
File without changes