"""Apple Reminders tools — uses compiled EventKit helper for speed.""" import json import subprocess from pathlib import Path from helpers import run_applescript, safe_applescript_string HELPER_BIN = Path(__file__).parent.parent / "helpers" / "reminders_helper" def _run_helper(*args: str, timeout: int = 15) -> dict | list: """Run the compiled EventKit reminders helper and return parsed JSON.""" result = subprocess.run( [str(HELPER_BIN)] + list(args), capture_output=True, text=True, timeout=timeout, ) if result.returncode != 0: stderr = result.stderr.strip() try: err = json.loads(result.stdout) raise RuntimeError(err.get("error", stderr)) except (json.JSONDecodeError, TypeError): raise RuntimeError(f"Reminders helper error: {stderr or result.stdout}") return json.loads(result.stdout) def list_lists() -> list[dict]: """List all reminder lists (e.g., Reminders, Shopping, Work).""" return _run_helper("lists") def get_reminders(list_name: str | None = None, include_completed: bool = False) -> dict: """Get reminders, optionally filtered by list name. Args: list_name: Filter to a specific list. None = all lists. include_completed: Include completed reminders. """ args = ["get"] if list_name: args += ["--list", list_name] if not include_completed: pass # Default is incomplete only return _run_helper(*args, timeout=30) def search_reminders(query: str) -> dict: """Search reminders by name across all lists.""" return _run_helper("search", query, timeout=30) def get_overdue_reminders() -> dict: """Get all overdue (past due) incomplete reminders.""" return _run_helper("get", "--overdue") def get_due_today() -> dict: """Get reminders due today.""" return _run_helper("get", "--due-today") def get_due_this_week() -> dict: """Get reminders due in the next 7 days.""" return _run_helper("get", "--due-this-week") def create_reminder(name: str, list_name: str = "Reminders", due_date: str | None = None, body: str | None = None, priority: int = 0) -> dict: """Create a new reminder.""" safe_name = safe_applescript_string(name) safe_list = safe_applescript_string(list_name) props = [f'name:"{safe_name}"'] if body: props.append(f'body:"{safe_applescript_string(body)}"') if priority > 0: props.append(f'priority:{priority}') props_str = ", ".join(props) due_line = "" if due_date: due_line = f''' set due date of newReminder to date "{due_date}"''' script = f''' tell application "Reminders" set theList to list "{safe_list}" set newReminder to make new reminder at end of theList with properties {{{props_str}}} {due_line} return id of newReminder end tell''' reminder_id = run_applescript(script) return {"id": reminder_id.strip(), "name": name, "list": list_name, "created": True} def complete_reminder(name: str, list_name: str | None = None) -> dict: """Mark a reminder as completed by name.""" safe_name = safe_applescript_string(name) if list_name: safe_list = safe_applescript_string(list_name) script = f''' tell application "Reminders" set theList to list "{safe_list}" set theReminders to (every reminder of theList whose name is "{safe_name}" and completed is false) if (count of theReminders) > 0 then set completed of item 1 of theReminders to true return "completed" else return "not_found" end if end tell''' else: script = f''' tell application "Reminders" repeat with L in lists set theReminders to (every reminder of L whose name is "{safe_name}" and completed is false) if (count of theReminders) > 0 then set completed of item 1 of theReminders to true return "completed" end if end repeat return "not_found" end tell''' result = run_applescript(script) if result == "completed": return {"name": name, "completed": True} raise RuntimeError(f"Reminder '{name}' not found or already completed") def delete_reminder(name: str, list_name: str | None = None) -> dict: """Delete a reminder by name.""" safe_name = safe_applescript_string(name) if list_name: safe_list = safe_applescript_string(list_name) script = f''' tell application "Reminders" set theList to list "{safe_list}" set theReminders to (every reminder of theList whose name is "{safe_name}") if (count of theReminders) > 0 then delete item 1 of theReminders return "deleted" else return "not_found" end if end tell''' else: script = f''' tell application "Reminders" repeat with L in lists set theReminders to (every reminder of L whose name is "{safe_name}") if (count of theReminders) > 0 then delete item 1 of theReminders return "deleted" end if end repeat return "not_found" end tell''' result = run_applescript(script) if result == "deleted": return {"name": name, "deleted": True} raise RuntimeError(f"Reminder '{name}' not found")