Files
troupe-standup/wizard-work/quill/standup-bot.py
T

99 lines
3.1 KiB
Python

#!/usr/bin/env python3
"""standup_bot.py — CLI Daily Standup Bot, Draft implementation.
Reads ./standup.md, formats a dated summary, writes to ./standup-output/,
and optionally emails via SMTP. Stdlib only.
"""
import argparse
import os
import smtplib
import sys
from datetime import date
from email.mime.text import MIMEText
from pathlib import Path
REQUIRED_SECTIONS = ("## Yesterday", "## Today", "## Blockers")
DEFAULT_INPUT = Path("./standup.md")
DEFAULT_OUTPUT_DIR = Path("./standup-output")
def parse_args(argv=None):
p = argparse.ArgumentParser(description="Daily standup formatter")
p.add_argument("--input", type=Path, default=DEFAULT_INPUT, help="standup markdown")
p.add_argument("--out-dir", type=Path, default=DEFAULT_OUTPUT_DIR, help="output directory")
p.add_argument("--to", default=None, help="recipient email (overrides STANDUP_TO)")
return p.parse_args(argv)
def read_standup(path: Path) -> str:
if not path.exists():
print(f"error: {path} not found", file=sys.stderr)
sys.exit(2)
text = path.read_text(encoding="utf-8")
missing = [s for s in REQUIRED_SECTIONS if s not in text]
if missing:
print(f"error: missing sections {missing!r} in {path}", file=sys.stderr)
sys.exit(2)
return text
def format_summary(text: str, source_name: str, recipient: str | None = None) -> str:
today = date.today().isoformat()
lines = [f"# Standup — {today}", "", f"_Source: {source_name}_", ""]
if recipient:
lines.append(f"_Recipient: {recipient}_")
lines.append("")
for section in REQUIRED_SECTIONS:
lines.append(section)
lines.append("")
capture = False
for line in text.splitlines():
if line.strip() == section:
capture = True
continue
if capture:
if line.startswith("## ") and line.strip() != section:
break
lines.append(line)
return "\n".join(lines) + "\n"
def write_output(summary: str, out_dir: Path) -> Path:
out_dir.mkdir(parents=True, exist_ok=True)
out_path = out_dir / f"{date.today().isoformat()}.md"
out_path.write_text(summary, encoding="utf-8")
return out_path
def maybe_email(summary: str, to_addr: str | None) -> None:
host = os.environ.get("SMTP_HOST")
user = os.environ.get("SMTP_USER")
pwd = os.environ.get("SMTP_PASS")
if not (host and user and pwd):
return
recipient = to_addr or os.environ.get("STANDUP_TO")
if not recipient:
return
msg = MIMEText(summary)
msg["Subject"] = f"Standup — {date.today().isoformat()}"
msg["From"] = user
msg["To"] = recipient
with smtplib.SMTP(host) as s:
s.login(user, pwd)
s.send_message(msg)
def main(argv=None) -> int:
args = parse_args(argv)
text = read_standup(args.input)
summary = format_summary(text, str(args.input), args.to)
print(summary, end="")
write_output(summary, args.out_dir)
maybe_email(summary, args.to)
return 0
if __name__ == "__main__":
sys.exit(main())