diff --git a/nerve/agent/tools/handlers/tasks.py b/nerve/agent/tools/handlers/tasks.py index cc7eea23..3fefa6de 100644 --- a/nerve/agent/tools/handlers/tasks.py +++ b/nerve/agent/tools/handlers/tasks.py @@ -294,9 +294,6 @@ async def task_update_handler(ctx: ToolContext, args: dict) -> ToolResult: if not task: return ToolResult.text(f"Task not found: {task_id}") - if status: - await ctx.db.update_task_status(task_id, status) - new_tags_str = "" if raw_tags: current_tags = set(parse_tags_string(task.get("tags", "") or "")) @@ -311,8 +308,6 @@ async def task_update_handler(ctx: ToolContext, args: dict) -> ToolResult: else: new_tags_str = tags_to_string(parse_tags_string(raw_tags)) - await ctx.db.update_task_tags(task_id, new_tags_str) - if ctx.workspace and (note or deadline or raw_tags or new_title): file_path = ctx.workspace / task["file_path"] if file_path.exists(): @@ -321,17 +316,6 @@ async def task_update_handler(ctx: ToolContext, args: dict) -> ToolResult: ) if new_title: content = re.sub(r"^# .+", f"# {new_title}", content, count=1) - await ctx.db.upsert_task( - task_id=task_id, - file_path=task["file_path"], - title=new_title, - status=status or task["status"], - source=task.get("source"), - source_url=task.get("source_url"), - deadline=deadline or task.get("deadline"), - tags=new_tags_str if raw_tags else (task.get("tags") or ""), - content=content, - ) if note: today = datetime.now(timezone.utc).strftime("%Y-%m-%d") content += f"\n- {today}: {note}" @@ -358,6 +342,29 @@ async def task_update_handler(ctx: ToolContext, args: dict) -> ToolResult: file_path.write_text, content, encoding="utf-8", ) + final_title = new_title or task["title"] + final_status = status or task["status"] + final_deadline = deadline or task.get("deadline") + final_tags = new_tags_str if raw_tags else (task.get("tags") or "") + await ctx.db.upsert_task( + task_id=task_id, + file_path=task["file_path"], + title=final_title, + status=final_status, + source=task.get("source"), + source_url=task.get("source_url"), + deadline=final_deadline, + tags=final_tags, + content=content, + ) + return ToolResult.text(f"Task {task_id} updated.") + + # Fall back to metadata updates when no task file was changed. + if status: + await ctx.db.update_task_status(task_id, status) + if raw_tags: + await ctx.db.update_task_tags(task_id, new_tags_str) + return ToolResult.text(f"Task {task_id} updated.") diff --git a/tests/test_task_statuses.py b/tests/test_task_statuses.py index 135fa61e..2aad109c 100644 --- a/tests/test_task_statuses.py +++ b/tests/test_task_statuses.py @@ -144,6 +144,54 @@ async def test_update_accepts_valid_status(self, db: Database, tmp_path): await task_update_handler(ctx, {"task_id": task_id, "status": "in_progress"}) assert (await db.get_task(task_id))["status"] == "in_progress" + async def test_update_deadline_syncs_database(self, db: Database, tmp_path): + ctx = self._ctx(db, tmp_path) + await task_create_handler(ctx, {"title": "Deadline task", "content": "x"}) + task_id = (await db.list_tasks(status="all"))[0]["id"] + + await task_update_handler(ctx, {"task_id": task_id, "deadline": "2026-08-01"}) + + task = await db.get_task(task_id) + assert task["deadline"] == "2026-08-01" + assert "**Deadline:** 2026-08-01" in (tmp_path / task["file_path"]).read_text( + encoding="utf-8", + ) + + async def test_update_note_refreshes_fts(self, db: Database, tmp_path): + ctx = self._ctx(db, tmp_path) + await task_create_handler(ctx, {"title": "Search task", "content": "x"}) + task_id = (await db.list_tasks(status="all"))[0]["id"] + + await task_update_handler(ctx, {"task_id": task_id, "note": "Investigated quasarflux"}) + + results = await db.search_tasks("quasarflux") + assert [task["id"] for task in results] == [task_id] + + async def test_update_combined_fields_indexes_final_state( + self, db: Database, tmp_path, + ): + ctx = self._ctx(db, tmp_path) + await task_create_handler(ctx, {"title": "Original title", "content": "x"}) + task_id = (await db.list_tasks(status="all"))[0]["id"] + + await task_update_handler( + ctx, + { + "task_id": task_id, + "title": "Renamed task", + "status": "in_progress", + "deadline": "2026-08-01", + "tags": "ops,urgent", + "note": "Found nebularift", + }, + ) + + task = await db.get_task(task_id) + assert (task["title"], task["status"], task["deadline"], task["tags"]) == ( + "Renamed task", "in_progress", "2026-08-01", "ops,urgent", + ) + assert [task["id"] for task in await db.search_tasks("nebularift")] == [task_id] + async def test_status_create_handler(self, db: Database, tmp_path): ctx = self._ctx(db, tmp_path) result = await task_status_create_handler(