import { sendEmail } from "../../channels/email/send"; import * as fs from "fs"; import * as path from "path"; const RADAR_DIR = path.resolve(__dirname, "../../../../palaces/manglasabang/secretariat/tasks-synced-from-linear-to-git/aceradar"); const BUCKETS = ["active", "inactive-todo"]; function today(): string { return new Date().toLocaleDateString("en-CA", { timeZone: "America/Los_Angeles" }); } function daysUntil(dateStr: string): number { const now = new Date(today()); const target = new Date(dateStr); return Math.ceil((target.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)); } interface RadarItem { identifier: string; title: string; dueDate: string; status: string; description: string; } function scanRadarItems(): RadarItem[] { const items: RadarItem[] = []; for (const bucket of BUCKETS) { const bucketPath = path.join(RADAR_DIR, bucket); if (!fs.existsSync(bucketPath)) continue; for (const folder of fs.readdirSync(bucketPath)) { const mdFile = path.join(bucketPath, folder, `${folder}.md`); if (!fs.existsSync(mdFile)) continue; const content = fs.readFileSync(mdFile, "utf8"); const dueDateMatch = content.match(/\*\*Due:\*\* (\d{4}-\d{2}-\d{2})/); if (!dueDateMatch) continue; const identifierMatch = content.match(/\*\*Linear:\*\* (MAN-\d+)/); const statusMatch = content.match(/\*\*Status:\*\* (.+)/); const titleMatch = content.match(/^# (.+)/m); const descMatch = content.match(/## Description\n([\s\S]*)/); items.push({ identifier: identifierMatch?.[1] || folder, title: titleMatch?.[1] || folder, dueDate: dueDateMatch[1], status: statusMatch?.[1] || "unknown", description: descMatch?.[1]?.trim() || "", }); } } return items; } export async function runRadar(): Promise { const todayStr = today(); const items = scanRadarItems(); const alerts: string[] = []; console.log(`[radar] checking ${items.length} items with due dates (${todayStr})`); for (const item of items) { const days = daysUntil(item.dueDate); if (days > 30) { console.log(`[radar] ${item.identifier} — ${days} days out, skipping`); continue; } const subject = `Radar: ${item.title} — ${days} days remaining`; const markdown = [ `## ${item.title}`, "", `**Due:** ${item.dueDate} (${days} days)`, `**Status:** ${item.status}`, "", item.description, "", `*Linear: ${item.identifier}*`, ].join("\n"); console.log(`[radar] alerting: ${item.identifier} — ${item.title} (${days} days left)`); await sendEmail("ace@manglasabang.com", { to: "junwon@manglasabang.com", subject, markdown, }); alerts.push(`${item.identifier}: ${item.title} (${days} days)`); } if (alerts.length === 0) { console.log("[radar] nothing to alert"); } else { console.log(`[radar] sent ${alerts.length} alert(s)`); } return alerts; } if (require.main === module) { runRadar() .then((alerts) => { if (alerts.length === 0) console.log("[radar] no alerts today"); else console.log(`[radar] done: ${alerts.join(", ")}`); }) .catch((err) => { console.error("[radar] fatal:", err); process.exit(1); }); }