diff --git a/README.md b/README.md index 1f36e7b..72f5d66 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,28 @@ --- +## Project implementation + +This repository contains not only the plan text, but also a small Python project that implements a basic progress tracker for this plan. + +### Source files + +- `main.py` — CLI entrypoint. +- `src/fluency_tracker/tracker.py` — parser of markdown checklist and report builder. +- `src/fluency_tracker/cli.py` — command-line interface. +- `requirements.txt` / `pyproject.toml` — dependency and project configuration files. + +### Run locally + +```bash +python -m pip install -r requirements.txt +python main.py --plan-file README.md +``` + +The command prints current progress and pending items from checklist tasks (`- [ ]` / `- [x]`). + +--- + ## 1. Цель и контекст ### Зачем мне AI fluency diff --git a/main.py b/main.py new file mode 100644 index 0000000..8f363c8 --- /dev/null +++ b/main.py @@ -0,0 +1,7 @@ +"""CLI entrypoint for AI fluency plan tracker.""" + +from src.fluency_tracker.cli import main + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4ea38f2 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,14 @@ +[build-system] +requires = ["setuptools>=68", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "ai-fluency-plan-tracker" +version = "0.1.0" +description = "Small CLI utility to track progress of AI Fluency plan." +readme = "README.md" +requires-python = ">=3.10" +dependencies = [] + +[tool.setuptools.packages.find] +where = ["src"] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a249f4a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# Runtime dependencies +# Kept intentionally minimal for the assignment project. diff --git a/src/fluency_tracker/__init__.py b/src/fluency_tracker/__init__.py new file mode 100644 index 0000000..b182dd4 --- /dev/null +++ b/src/fluency_tracker/__init__.py @@ -0,0 +1,2 @@ +"""AI Fluency tracker package.""" + diff --git a/src/fluency_tracker/__pycache__/__init__.cpython-310.pyc b/src/fluency_tracker/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..3c76453 Binary files /dev/null and b/src/fluency_tracker/__pycache__/__init__.cpython-310.pyc differ diff --git a/src/fluency_tracker/__pycache__/cli.cpython-310.pyc b/src/fluency_tracker/__pycache__/cli.cpython-310.pyc new file mode 100644 index 0000000..5d461f4 Binary files /dev/null and b/src/fluency_tracker/__pycache__/cli.cpython-310.pyc differ diff --git a/src/fluency_tracker/__pycache__/tracker.cpython-310.pyc b/src/fluency_tracker/__pycache__/tracker.cpython-310.pyc new file mode 100644 index 0000000..a1cf48a Binary files /dev/null and b/src/fluency_tracker/__pycache__/tracker.cpython-310.pyc differ diff --git a/src/fluency_tracker/cli.py b/src/fluency_tracker/cli.py new file mode 100644 index 0000000..8be6636 --- /dev/null +++ b/src/fluency_tracker/cli.py @@ -0,0 +1,31 @@ +"""CLI for AI fluency plan tracker.""" + +from __future__ import annotations + +import argparse +from pathlib import Path + +from .tracker import build_report, parse_tasks + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser( + description="Show progress report for AI fluency plan markdown checklist." + ) + parser.add_argument( + "--plan-file", + default="README.md", + help="Path to markdown file with checklist tasks (default: README.md).", + ) + return parser + + +def main() -> int: + parser = build_parser() + args = parser.parse_args() + plan_file = Path(args.plan_file) + if not plan_file.exists(): + parser.error(f"Plan file does not exist: {plan_file}") + tasks = parse_tasks(plan_file) + print(build_report(tasks)) + return 0 diff --git a/src/fluency_tracker/tracker.py b/src/fluency_tracker/tracker.py new file mode 100644 index 0000000..c6a4aea --- /dev/null +++ b/src/fluency_tracker/tracker.py @@ -0,0 +1,49 @@ +"""Helpers to parse and report AI fluency progress.""" + +from __future__ import annotations + +from dataclasses import dataclass +from pathlib import Path +import re + + +CHECKBOX_PATTERN = re.compile(r"^- \[(?P[ xX])\] (?P.+)$") + + +@dataclass(frozen=True) +class Task: + title: str + done: bool + + +def parse_tasks(markdown_path: Path) -> list[Task]: + tasks: list[Task] = [] + for line in markdown_path.read_text(encoding="utf-8").splitlines(): + match = CHECKBOX_PATTERN.match(line.strip()) + if not match: + continue + tasks.append(Task(title=match.group("task"), done=match.group("mark").lower() == "x")) + return tasks + + +def build_report(tasks: list[Task]) -> str: + total = len(tasks) + done = sum(task.done for task in tasks) + pending = total - done + progress = 0.0 if total == 0 else (done / total) * 100 + lines = [ + "AI Fluency Plan Progress Report", + "-" * 32, + f"Total tasks : {total}", + f"Done tasks : {done}", + f"Pending tasks : {pending}", + f"Progress : {progress:.1f}%", + "", + ] + if pending > 0: + lines.append("Pending items:") + for task in (t for t in tasks if not t.done): + lines.append(f"- {task.title}") + else: + lines.append("All tasks are completed.") + return "\n".join(lines)