#!/usr/bin/env python3 """ Update the single spooler file for a message after sending a reply. One file per message: read the .pending file (same base), add response data and set status to responded, write back. No separate .response file; no file deletion. Usage: ./gitea-issues/write-response-spooler.sh --base --to --subject "..." --body "..." [--in-reply-to ""] base = filename base without extension (e.g. 2026-03-14T094530.a1b2c3d4.user_example.com). """ from __future__ import annotations import argparse import json import sys from datetime import datetime, timezone from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent)) from project_config import data_issues_dir, load_project_config def main() -> int: conf = load_project_config() if not conf: print("[write-response-spooler] No project config.", file=sys.stderr) return 1 spool = data_issues_dir() spool.mkdir(parents=True, exist_ok=True) ap = argparse.ArgumentParser(description="Update spooler file in place after sending reply") ap.add_argument("--base", required=True, help="Base name (e.g. 2026-03-14T094530.a1b2c3d4.user_example.com)") ap.add_argument("--to", required=True, help="Recipient address") ap.add_argument("--subject", required=True, help="Subject sent") ap.add_argument("--body", required=True, help="Body sent") ap.add_argument("--in-reply-to", default="", help="Message-ID we replied to") args = ap.parse_args() base = args.base.strip() if not base or "/" in base or ".." in base: print("[write-response-spooler] Invalid --base.", file=sys.stderr) return 1 path = spool / f"{base}.pending" if not path.exists(): print(f"[write-response-spooler] No such file: {path.name}", file=sys.stderr) return 1 try: data = json.loads(path.read_text(encoding="utf-8")) except (json.JSONDecodeError, OSError) as e: print(f"[write-response-spooler] Read error: {e}", file=sys.stderr) return 1 now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") data["status"] = "responded" data["response"] = { "in_reply_to_message_id": args.in_reply_to or "", "to": args.to.strip(), "subject": args.subject.strip(), "body": args.body, "sent_at": now, } path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8") print(f"[write-response-spooler] Updated {path.name} (status=responded)") return 0 if __name__ == "__main__": sys.exit(main())