mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
Concurrent terminal calls in one session both source AND rewrite the shared env snapshot. The per-command re-dump used `export -p > snap` — a non-atomic truncate-then-write in place (the code even noted "last-writer-wins"). A concurrent `source snap` could read a half-written file and embed literal `declare -x` / `export` fragments into PATH, breaking `ls`/`git`/`tr` with command-not-found until PATH was manually repaired. The corruption persisted because the malformed env got saved back into the snapshot. Write to a unique temp file then `mv -f` over the snapshot. `mv`/rename is atomic on POSIX (same filesystem), so a reader always sees the old-complete or new-complete file — never a torn one. Applied at both the init_session bootstrap and the per-command re-dump. `$$` (bash PID) makes the temp name unique per concurrent process so their temp writes can't collide before the mv. Salvaged from #38279 by @kyssta-exe (authorship preserved via cherry-pick). On top of the original I hardened the temp-path quoting: the static path is now shlex-quoted with `$$` left outside the quotes to expand, so a snapshot path with a space or a Windows `C:/Users/...` drive letter doesn't break the shell (matching the existing quoting care for the snapshot path itself; `bash -n` verified on a spaced path). Added a regression test class (atomic temp+mv used, not in-place write; per-process-unique temp; static part quoted; bootstrap also atomic). 22 tests pass, mutation-verified (reverting to the in-place write fails the atomic tests), ruff clean. Closes #38249. Supersedes #38267 (serialize-execution lock — heavier and serializes the spawn-per-call concurrency this fix preserves). |
||
|---|---|---|
| .. | ||
| __init__.py | ||
| base.py | ||
| daytona.py | ||
| docker.py | ||
| file_sync.py | ||
| local.py | ||
| managed_modal.py | ||
| modal.py | ||
| modal_utils.py | ||
| singularity.py | ||
| ssh.py | ||