fix(gateway): only stamp a session's own directory on its row

Two existing cases in tests/test_tui_gateway_server.py covered the row's cwd
contract and this change had to answer both.

`_persisted_session_cwd` reached through `_session_cwd`, which falls back to
the gateway-wide completion cwd when the session carries none. That belongs to
no session in particular, so a session that never had a directory was given
one. Read the session's own `cwd` instead.

The remaining case asserted that a terminal session's directory is discarded,
which is the behavior this branch deliberately changes. Split it in two: a
terminal session now records its workspace, and the desktop keeps the "No
workspace" default it was written to protect.
This commit is contained in:
Brooklyn Nicholson 2026-07-26 01:33:20 -05:00
parent 3172b8739e
commit ad81e3c16f
2 changed files with 33 additions and 5 deletions

View file

@ -4066,9 +4066,13 @@ def test_ensure_session_db_row_persists_session_source(monkeypatch):
]
def test_ensure_session_db_row_defaults_to_no_workspace(monkeypatch, tmp_path):
"""Without an explicit workspace, cwd is left null so the session groups
under "No workspace" rather than the gateway's launch directory."""
def test_ensure_session_db_row_records_a_terminal_workspace(monkeypatch, tmp_path):
"""A terminal session's directory IS its workspace, so the row records it.
The user cd'd there before running hermes. Leaving it null stranded the row
with no cwd and no git_repo_root, so the sidebar could never place the
session under its project.
"""
created = []
class _FakeDB:
@ -4085,7 +4089,28 @@ def test_ensure_session_db_row_defaults_to_no_workspace(monkeypatch, tmp_path):
server._ensure_session_db_row({"session_key": "k1", "cwd": str(tmp_path)})
assert created == [
{"key": "k1", "source": "tui", "model": "test-model", "model_config": None, "cwd": None}
{"key": "k1", "source": "tui", "model": "test-model", "model_config": None, "cwd": str(tmp_path)}
]
def test_ensure_session_db_row_defaults_desktop_to_no_workspace(monkeypatch, tmp_path):
"""The desktop launches from wherever the bundle was opened, so an unpicked
cwd is an artifact those chats stay null and group under "No workspace"."""
created = []
class _FakeDB:
def create_session(self, key, source=None, model=None, model_config=None, parent_session_id=None, cwd=None, profile_name=None):
created.append(
{"key": key, "source": source, "model": model, "model_config": model_config, "cwd": cwd}
)
monkeypatch.setattr(server, "_get_db", lambda: _FakeDB())
monkeypatch.setattr(server, "_resolve_model", lambda: "test-model")
server._ensure_session_db_row({"session_key": "k1", "source": "desktop", "cwd": str(tmp_path)})
assert created == [
{"key": "k1", "source": "desktop", "model": "test-model", "model_config": None, "cwd": None}
]

View file

@ -2102,7 +2102,10 @@ def _persisted_session_cwd(session: dict) -> str | None:
return _session_cwd(session)
if _session_source(session) in _LAUNCH_CWD_NOT_A_WORKSPACE:
return None
return _session_cwd(session) or None
# Only the session's OWN directory. `_session_cwd` falls back to the
# gateway-wide completion cwd, which belongs to no session in particular —
# stamping that would invent a workspace for a session that never had one.
return str(session.get("cwd") or "") or None
def _heal_dead_cwd(cwd: str) -> str: