The per-session record store is now the ONLY cwd mechanism. Deleted:
- env.cwd_owner stamping + prev_owner threading (terminal_tool): the
shared env no longer carries ownership metadata at all
- _resolve_command_cwd's env/prev_owner params: resolution is
workdir > session record > config/override default
- file_tools._live_cwd_if_owned + _get_live_tracking_cwd: path
resolution never consults the shared env's live cwd
- file_tools._last_known_cwd + _remember_last_known_cwd +
_last_known_cwd_for: the #26211 preserved-anchor registry is
subsumed by the session record, which never lived on the env and
therefore cannot be lost to env cleanup. The _get_file_ops
stale-cache rescue now writes the record instead.
- env recreation (both _get_file_ops and terminal_tool) seeds the
fresh env from override > session record > config
Why no transition fallback: the legacy state was process-local and
in-memory exactly like the record store — after a restart both start
empty, and within a running process every legacy write site has been
dual-writing the record since step 1. There is no populated-legacy/
empty-record state to fall back for.
Tests updated to drive the record store instead of the deleted
mechanism; the cross-session isolation suite now asserts the same
behavior contracts (no leak, cd isolation, #26211 persistence)
against the new architecture, plus a new "session C inherits nothing"
case that the old ownership guard could not express.
The terminal environment is shared process-globally (collapsed to the
default key), so env.cwd tracks the LAST session that ran a command.
_resolve_command_cwd() trusted env.cwd unconditionally — no ownership
check — so when session A left env.cwd pointing at A's checkout,
session B's first terminal command inherited A's stale cwd and ran in
the wrong workspace.
The file tools already solved this exact shared-env problem with
_live_cwd_if_owned() checking env.cwd_owner. The terminal tool never
got the same guard.
Fix: capture env.cwd_owner BEFORE the current session claims it, and
pass it as prev_owner to _resolve_command_cwd. When the previous owner
was a different session, env.cwd is stale — fall through to default_cwd
(the config/override cwd for this session) instead. Once the session
has claimed the env, subsequent calls in the same session still trust
env.cwd so in-session state survives.
* fix(terminal): require approval for host-bound Docker commands
The Docker terminal backend blanket-skips dangerous-command approval on
the assumption that the container is isolated from the host. That holds
only when nothing is bind-mounted in. Once a host path is exposed (via
TERMINAL_DOCKER_MOUNT_CWD_TO_WORKSPACE or a host-path entry in
TERMINAL_DOCKER_VOLUMES), a command like `rm -rf /workspace` reaches
real host files but is still auto-approved.
Detect host bind mounts and route those sessions through the normal
approval flow. Isolated Docker keeps the fast path. The same gating is
applied to the execute_code guard, which had the identical blanket skip.
Co-authored-by: Hermes Agent <agent@nousresearch.com>
* chore: add AUTHOR_MAP entry for PR #6436 salvage (Kolektori)
* test: accept has_host_access kwarg in _check_all_guards mocks
The host-bound Docker approval fix adds a has_host_access kwarg to the
_check_all_guards wrapper. Six pre-existing tests monkeypatch it with a
fixed (command, env_type) / (cmd, env) lambda signature, which now
raises TypeError when terminal_tool passes the new kwarg. Widen those
mock signatures to accept **kwargs.
---------
Co-authored-by: Kolektori <256073454+Kolektori@users.noreply.github.com>
Co-authored-by: Hermes Agent <agent@nousresearch.com>
`os.getcwd()` raises FileNotFoundError when the process's working
directory was removed out from under it (e.g. a scratch workspace
cleaned up mid-session), crashing terminal env setup.
Extract a `_safe_getcwd()` helper that falls back to TERMINAL_CWD, then
the user's home, on FileNotFoundError, and route all three `os.getcwd()`
call sites in terminal_tool.py through it (local default_cwd, the Docker
cwd-passthrough source, and the debug-config print) so the same crash
can't resurface at a sibling site. Adds unit tests for the real-cwd path
and both fallback branches.
Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
terminal_tool re-sent the init-time/config cwd on every command, clobbering
session-local `cd` state: the environment tracked the new directory in
`env.cwd`, but foreground/background calls forced the old cwd back. A small
`_resolve_command_cwd` resolver now applies the precedence
`workdir > live env.cwd > config/override cwd` to:
- foreground `env.execute(...)`
- background `process_registry.spawn_local(...)`
- background `process_registry.spawn_via_env(...)`
Additionally, syncing the cwd onto the live cached env when a `cwd` override is
(re-)registered. Preferring live `env.cwd` would otherwise demote the ACP
`update_cwd` override (registered via `register_task_env_overrides` on
`session/load` / `session/resume`) below an already-set `env.cwd`, silently
ignoring an editor's mid-session project-root change once any command had run.
`register_task_env_overrides` now pushes a new cwd onto the cached env so an
explicit ACP cwd change wins, while ordinary in-session `cd` tracking is
preserved.
Regression coverage:
- foreground/background commands follow live `env.cwd`
- explicit `workdir` still overrides everything
- registering a cwd override updates the live env cwd (ACP authority)
- no-op when no live env exists; non-cwd overrides leave env.cwd untouched
Based on #35510 by @Dusk1e.
Co-authored-by: Dusk1e <yusufalweshdemir@gmail.com>