initial: hermes-dashboard snapshot (post overview + git integration)
This commit is contained in:
78
services/worker.py
Normal file
78
services/worker.py
Normal file
@@ -0,0 +1,78 @@
|
||||
"""Worker service — process scanning and SOUL.md reading."""
|
||||
|
||||
import logging
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
import psutil
|
||||
|
||||
import config
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_running_processes() -> list[dict[str, Any]]:
|
||||
"""Scan for opencode worker processes (cmdline contains both 'opencode' and 'run')."""
|
||||
processes: list[dict[str, Any]] = []
|
||||
try:
|
||||
for proc in psutil.process_iter(["pid", "create_time", "cmdline"]):
|
||||
try:
|
||||
cmdline = proc.info.get("cmdline") or []
|
||||
cmdline_str = " ".join(cmdline)
|
||||
if "opencode" in cmdline_str and "run" in cmdline_str:
|
||||
# Truncate cmdline to 200 chars
|
||||
if len(cmdline_str) > 200:
|
||||
cmdline_str = cmdline_str[:200] + "..."
|
||||
|
||||
# Calculate elapsed time
|
||||
create_time = proc.info.get("create_time", 0)
|
||||
processes.append({
|
||||
"pid": proc.info["pid"],
|
||||
"cmdline": cmdline_str,
|
||||
"create_time": create_time,
|
||||
})
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
continue
|
||||
except Exception as exc:
|
||||
logger.exception("get_running_processes failed")
|
||||
return processes
|
||||
|
||||
|
||||
def get_current_task() -> dict[str, Any] | None:
|
||||
"""Find the currently running task (status=running) from kanban DB."""
|
||||
try:
|
||||
from extensions import get_db
|
||||
db = get_db()
|
||||
row = db.execute(
|
||||
"SELECT * FROM tasks WHERE status = 'running' ORDER BY started_at DESC LIMIT 1"
|
||||
).fetchone()
|
||||
if row:
|
||||
return dict(row)
|
||||
except Exception as exc:
|
||||
logger.debug("get_current_task failed: %s", exc)
|
||||
return None
|
||||
|
||||
|
||||
def get_soul_excerpt(max_chars: int = 2000) -> str:
|
||||
"""Read first max_chars from SOUL.md."""
|
||||
try:
|
||||
with open(config.SOUL_MD_PATH, "r", encoding="utf-8") as f:
|
||||
content = f.read(max_chars)
|
||||
return content
|
||||
except (FileNotFoundError, PermissionError, OSError) as exc:
|
||||
logger.debug("SOUL.md read failed: %s", exc)
|
||||
return f"(SOUL.md not available: {exc})"
|
||||
|
||||
|
||||
def get_worker_status() -> dict[str, Any]:
|
||||
"""Aggregate worker status: current task, processes, soul excerpt."""
|
||||
return {
|
||||
"current_task": get_current_task(),
|
||||
"processes": get_running_processes(),
|
||||
"soul_excerpt": get_soul_excerpt(500),
|
||||
}
|
||||
|
||||
|
||||
def get_soul_full() -> dict[str, str]:
|
||||
"""Return first 2000 chars of SOUL.md."""
|
||||
return {"content": get_soul_excerpt(2000)}
|
||||
Reference in New Issue
Block a user