fix(init): target the session's active directory, not the process cwd - #96378
Conversation
This PR makes
|
43c115e to
8e19574
Compare
|
Rebased onto current 1. Stale-record guard — fixed, at the shared point. You were right: One consequence your review implies but doesn't state: without the guard the prompt lands in generate mode pointing at a path that doesn't exist, and Pinned by two new tests: a stale explicit 2. Gateway session key — confirmed, no gap. Test evidence on the rebase (Windows 11): |
/init resolved its project directory via os.getcwd() — the process launch directory — on all three dispatch surfaces (CLI, gateway, TUI/desktop). On the desktop app the process launches from the home directory, so /init scanned the HOME and merge-updated the home directory's AGENTS.md even though the session was attached to a project workspace (its terminal commands ran in the right directory). Resolve the session's ACTIVE directory instead: the terminal tool's per-session cwd record (seeded when a workspace attaches, updated after every cd) first, then resolve_agent_cwd()'s canonical ladder (session contextvar -> TERMINAL_CWD -> process cwd). Dispatch sites pass the session key so multi-session hosts consult the right record. The stale-record guard lives in build_init_prompt_for_cwd: a cwd that names a deleted directory (removed project, linked worktree) falls through to the session ladder on every surface instead of each dispatch site validating its own record. Without it the TUI/desktop path handed a truthy-but-dead record straight through as cwd, so /init targeted a directory that no longer existed — write_file would have recreated it and written a fresh AGENTS.md into it. Regression tests cover: session record wins over the process cwd, stale-record fallback, explicit cwd precedence, ambient session key, a stale explicit cwd falling through to the session record, and the TUI/desktop command.dispatch path end-to-end (live record, and a stale record falling through to the session's attached workspace). Fixes NousResearch#96376
8e19574 to
9e3d3b8
Compare
OutThisLife
left a comment
There was a problem hiding this comment.
Reviewed on current main: the diff covers the linked issue, and the new tests fail on main and pass here.
Head branch was pushed to by a user without write access
OutThisLife
left a comment
There was a problem hiding this comment.
Re-reviewed the new head: adds only the contributor email mapping.
Pull request was closed
What does this PR do?
/initresolved its project directory viaos.getcwd()— the process launch directory — on all three dispatch surfaces (CLI, gateway, TUI/desktop). On the desktop app the process launches from the home directory, so/initscanned the HOME and merge-updated the home directory'sAGENTS.mdeven though the session was attached to a project workspace (and its terminal commands ran in the right directory).This PR makes
/inittarget the session's ACTIVE directory:tools.terminal_tool.get_session_cwd) — seeded when a workspace attaches to the session (desktop project picker,project_create/project_switch, gatewayterminal.cwd) and updated after every completed command, so it trackscd. Keyed bysession_key; dispatch sites pass it so multi-session hosts consult the right record.agent.runtime_cwd.resolve_agent_cwd()— the codebase's canonical ladder (session contextvar →TERMINAL_CWD→ process cwd), already used by the system prompt and tool surfaces.A record for a deleted directory (removed project, linked worktree) falls through to the ladder on every surface — the guard lives in
build_init_prompt_for_cwd(), so no dispatch site can hand a truthy-but-deadcwdstraight through. An explicitcwdstill wins while it exists (tests pass it directly).Related Issue
Fixes #96376
Related (sibling, distinct): #76902
Type of Change
Changes Made
hermes_cli/init_command.py— new_resolve_session_cwd()(record →resolve_agent_cwd()ladder);build_init_prompt_for_cwd()gains asession_keyparam and uses the resolver instead ofos.getcwd(); an explicitcwdthat no longer exists falls through to that resolverhermes_cli/cli_commands_mixin.py— CLI/initpassessession_key=""(single-session CLI's"default"record; previous behavior preserved when no record exists)gateway/run_inbound.py— gateway/init(_hm_cmd_init) passessession_key=_quick_key or self._session_key_for_source(source)tui_gateway/methods_tools.py— TUI/desktop/initbecomes a dedicated_cmd_inithandler (replacing the generic_prompt_builtinfactory): the session's live cwd record when it still exists, else the session's attached workspace (_session_cwd), else the builder's laddertests/hermes_cli/test_init_command.py— 5 regression tests (session record, stale-record fallback, explicit-cwd precedence, ambient session key, stale explicitcwdfall-through)tests/tui_gateway/test_init_targets_session_cwd.py— new: drives the realcommand.dispatchhandler for/init(live record, and a stale record falling through to the session workspace)How to Test
/initin that session.for the project at: <project>and reads the project'sAGENTS.mdfor merge, not the home directory's.pytest tests/hermes_cli/test_init_command.py tests/tui_gateway/test_init_targets_session_cwd.py -q— 13 passed (6 pre-existing + 5 builder regressions + 2 TUI/desktop dispatches).Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests pass — targeted suites re-run on this rebase onto currentmain:test_init_command.py+test_init_targets_session_cwd.py(13 passed), and the othercommand.dispatchconsumerstest_goal_dispatch.py+test_compress_lock_skip.py+test_composite_carrier_rewind.py(90 passed)Documentation & Housekeeping
docs/, docstrings) — docstrings on the resolver +build_init_prompt_for_cwdcli-config.yaml.exampleif I added/changed config keys — N/A (no config keys)CONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — N/Aos.pathpaths only/inithas no engine)Screenshots / Logs
Repro evidence is in the issue: session
20260827_212218_17afe7— session row recordedcwd = C:\Users\funky\AppDev\infinite-jukeboxwhile the injected/initprompt targetedC:\Users\funky(home dir). After this patch the resolver returns the session record first.