refactor: rename and enhance shell detection in local environment

Renamed _find_shell to _find_bash to clarify its purpose of specifically locating bash. Improved the shell detection logic to prioritize bash over the user's $SHELL, ensuring compatibility with the fence wrapper's syntax requirements. Added a backward compatibility alias for _find_shell to maintain existing imports in process_registry.py.
This commit is contained in:
teknium1 2026-03-08 03:00:05 -07:00
parent b10ff83566
commit b383cafc44

View file

@ -17,19 +17,19 @@ from tools.environments.base import BaseEnvironment
_OUTPUT_FENCE = "__HERMES_FENCE_a9f7b3__" _OUTPUT_FENCE = "__HERMES_FENCE_a9f7b3__"
def _find_shell() -> str: def _find_bash() -> str:
"""Find the best shell for command execution. """Find bash for command execution.
On Unix: uses $SHELL, falls back to bash. The fence wrapper uses bash syntax (semicolons, $?, printf), so we
must use bash not the user's $SHELL which could be fish/zsh/etc.
On Windows: uses Git Bash (bundled with Git for Windows). On Windows: uses Git Bash (bundled with Git for Windows).
Raises RuntimeError if no suitable shell is found on Windows.
""" """
if not _IS_WINDOWS: if not _IS_WINDOWS:
return ( return (
os.environ.get("SHELL") shutil.which("bash")
or shutil.which("bash")
or ("/usr/bin/bash" if os.path.isfile("/usr/bin/bash") else None) or ("/usr/bin/bash" if os.path.isfile("/usr/bin/bash") else None)
or ("/bin/bash" if os.path.isfile("/bin/bash") else None) or ("/bin/bash" if os.path.isfile("/bin/bash") else None)
or os.environ.get("SHELL") # last resort: whatever they have
or "/bin/sh" or "/bin/sh"
) )
@ -59,6 +59,11 @@ def _find_shell() -> str:
"Or set HERMES_GIT_BASH_PATH to your bash.exe location." "Or set HERMES_GIT_BASH_PATH to your bash.exe location."
) )
# Backward compat — process_registry.py imports this name
_find_shell = _find_bash
# Noise lines emitted by interactive shells when stdin is not a terminal. # Noise lines emitted by interactive shells when stdin is not a terminal.
# Used as a fallback when output fence markers are missing. # Used as a fallback when output fence markers are missing.
_SHELL_NOISE_SUBSTRINGS = ( _SHELL_NOISE_SUBSTRINGS = (
@ -159,13 +164,11 @@ class LocalEnvironment(BaseEnvironment):
exec_command = self._prepare_command(command) exec_command = self._prepare_command(command)
try: try:
# Use the user's shell as an interactive login shell (-lic) so # The fence wrapper uses bash syntax (semicolons, $?, printf).
# that ALL rc files are sourced — including content after the # Always use bash for the wrapper — NOT $SHELL which could be
# interactive guard in .bashrc (case $- in *i*)..esac) where # fish, zsh, or another shell with incompatible syntax.
# tools like nvm, pyenv, and cargo install their init scripts. # The -lic flags source rc files so tools like nvm/pyenv work.
# -l alone isn't enough: .profile sources .bashrc, but the guard user_shell = _find_bash()
# returns early because the shell isn't interactive.
user_shell = _find_shell()
# Wrap with output fences so we can later extract the real # Wrap with output fences so we can later extract the real
# command output and discard shell init/exit noise. # command output and discard shell init/exit noise.
fenced_cmd = ( fenced_cmd = (