fix(cli): local backend CLI always uses launch directory, stops .env sync of TERMINAL_CWD (#19334)
The old CWD heuristic was fooled by: 1. TERMINAL_CWD persisted to .env by `hermes config set terminal.cwd` 2. Inherited TERMINAL_CWD from parent hermes processes 3. Only resolved when config had a placeholder value (not explicit paths) Fix: - load_cli_config() unconditionally uses os.getcwd() for local backend - TERMINAL_CWD always force-exported in CLI mode (overrides stale values) - Gateway sets _HERMES_GATEWAY=1 marker so lazy cli.py imports don't clobber - Remove terminal.cwd from config-set .env sync map (prevents re-poisoning) - Clarify setup wizard label as 'Gateway working directory' Closes #19214
This commit is contained in:
52
cli.py
52
cli.py
@@ -459,32 +459,19 @@ def load_cli_config() -> Dict[str, Any]:
|
||||
if "backend" in terminal_config:
|
||||
terminal_config["env_type"] = terminal_config["backend"]
|
||||
|
||||
# Handle special cwd values: "." or "auto" means use current working directory.
|
||||
# Only resolve to the host's CWD for the local backend where the host
|
||||
# filesystem is directly accessible. For ALL remote/container backends
|
||||
# (ssh, docker, modal, singularity), the host path doesn't exist on the
|
||||
# target -- remove the key so terminal_tool.py uses its per-backend default.
|
||||
#
|
||||
# GUARD: If TERMINAL_CWD is already set to a real absolute path (by the
|
||||
# gateway's config bridge earlier in the process), don't clobber it.
|
||||
# This prevents a lazy import of cli.py during gateway runtime from
|
||||
# rewriting TERMINAL_CWD to the service's working directory.
|
||||
# See issue #10817.
|
||||
# CWD resolution for CLI/TUI. The gateway has its own config bridge in
|
||||
# gateway/run.py but may lazily import cli.py (triggering this code).
|
||||
# Local backend: always os.getcwd(). Use `cd /dir && hermes` to control it.
|
||||
# Non-local with placeholder: pop so terminal_tool uses its per-backend default.
|
||||
# Non-local with explicit path: keep as-is.
|
||||
_CWD_PLACEHOLDERS = (".", "auto", "cwd")
|
||||
if terminal_config.get("cwd") in _CWD_PLACEHOLDERS:
|
||||
_existing_cwd = os.environ.get("TERMINAL_CWD", "")
|
||||
if _existing_cwd and _existing_cwd not in _CWD_PLACEHOLDERS and os.path.isabs(_existing_cwd):
|
||||
# Gateway (or earlier startup) already resolved a real path — keep it
|
||||
terminal_config["cwd"] = _existing_cwd
|
||||
defaults["terminal"]["cwd"] = _existing_cwd
|
||||
else:
|
||||
effective_backend = terminal_config.get("env_type", "local")
|
||||
if effective_backend == "local":
|
||||
terminal_config["cwd"] = os.getcwd()
|
||||
defaults["terminal"]["cwd"] = terminal_config["cwd"]
|
||||
else:
|
||||
# Remove so TERMINAL_CWD stays unset → tool picks backend default
|
||||
terminal_config.pop("cwd", None)
|
||||
effective_backend = terminal_config.get("env_type", "local")
|
||||
|
||||
if effective_backend == "local":
|
||||
terminal_config["cwd"] = os.getcwd()
|
||||
defaults["terminal"]["cwd"] = terminal_config["cwd"]
|
||||
elif terminal_config.get("cwd") in _CWD_PLACEHOLDERS:
|
||||
terminal_config.pop("cwd", None)
|
||||
|
||||
env_mappings = {
|
||||
"env_type": "TERMINAL_ENV",
|
||||
@@ -517,13 +504,18 @@ def load_cli_config() -> Dict[str, Any]:
|
||||
"sudo_password": "SUDO_PASSWORD",
|
||||
}
|
||||
|
||||
# Apply config values to env vars so terminal_tool picks them up.
|
||||
# If the config file explicitly has a [terminal] section, those values are
|
||||
# authoritative and override any .env settings. When using defaults only
|
||||
# (no config file or no terminal section), don't overwrite env vars that
|
||||
# were already set by .env -- the user's .env is the fallback source.
|
||||
# Bridge config → env vars for terminal_tool. TERMINAL_CWD is force-exported
|
||||
# UNLESS we're inside a gateway process (detected by _HERMES_GATEWAY marker)
|
||||
# where it was already set correctly by gateway/run.py's config bridge.
|
||||
_is_gateway = os.environ.get("_HERMES_GATEWAY") == "1"
|
||||
for config_key, env_var in env_mappings.items():
|
||||
if config_key in terminal_config:
|
||||
if env_var == "TERMINAL_CWD":
|
||||
if _is_gateway:
|
||||
continue
|
||||
# CLI: always export (overrides stale .env or inherited values)
|
||||
os.environ[env_var] = str(terminal_config[config_key])
|
||||
continue
|
||||
if _file_has_terminal_config or env_var not in os.environ:
|
||||
val = terminal_config[config_key]
|
||||
if isinstance(val, list):
|
||||
|
||||
Reference in New Issue
Block a user