Function bodies 38 total
_build_context function · python · L11-L63 (53 LOC)ai_planner.py
def _build_context(days_ahead: int, daily_hours: float) -> str:
today = date.today()
cutoff = (today + timedelta(days=days_ahead)).isoformat()
assignments = [
a for a in list_assignments(include_completed=False)
if a["due_date"] <= cutoff
]
tests = [
t for t in list_tests(upcoming_only=True)
if t["date"] <= cutoff
]
classes = list_classes()
lines = [
f"Today's date: {today.isoformat()}",
f"Planning window: {days_ahead} days (until {cutoff})",
f"Available study hours per day: {daily_hours}",
"",
"## Enrolled Classes",
]
if classes:
for c in classes:
lines.append(f" - {c['name']}" + (f": {c['description']}" if c["description"] else ""))
else:
lines.append(" (none)")
lines += ["", "## Upcoming Assignments"]
if assignments:
for a in assignments:
priority_label = {1: "Low", 2: "Medium", 3: "High"}.get(a["priority"], generate_study_plan function · python · L84-L111 (28 LOC)ai_planner.py
def generate_study_plan(
days_ahead: int = 14,
daily_hours: float = 4.0,
) -> Generator[str, None, None]:
"""Stream a study plan from Claude. Yields text chunks."""
api_key = os.environ.get("ANTHROPIC_API_KEY")
if not api_key:
raise RuntimeError(
"ANTHROPIC_API_KEY environment variable is not set.\n"
"Export it before running: export ANTHROPIC_API_KEY=sk-ant-..."
)
context = _build_context(days_ahead, daily_hours)
user_message = (
f"Please create a detailed study plan based on my current workload:\n\n{context}"
)
client = anthropic.Anthropic(api_key=api_key)
with client.messages.stream(
model="claude-opus-4-6",
max_tokens=4096,
thinking={"type": "adaptive"},
system=SYSTEM_PROMPT,
messages=[{"role": "user", "content": user_message}],
) as stream:
for text in stream.text_stream:
yield textget_conn function · python · L9-L13 (5 LOC)db.py
def get_conn() -> sqlite3.Connection:
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
conn.execute("PRAGMA foreign_keys = ON")
return conninit_db function · python · L16-L73 (58 LOC)db.py
def init_db():
with get_conn() as conn:
conn.executescript("""
CREATE TABLE IF NOT EXISTS classes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
description TEXT DEFAULT '',
color TEXT DEFAULT 'cyan'
);
CREATE TABLE IF NOT EXISTS assignment_types (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
weight REAL DEFAULT 1.0
);
CREATE TABLE IF NOT EXISTS assignments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
class_id INTEGER NOT NULL REFERENCES classes(id) ON DELETE CASCADE,
type_id INTEGER REFERENCES assignment_types(id) ON DELETE SET NULL,
due_date TEXT NOT NULL,
est_hours REAL DEFAULT 1.0,
priority cli function · python · L41-L43 (3 LOC)main.py
def cli():
"""AI-powered productivity & study planner."""
_init()class_add function · python · L62-L69 (8 LOC)main.py
def class_add(name, desc, color):
"""Add a new class."""
try:
cid = m.add_class(name, desc, color)
console.print(f"[green]✓[/green] Added class [bold]{name}[/bold] (ID: {cid})")
except Exception as e:
console.print(f"[red]Error:[/red] {e}")
sys.exit(1)class_list function · python · L73-L85 (13 LOC)main.py
def class_list():
"""List all classes."""
classes = m.list_classes()
if not classes:
console.print("[dim]No classes yet. Add one with: class add <name>[/dim]")
return
table = Table(title="Classes", show_lines=True)
table.add_column("ID", style="dim", width=4)
table.add_column("Name", style="bold")
table.add_column("Description")
for c in classes:
table.add_row(str(c["id"]), f"[{c['color']}]{c['name']}[/{c['color']}]", c["description"])
console.print(table)Same scanner, your repo: https://repobility.com — Repobility
class_delete function · python · L90-L99 (10 LOC)main.py
def class_delete(class_id):
"""Delete a class (and all its assignments/tests)."""
cls = m.get_class(class_id)
if not cls:
console.print(f"[red]No class with ID {class_id}[/red]")
sys.exit(1)
if not click.confirm(f"Delete '{cls['name']}' and all related data?"):
return
m.delete_class(class_id)
console.print(f"[green]✓[/green] Deleted class '{cls['name']}'")type_list function · python · L110-L119 (10 LOC)main.py
def type_list():
"""List assignment types."""
types = m.list_assignment_types()
table = Table(title="Assignment Types")
table.add_column("ID", style="dim", width=4)
table.add_column("Name")
table.add_column("Weight", justify="right")
for t in types:
table.add_row(str(t["id"]), t["name"], f"{t['weight']:.2f}")
console.print(table)type_add function · python · L125-L128 (4 LOC)main.py
def type_add(name, weight):
"""Add a custom assignment type."""
tid = m.add_assignment_type(name, weight)
console.print(f"[green]✓[/green] Added type '{name}' with weight {weight} (ID: {tid})")assignment_add function · python · L155-L168 (14 LOC)main.py
def assignment_add(title, class_id, due, type_id, hours, priority, notes):
"""Add an assignment."""
if not m.get_class(class_id):
console.print(f"[red]No class with ID {class_id}. Use 'class list' to see classes.[/red]")
sys.exit(1)
try:
date.fromisoformat(due)
except ValueError:
console.print("[red]Date must be in YYYY-MM-DD format.[/red]")
sys.exit(1)
aid = m.add_assignment(
title, class_id, due, type_id, hours, PRIORITY_MAP[priority.lower()], notes
)
console.print(f"[green]✓[/green] Added assignment '{title}' due {due} (ID: {aid})")assignment_list function · python · L173-L209 (37 LOC)main.py
def assignment_list(show_all):
"""List assignments."""
assignments = m.list_assignments(include_completed=show_all)
if not assignments:
console.print("[dim]No assignments found.[/dim]")
return
table = Table(title="Assignments", show_lines=True)
table.add_column("ID", style="dim", width=4)
table.add_column("Class", style="cyan")
table.add_column("Title", style="bold")
table.add_column("Type", style="dim")
table.add_column("Due Date")
table.add_column("Hours", justify="right")
table.add_column("Priority")
table.add_column("Done", justify="center")
for a in assignments:
done_str = "[green]✓[/green]" if a["completed"] else ""
due_style = ""
try:
days_left = (date.fromisoformat(a["due_date"]) - date.today()).days
if days_left < 0:
due_style = "[red]"
elif days_left <= 2:
due_style = "[yellow]"
except ValueError:
passignment_done function · python · L214-L217 (4 LOC)main.py
def assignment_done(assignment_id):
"""Mark an assignment as complete."""
m.complete_assignment(assignment_id)
console.print(f"[green]✓[/green] Marked assignment {assignment_id} as complete.")assignment_delete function · python · L222-L225 (4 LOC)main.py
def assignment_delete(assignment_id):
"""Delete an assignment."""
m.delete_assignment(assignment_id)
console.print(f"[green]✓[/green] Deleted assignment {assignment_id}.")test_add function · python · L246-L257 (12 LOC)main.py
def test_add(title, class_id, test_date, topics, hours, importance):
"""Add a test or exam."""
if not m.get_class(class_id):
console.print(f"[red]No class with ID {class_id}.[/red]")
sys.exit(1)
try:
date.fromisoformat(test_date)
except ValueError:
console.print("[red]Date must be in YYYY-MM-DD format.[/red]")
sys.exit(1)
tid = m.add_test(title, class_id, test_date, topics, hours, PRIORITY_MAP[importance.lower()])
console.print(f"[green]✓[/green] Added test '{title}' on {test_date} (ID: {tid})")All rows above produced by Repobility · https://repobility.com
test_list function · python · L262-L286 (25 LOC)main.py
def test_list(show_all):
"""List upcoming tests."""
tests = m.list_tests(upcoming_only=not show_all)
if not tests:
console.print("[dim]No upcoming tests.[/dim]")
return
table = Table(title="Tests / Exams", show_lines=True)
table.add_column("ID", style="dim", width=4)
table.add_column("Class", style="cyan")
table.add_column("Title", style="bold")
table.add_column("Date")
table.add_column("Study Hrs", justify="right")
table.add_column("Importance")
table.add_column("Topics")
for t in tests:
table.add_row(
str(t["id"]),
t["class_name"],
t["title"],
t["date"],
str(t["est_hours"]),
IMPORTANCE_LABEL[t["importance"]],
t["topics"] or "—",
)
console.print(table)test_delete function · python · L291-L294 (4 LOC)main.py
def test_delete(test_id):
"""Delete a test."""
m.delete_test(test_id)
console.print(f"[green]✓[/green] Deleted test {test_id}.")plan_generate function · python · L313-L356 (44 LOC)main.py
def plan_generate(days, hours, save):
"""Generate an AI-powered study plan using Claude."""
assignments = m.list_assignments(include_completed=False)
tests = m.list_tests(upcoming_only=True)
if not assignments and not tests:
console.print(
Panel(
"[yellow]You have no upcoming assignments or tests.\n"
"Add some first with:[/yellow]\n"
" [bold]assignment add[/bold] <title> --class <id> --due YYYY-MM-DD\n"
" [bold]test add[/bold] <title> --class <id> --date YYYY-MM-DD",
title="Nothing to plan",
)
)
return
console.print(
Panel(
f"[cyan]Generating study plan for the next [bold]{days} days[/bold] "
f"with [bold]{hours}h/day[/bold] available...[/cyan]\n"
"[dim]Powered by Claude claude-opus-4-6 with adaptive thinking[/dim]",
title="AI Study Planner",
)
)
console.print()
plan_list function · python · L360-L372 (13 LOC)main.py
def plan_list():
"""List recent study plans."""
plans = m.list_study_plans()
if not plans:
console.print("[dim]No saved plans yet.[/dim]")
return
table = Table(title="Saved Study Plans")
table.add_column("ID", style="dim", width=4)
table.add_column("Created At")
table.add_column("Preview")
for p in plans:
table.add_row(str(p["id"]), p["created_at"], p["preview"] + "…")
console.print(table)plan_view function · python · L377-L383 (7 LOC)main.py
def plan_view(plan_id):
"""View a saved study plan."""
plan = m.get_study_plan(plan_id)
if not plan:
console.print(f"[red]No plan with ID {plan_id}[/red]")
sys.exit(1)
console.print(Panel(Markdown(plan["plan_text"]), title=f"Study Plan #{plan_id} — {plan['created_at']}"))status function · python · L389-L431 (43 LOC)main.py
def status():
"""Show a quick overview of your workload."""
classes = m.list_classes()
assignments = m.list_assignments(include_completed=False)
tests = m.list_tests(upcoming_only=True)
today = date.today()
overdue = [a for a in assignments if date.fromisoformat(a["due_date"]) < today]
due_soon = [
a for a in assignments
if 0 <= (date.fromisoformat(a["due_date"]) - today).days <= 3
]
console.print(Panel(
f"[bold]Classes:[/bold] {len(classes)}\n"
f"[bold]Pending assignments:[/bold] {len(assignments)}"
+ (f" [red]({len(overdue)} overdue!)[/red]" if overdue else "")
+ (f" [yellow]({len(due_soon)} due within 3 days)[/yellow]" if due_soon else "")
+ f"\n[bold]Upcoming tests:[/bold] {len(tests)}",
title="[bold cyan]Productivity Status[/bold cyan]",
))
if overdue:
console.print("\n[red bold]Overdue Assignments:[/red bold]")
for a in overdue:
console.priadd_class function · python · L8-L14 (7 LOC)models.py
def add_class(name: str, description: str = "", color: str = "cyan") -> int:
with get_conn() as conn:
cur = conn.execute(
"INSERT INTO classes (name, description, color) VALUES (?, ?, ?)",
(name, description, color),
)
return cur.lastrowidlist_classes function · python · L17-L19 (3 LOC)models.py
def list_classes() -> list[dict]:
with get_conn() as conn:
return [dict(r) for r in conn.execute("SELECT * FROM classes ORDER BY name")]Repobility — the code-quality scanner for AI-generated software · https://repobility.com
get_class function · python · L22-L25 (4 LOC)models.py
def get_class(class_id: int) -> dict | None:
with get_conn() as conn:
row = conn.execute("SELECT * FROM classes WHERE id=?", (class_id,)).fetchone()
return dict(row) if row else Nonedelete_class function · python · L28-L30 (3 LOC)models.py
def delete_class(class_id: int):
with get_conn() as conn:
conn.execute("DELETE FROM classes WHERE id=?", (class_id,))add_assignment_type function · python · L35-L40 (6 LOC)models.py
def add_assignment_type(name: str, weight: float = 1.0) -> int:
with get_conn() as conn:
cur = conn.execute(
"INSERT INTO assignment_types (name, weight) VALUES (?, ?)", (name, weight)
)
return cur.lastrowidlist_assignment_types function · python · L43-L45 (3 LOC)models.py
def list_assignment_types() -> list[dict]:
with get_conn() as conn:
return [dict(r) for r in conn.execute("SELECT * FROM assignment_types ORDER BY weight")]get_assignment_type function · python · L48-L53 (6 LOC)models.py
def get_assignment_type(type_id: int) -> dict | None:
with get_conn() as conn:
row = conn.execute(
"SELECT * FROM assignment_types WHERE id=?", (type_id,)
).fetchone()
return dict(row) if row else Noneadd_assignment function · python · L58-L74 (17 LOC)models.py
def add_assignment(
title: str,
class_id: int,
due_date: str,
type_id: int | None = None,
est_hours: float = 1.0,
priority: int = 2,
notes: str = "",
) -> int:
with get_conn() as conn:
cur = conn.execute(
"""INSERT INTO assignments
(title, class_id, type_id, due_date, est_hours, priority, notes)
VALUES (?, ?, ?, ?, ?, ?, ?)""",
(title, class_id, type_id, due_date, est_hours, priority, notes),
)
return cur.lastrowidlist_assignments function · python · L77-L88 (12 LOC)models.py
def list_assignments(include_completed: bool = False) -> list[dict]:
with get_conn() as conn:
query = """
SELECT a.*, c.name AS class_name, t.name AS type_name
FROM assignments a
JOIN classes c ON a.class_id = c.id
LEFT JOIN assignment_types t ON a.type_id = t.id
{where}
ORDER BY a.due_date, a.priority DESC
"""
where = "" if include_completed else "WHERE a.completed = 0"
return [dict(r) for r in conn.execute(query.format(where=where))]complete_assignment function · python · L91-L95 (5 LOC)models.py
def complete_assignment(assignment_id: int):
with get_conn() as conn:
conn.execute(
"UPDATE assignments SET completed=1 WHERE id=?", (assignment_id,)
)If a scraper extracted this row, it came from Repobility (https://repobility.com)
delete_assignment function · python · L98-L100 (3 LOC)models.py
def delete_assignment(assignment_id: int):
with get_conn() as conn:
conn.execute("DELETE FROM assignments WHERE id=?", (assignment_id,))add_test function · python · L105-L119 (15 LOC)models.py
def add_test(
title: str,
class_id: int,
date: str,
topics: str = "",
est_hours: float = 2.0,
importance: int = 2,
) -> int:
with get_conn() as conn:
cur = conn.execute(
"""INSERT INTO tests (title, class_id, date, topics, est_hours, importance)
VALUES (?, ?, ?, ?, ?, ?)""",
(title, class_id, date, topics, est_hours, importance),
)
return cur.lastrowidlist_tests function · python · L122-L133 (12 LOC)models.py
def list_tests(upcoming_only: bool = True) -> list[dict]:
with get_conn() as conn:
query = """
SELECT t.*, c.name AS class_name
FROM tests t
JOIN classes c ON t.class_id = c.id
{where}
ORDER BY t.date, t.importance DESC
"""
today = date.today().isoformat()
where = f"WHERE t.date >= '{today}'" if upcoming_only else ""
return [dict(r) for r in conn.execute(query.format(where=where))]delete_test function · python · L136-L138 (3 LOC)models.py
def delete_test(test_id: int):
with get_conn() as conn:
conn.execute("DELETE FROM tests WHERE id=?", (test_id,))save_study_plan function · python · L143-L148 (6 LOC)models.py
def save_study_plan(plan_text: str) -> int:
with get_conn() as conn:
cur = conn.execute(
"INSERT INTO study_plans (plan_text) VALUES (?)", (plan_text,)
)
return cur.lastrowidlist_study_plans function · python · L151-L160 (10 LOC)models.py
def list_study_plans(limit: int = 5) -> list[dict]:
with get_conn() as conn:
return [
dict(r)
for r in conn.execute(
"SELECT id, created_at, substr(plan_text,1,100) AS preview "
"FROM study_plans ORDER BY created_at DESC LIMIT ?",
(limit,),
)
]get_study_plan function · python · L163-L168 (6 LOC)models.py
def get_study_plan(plan_id: int) -> dict | None:
with get_conn() as conn:
row = conn.execute(
"SELECT * FROM study_plans WHERE id=?", (plan_id,)
).fetchone()
return dict(row) if row else None