Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions tools/environments/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,19 @@ def _run_bash(self, cmd_string: str, *, login: bool = False,
args = [bash, "-l", "-c", cmd_string] if login else [bash, "-c", cmd_string]
run_env = _make_run_env(self.env)

# Validate that self.cwd still exists. When subagents share a single
# LocalEnvironment and one cd's into a temp dir that gets deleted,
# subprocess.Popen raises FileNotFoundError for ALL subsequent calls.
# The shell script from _wrap_command already does `cd -- <path>` so
# Popen's cwd just needs to be a valid launch directory for bash.
popen_cwd = self.cwd
if not os.path.isdir(popen_cwd):
# Reset self.cwd to a safe fallback so future calls don't
# keep hitting the same stale path.
fallback = os.path.expanduser("~") if os.path.isdir(os.path.expanduser("~")) else "/"
self.cwd = fallback
popen_cwd = fallback

proc = subprocess.Popen(
args,
text=True,
Expand All @@ -368,7 +381,7 @@ def _run_bash(self, cmd_string: str, *, login: bool = False,
stderr=subprocess.STDOUT,
stdin=subprocess.PIPE if stdin_data is not None else subprocess.DEVNULL,
preexec_fn=None if _IS_WINDOWS else os.setsid,
cwd=self.cwd,
cwd=popen_cwd,
)
if not _IS_WINDOWS:
try:
Expand Down Expand Up @@ -456,8 +469,14 @@ def _update_cwd(self, result: dict):
try:
with open(self._cwd_file) as f:
cwd_path = f.read().strip()
if cwd_path:
if cwd_path and os.path.isdir(cwd_path):
self.cwd = cwd_path
elif cwd_path and not os.path.isdir(cwd_path):
# The recorded cwd no longer exists (temp dir deleted by
# another process). Reset to a safe fallback so subsequent
# commands don't loop on exit-126 from a stale cd target.
fallback = os.path.expanduser("~") if os.path.isdir(os.path.expanduser("~")) else "/"
self.cwd = fallback
except (OSError, FileNotFoundError):
pass

Expand Down
Loading