Add SessionService.clone_session_for_window
Opens a fresh harness session with the same project, harness, and model as the source window, creating a new sibling hqt-<id> conversation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -440,6 +440,33 @@ class SessionService:
|
||||
raise ServiceError(f"{window_name!r} is not an hqt session window")
|
||||
return await self.open_tool_window(session_id, tool)
|
||||
|
||||
async def clone_session_for_window(
|
||||
self, window_name: str
|
||||
) -> "CreateSessionResult":
|
||||
"""Open a fresh harness session cloning the one in `window_name`.
|
||||
|
||||
Same project, harness, and model as the source session, but a brand-new
|
||||
conversation (a new hqt-<id> window at the next index). Raises
|
||||
ServiceError if `window_name` is not an active hqt session window — so
|
||||
invoking clone from a tool window (nvim/shell) or the TUI is a clean
|
||||
no-op.
|
||||
"""
|
||||
with self.factory() as db:
|
||||
sess = (
|
||||
db.query(Session)
|
||||
.options(selectinload(Session.harness))
|
||||
.filter_by(tmux_session_name=window_name, archived=False)
|
||||
.first()
|
||||
)
|
||||
if sess is None:
|
||||
raise ServiceError(f"{window_name!r} is not an hqt session window")
|
||||
project_id = sess.project_id
|
||||
harness_name = sess.harness.name
|
||||
model = sess.model
|
||||
return await self.create_session(
|
||||
project_id, harness_name, nickname=None, model=model
|
||||
)
|
||||
|
||||
async def stop_session(self, session_id: int) -> None:
|
||||
with self.factory() as db:
|
||||
sess = db.get(Session, session_id)
|
||||
|
||||
@@ -1601,3 +1601,36 @@ async def test_open_tool_window_for_window_resolves_by_name(
|
||||
async def test_open_tool_window_for_window_unknown_window_raises(service):
|
||||
with pytest.raises(ServiceError):
|
||||
await service.open_tool_window_for_window("not-an-hqt-window", "nvim")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Task 5: clone_session_for_window
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_clone_session_for_window_reuses_project_harness_model(
|
||||
service, db, monkeypatch
|
||||
):
|
||||
await service.create_session(
|
||||
project_id=1, harness_name="claude-code", nickname="orig", model="opus"
|
||||
)
|
||||
captured = {}
|
||||
|
||||
async def fake_create(project_id, harness_name, nickname=None, model=None):
|
||||
captured["args"] = (project_id, harness_name, nickname, model)
|
||||
return "SENTINEL"
|
||||
|
||||
monkeypatch.setattr(service, "create_session", fake_create)
|
||||
|
||||
result = await service.clone_session_for_window("hqt-1")
|
||||
|
||||
assert result == "SENTINEL"
|
||||
# Same project + harness + model; a fresh sibling, so no nickname.
|
||||
assert captured["args"] == (1, "claude-code", None, "opus")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_clone_session_for_window_unknown_window_raises(service):
|
||||
with pytest.raises(ServiceError):
|
||||
await service.clone_session_for_window("not-an-hqt-window")
|
||||
|
||||
Reference in New Issue
Block a user