dayhoff-tools 1.8.2__tar.gz → 1.8.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.
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/PKG-INFO +1 -1
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/cli/engine_commands.py +67 -61
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/pyproject.toml +1 -1
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/README.md +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/__init__.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/chemistry/standardizer.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/chemistry/utils.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/cli/__init__.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/cli/cloud_commands.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/cli/main.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/cli/swarm_commands.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/cli/utility_commands.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/deployment/base.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/deployment/deploy_aws.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/deployment/deploy_gcp.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/deployment/deploy_utils.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/deployment/job_runner.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/deployment/processors.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/deployment/swarm.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/embedders.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/fasta.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/file_ops.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/h5.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/intake/gcp.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/intake/gtdb.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/intake/kegg.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/intake/mmseqs.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/intake/structure.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/intake/uniprot.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/logs.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/sqlite.py +0 -0
- {dayhoff_tools-1.8.2 → dayhoff_tools-1.8.3}/dayhoff_tools/warehouse.py +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":
|
@@ -964,68 +999,37 @@ def engine_status(
|
|
964
999
|
for k, v in overlay.items():
|
965
1000
|
idle_detector.setdefault(k, v)
|
966
1001
|
|
967
|
-
#
|
1002
|
+
# Activity Sensors (show all with YES/no)
|
968
1003
|
if idle_detector.get("available"):
|
969
1004
|
status_lines.append("")
|
970
|
-
status_lines.append("[bold]
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
if idle_detector.get("coffee_lock"):
|
986
|
-
status_lines.append(
|
987
|
-
f" • [cyan]☕ Caffeinated for another {idle_detector['coffee_lock']}[/cyan]"
|
988
|
-
)
|
989
|
-
|
990
|
-
# SSH sessions
|
991
|
-
ssh_sessions = idle_detector.get("ssh_sessions", [])
|
992
|
-
if ssh_sessions:
|
993
|
-
status_lines.append(f" • [blue]SSH Sessions ({len(ssh_sessions)}):[/blue]")
|
994
|
-
for session in ssh_sessions:
|
995
|
-
idle_time = session.get("idle_time")
|
996
|
-
if isinstance(idle_time, (int, float)):
|
997
|
-
idle_disp = f"{int(idle_time)//60}m"
|
998
|
-
else:
|
999
|
-
idle_disp = str(idle_time) if idle_time else "0m"
|
1000
|
-
status_lines.append(
|
1001
|
-
f" - {session.get('tty', 'pts/?')} (pid {session.get('pid', '?')}, idle {idle_disp}) from {session.get('from_ip', 'unknown')}"
|
1002
|
-
)
|
1003
|
-
|
1004
|
-
# IDE connections
|
1005
|
-
ide_conn = idle_detector.get("ide_connections")
|
1006
|
-
if ide_conn:
|
1007
|
-
status_lines.append(
|
1008
|
-
f" • [magenta]🖥 IDE connected ({ide_conn['connection_count']} connections)[/magenta]"
|
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 ''}"
|
1009
1020
|
)
|
1010
1021
|
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
if active_sensors:
|
1016
|
-
status_lines.append("")
|
1017
|
-
status_lines.append("[bold]Active Sensors:[/bold]")
|
1018
|
-
for r in active_sensors:
|
1019
|
-
sensor = r.get("sensor", "Sensor")
|
1020
|
-
reason = r.get("reason") or "active"
|
1021
|
-
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", "🐳"))
|
1022
1026
|
|
1023
1027
|
# Audit one-liner (best-effort SSM fetch)
|
1024
1028
|
try:
|
1025
1029
|
last_audit = _fetch_last_audit_via_ssm(engine["instance_id"])
|
1026
1030
|
if last_audit:
|
1027
1031
|
status_lines.append("")
|
1028
|
-
status_lines.append("[bold]
|
1032
|
+
status_lines.append("[bold]Shutdown Audit:[/bold]")
|
1029
1033
|
status_lines.append(f" • {_summarize_audit(last_audit)}")
|
1030
1034
|
except Exception:
|
1031
1035
|
pass
|
@@ -1036,8 +1040,10 @@ def engine_status(
|
|
1036
1040
|
for studio in attached_studios:
|
1037
1041
|
status_lines.append(f" • {studio['user']} ({studio['studio_id']})")
|
1038
1042
|
|
1043
|
+
# Combine top summary and details
|
1044
|
+
all_lines = top_lines + status_lines
|
1039
1045
|
console.print(
|
1040
|
-
Panel("\n".join(
|
1046
|
+
Panel("\n".join(all_lines), title="Engine Status", border_style="blue")
|
1041
1047
|
)
|
1042
1048
|
|
1043
1049
|
if show_log:
|
@@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
|
|
5
5
|
|
6
6
|
[project]
|
7
7
|
name = "dayhoff-tools"
|
8
|
-
version = "1.8.
|
8
|
+
version = "1.8.3"
|
9
9
|
description = "Common tools for all the repos at Dayhoff Labs"
|
10
10
|
authors = [
|
11
11
|
{name = "Daniel Martin-Alarcon", email = "dma@dayhofflabs.com"}
|
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
|