hte-cli 0.2.28__tar.gz → 0.2.29__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 (32) hide show
  1. {hte_cli-0.2.28 → hte_cli-0.2.29}/PKG-INFO +1 -1
  2. {hte_cli-0.2.28 → hte_cli-0.2.29}/pyproject.toml +1 -1
  3. {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/cli.py +211 -13
  4. {hte_cli-0.2.28 → hte_cli-0.2.29}/uv.lock +1 -1
  5. {hte_cli-0.2.28 → hte_cli-0.2.29}/.gitignore +0 -0
  6. {hte_cli-0.2.28 → hte_cli-0.2.29}/README.md +0 -0
  7. {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/__init__.py +0 -0
  8. {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/__main__.py +0 -0
  9. {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/api_client.py +0 -0
  10. {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/config.py +0 -0
  11. {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/errors.py +0 -0
  12. {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/events.py +0 -0
  13. {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/image_utils.py +0 -0
  14. {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/runner.py +0 -0
  15. {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/scorers.py +0 -0
  16. {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/version_check.py +0 -0
  17. {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/__init__.py +0 -0
  18. {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/__init__.py +0 -0
  19. {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/automated_runner.py +0 -0
  20. {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/conftest.py +0 -0
  21. {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/e2e_test.py +0 -0
  22. {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/test_benchmark_flows.py +0 -0
  23. {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/test_eval_logs.py +0 -0
  24. {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/test_infrastructure.py +0 -0
  25. {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/test_runtime_imports.py +0 -0
  26. {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/test_session_lifecycle.py +0 -0
  27. {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/verify_docker_deps.py +0 -0
  28. {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/unit/__init__.py +0 -0
  29. {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/unit/conftest.py +0 -0
  30. {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/unit/test_image_utils.py +0 -0
  31. {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/unit/test_runner.py +0 -0
  32. {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/unit/test_scorers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hte-cli
3
- Version: 0.2.28
3
+ Version: 0.2.29
4
4
  Summary: Human Time-to-Completion Evaluation CLI
5
5
  Project-URL: Homepage, https://github.com/sean-peters-au/lyptus-mono
6
6
  Author: Lyptus Research
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "hte-cli"
3
- version = "0.2.28"
3
+ version = "0.2.29"
4
4
  description = "Human Time-to-Completion Evaluation CLI"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -347,6 +347,7 @@ def session_join(ctx, session_id: str, force_setup: bool):
347
347
  console.print(f"[bold]Step 2:[/bold] Pulling {len(images)} Docker image(s)...")
348
348
  pull_start = time.monotonic()
349
349
  pull_errors = {}
350
+ x86_images_on_arm = [] # Track x86 images that need QEMU
350
351
 
351
352
  for img in images:
352
353
  short_name = img.split("/")[-1][:40]
@@ -386,6 +387,25 @@ def session_join(ctx, session_id: str, force_setup: bool):
386
387
  )
387
388
  pulled_images.append(img)
388
389
  continue
390
+ elif "failed to re-pull" in fix_msg:
391
+ # No ARM variant available - this is an x86-only image
392
+ # Re-pull the amd64 version and warn about QEMU
393
+ console.print(
394
+ f" [dim]No ARM variant available - re-pulling x86 version...[/dim]"
395
+ )
396
+ success = pull_image_with_progress(img)
397
+ if success:
398
+ console.print(
399
+ f" [yellow]![/yellow] {short_name} [dim](x86-only image, needs QEMU)[/dim]"
400
+ )
401
+ x86_images_on_arm.append(img)
402
+ pulled_images.append(img)
403
+ continue
404
+ else:
405
+ console.print(f" [red]✗[/red] {short_name} [dim](failed to pull)[/dim]")
406
+ failed_images.append(img)
407
+ pull_errors[img] = "failed to pull x86 fallback"
408
+ continue
389
409
  else:
390
410
  console.print(f" [red]✗[/red] {short_name} [dim]({fix_msg})[/dim]")
391
411
  failed_images.append(img)
@@ -396,14 +416,9 @@ def session_join(ctx, session_id: str, force_setup: bool):
396
416
  last_status = ["connecting..."]
397
417
  last_error = [""]
398
418
 
399
- # On Linux ARM64, use host platform if no explicit platform in compose
400
- # This prevents pulling amd64 images that won't run
419
+ # Use platform from compose if specified, otherwise let Docker decide
420
+ # (Docker will prefer native arch for multi-arch images, or pull what's available)
401
421
  pull_platform = platform
402
- if not pull_platform and is_linux_arm and host_platform:
403
- pull_platform = host_platform
404
- console.print(
405
- f" [dim]Pulling {short_name} with platform {host_platform}...[/dim]"
406
- )
407
422
 
408
423
  with console.status(
409
424
  f"[yellow]↓[/yellow] {short_name} [dim]connecting...[/dim]"
@@ -432,12 +447,28 @@ def session_join(ctx, session_id: str, force_setup: bool):
432
447
  )
433
448
 
434
449
  if success:
435
- # Show platform info on Linux ARM64 for confirmation
436
- if is_linux_arm and pull_platform:
437
- arch_short = pull_platform.split("/")[-1] # e.g., "arm64"
438
- console.print(
439
- f" [green]✓[/green] {short_name} [dim](downloaded, arch: {arch_short})[/dim]"
440
- )
450
+ # On Linux ARM64, verify pulled image architecture
451
+ if is_linux_arm:
452
+ from hte_cli.image_utils import get_image_architecture
453
+ pulled_arch = get_image_architecture(img)
454
+
455
+ if pulled_arch == "arm64":
456
+ console.print(
457
+ f" [green]✓[/green] {short_name} [dim](downloaded, arch: arm64)[/dim]"
458
+ )
459
+ elif pulled_arch == "amd64":
460
+ # x86 image on ARM host - needs QEMU emulation
461
+ console.print(
462
+ f" [yellow]![/yellow] {short_name} [dim](downloaded, arch: amd64)[/dim]"
463
+ )
464
+ console.print(
465
+ f" [yellow]This is an x86 image - requires QEMU emulation on ARM[/yellow]"
466
+ )
467
+ x86_images_on_arm.append(img)
468
+ else:
469
+ console.print(
470
+ f" [green]✓[/green] {short_name} [dim](downloaded)[/dim]"
471
+ )
441
472
  else:
442
473
  console.print(f" [green]✓[/green] {short_name} [dim](downloaded)[/dim]")
443
474
  pulled_images.append(img)
@@ -458,6 +489,19 @@ def session_join(ctx, session_id: str, force_setup: bool):
458
489
  )
459
490
  console.print()
460
491
 
492
+ # Warn about x86 images on ARM that need QEMU
493
+ if x86_images_on_arm:
494
+ console.print(
495
+ f"[yellow]⚠ Warning:[/yellow] {len(x86_images_on_arm)} x86 image(s) detected on ARM host"
496
+ )
497
+ console.print(
498
+ " These require QEMU emulation. If container fails to start, run:"
499
+ )
500
+ console.print(
501
+ " [bold]docker run --privileged --rm tonistiigi/binfmt --install all[/bold]"
502
+ )
503
+ console.print()
504
+
461
505
  # Fail fast if any required image couldn't be pulled
462
506
  if failed_images:
463
507
  console.print(
@@ -750,6 +794,160 @@ def tasks_pull_images(ctx, count: int):
750
794
  console.print("[yellow]Image pulling not yet implemented.[/yellow]")
751
795
 
752
796
 
797
+ @cli.command("diagnose")
798
+ def diagnose_cmd():
799
+ """
800
+ Diagnose Docker and architecture setup.
801
+
802
+ Checks Docker installation, architecture detection, and image compatibility.
803
+ Useful for troubleshooting before running tasks.
804
+ """
805
+ import subprocess
806
+ import sys as system_module
807
+ from hte_cli.image_utils import (
808
+ get_host_architecture,
809
+ get_host_docker_platform,
810
+ is_running_in_linux_vm_on_arm,
811
+ get_image_architecture,
812
+ check_image_exists_locally,
813
+ )
814
+
815
+ console.print("[bold]HTE-CLI Diagnostics[/bold]")
816
+ console.print("=" * 50)
817
+ console.print()
818
+
819
+ # CLI version
820
+ console.print(f"[bold]CLI Version:[/bold] {__version__}")
821
+ console.print()
822
+
823
+ # Platform info
824
+ console.print("[bold]Platform:[/bold]")
825
+ host_arch = get_host_architecture()
826
+ host_platform = get_host_docker_platform()
827
+ is_linux_arm = is_running_in_linux_vm_on_arm()
828
+
829
+ console.print(f" OS: {system_module.platform}")
830
+ console.print(f" Architecture: {host_arch}")
831
+ console.print(f" Docker platform: {host_platform or 'unknown'}")
832
+
833
+ if is_linux_arm:
834
+ console.print()
835
+ console.print("[yellow]⚠ Linux ARM64 detected![/yellow]")
836
+ console.print(" This environment may have architecture compatibility issues.")
837
+ console.print(" The CLI will automatically handle multi-arch images.")
838
+ console.print(" For x86-only images (CTF challenges), QEMU emulation is required.")
839
+ console.print()
840
+
841
+ # Docker checks
842
+ console.print("[bold]Docker:[/bold]")
843
+
844
+ # Check Docker installed
845
+ try:
846
+ result = subprocess.run(
847
+ ["docker", "--version"],
848
+ capture_output=True,
849
+ text=True,
850
+ timeout=10,
851
+ )
852
+ if result.returncode == 0:
853
+ console.print(f" [green]✓[/green] Docker: {result.stdout.strip()}")
854
+ else:
855
+ console.print(" [red]✗[/red] Docker not working")
856
+ except Exception as e:
857
+ console.print(f" [red]✗[/red] Docker not found: {e}")
858
+
859
+ # Check Docker daemon
860
+ try:
861
+ result = subprocess.run(
862
+ ["docker", "info"],
863
+ capture_output=True,
864
+ text=True,
865
+ timeout=10,
866
+ )
867
+ if result.returncode == 0:
868
+ console.print(" [green]✓[/green] Docker daemon running")
869
+ else:
870
+ console.print(" [red]✗[/red] Docker daemon not running")
871
+ except Exception:
872
+ console.print(" [red]✗[/red] Cannot connect to Docker daemon")
873
+
874
+ # Check Compose version
875
+ try:
876
+ result = subprocess.run(
877
+ ["docker", "compose", "version", "--short"],
878
+ capture_output=True,
879
+ text=True,
880
+ timeout=10,
881
+ )
882
+ if result.returncode == 0:
883
+ version = result.stdout.strip()
884
+ console.print(f" [green]✓[/green] Docker Compose: {version}")
885
+ else:
886
+ console.print(" [yellow]![/yellow] Docker Compose not available")
887
+ except Exception:
888
+ console.print(" [yellow]![/yellow] Docker Compose not found")
889
+
890
+ console.print()
891
+
892
+ # Test images
893
+ console.print("[bold]Image Architecture Test:[/bold]")
894
+ test_images = [
895
+ ("python:3.12-slim", "multi-arch (nl2bash/cybashbench)"),
896
+ ("cybench/cybench:latest", "x86-only (cybench/cybergym)"),
897
+ ]
898
+
899
+ for image, description in test_images:
900
+ if check_image_exists_locally(image):
901
+ arch = get_image_architecture(image)
902
+ if arch:
903
+ if is_linux_arm and arch == "amd64":
904
+ console.print(
905
+ f" [yellow]![/yellow] {image}: {arch} [dim](x86 on ARM - needs QEMU)[/dim]"
906
+ )
907
+ else:
908
+ console.print(f" [green]✓[/green] {image}: {arch}")
909
+ else:
910
+ console.print(f" [dim]?[/dim] {image}: cached (unknown arch)")
911
+ else:
912
+ console.print(f" [dim]-[/dim] {image}: not cached - {description}")
913
+
914
+ console.print()
915
+
916
+ # QEMU check (for Linux ARM64)
917
+ if is_linux_arm:
918
+ console.print("[bold]QEMU Emulation:[/bold]")
919
+ try:
920
+ # Check if binfmt is set up for x86
921
+ result = subprocess.run(
922
+ ["docker", "run", "--rm", "--platform", "linux/amd64", "alpine", "uname", "-m"],
923
+ capture_output=True,
924
+ text=True,
925
+ timeout=30,
926
+ )
927
+ if result.returncode == 0 and "x86_64" in result.stdout:
928
+ console.print(" [green]✓[/green] QEMU x86 emulation working")
929
+ else:
930
+ console.print(" [red]✗[/red] QEMU x86 emulation NOT working")
931
+ console.print()
932
+ console.print(" [yellow]To enable QEMU emulation, run:[/yellow]")
933
+ console.print(" [bold]docker run --privileged --rm tonistiigi/binfmt --install all[/bold]")
934
+ except subprocess.TimeoutExpired:
935
+ console.print(" [yellow]![/yellow] QEMU test timed out")
936
+ except Exception as e:
937
+ console.print(f" [red]✗[/red] QEMU test failed: {e}")
938
+ console.print()
939
+
940
+ console.print("[bold]Recommendation:[/bold]")
941
+ if is_linux_arm:
942
+ console.print(" For nl2bash/cybashbench: Should work with native ARM images")
943
+ console.print(" For CTF challenges (cybench, nyuctf, etc.): Requires QEMU emulation")
944
+ else:
945
+ console.print(" [green]✓[/green] Standard platform - all benchmarks should work")
946
+
947
+ console.print()
948
+ console.print("[dim]Run 'hte-cli session join <id>' to test with a real task[/dim]")
949
+
950
+
753
951
  # =============================================================================
754
952
  # Helper Functions
755
953
  # =============================================================================
@@ -625,7 +625,7 @@ wheels = [
625
625
 
626
626
  [[package]]
627
627
  name = "hte-cli"
628
- version = "0.2.28"
628
+ version = "0.2.29"
629
629
  source = { editable = "." }
630
630
  dependencies = [
631
631
  { name = "click" },
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