From b496ee4a3aeeec8b21842aac0c65053a1de9000e Mon Sep 17 00:00:00 2001 From: Claw Date: Fri, 6 Mar 2026 00:27:43 +0000 Subject: [PATCH] feat: ATS breakdown in Telegram summary after each apply run --- job_applier.mjs | 6 ++++-- lib/notify.mjs | 27 ++++++++++++++++++++------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/job_applier.mjs b/job_applier.mjs index b2429f1..edbf6b8 100644 --- a/job_applier.mjs +++ b/job_applier.mjs @@ -65,7 +65,8 @@ async function main() { const results = { submitted: 0, failed: 0, needs_answer: 0, total: jobs.length, - skipped_recruiter: 0, skipped_external: 0, skipped_no_easy_apply: 0 + skipped_recruiter: 0, skipped_external: 0, skipped_no_easy_apply: 0, + atsCounts: {} }; // Group by platform @@ -173,10 +174,11 @@ async function handleResult(job, result, results, settings) { case 'skipped_external_unsupported': { const atsUrl = result.externalUrl || ''; const atsDomain = atsUrl ? (new URL(atsUrl).hostname.replace('www.', '').split('.')[0]) : 'unknown'; - console.log(` ⏭️ Skipped — external ATS: ${atsDomain || 'unknown'}`); + console.log(` ⏭️ Skipped — external ATS: ${atsDomain}`); updateJobStatus(job.id, 'skipped_external_unsupported', { title, company, ats_url: atsUrl, ats_platform: atsDomain }); appendLog({ ...job, title, company, status: 'skipped_external_unsupported', ats_url: atsUrl, ats_platform: atsDomain }); results.skipped_external++; + results.atsCounts[atsDomain] = (results.atsCounts[atsDomain] || 0) + 1; break; } diff --git a/lib/notify.mjs b/lib/notify.mjs index caef492..f60e160 100644 --- a/lib/notify.mjs +++ b/lib/notify.mjs @@ -46,15 +46,28 @@ export function formatSearchSummary(added, skipped, platforms) { export function formatApplySummary(results) { const { submitted, failed, needs_answer, total, - skipped_recruiter, skipped_external, skipped_no_easy_apply } = results; + skipped_recruiter, skipped_external, skipped_no_easy_apply, atsCounts } = results; + const lines = [ - `✅ *Apply Run Complete*`, - `Applied: ${submitted} | Failed: ${failed} | Needs answer: ${needs_answer}`, - `Skipped: ${skipped_recruiter} recruiter-only | ${skipped_external} external ATS | ${skipped_no_easy_apply} no Easy Apply`, - `Total processed: ${total}`, + `✅ *Apply Run Complete* — ${total} jobs processed`, + ``, + `📬 Applied: ${submitted}`, + `⏭️ Skipped (no Easy Apply): ${skipped_no_easy_apply}`, + `🚫 Recruiter-only: ${skipped_recruiter}`, + `❌ Failed: ${failed}`, + `💬 Needs your answer: ${needs_answer}`, ]; - if (needs_answer > 0) lines.push(`\n💬 Check messages — I sent questions that need your answers`); - if (skipped_external > 0) lines.push(`\n🔜 ${skipped_external} external ATS jobs saved for when Greenhouse/Lever support lands`); + + if (skipped_external > 0 && atsCounts) { + const sorted = Object.entries(atsCounts).sort((a, b) => b[1] - a[1]); + lines.push(``, `🌐 *External ATS — ${skipped_external} jobs* (saved for later):`); + for (const [platform, count] of sorted) { + lines.push(` • ${platform}: ${count}`); + } + } + + if (needs_answer > 0) lines.push(``, `💬 Check Telegram — questions waiting for your answers`); + return lines.join('\n'); }