// Cron — scheduled agent runs, with run history and a calendar heat strip. const CRON_JOBS = [ { id: 'daily-summary', name: 'Daily standup summary', schedule: '0 9 * * 1-5', cronText: 'Weekdays at 9:00am', enabled: true, lastRun: '2h ago', lastStatus: 'ok', avgDuration: '38s', nextRun: 'tomorrow 9:00am', personality: 'Hermes', desc: 'Read yesterday\'s commits + Linear updates and post a summary to #standup.', runs7d: 5 }, { id: 'incident-triage', name: 'Incident triage', schedule: '*/15 * * * *', cronText: 'Every 15 minutes', enabled: true, lastRun: '3m ago', lastStatus: 'ok', avgDuration: '4.2s', nextRun: 'in 12m', personality: 'Forge', desc: 'Poll Sentry for unresolved high-severity issues and create Linear tickets.', runs7d: 672 }, { id: 'design-review', name: 'Friday design review prep', schedule: '0 16 * * 4', cronText: 'Thursdays at 4:00pm', enabled: true, lastRun: 'yesterday', lastStatus: 'ok', avgDuration: '2m 14s', nextRun: 'Thursday 4:00pm', personality: 'Atlas', desc: 'Collect new Figma frames + recent PRs, draft an agenda for the design review.', runs7d: 1 }, { id: 'docs-stale', name: 'Find stale docs', schedule: '0 0 * * 0', cronText: 'Sundays at midnight', enabled: false, lastRun: '8d ago', lastStatus: 'skipped', avgDuration: '47s', nextRun: 'paused', personality: 'Hermes', desc: 'Scan the docs site for pages not updated in >90 days; open a checklist.', runs7d: 0 }, { id: 'release-notes', name: 'Draft release notes', schedule: '0 14 * * 5', cronText: 'Fridays at 2:00pm', enabled: true, lastRun: '6d ago', lastStatus: 'failed', avgDuration: '1m 03s', nextRun: 'Friday 2:00pm', personality: 'Atlas', desc: 'Walk merged PRs since last tag; group by area; write user-facing release notes.', runs7d: 1 }, ]; const RUN_HISTORY = [ { when: '2h ago', status: 'ok', duration: '36s', ts: '2026-04-25 09:00:14' }, { when: 'yesterday', status: 'ok', duration: '41s', ts: '2026-04-24 09:00:08' }, { when: '2d ago', status: 'ok', duration: '38s', ts: '2026-04-23 09:00:11' }, { when: '3d ago', status: 'ok', duration: '34s', ts: '2026-04-22 09:00:06' }, { when: '4d ago', status: 'failed', duration: '12s', ts: '2026-04-21 09:00:09', error: 'github: 502 bad gateway' }, { when: '5d ago', status: 'ok', duration: '40s', ts: '2026-04-18 09:00:12' }, { when: '6d ago', status: 'ok', duration: '37s', ts: '2026-04-17 09:00:09' }, ]; function Cron() { const [active, setActive] = React.useState('daily-summary'); const job = CRON_JOBS.find(j => j.id === active); React.useEffect(() => { requestAnimationFrame(() => window.lucide && window.lucide.createIcons()); }); return (
Timezone: PTNew cron job} />
{CRON_JOBS.map(j => setActive(j.id)} />)}
); } function CronRow({ j, active, onClick }) { const [hover, setHover] = React.useState(false); const tone = j.lastStatus === 'failed' ? 'red' : j.lastStatus === 'skipped' ? 'gray' : 'green'; return (
setHover(true)} onMouseLeave={() => setHover(false)} style={{ padding: '11px 12px', borderRadius: 7, cursor: 'pointer', marginBottom: 2, background: active ? 'var(--accent-tint)' : (hover ? 'var(--bg-quaternary)' : 'transparent'), }}>
{j.name}
{!j.enabled && paused}
{j.schedule} · next {j.nextRun}
); } function CronDetail({ job }) { return ( <>
{job.name}
{job.enabled ? active : paused}
{job.desc}
Run now
} /> } /> } last /> {job.personality}} /> Edit} /> } last /> {RUN_HISTORY.map((r, i) => )} ); } function RunRow({ r, last }) { const tone = r.status === 'failed' ? 'red' : r.status === 'skipped' ? 'gray' : 'green'; const icon = r.status === 'failed' ? 'x' : r.status === 'skipped' ? 'minus' : 'check'; return (
{r.status}
{r.when} {r.ts}
{r.error &&
{r.error}
}
{r.duration} View log
); } window.Cron = Cron;