dayhoff-tools 1.8.1__py3-none-any.whl → 1.8.3__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.
- dayhoff_tools/cli/engine_commands.py +69 -71
- {dayhoff_tools-1.8.1.dist-info → dayhoff_tools-1.8.3.dist-info}/METADATA +1 -1
- {dayhoff_tools-1.8.1.dist-info → dayhoff_tools-1.8.3.dist-info}/RECORD +5 -5
- {dayhoff_tools-1.8.1.dist-info → dayhoff_tools-1.8.3.dist-info}/WHEEL +0 -0
- {dayhoff_tools-1.8.1.dist-info → dayhoff_tools-1.8.3.dist-info}/entry_points.txt +0 -0
@@ -841,21 +841,56 @@ def engine_status(
|
|
841
841
|
else f"[bold]Started:[/bold] {launch_time.strftime('%Y-%m-%d %H:%M:%S')} ({format_duration(uptime)} ago)"
|
842
842
|
)
|
843
843
|
|
844
|
+
# ---------------- Front-loaded summary ----------------
|
845
|
+
running_state = engine["state"].lower()
|
846
|
+
if running_state == "running":
|
847
|
+
run_disp = "[green]Running[/green]"
|
848
|
+
elif running_state == "pending":
|
849
|
+
run_disp = "[yellow]Starting...[/yellow]"
|
850
|
+
elif running_state == "stopped":
|
851
|
+
run_disp = "[dim]Stopped[/dim]"
|
852
|
+
else:
|
853
|
+
run_disp = engine["state"]
|
854
|
+
|
855
|
+
active_disp = (
|
856
|
+
"[green]Active[/green]"
|
857
|
+
if idle_detector.get("status") == "active"
|
858
|
+
else "[dim]Idle[/dim]"
|
859
|
+
)
|
860
|
+
|
861
|
+
top_lines = [
|
862
|
+
f"[blue]{engine['name']}[/blue] {run_disp} {active_disp}",
|
863
|
+
]
|
864
|
+
|
865
|
+
# Studios summary next, with studio name in purple/magenta
|
866
|
+
studios_line = None
|
867
|
+
if attached_studios:
|
868
|
+
stu_texts = [
|
869
|
+
f"[magenta]{s.get('user', 'studio')}[/magenta] ({s.get('studio_id', 'unknown')})"
|
870
|
+
for s in attached_studios
|
871
|
+
]
|
872
|
+
studios_line = "Studios: " + ", ".join(stu_texts)
|
873
|
+
top_lines.append(studios_line)
|
874
|
+
|
875
|
+
# Paragraph break
|
876
|
+
top_lines.append("")
|
877
|
+
|
878
|
+
# ---------------- Details block (white/default) ----------------
|
844
879
|
status_lines = [
|
845
|
-
f"
|
846
|
-
f"
|
847
|
-
f"
|
848
|
-
f"
|
849
|
-
f"
|
850
|
-
f"
|
880
|
+
f"Name: {engine['name']}",
|
881
|
+
f"Instance: {engine['instance_id']}",
|
882
|
+
f"Type: {engine['engine_type']} ({engine['instance_type']})",
|
883
|
+
f"Status: {engine['state']}",
|
884
|
+
f"User: {engine['user']}",
|
885
|
+
f"IP: {engine.get('public_ip', 'N/A')}",
|
851
886
|
started_line,
|
852
|
-
f"
|
887
|
+
f"$/hour: ${hourly_cost:.2f}",
|
853
888
|
]
|
854
889
|
|
855
890
|
# Disk usage (like list --detailed)
|
856
891
|
if engine["state"].lower() == "running":
|
857
892
|
disk_usage = get_disk_usage_via_ssm(engine["instance_id"]) or "-"
|
858
|
-
status_lines.append(f"
|
893
|
+
status_lines.append(f"Disk: {disk_usage}")
|
859
894
|
|
860
895
|
# Health report (only if bootstrap finished)
|
861
896
|
if stage_val == "finished":
|
@@ -954,16 +989,8 @@ def engine_status(
|
|
954
989
|
except Exception:
|
955
990
|
return None
|
956
991
|
|
957
|
-
#
|
958
|
-
overlay = (
|
959
|
-
_fetch_idle_summary_via_ssm(engine["instance_id"])
|
960
|
-
if not idle_detector.get("available")
|
961
|
-
or not any(
|
962
|
-
k in idle_detector
|
963
|
-
for k in ("ide_connections", "ssh_sessions", "coffee_lock")
|
964
|
-
)
|
965
|
-
else None
|
966
|
-
)
|
992
|
+
# Always try to enrich from on-engine summary (fast, best-effort)
|
993
|
+
overlay = _fetch_idle_summary_via_ssm(engine["instance_id"])
|
967
994
|
if overlay:
|
968
995
|
# If API didn't indicate availability, replace entirely; otherwise fill gaps
|
969
996
|
if not idle_detector.get("available"):
|
@@ -972,68 +999,37 @@ def engine_status(
|
|
972
999
|
for k, v in overlay.items():
|
973
1000
|
idle_detector.setdefault(k, v)
|
974
1001
|
|
975
|
-
#
|
1002
|
+
# Activity Sensors (show all with YES/no)
|
976
1003
|
if idle_detector.get("available"):
|
977
1004
|
status_lines.append("")
|
978
|
-
status_lines.append("[bold]
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
if idle_detector.get("coffee_lock"):
|
994
|
-
status_lines.append(
|
995
|
-
f" • [cyan]☕ Caffeinated for another {idle_detector['coffee_lock']}[/cyan]"
|
1005
|
+
status_lines.append("[bold]Activity Sensors:[/bold]")
|
1006
|
+
reasons_raw = idle_detector.get("_reasons_raw", []) or []
|
1007
|
+
by_sensor: Dict[str, Dict[str, Any]] = {}
|
1008
|
+
for r in reasons_raw:
|
1009
|
+
nm = r.get("sensor")
|
1010
|
+
if nm:
|
1011
|
+
by_sensor[nm] = r
|
1012
|
+
|
1013
|
+
def _sensor_line(label: str, key: str, emoji: str) -> str:
|
1014
|
+
r = by_sensor.get(key, {})
|
1015
|
+
active = bool(r.get("active"))
|
1016
|
+
reason_txt = r.get("reason") or ("" if not active else "active")
|
1017
|
+
flag = "[green]YES[/green]" if active else "no"
|
1018
|
+
return (
|
1019
|
+
f" {emoji} {label}: {flag} {('- ' + reason_txt) if reason_txt else ''}"
|
996
1020
|
)
|
997
1021
|
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
for session in ssh_sessions:
|
1003
|
-
idle_time = session.get("idle_time")
|
1004
|
-
if isinstance(idle_time, (int, float)):
|
1005
|
-
idle_disp = f"{int(idle_time)//60}m"
|
1006
|
-
else:
|
1007
|
-
idle_disp = str(idle_time) if idle_time else "0m"
|
1008
|
-
status_lines.append(
|
1009
|
-
f" - {session.get('tty', 'pts/?')} (pid {session.get('pid', '?')}, idle {idle_disp}) from {session.get('from_ip', 'unknown')}"
|
1010
|
-
)
|
1011
|
-
|
1012
|
-
# IDE connections
|
1013
|
-
ide_conn = idle_detector.get("ide_connections")
|
1014
|
-
if ide_conn:
|
1015
|
-
status_lines.append(
|
1016
|
-
f" • [magenta]🖥 IDE connected ({ide_conn['connection_count']} connections)[/magenta]"
|
1017
|
-
)
|
1018
|
-
|
1019
|
-
# Sensors contributing to ACTIVE
|
1020
|
-
reasons_raw = idle_detector.get("_reasons_raw")
|
1021
|
-
if isinstance(reasons_raw, list):
|
1022
|
-
active_sensors = [r for r in reasons_raw if r.get("active")]
|
1023
|
-
if active_sensors:
|
1024
|
-
status_lines.append("")
|
1025
|
-
status_lines.append("[bold]Active Sensors:[/bold]")
|
1026
|
-
for r in active_sensors:
|
1027
|
-
sensor = r.get("sensor", "Sensor")
|
1028
|
-
reason = r.get("reason") or "active"
|
1029
|
-
status_lines.append(f" • {sensor}: {reason}")
|
1022
|
+
status_lines.append(_sensor_line("Coffee", "CoffeeLockSensor", "☕"))
|
1023
|
+
status_lines.append(_sensor_line("Shell", "ActiveLoginSensor", "🐚"))
|
1024
|
+
status_lines.append(_sensor_line("IDE", "IDEConnectionSensor", "🖥"))
|
1025
|
+
status_lines.append(_sensor_line("Docker", "DockerWorkloadSensor", "🐳"))
|
1030
1026
|
|
1031
1027
|
# Audit one-liner (best-effort SSM fetch)
|
1032
1028
|
try:
|
1033
1029
|
last_audit = _fetch_last_audit_via_ssm(engine["instance_id"])
|
1034
1030
|
if last_audit:
|
1035
1031
|
status_lines.append("")
|
1036
|
-
status_lines.append("[bold]
|
1032
|
+
status_lines.append("[bold]Shutdown Audit:[/bold]")
|
1037
1033
|
status_lines.append(f" • {_summarize_audit(last_audit)}")
|
1038
1034
|
except Exception:
|
1039
1035
|
pass
|
@@ -1044,8 +1040,10 @@ def engine_status(
|
|
1044
1040
|
for studio in attached_studios:
|
1045
1041
|
status_lines.append(f" • {studio['user']} ({studio['studio_id']})")
|
1046
1042
|
|
1043
|
+
# Combine top summary and details
|
1044
|
+
all_lines = top_lines + status_lines
|
1047
1045
|
console.print(
|
1048
|
-
Panel("\n".join(
|
1046
|
+
Panel("\n".join(all_lines), title="Engine Status", border_style="blue")
|
1049
1047
|
)
|
1050
1048
|
|
1051
1049
|
if show_log:
|
@@ -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=
|
6
|
+
dayhoff_tools/cli/engine_commands.py,sha256=YOqkfwQaqfOAYr1TDh6_A_FseSWTzIWR-Pu9S6yDaAQ,108026
|
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.8.
|
31
|
-
dayhoff_tools-1.8.
|
32
|
-
dayhoff_tools-1.8.
|
33
|
-
dayhoff_tools-1.8.
|
30
|
+
dayhoff_tools-1.8.3.dist-info/METADATA,sha256=ekav7L5GELaqDK05WRuzyL3dBUcnI5wB0rz31Jwz0-o,2914
|
31
|
+
dayhoff_tools-1.8.3.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
32
|
+
dayhoff_tools-1.8.3.dist-info/entry_points.txt,sha256=iAf4jteNqW3cJm6CO6czLxjW3vxYKsyGLZ8WGmxamSc,49
|
33
|
+
dayhoff_tools-1.8.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|