- Add update_project_state() helper: updates Current Task + Last Updated in PROJECT_STATE.md via regex sub, preserving all surrounding formatting. - Add update_agent_handoff() helper: updates Current Stage + Current Task sections in AGENT_HANDOFF.md, auto-detected from project_stage(). - Wire both helpers into rdb start TASK-ID and rdb complete TASK-ID CLI commands so task lifecycle transitions propagate to all control files. - ADDING test_status.py with 5 tests: update_project_state task/timestamp updates, missing-file false return, agent handoff update and miss. Acceptance criteria met: - rdb start/complete now update PROJECT_STATE.md - rdb start/complete now update AGENT_HANDOFF.md - RUN_LOG.md already updated (pre-existing) - Task formatting preserved (regex sub targets single line only)
63 lines
2.0 KiB
Python
63 lines
2.0 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import date
|
|
from pathlib import Path
|
|
import re
|
|
|
|
from .tasks import read_tasks
|
|
|
|
|
|
def project_stage(root: Path) -> str:
|
|
if not (root / "context" / "discovery-log.md").exists():
|
|
return "NOT_INITIALISED"
|
|
tasks = read_tasks(root)
|
|
if not tasks:
|
|
return "DISCOVERY"
|
|
if any(task.status.lower() == "in progress" for task in tasks):
|
|
return "BUILDING"
|
|
if any(task.status.lower() == "todo" for task in tasks):
|
|
return "TASKS_READY"
|
|
return "REVIEW_READY"
|
|
|
|
|
|
def task_counts(root: Path) -> dict[str, int]:
|
|
counts: dict[str, int] = {}
|
|
for task in read_tasks(root):
|
|
counts[task.status] = counts.get(task.status, 0) + 1
|
|
return counts
|
|
|
|
|
|
_CURRENT_TASK_RE = re.compile(r"^(Current Task): .+$", re.MULTILINE)
|
|
_UPDATED_RE = re.compile(r"^(Last Updated): .+$", re.MULTILINE)
|
|
|
|
|
|
def update_project_state(root: Path, task_id: str = "None") -> bool:
|
|
"""Update PROJECT_STATE.md current task and timestamp."""
|
|
path = root / "PROJECT_STATE.md"
|
|
if not path.exists():
|
|
return False
|
|
|
|
text = path.read_text(encoding="utf-8")
|
|
text = _CURRENT_TASK_RE.sub(f"Current Task: {task_id}", text, count=1)
|
|
text = _UPDATED_RE.sub(f"Last Updated: {date.today().isoformat()}", text, count=1)
|
|
path.write_text(text, encoding="utf-8")
|
|
return True
|
|
|
|
|
|
_STAGE_RE = re.compile(r"(## Current Stage\n\n)[\s\S]+?(?=\n)", re.MULTILINE | re.DOTALL)
|
|
_TASK_RE = re.compile(r"(## Current Task\n\n)[\s\S]+?(?=\n)", re.MULTILINE | re.DOTALL)
|
|
|
|
|
|
def update_agent_handoff(root: Path, task_id: str = "None") -> bool:
|
|
"""Update AGENT_HANDOFF.md current stage and task."""
|
|
path = root / "AGENT_HANDOFF.md"
|
|
if not path.exists():
|
|
return False
|
|
|
|
text = path.read_text(encoding="utf-8")
|
|
stage = project_stage(root)
|
|
text = _STAGE_RE.sub(f"## Current Stage\n\n{stage}", text, count=1)
|
|
text = _TASK_RE.sub(f"## Current Task\n\n{task_id}", text, count=1)
|
|
path.write_text(text, encoding="utf-8")
|
|
return True
|