fix: handle scheduled prompts on session deletion
This commit is contained in:
@@ -423,7 +423,8 @@ class SessionService:
|
|||||||
self, session_id: int, prompt: str, due_at: datetime
|
self, session_id: int, prompt: str, due_at: datetime
|
||||||
) -> ScheduledPrompt:
|
) -> ScheduledPrompt:
|
||||||
"""Create or replace the pending scheduled prompt for a session."""
|
"""Create or replace the pending scheduled prompt for a session."""
|
||||||
if not prompt.strip():
|
prompt = prompt.strip()
|
||||||
|
if not prompt:
|
||||||
raise ServiceError("Prompt cannot be empty")
|
raise ServiceError("Prompt cannot be empty")
|
||||||
with self.factory() as db:
|
with self.factory() as db:
|
||||||
sess = db.get(Session, session_id)
|
sess = db.get(Session, session_id)
|
||||||
@@ -504,6 +505,11 @@ class SessionService:
|
|||||||
force,
|
force,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
scheduled = (
|
||||||
|
db.query(ScheduledPrompt).filter_by(session_id=session_id).one_or_none()
|
||||||
|
)
|
||||||
|
if scheduled is not None:
|
||||||
|
db.delete(scheduled)
|
||||||
db.delete(sess)
|
db.delete(sess)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
|||||||
@@ -704,6 +704,27 @@ async def test_sync_window_labels_covers_all_projects(factory, db, tmux, harness
|
|||||||
assert labelled == {"hqt-1", "hqt-2"}
|
assert labelled == {"hqt-1", "hqt-2"}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_sync_window_labels_includes_pending_scheduled_prompt(
|
||||||
|
factory, db, tmux, harnesses
|
||||||
|
):
|
||||||
|
"""sync_window_labels returns SessionInfo with pending scheduled prompt metadata."""
|
||||||
|
from hqt.tmux.runner import WindowInfo
|
||||||
|
|
||||||
|
service = SessionService(factory=factory, tmux=tmux, harnesses=harnesses)
|
||||||
|
result = await service.create_session(project_id=1, harness_name="claude-code")
|
||||||
|
due_at = datetime(2026, 6, 11, 12)
|
||||||
|
service.schedule_prompt(result.session.id, "run the tests", due_at)
|
||||||
|
tmux.poll_info.return_value = {"hqt-1": WindowInfo(alive=False, last_activity=0)}
|
||||||
|
tmux.set_window_label = AsyncMock()
|
||||||
|
|
||||||
|
infos = await service.sync_window_labels()
|
||||||
|
|
||||||
|
assert infos[0].scheduled_prompt is not None
|
||||||
|
assert infos[0].scheduled_prompt.prompt == "run the tests"
|
||||||
|
assert infos[0].scheduled_prompt.status == "pending"
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Item 3: real-configurator integration-seam test
|
# Item 3: real-configurator integration-seam test
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -1499,6 +1520,20 @@ async def test_delete_session_remove_worktree_false_skips_removal(
|
|||||||
assert db.get(Session, sess_id) is None
|
assert db.get(Session, sess_id) is None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_delete_session_deletes_scheduled_prompt(service, db):
|
||||||
|
sess = _seed_session(db)
|
||||||
|
sess_id = sess.id
|
||||||
|
due_at = datetime(2026, 6, 11, 12)
|
||||||
|
service.schedule_prompt(sess_id, "run the tests", due_at)
|
||||||
|
|
||||||
|
await service.delete_session(sess_id)
|
||||||
|
|
||||||
|
db.expire_all()
|
||||||
|
assert db.get(Session, sess_id) is None
|
||||||
|
assert db.query(ScheduledPrompt).filter_by(session_id=sess_id).one_or_none() is None
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_worktree_state_for_plain_session_returns_none(
|
async def test_worktree_state_for_plain_session_returns_none(
|
||||||
service, db, tmux, harnesses, fake_worktree
|
service, db, tmux, harnesses, fake_worktree
|
||||||
|
|||||||
Reference in New Issue
Block a user