refactor(web-profiles/status): AST-neutral bracket hugging

This commit is contained in:
Teknium
2026-09-02 21:14:17 -07:00
parent 48751f0916
commit 976b008611
3 changed files with 47 additions and 92 deletions
+17 -31
View File
@@ -90,8 +90,7 @@ def _profile_to_dict(info) -> Dict[str, Any]:
"distribution_name": attr("distribution_name", None),
"distribution_version": attr("distribution_version", None),
"distribution_source": attr("distribution_source", None),
"has_alias": attr("alias_path", None) is not None,
}
"has_alias": attr("alias_path", None) is not None}
def _profile_setup_command(name: str) -> str:
@@ -128,7 +127,8 @@ def _disable_unselected_skills(profile_dir: Path, keep: List[str]) -> int:
keep_set = {s.strip() for s in keep if s and s.strip()}
with _hermes_home_scope(profile_dir):
skills_root = profile_dir / "skills"
installed = [md.parent.name for md in skills_root.rglob("SKILL.md")] if skills_root.is_dir() else []
installed = ([md.parent.name for md in skills_root.rglob("SKILL.md")]
if skills_root.is_dir() else [])
cfg = load_config()
disabled = get_disabled_skills(cfg)
newly = 0
@@ -202,8 +202,7 @@ def _tag_rows(rows: List[Dict[str, Any]], name: str, now: float) -> List[Dict[st
s["profile"] = name
s["is_default_profile"] = name == "default"
s["is_active"] = (
s.get("ended_at") is None
and (now - s.get("last_active", s.get("started_at", 0))) < 300
s.get("ended_at") is None and (now - s.get("last_active", s.get("started_at", 0))) < 300
)
s["archived"] = bool(s.get("archived"))
s["pinned"] = bool(s.get("pinned"))
@@ -413,8 +412,7 @@ def get_profiles_sessions(
source: str = None,
sources: str = None,
exclude_sources: str = None,
full: bool = False,
):
full: bool = False):
"""Unified, read-only session list aggregated across ALL profiles.
Process-light: opens each profile's ``state.db`` directly from disk — it does NOT spawn
@@ -441,8 +439,7 @@ def get_profiles_sessions(
exclude_sources=_csv_list(exclude_sources) or None,
min_message_count=max(0, min_messages),
include_archived=archived == "include",
archived_only=archived == "only",
)
archived_only=archived == "only")
# Over-fetch per profile so the merged+sorted window is correct for the requested page.
# Capped so a huge profile can't blow up the response.
per_profile = min(max(limit + offset, limit), 500)
@@ -456,8 +453,7 @@ def get_profiles_sessions(
rows = db.list_sessions_rich(
limit=per_profile, offset=0, order_by_last_active=order == "recent",
# Same SQL-level blob skip as /api/sessions.
compact_rows=not full, include_pinned=True, **filters,
)
compact_rows=not full, include_pinned=True, **filters)
totals[name] = db.session_count(exclude_children=True, **filters)
merged.extend(_tag_rows(rows, name, now))
_read_profile_db(name, home, errors, _read)
@@ -479,8 +475,7 @@ def get_profiles_sessions_sidebar(
recents_exclude: str = None,
cron_limit: int = 50,
messaging_limit: int = 100,
messaging_exclude: str = None,
):
messaging_exclude: str = None):
"""Batched sidebar session slices — one profile-DB open per refresh.
The desktop sidebar needs three source-scoped windows per refresh: recents (local
@@ -518,8 +513,7 @@ def get_profiles_sessions_sidebar(
return db.list_sessions_rich(
source=source, exclude_sources=exclude or None, limit=cap, offset=0,
min_message_count=1, include_archived=False, archived_only=False,
order_by_last_active=True, compact_rows=True, include_pinned=True,
)
order_by_last_active=True, compact_rows=True, include_pinned=True)
def _build_slices(db, cache_key):
slices = {
@@ -528,8 +522,7 @@ def get_profiles_sessions_sidebar(
# and a total that shrank when you scrolled would be worse than no total at all.
"usage": db.usage_totals(),
"cron": _slice(db, source="cron", cap=cron_cap),
"messaging": _slice(db, exclude=messaging_exclude_list, cap=messaging_cap),
}
"messaging": _slice(db, exclude=messaging_exclude_list, cap=messaging_cap)}
_sidebar_profile_cache_put(cache_key, slices)
return slices
@@ -571,8 +564,7 @@ def get_profiles_sessions_sidebar(
"profiles_truncated": recents_truncated, "profiles_usage": profile_totals},
"cron": {"sessions": _window(cron_rows, cron_cap)},
"messaging": {"sessions": _window(messaging_rows, messaging_cap), "total": len(messaging_rows)},
"errors": errors,
}
"errors": errors}
def _merge_by_id(into: Dict[str, Dict[str, Any]], entries: List[Dict[str, Any]], child_key: str) -> None:
@@ -601,8 +593,7 @@ def _merge_profile_tree(
merged: Dict[str, Dict[str, Any]],
projects: List[Dict[str, Any]],
profile: str,
preview_limit: int,
) -> None:
preview_limit: int) -> None:
"""Fold one profile's projects into the shared tree, keyed by folder.
The same checkout in two profiles is one group, as is ``__no_project__`` (every profile
@@ -677,8 +668,7 @@ def get_profiles_projects_tree(preview_limit: int = 3, session_limit: int = 2000
"projects": sorted(merged.values(), key=lambda p: p.get("lastActive") or 0, reverse=True),
# Ownership is per profile, so no project is "the active one" here; the desktop only
# reads active_id to bias its overview sort.
"active_id": None, "scoped_session_ids": scoped_session_ids, "errors": errors,
}
"active_id": None, "scoped_session_ids": scoped_session_ids, "errors": errors}
# `gh pr create` prints the PR url and nothing else, so a tool result whose whole output IS
@@ -803,8 +793,7 @@ async def create_profile_endpoint(body: ProfileCreate):
{"identifier": ident, "pid": _best_effort(
"Spawning hub-skill install %s for new profile %s failed", ident, body.name,
fn=lambda: _spawn_install(ident))}
for ident in ((i or "").strip() for i in body.hub_skills) if ident
]
for ident in ((i or "").strip() for i in body.hub_skills) if ident]
return {"ok": True, "name": body.name, "path": str(path), "model_set": model_set,
"mcp_written": mcp_written, "skills_disabled": skills_disabled,
@@ -855,8 +844,7 @@ async def get_profile_setup_command(name: str):
_LINUX_TERMINALS = (
("x-terminal-emulator", "-e"), ("gnome-terminal", "--"), ("konsole", "-e"),
("xfce4-terminal", None), ("mate-terminal", None), ("lxterminal", None),
("tilix", "-e"), ("alacritty", "-e"), ("kitty", ""), ("xterm", "-e"),
)
("tilix", "-e"), ("alacritty", "-e"), ("kitty", ""), ("xterm", "-e"))
def _linux_terminal_commands(command: str) -> list:
@@ -864,8 +852,7 @@ def _linux_terminal_commands(command: str) -> list:
quoted = f"sh -lc '{command}'"
return [
(exe, [exe, "-e", quoted] if flag is None else [exe, *([flag] if flag else []), *sh])
for exe, flag in _LINUX_TERMINALS
]
for exe, flag in _LINUX_TERMINALS]
@router.post("/api/profiles/{name}/open-terminal")
@@ -1028,8 +1015,7 @@ async def describe_profile_auto_endpoint(name: str, body: ProfileDescribeAuto):
"description": outcome.description,
# Only a successful generation is an auto-authored description. A failed sweep
# leaves any existing description untouched, so don't claim it's auto-generated.
"description_auto": bool(outcome.ok),
}
"description_auto": bool(outcome.ok)}
# ── Export / Import ──────────────────────────────────────────────────────────
+26 -52
View File
@@ -75,8 +75,7 @@ def _count_status_active_sessions() -> int:
return sum(
1 for s in sessions
if s.get("ended_at") is None
and (now - s.get("last_active", s.get("started_at", 0))) < 300
)
and (now - s.get("last_active", s.get("started_at", 0))) < 300)
finally:
db.close()
@@ -85,13 +84,11 @@ async def _status_active_sessions() -> int:
try:
return await asyncio.wait_for(
run_in_threadpool(_count_status_active_sessions),
timeout=_STATUS_ACTIVE_SESSIONS_TIMEOUT,
)
timeout=_STATUS_ACTIVE_SESSIONS_TIMEOUT)
except asyncio.TimeoutError:
_log.debug(
"/api/status active session count exceeded %.2fs; returning 0",
_STATUS_ACTIVE_SESSIONS_TIMEOUT,
)
_STATUS_ACTIVE_SESSIONS_TIMEOUT)
except Exception as exc:
_log.debug("/api/status active session count unavailable: %s", exc)
return 0
@@ -107,8 +104,7 @@ async def get_ssh_ownership(request: Request):
"ok": True,
"sshOwnerNonce": _SSH_OWNER_NONCE,
"protocolVersion": 1,
"runtimeIntact": _ssh_runtime_intact(),
}
"runtimeIntact": _ssh_runtime_intact()}
@router.get("/api/health")
@@ -117,8 +113,7 @@ async def get_health():
return {
"ok": True,
"version": __version__,
"auth_required": bool(getattr(app.state, "auth_required", False)),
}
"auth_required": bool(getattr(app.state, "auth_required", False))}
# Profile segment mirrors hermes_cli.profiles._PROFILE_ID_RE. Platform segment mirrors the
@@ -202,8 +197,7 @@ def _bounded_health_probe():
_log.warning(
"/api/status gateway health probe exceeded %.2fs; "
"using local status",
_GATEWAY_HEALTH_ROUTE_TIMEOUT,
)
_GATEWAY_HEALTH_ROUTE_TIMEOUT)
return False, None
except Exception:
return False, None
@@ -226,8 +220,7 @@ def _project_gateway_platforms(gateway_platforms: dict, configured: "set[str] |
platforms = {
key: _public_platform_entry(value)
for key, value in gateway_platforms.items()
if _status_platform_key_allowed(key, configured)
}
if _status_platform_key_allowed(key, configured)}
if gateway_running:
return platforms
if gateway_state == "startup_failed":
@@ -297,8 +290,7 @@ async def _resolve_gateway_status(profile_dir: Optional[Path], health_url) -> Di
return {
"runtime": runtime, "gateway_running": gateway_running, "gateway_pid": liveness.pid,
"gateway_state": gateway_state, "gateway_platforms": gateway_platforms,
"gateway_exit_reason": gateway_exit_reason, "gateway_updated_at": gateway_updated_at,
}
"gateway_exit_reason": gateway_exit_reason, "gateway_updated_at": gateway_updated_at}
def _auth_gate_status() -> Dict[str, Any]:
@@ -318,9 +310,7 @@ def _auth_gate_status() -> Dict[str, Any]:
auth_flows: list[str] = []
try:
from hermes_cli.dashboard_auth import (
list_providers as _list_providers,
list_session_providers as _list_session_providers,
)
list_providers as _list_providers, list_session_providers as _list_session_providers)
auth_providers = [p.name for p in _list_providers()]
if auth_required:
auth_flows.append("cookie")
@@ -357,10 +347,8 @@ async def _component_health(gateway: Dict[str, Any]) -> Dict[str, Any]:
components: Dict[str, Any] = {
"gateway": {
"status": "ok" if gateway_running and gateway_state in {"running", "draining"} else "degraded",
"state": gateway_state or ("running" if gateway_running else "stopped"),
},
"dashboard": DASHBOARD_HEALTH.snapshot(),
}
"state": gateway_state or ("running" if gateway_running else "stopped")},
"dashboard": DASHBOARD_HEALTH.snapshot()}
try:
from gateway.readiness import _probe_state_db
@@ -371,14 +359,12 @@ async def _component_health(gateway: Dict[str, Any]) -> Dict[str, Any]:
platform_states = [
str(value.get("state") or value.get("status") or "").lower()
for value in gateway_platforms.values()
if isinstance(value, dict)
]
if isinstance(value, dict)]
connected = sum(1 for state in platform_states if state in _HEALTHY_PLATFORM_STATES)
components["platforms"] = {
"status": "ok" if connected == len(platform_states) else "degraded",
"configured": len(gateway_platforms),
"connected": connected,
}
"connected": connected}
return components
@@ -485,8 +471,7 @@ async def get_status(profile: Optional[str] = None):
"restart_drain_timeout": restart_drain_timeout,
"active_sessions": active_sessions,
**auth,
"nous_session_valid": _nous_session_validity(),
}
"nous_session_valid": _nous_session_validity()}
# Stable per-install identity. First call may touch disk, so keep it off the loop;
# afterwards it is a process-global cache hit. Omitted (not null) when unpersistable
@@ -519,8 +504,7 @@ async def get_status(profile: Optional[str] = None):
"env_path": str(get_env_path()),
"gateway_pid": gateway["gateway_pid"],
"gateway_health_url": _GATEWAY_HEALTH_URL,
"gateways": topology["gateways"],
})
"gateways": topology["gateways"]})
return status
finally:
@@ -540,15 +524,13 @@ async def get_system_stats():
system=_platform.system(),
release=_platform.release(),
version=_platform.version(),
platform_label=_platform.platform(),
),
platform_label=_platform.platform()),
"arch": _platform.machine(),
"hostname": _platform.node(),
"python_version": _platform.python_version(),
"python_impl": _platform.python_implementation(),
"hermes_version": __version__,
"cpu_count": os.cpu_count(),
}
"cpu_count": os.cpu_count()}
def _optional(fill):
try:
@@ -579,7 +561,8 @@ async def get_system_stats():
import psutil # type: ignore
vm = psutil.virtual_memory()
info["memory"] = {"total": vm.total, "available": vm.available, "used": vm.used, "percent": vm.percent}
info["memory"] = {"total": vm.total, "available": vm.available, "used": vm.used,
"percent": vm.percent}
for fill in (_disk, _cpu, _uptime, _process):
_optional(fill)
info["psutil"] = True
@@ -617,8 +600,7 @@ async def get_curator_status():
"last_run_at": state.get("last_run_at"),
"min_idle_hours": _safe_call(curator, "get_min_idle_hours", None),
"stale_after_days": _safe_call(curator, "get_stale_after_days", None),
"archive_after_days": _safe_call(curator, "get_archive_after_days", None),
}
"archive_after_days": _safe_call(curator, "get_archive_after_days", None)}
@router.put("/api/curator/paused")
@@ -751,8 +733,7 @@ def _get_portal_status_sync():
"inference_url": auth.get("inference_base_url"),
"provider": str((model_cfg or {}).get("provider") or ""),
"subscription_url": "https://portal.nousresearch.com/manage-subscription",
"features": features,
}
"features": features}
# ---------------------------------------------------------------------------
@@ -790,10 +771,7 @@ async def run_debug_share_endpoint(body: DebugShareRequest | None = None):
req = body or DebugShareRequest()
try:
result = await asyncio.to_thread(
build_debug_share,
log_lines=max(1, min(int(req.lines), 5000)),
redact=bool(req.redact),
)
build_debug_share, log_lines=max(1, min(int(req.lines), 5000)), redact=bool(req.redact))
except RuntimeError as exc:
# Required summary-report upload failed (offline / paste service down).
raise HTTPException(status_code=502, detail=f"Upload failed: {exc}")
@@ -806,8 +784,7 @@ async def run_debug_share_endpoint(body: DebugShareRequest | None = None):
"urls": result.urls,
"failures": result.failures,
"redacted": result.redacted,
"auto_delete_seconds": result.auto_delete_seconds,
}
"auto_delete_seconds": result.auto_delete_seconds}
# ---------------------------------------------------------------------------
@@ -821,8 +798,7 @@ async def get_logs(
lines: int = 100,
level: Optional[str] = None,
component: Optional[str] = None,
search: Optional[str] = None,
):
search: Optional[str] = None):
from hermes_cli.logs import _read_tail, LOG_FILES
log_name = LOG_FILES.get(file)
@@ -847,8 +823,7 @@ async def get_logs(
raise HTTPException(
status_code=400,
detail=f"Unknown component: {component}. "
f"Available: {', '.join(sorted(COMPONENT_PREFIXES))}",
)
f"Available: {', '.join(sorted(COMPONENT_PREFIXES))}")
else:
comp_prefixes = None
@@ -857,8 +832,7 @@ async def get_logs(
log_path, min(lines, 500) if not search else 2000,
has_filters=has_filters,
min_level=min_level,
component_prefixes=comp_prefixes,
)
component_prefixes=comp_prefixes)
# _read_tail doesn't support free-text search, so post-filter (case-insensitive
# substring) here and trim to the requested line count afterward.
if search:
+4 -9
View File
@@ -122,8 +122,7 @@ def _fallback_profile_entry(profiles_mod, name: str, home: Path, *, is_default:
"gateway_running": _safe(gateway_running, False),
"description": meta("description", ""), "description_auto": meta("description_auto", False),
"distribution_name": None, "distribution_version": None, "distribution_source": None,
"has_alias": False,
}
"has_alias": False}
def _fallback_profile_dicts(profiles_mod) -> List[Dict[str, Any]]:
@@ -281,9 +280,7 @@ _TERMINAL_BACKENDS: List[Dict[str, str]] = [
"Run commands in a Singularity/Apptainer container (HPC-friendly, rootless)."),
("modal", "Modal", "Run commands in a Modal cloud sandbox."),
("daytona", "Daytona", "Run commands in a Daytona cloud sandbox."),
("ssh", "SSH", "Run commands on a remote host over SSH."),
)
]
("ssh", "SSH", "Run commands on a remote host over SSH."))]
def _plugin_terminal_backend_rows() -> List[Dict[str, str]]:
@@ -349,8 +346,7 @@ def _aux_usage_rows(db, cutoff: float) -> List[Dict[str, Any]]:
def _merge_aux_into_by_model(
by_model: List[Dict[str, Any]], aux_rows: List[Dict[str, Any]]
) -> List[Dict[str, Any]]:
by_model: List[Dict[str, Any]], aux_rows: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""Fold aux usage rows into the sessions-derived per-model list.
Aux usage lives only in session_model_usage (never in the sessions counters), so
@@ -430,7 +426,6 @@ def _installed_hub_identifiers(profile: Optional[str] = None) -> dict:
return {
entry["identifier"]: {"name": entry.get("name"), "trust_level": entry.get("trust_level"),
"scan_verdict": entry.get("scan_verdict")}
for entry in lock.list_installed() if entry.get("identifier")
}
for entry in lock.list_installed() if entry.get("identifier")}
except Exception:
return {}