diff --git a/hermes_cli/status_report.py b/hermes_cli/status_report.py index a7bc0c0436..1cfb1a317d 100644 --- a/hermes_cli/status_report.py +++ b/hermes_cli/status_report.py @@ -13,6 +13,7 @@ They now all call :func:`build_status_fields`; a surface only adds its own heade from __future__ import annotations from datetime import datetime +from pathlib import Path from typing import Any STATUS_STAMP = "%Y-%m-%d %H:%M" @@ -69,6 +70,7 @@ def build_status_fields( created_fallback: datetime | None = None, tokens: int | None = None, agent_running: bool = False, + home: str | Path | None = None, ) -> dict[str, Any]: """Common ``/status`` facts, pre-formatted for display. @@ -76,6 +78,8 @@ def build_status_fields( (CLI ``self.model``, TUI metadata mirror, gateway's resolved route) and are also what a surface passes when it has no live agent. ``created`` / ``last_activity`` override the ``meta`` row scan for surfaces whose session store is authoritative (gateway SessionEntry). + ``home`` is an explicit owning-profile path for multiplexed surfaces; omitted callers keep + the process/current-profile lookup. """ from hermes_constants import display_hermes_home @@ -89,7 +93,7 @@ def build_status_fields( row_title = meta.get("title") if title is None else title return { "session_id": str(session_id or ""), - "path": display_hermes_home(), + "path": display_hermes_home(Path(home) if home else None), "title": (row_title or "").strip(), "model": getattr(agent, "model", None) or model or "", "provider": getattr(agent, "provider", None) or provider or "", diff --git a/tests/tui_gateway/test_status_profile_home.py b/tests/tui_gateway/test_status_profile_home.py new file mode 100644 index 0000000000..330f6f7721 --- /dev/null +++ b/tests/tui_gateway/test_status_profile_home.py @@ -0,0 +1,75 @@ +"""Profile-owned /status path rendering for multiplexed TUI/Desktop sessions (#124500).""" + +import threading + +from tui_gateway import server + + +def _session(profile_home=None): + row = { + "session_key": "status-row", + "history": [], + "history_lock": threading.Lock(), + "running": False, + "agent": None, + "created_at": 1.0, + "last_active": 1.0, + } + if profile_home is not None: + row["profile_home"] = str(profile_home) + return row + + +def test_session_status_path_uses_owning_profile_home(monkeypatch, tmp_path): + launch_home = tmp_path / "profiles" / "launch" + profile_home = tmp_path / "profiles" / "ember" + launch_home.mkdir(parents=True) + profile_home.mkdir(parents=True) + monkeypatch.setenv("HERMES_HOME", str(launch_home)) + + class LaunchDB: + def get_session(self, _key): + raise AssertionError("secondary-profile status must not read the launch DB") + + class ProfileDB: + def __init__(self, db_path=None): + assert str(db_path) == str(profile_home / "state.db") + + def get_session(self, key): + return {"id": key, "title": "owned", "started_at": 1} + + def close(self): + pass + + server._sessions["status-profile-home"] = _session(profile_home) + monkeypatch.setattr(server, "_get_db", lambda: LaunchDB()) + monkeypatch.setattr("hermes_state_registry.acquire", ProfileDB) + try: + resp = server.handle_request( + {"id": "1", "method": "session.status", "params": {"session_id": "status-profile-home"}} + ) + output = resp["result"]["output"] + assert f"Path: {profile_home}" in output + assert f"Path: {launch_home}" not in output + finally: + server._sessions.pop("status-profile-home", None) + + +def test_session_status_path_without_profile_home_keeps_launch_home(monkeypatch, tmp_path): + launch_home = tmp_path / "launch" + launch_home.mkdir() + monkeypatch.setenv("HERMES_HOME", str(launch_home)) + + class LaunchDB: + def get_session(self, key): + return {"id": key, "title": "launch", "started_at": 1} + + server._sessions["status-launch-home"] = _session() + monkeypatch.setattr(server, "_get_db", lambda: LaunchDB()) + try: + resp = server.handle_request( + {"id": "1", "method": "session.status", "params": {"session_id": "status-launch-home"}} + ) + assert f"Path: {launch_home}" in resp["result"]["output"] + finally: + server._sessions.pop("status-launch-home", None) diff --git a/tui_gateway/methods_session.py b/tui_gateway/methods_session.py index cce29de6de..7b6e85b8b4 100644 --- a/tui_gateway/methods_session.py +++ b/tui_gateway/methods_session.py @@ -1843,6 +1843,7 @@ def _(rid, params: dict, session: dict) -> dict: model=mirror.get("model") or getattr(live_agent, "model", None), provider=mirror.get("provider") or getattr(live_agent, "provider", None), tokens=_session_usage_snapshot(session).get("total"), agent_running=bool(session.get("running")), + home=session.get("profile_home"), ) project = _project_info_for_cwd(_display_session_cwd(session)) lines = [