diff --git a/core/obsidian_sync.py b/core/obsidian_sync.py index 25dafd6..da4256c 100644 --- a/core/obsidian_sync.py +++ b/core/obsidian_sync.py @@ -90,7 +90,7 @@ def parse_task_checkboxes( Returns: [{"task_id": "KIN-013", "done": True, "title": "..."}] """ - pattern = re.compile(r"^[-*]\s+\[([xX ])\]\s+([A-Z]+-\d+)\s+(.+)$") + pattern = re.compile(r"^[-*]\s+\[([xX ])\]\s+([A-Z][A-Z0-9]*-\d+)\s+(.+)$") results: list[dict] = [] search_dirs = [ diff --git a/tests/test_api.py b/tests/test_api.py index d61166a..75c87fc 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -142,6 +142,32 @@ def test_reject_not_found(client): assert r.status_code == 404 +def test_revise_task(client): + from core.db import init_db + from core import models + conn = init_db(api_module.DB_PATH) + models.update_task(conn, "P1-001", status="review") + conn.close() + + r = client.post("/api/tasks/P1-001/revise", json={ + "comment": "Доисследуй edge case с пустым массивом" + }) + assert r.status_code == 200 + assert r.json()["status"] == "in_progress" + + # Verify task is in_progress with revise_comment stored + conn = init_db(api_module.DB_PATH) + row = conn.execute("SELECT status, revise_comment FROM tasks WHERE id = 'P1-001'").fetchone() + conn.close() + assert row["status"] == "in_progress" + assert row["revise_comment"] == "Доисследуй edge case с пустым массивом" + + +def test_revise_not_found(client): + r = client.post("/api/tasks/NOPE/revise", json={"comment": "fix it"}) + assert r.status_code == 404 + + def test_task_pipeline_not_found(client): r = client.get("/api/tasks/NOPE/pipeline") assert r.status_code == 404 diff --git a/tests/test_obsidian_sync.py b/tests/test_obsidian_sync.py index ed934ea..0b5eeea 100644 --- a/tests/test_obsidian_sync.py +++ b/tests/test_obsidian_sync.py @@ -157,14 +157,14 @@ def test_sync_updates_task_status(db, tmp_vault): tmp_vault.mkdir(parents=True) models.update_project(db, "proj1", obsidian_vault_path=str(tmp_vault)) - task = models.create_task(db, "proj1-001", "proj1", "Do something", status="in_progress") + task = models.create_task(db, "PROJ1-001", "proj1", "Do something", status="in_progress") assert task["status"] == "in_progress" # Write checkbox file tasks_dir = tmp_vault / "proj1" / "tasks" tasks_dir.mkdir(parents=True) (tasks_dir / "sprint.md").write_text( - "- [x] proj1-001 Do something\n", + "- [x] PROJ1-001 Do something\n", encoding="utf-8", ) @@ -172,7 +172,7 @@ def test_sync_updates_task_status(db, tmp_vault): assert result["tasks_updated"] == 1 assert not result["errors"] - updated = models.get_task(db, "proj1-001") + updated = models.get_task(db, "PROJ1-001") assert updated["status"] == "done" diff --git a/web/frontend/src/views/TaskDetail.vue b/web/frontend/src/views/TaskDetail.vue index 6204b2c..54da141 100644 --- a/web/frontend/src/views/TaskDetail.vue +++ b/web/frontend/src/views/TaskDetail.vue @@ -193,6 +193,18 @@ async function reject() { } } +async function revise() { + if (!task.value || !reviseComment.value) return + try { + await api.reviseTask(props.id, reviseComment.value) + showRevise.value = false + reviseComment.value = '' + await load() + } catch (e: any) { + error.value = e.message + } +} + async function runPipeline() { try { await api.runTask(props.id) @@ -438,6 +450,11 @@ async function saveEdit() { class="px-4 py-2 text-sm bg-green-900/50 text-green-400 border border-green-800 rounded hover:bg-green-900"> ✓ Approve + + 🔄 Revise + @@ -542,6 +559,19 @@ async function saveEdit() { + + + + Опишите, что доработать или уточнить агенту. Задача вернётся в работу с вашим комментарием. + + + 🔄 Отправить на доработку + + + +
Опишите, что доработать или уточнить агенту. Задача вернётся в работу с вашим комментарием.