fix(tui): use a named SSH profile's working directory in the desktop app

The app showed the profile's terminal.cwd, but SSH sessions still ran in the
launch profile's directory because a remote path that does not exist on the
desktop host was discarded.

(cherry picked from commit e4f4a43ebc4408adb6ac37e8de1ee7ff414a9158)
This commit is contained in:
xxxigm
2026-09-26 19:05:46 +07:00
committed by kshitij
parent 3d3a268761
commit e8d86e7405
2 changed files with 64 additions and 2 deletions

View File

@@ -965,7 +965,11 @@ def _(rid, params: dict) -> dict:
_resume_follow_tip(ctx)
if (resp := _resume_guard(ctx)) is not None:
return resp
ctx.profile_resume_cwd = _str_param(ctx.found, "cwd") or _profile_configured_cwd(ctx.profile_home)
ctx.profile_resume_cwd = (
_str_param(ctx.found, "cwd")
or _profile_configured_cwd(ctx.profile_home)
or _declared_remote_profile_cwd(ctx.profile_home)
)
# Fast path: reuse a session live IN THIS PROFILE (never another profile's runtime).
with _session_resume_lock:
live = _find_live_session_by_key(ctx.target, ctx.profile_home)

View File

@@ -30,9 +30,15 @@ def _completion_cwd(params: dict | None = None) -> str:
# cannot tell the two apart, so the desktop ships the flag alongside the path.
client_cwd = params.get("cwd")
if not params.get("cwd_explicit") and client_cwd:
profile_cwd = _profile_configured_cwd(_profile_home(params.get("profile")))
profile_home = _profile_home(params.get("profile"))
profile_cwd = _profile_configured_cwd(profile_home)
if profile_cwd:
return profile_cwd
# SSH cwd usually does not exist on the desktop host, so the isdir
# check above drops it and the launch profile's workspace wins.
remote_cwd = _declared_remote_profile_cwd(profile_home)
if remote_cwd:
return remote_cwd
# A session bound to another profile resolves its workspace from THAT profile's config before the launch profile's
# env var; the dashboard's in-memory gateway does NOT inherit the PTY child's bridged TERMINAL_CWD, so a configured
# terminal.cwd is read directly.
@@ -52,6 +58,10 @@ def _completion_cwd(params: dict | None = None) -> str:
return resolved
if os.path.isdir(resolved):
return resolved
if not params.get("cwd_explicit"):
remote_cwd = _declared_remote_profile_cwd(_profile_home(params.get("profile")))
if remote_cwd:
return remote_cwd
return os.getcwd()
@@ -64,6 +74,48 @@ def _workdir_terminal_cfg(key: str) -> str:
return ""
_REMOTE_CWD_PLACEHOLDERS = {".", "./", "auto", "cwd"}
def _profile_terminal_section(profile_home) -> dict:
"""``terminal:`` from a profile's own config.yaml, or {}."""
if not profile_home:
return {}
with contextlib.suppress(Exception):
from pathlib import Path
from hermes_cli.config_effective import load_user_config_effective
path = Path(profile_home) / "config.yaml"
if not path.is_file():
return {}
cfg = load_user_config_effective(path)
terminal = cfg.get("terminal") if isinstance(cfg, dict) else None
return terminal if isinstance(terminal, dict) else {}
return {}
def _declared_remote_profile_cwd(profile_home) -> str | None:
"""A non-local profile's ``terminal.cwd``, kept when the path is not on this host.
``_profile_configured_cwd`` requires ``os.path.isdir``. An SSH working
directory lives on the remote, so that check drops it and the desktop
keeps using the launch profile's ``TERMINAL_CWD``.
"""
terminal = _profile_terminal_section(profile_home)
if not terminal:
return None
backend = str(terminal.get("backend") or "").strip().lower() or _effective_terminal_backend()
if not backend or backend == "local":
return None
raw = str(terminal.get("cwd") or "").strip()
if not raw or raw in _REMOTE_CWD_PLACEHOLDERS:
return None
if raw == "~" or raw.startswith("~/") or os.path.isabs(raw):
return raw
return None
def _terminal_task_cwd(session: dict | None) -> str:
"""The cwd terminal_tool should use for this TUI session (NOT host-validated: a non-local backend's cwd lives
inside the target environment)."""
@@ -79,6 +131,12 @@ def _terminal_task_cwd_with_source(session: dict | None) -> tuple[str, str]:
# THIS session's explicit workspace beats the LAST session's env var.
if session and session.get("explicit_cwd") and session.get("cwd"):
return str(session["cwd"]), "session"
# Process TERMINAL_CWD is the launch profile. A named SSH profile's
# terminal.cwd is on the remote and must not lose to that env var.
if backend == "ssh":
remote_cwd = _declared_remote_profile_cwd((session or {}).get("profile_home"))
if remote_cwd:
return remote_cwd, "session"
raw = os.environ.get("TERMINAL_CWD", "").strip() or _workdir_terminal_cfg("cwd")
if raw and raw not in {".", "auto", "cwd"}:
return raw, "process"