/* Schedules — recurring agent spawns. Every interval the worker starts a fresh, * stateless agent named - with the stored prompt. The canonical * pattern: keep state in a file in the repo and have the prompt continue from it. */ "use client"; import { useMemo, useState } from "react"; import { useDashboard } from "@/components/store"; import { Badge, Button, Card, Input, Select, Textarea, Toggle } from "@/components/ui"; import { fmtFull } from "@/lib/format"; const ROLE_OPTS = [ { value: "", label: "Role — none" }, { value: "junior", label: "junior" }, { value: "senior", label: "senior" }, { value: "deploy", label: "deploy" }, ]; const INTERVAL_OPTS = [ { value: "900", label: "every 15 minutes" }, { value: "1800", label: "every 30 minutes" }, { value: "3600", label: "every hour" }, { value: "21600", label: "every 6 hours" }, { value: "86400", label: "every day" }, { value: "604800", label: "every week" }, ]; const TASK_PLACEHOLDER = "Read @notes.md and continue from where it left off. Before finishing, overwrite " + "@notes.md with the current state so the next run can pick up from there."; function intervalLabel(seconds: number): string { const opt = INTERVAL_OPTS.find((o) => Number(o.value) === seconds); if (opt) return opt.label; if (seconds % 3600 === 0) return `every ${seconds / 3600}h`; if (seconds % 60 === 0) return `every ${seconds / 60}m`; return `every ${seconds}s`; } const emptyForm = { name_prefix: "", task: "", interval: "3600", role: "" }; export function SchedulesSection() { const s = useDashboard(); const [form, setForm] = useState(emptyForm); const projectOpts = useMemo( () => s.projects.map((p) => ({ value: p.id, label: p.id })), [s.projects], ); const create = async () => { const ok = await s.createSchedule(s.selectedProjectId, { name_prefix: form.name_prefix, task: form.task, interval_seconds: Number(form.interval), role: form.role, }); if (ok) setForm(emptyForm); }; return ( <>
Schedules
Spawn a fresh agent on an interval. Each run is stateless — keep continuity in a file the prompt reads and overwrites.
{s.projects.length === 0 ? (
Register a repository first.
) : ( <>
setForm({ ...form, name_prefix: v })} placeholder="nightly" /> setForm({ ...form, role: v })} options={ROLE_OPTS} />