178 lines
5.1 KiB
Python
178 lines
5.1 KiB
Python
"""Service for writing progress log entries."""
|
|
|
|
from datetime import date
|
|
from pathlib import Path
|
|
|
|
from development_hub.paths import paths
|
|
|
|
|
|
class ProgressWriter:
|
|
"""Writes daily progress log entries to markdown files."""
|
|
|
|
def __init__(self, progress_dir: Path | None = None):
|
|
"""Initialize progress writer.
|
|
|
|
Args:
|
|
progress_dir: Directory for progress files. Defaults to settings value.
|
|
"""
|
|
self._progress_dir = progress_dir or paths.progress_dir
|
|
|
|
def get_today_path(self) -> Path:
|
|
"""Get path to today's progress file."""
|
|
today = date.today()
|
|
filename = today.strftime("%Y-%m-%d.md")
|
|
return self._progress_dir / filename
|
|
|
|
def file_exists(self) -> bool:
|
|
"""Check if today's progress file already exists."""
|
|
return self.get_today_path().exists()
|
|
|
|
def create_progress_entry(
|
|
self,
|
|
projects: list[str],
|
|
focus: list[str],
|
|
completed: list[str],
|
|
in_progress: list[str],
|
|
blocked: list[str] | None = None,
|
|
next_tasks: list[str] | None = None,
|
|
notes: str | None = None,
|
|
) -> Path:
|
|
"""Create or update today's progress log entry.
|
|
|
|
Args:
|
|
projects: List of project keys worked on
|
|
focus: Primary focus items
|
|
completed: Completed tasks
|
|
in_progress: Tasks in progress
|
|
blocked: Blocked items (optional)
|
|
next_tasks: Next up items (optional)
|
|
notes: Additional notes (optional)
|
|
|
|
Returns:
|
|
Path to the created/updated file
|
|
"""
|
|
today = date.today()
|
|
path = self.get_today_path()
|
|
|
|
# Build content
|
|
lines = [
|
|
"---",
|
|
f"date: {today.isoformat()}",
|
|
f"projects: [{', '.join(projects)}]",
|
|
"---",
|
|
"",
|
|
]
|
|
|
|
# Focus section
|
|
if focus:
|
|
lines.append("## Focus")
|
|
for item in focus:
|
|
lines.append(f"- {item}")
|
|
lines.append("")
|
|
|
|
# Completed section
|
|
lines.append("## Completed")
|
|
if completed:
|
|
for item in completed:
|
|
lines.append(f"- [x] {item}")
|
|
else:
|
|
lines.append("(none yet)")
|
|
lines.append("")
|
|
|
|
# In Progress section
|
|
lines.append("## In Progress")
|
|
if in_progress:
|
|
for item in in_progress:
|
|
lines.append(f"- [ ] {item}")
|
|
else:
|
|
lines.append("(none)")
|
|
lines.append("")
|
|
|
|
# Blocked section
|
|
lines.append("## Blocked")
|
|
if blocked:
|
|
for item in blocked:
|
|
lines.append(f"- {item}")
|
|
else:
|
|
lines.append("(none)")
|
|
lines.append("")
|
|
|
|
# Next section
|
|
if next_tasks:
|
|
lines.append("## Next")
|
|
for i, item in enumerate(next_tasks, 1):
|
|
lines.append(f"{i}. {item}")
|
|
lines.append("")
|
|
|
|
# Notes section
|
|
if notes:
|
|
lines.append("## Notes")
|
|
lines.append(notes)
|
|
lines.append("")
|
|
|
|
# Write file
|
|
self._progress_dir.mkdir(parents=True, exist_ok=True)
|
|
path.write_text("\n".join(lines))
|
|
|
|
return path
|
|
|
|
def append_completed(self, task: str) -> bool:
|
|
"""Append a completed task to today's progress.
|
|
|
|
Args:
|
|
task: The completed task description
|
|
|
|
Returns:
|
|
True if successful, False if no progress file exists
|
|
"""
|
|
path = self.get_today_path()
|
|
if not path.exists():
|
|
return False
|
|
|
|
content = path.read_text()
|
|
lines = content.split("\n")
|
|
|
|
# Find the Completed section
|
|
for i, line in enumerate(lines):
|
|
if line.strip() == "## Completed":
|
|
# Find where to insert (after the header)
|
|
insert_idx = i + 1
|
|
# Skip (none yet) if present
|
|
if insert_idx < len(lines) and lines[insert_idx].strip() == "(none yet)":
|
|
lines[insert_idx] = f"- [x] {task}"
|
|
else:
|
|
lines.insert(insert_idx, f"- [x] {task}")
|
|
path.write_text("\n".join(lines))
|
|
return True
|
|
|
|
return False
|
|
|
|
def append_in_progress(self, task: str) -> bool:
|
|
"""Append an in-progress task to today's progress.
|
|
|
|
Args:
|
|
task: The task description
|
|
|
|
Returns:
|
|
True if successful, False if no progress file exists
|
|
"""
|
|
path = self.get_today_path()
|
|
if not path.exists():
|
|
return False
|
|
|
|
content = path.read_text()
|
|
lines = content.split("\n")
|
|
|
|
# Find the In Progress section
|
|
for i, line in enumerate(lines):
|
|
if line.strip() == "## In Progress":
|
|
insert_idx = i + 1
|
|
if insert_idx < len(lines) and lines[insert_idx].strip() == "(none)":
|
|
lines[insert_idx] = f"- [ ] {task}"
|
|
else:
|
|
lines.insert(insert_idx, f"- [ ] {task}")
|
|
path.write_text("\n".join(lines))
|
|
return True
|
|
|
|
return False
|