dayhoff-tools 1.9.7__py3-none-any.whl → 1.9.9__py3-none-any.whl

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.
@@ -709,11 +709,7 @@ def engine_status(
709
709
  engine = resolve_engine(name_or_id, engines)
710
710
 
711
711
  # Fast status display (default)
712
- if not detailed:
713
- # Skip the API call for studios - use basic info we already have
714
- attached_studios = []
715
- studio_user = engine.get("user") # Use the engine's user as studio owner
716
-
712
+ if not detailed:
717
713
  # Fetch idle status via SSM with longer timeout
718
714
  ssm = boto3.client("ssm", region_name="us-east-1")
719
715
  idle_data = None # Use None to indicate no data received
@@ -781,7 +777,11 @@ def engine_status(
781
777
  if is_idle:
782
778
  if isinstance(timeout_sec, int) and isinstance(idle_seconds, int):
783
779
  remaining = max(0, timeout_sec - idle_seconds)
784
- idle_disp = f" [yellow]Idle {idle_seconds//60}m/{timeout_sec//60}m: [red]{remaining//60}m {remaining%60}s[/red] left[/yellow]"
780
+ remaining_mins = remaining // 60
781
+ if remaining_mins == 0:
782
+ idle_disp = f" [yellow]Idle {idle_seconds//60}m/{timeout_sec//60}m: [red]<1m[/red] left[/yellow]"
783
+ else:
784
+ idle_disp = f" [yellow]Idle {idle_seconds//60}m/{timeout_sec//60}m: [red]{remaining_mins}m[/red] left[/yellow]"
785
785
  else:
786
786
  idle_disp = " [yellow]Idle ?/?[/yellow]"
787
787
  else:
@@ -790,17 +790,12 @@ def engine_status(
790
790
 
791
791
  # Build status lines - minimal info for fast view
792
792
  status_lines = [
793
- f"[blue]{engine['name']}[/blue] {run_disp}{idle_disp}\n",
793
+ f"[blue]{engine['name']}[/blue] {run_disp}{idle_disp}",
794
794
  ]
795
795
 
796
- # Add studio owner if known
797
- if studio_user:
798
- status_lines.append(f"Studio: [magenta]{studio_user}[/magenta]")
799
-
800
796
  # Add activity sensors if we have idle data
801
797
  if idle_data and idle_data.get("reasons"):
802
- status_lines.append("")
803
- status_lines.append("[bold]Activity:[/bold]")
798
+ status_lines.append("") # blank line before sensors
804
799
 
805
800
  sensor_map = {
806
801
  "CoffeeLockSensor": ("☕", "Coffee"),
@@ -889,14 +884,14 @@ def engine_status(
889
884
 
890
885
  # Compose Active/Idle header with extra detail when idle
891
886
  def _compute_active_disp(idle_info: Dict[str, Any]) -> str:
887
+ # If we don't have idle info or it's explicitly unavailable, show N/A
888
+ if not idle_info or idle_info.get("available") == False:
889
+ return "[dim]N/A[/dim]"
890
+
892
891
  if idle_info.get("status") == "active":
893
892
  return "[green]Active[/green]"
894
893
  if running_state in ("stopped", "stopping"):
895
894
  return "[dim]N/A[/dim]"
896
-
897
- # If we don't have idle info at all, show N/A
898
- if not idle_info.get("available"):
899
- return "[dim]N/A[/dim]"
900
895
 
901
896
  # If idle, show time/threshold with time remaining if available
902
897
  if idle_info.get("status") == "idle":
@@ -904,7 +899,11 @@ def engine_status(
904
899
  thresh_v = idle_info.get("idle_threshold")
905
900
  if isinstance(idle_seconds_v, (int, float)) and isinstance(thresh_v, (int, float)):
906
901
  remaining = max(0, int(thresh_v) - int(idle_seconds_v))
907
- return f"[yellow]Idle {int(idle_seconds_v)//60}m/{int(thresh_v)//60}m: [red]{remaining//60}m {remaining%60}s[/red] left[/yellow]"
902
+ remaining_mins = remaining // 60
903
+ if remaining_mins == 0:
904
+ return f"[yellow]Idle {int(idle_seconds_v)//60}m/{int(thresh_v)//60}m: [red]<1m[/red] left[/yellow]"
905
+ else:
906
+ return f"[yellow]Idle {int(idle_seconds_v)//60}m/{int(thresh_v)//60}m: [red]{remaining_mins}m[/red] left[/yellow]"
908
907
  elif isinstance(thresh_v, (int, float)):
909
908
  return f"[yellow]Idle ?/{int(thresh_v)//60}m[/yellow]"
910
909
  else:
@@ -949,47 +948,51 @@ def engine_status(
949
948
  disk_usage = get_disk_usage_via_ssm(engine["instance_id"]) or "-"
950
949
  status_lines.append(f"Disk: {disk_usage}")
951
950
 
952
- # Idle timeout (show even when not idle)
953
- idle_threshold_secs: Optional[int] = None
954
- # Prefer value from idle detector overlay if present
955
- try:
956
- if isinstance(idle_detector.get("idle_threshold"), (int, float)):
957
- idle_threshold_secs = int(idle_detector["idle_threshold"])
958
- except Exception:
959
- idle_threshold_secs = None
960
-
961
- if idle_threshold_secs is None and engine["state"].lower() == "running":
962
- # Fallback: read /etc/engine.env via SSM
951
+ # Idle timeout (show even when not idle) - but only if we have data
952
+ if idle_detector.get("available"):
953
+ idle_threshold_secs: Optional[int] = None
954
+ # Prefer value from idle detector overlay if present
963
955
  try:
964
- ssm = boto3.client("ssm", region_name="us-east-1")
965
- resp = ssm.send_command(
966
- InstanceIds=[engine["instance_id"]],
967
- DocumentName="AWS-RunShellScript",
968
- Parameters={
969
- "commands": [
970
- "grep -E '^IDLE_TIMEOUT_SECONDS=' /etc/engine.env | cut -d'=' -f2 || echo 1800",
971
- ],
972
- "executionTimeout": ["5"],
973
- },
974
- )
975
- cid = resp["Command"]["CommandId"]
976
- time.sleep(1)
977
- inv = ssm.get_command_invocation(
978
- CommandId=cid, InstanceId=engine["instance_id"]
979
- )
980
- if inv.get("Status") == "Success":
981
- out = (inv.get("StandardOutputContent") or "").strip()
982
- if out:
983
- idle_threshold_secs = int(out.splitlines()[0].strip())
956
+ if isinstance(idle_detector.get("idle_threshold"), (int, float)):
957
+ idle_threshold_secs = int(idle_detector["idle_threshold"])
984
958
  except Exception:
985
959
  idle_threshold_secs = None
986
960
 
987
- if idle_threshold_secs is None:
988
- idle_threshold_secs = 1800
961
+ if idle_threshold_secs is None and engine["state"].lower() == "running":
962
+ # Fallback: read /etc/engine.env via SSM
963
+ try:
964
+ ssm = boto3.client("ssm", region_name="us-east-1")
965
+ resp = ssm.send_command(
966
+ InstanceIds=[engine["instance_id"]],
967
+ DocumentName="AWS-RunShellScript",
968
+ Parameters={
969
+ "commands": [
970
+ "grep -E '^IDLE_TIMEOUT_SECONDS=' /etc/engine.env | cut -d'=' -f2 || echo '?'",
971
+ ],
972
+ "executionTimeout": ["5"],
973
+ },
974
+ )
975
+ cid = resp["Command"]["CommandId"]
976
+ time.sleep(1)
977
+ inv = ssm.get_command_invocation(
978
+ CommandId=cid, InstanceId=engine["instance_id"]
979
+ )
980
+ if inv.get("Status") == "Success":
981
+ out = (inv.get("StandardOutputContent") or "").strip()
982
+ if out and out != "?" and out.isdigit():
983
+ idle_threshold_secs = int(out)
984
+ except Exception:
985
+ idle_threshold_secs = None
989
986
 
990
- status_lines.append(
991
- f"Idle timeout: {idle_threshold_secs//60}m ({idle_threshold_secs}s)"
992
- )
987
+ if idle_threshold_secs is not None:
988
+ status_lines.append(
989
+ f"Idle timeout: {idle_threshold_secs//60}m ({idle_threshold_secs}s)"
990
+ )
991
+ else:
992
+ status_lines.append("Idle timeout: unknown")
993
+ else:
994
+ # No idle detector data available
995
+ status_lines.append("Idle timeout: N/A")
993
996
 
994
997
  # Health report (only if bootstrap finished)
995
998
  if stage_val == "finished":
@@ -1133,13 +1136,14 @@ def engine_status(
1133
1136
  else:
1134
1137
  for k, v in overlay.items():
1135
1138
  idle_detector.setdefault(k, v)
1139
+ else:
1140
+ # SSM failed - mark as unavailable if we don't have good data
1141
+ if not idle_detector.get("available"):
1142
+ idle_detector = {"available": False} # Mark as unavailable
1136
1143
 
1137
- # Recompute header display using enriched overlay values
1138
- try:
1139
- active_disp = _compute_active_disp(idle_detector)
1140
- top_lines[0] = f"[blue]{engine['name']}[/blue] {run_disp} {active_disp}\n"
1141
- except Exception:
1142
- pass
1144
+ # Recompute header display with latest data
1145
+ active_disp = _compute_active_disp(idle_detector)
1146
+ top_lines[0] = f"[blue]{engine['name']}[/blue] {run_disp} {active_disp}\n"
1143
1147
 
1144
1148
  # Activity Sensors (show all with YES/no)
1145
1149
  if idle_detector.get("available"):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dayhoff-tools
3
- Version: 1.9.7
3
+ Version: 1.9.9
4
4
  Summary: Common tools for all the repos at Dayhoff Labs
5
5
  Author: Daniel Martin-Alarcon
6
6
  Author-email: dma@dayhofflabs.com
@@ -3,7 +3,7 @@ dayhoff_tools/chemistry/standardizer.py,sha256=uMn7VwHnx02nc404eO6fRuS4rsl4dvSPf
3
3
  dayhoff_tools/chemistry/utils.py,sha256=jt-7JgF-GeeVC421acX-bobKbLU_X94KNOW24p_P-_M,2257
4
4
  dayhoff_tools/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  dayhoff_tools/cli/cloud_commands.py,sha256=33qcWLmq-FwEXMdL3F0OHm-5Stlh2r65CldyEZgQ1no,40904
6
- dayhoff_tools/cli/engine_commands.py,sha256=6dvAYmpg4H3ulTx3duPCd5JzQtMl6lgh1MsnotzxEC8,112564
6
+ dayhoff_tools/cli/engine_commands.py,sha256=OHaaF28Dh1WSh2c-YKTRfIlYNCrlld0LvgyRIP9e_Hc,113202
7
7
  dayhoff_tools/cli/main.py,sha256=LoFs3SI4fdCjP4pdxEAhri-_q0dmNYupmBCRE4KbBac,5933
8
8
  dayhoff_tools/cli/swarm_commands.py,sha256=5EyKj8yietvT5lfoz8Zx0iQvVaNgc3SJX1z2zQR6o6M,5614
9
9
  dayhoff_tools/cli/utility_commands.py,sha256=WQTHOh1MttuxaJjl2c6zMa4x7_JuaKMQgcyotYrU3GA,25883
@@ -27,7 +27,7 @@ dayhoff_tools/intake/uniprot.py,sha256=BZYJQF63OtPcBBnQ7_P9gulxzJtqyorgyuDiPeOJq
27
27
  dayhoff_tools/logs.py,sha256=DKdeP0k0kliRcilwvX0mUB2eipO5BdWUeHwh-VnsICs,838
28
28
  dayhoff_tools/sqlite.py,sha256=jV55ikF8VpTfeQqqlHSbY8OgfyfHj8zgHNpZjBLos_E,18672
29
29
  dayhoff_tools/warehouse.py,sha256=UETBtZD3r7WgvURqfGbyHlT7cxoiVq8isjzMuerKw8I,24475
30
- dayhoff_tools-1.9.7.dist-info/METADATA,sha256=JUzRKthCiuuhJ7UA71zTnHTTqmBm64_hjKdBR-qUgyc,2914
31
- dayhoff_tools-1.9.7.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
32
- dayhoff_tools-1.9.7.dist-info/entry_points.txt,sha256=iAf4jteNqW3cJm6CO6czLxjW3vxYKsyGLZ8WGmxamSc,49
33
- dayhoff_tools-1.9.7.dist-info/RECORD,,
30
+ dayhoff_tools-1.9.9.dist-info/METADATA,sha256=01FYQCJJf9a5Y0BngfeSTZesnMURFjXTFPgHK30CWdA,2914
31
+ dayhoff_tools-1.9.9.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
32
+ dayhoff_tools-1.9.9.dist-info/entry_points.txt,sha256=iAf4jteNqW3cJm6CO6czLxjW3vxYKsyGLZ8WGmxamSc,49
33
+ dayhoff_tools-1.9.9.dist-info/RECORD,,