From 094824abb2d21495e6e551fced894fcdafdd8caf Mon Sep 17 00:00:00 2001 From: Matthew Jackson Date: Fri, 6 Mar 2026 13:23:39 -0800 Subject: [PATCH] Add dedicated 'closed' status for listings no longer accepting applications Distinguishes closed listings from missing apply buttons. Shows in summary as a separate line item. Co-Authored-By: Claude Opus 4.6 --- job_applier.mjs | 7 +++++++ lib/apply/easy_apply.mjs | 2 +- lib/apply/wellfound.mjs | 2 +- lib/notify.mjs | 3 ++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/job_applier.mjs b/job_applier.mjs index f0ba79d..1d8bf40 100644 --- a/job_applier.mjs +++ b/job_applier.mjs @@ -304,6 +304,13 @@ async function handleResult(job, result, results, settings, profile, apiKey) { break; } + case 'closed': + console.log(` đŸšĢ Closed — no longer accepting applications`); + updateJobStatus(job.id, 'closed', { title, company }); + appendLog({ ...job, title, company, status: 'closed' }); + results.closed = (results.closed || 0) + 1; + break; + case 'no_modal': case 'skipped_no_apply': case 'skipped_easy_apply_unsupported': diff --git a/lib/apply/easy_apply.mjs b/lib/apply/easy_apply.mjs index 9196b7a..7fe429d 100644 --- a/lib/apply/easy_apply.mjs +++ b/lib/apply/easy_apply.mjs @@ -154,7 +154,7 @@ export async function apply(page, job, formFiller) { }).catch(() => false); if (closed) { console.log(` â„šī¸ Job closed — no longer accepting applications`); - return { status: 'skipped_no_apply', meta }; + return { status: 'closed', meta }; } console.log(` ❌ Modal did not open. Page URL: ${page.url()}`); return { status: 'no_modal', meta }; diff --git a/lib/apply/wellfound.mjs b/lib/apply/wellfound.mjs index 8687775..331c085 100644 --- a/lib/apply/wellfound.mjs +++ b/lib/apply/wellfound.mjs @@ -24,7 +24,7 @@ export async function apply(page, job, formFiller) { }).catch(() => false); if (closed) { console.log(` â„šī¸ Job closed — no longer available`); - return { status: 'skipped_no_apply', meta }; + return { status: 'closed', meta }; } const applyBtn = page.locator('a:has-text("Apply"), button:has-text("Apply Now"), a:has-text("Apply Now")').first(); diff --git a/lib/notify.mjs b/lib/notify.mjs index c563e18..2d2624d 100644 --- a/lib/notify.mjs +++ b/lib/notify.mjs @@ -95,7 +95,7 @@ export function formatSearchSummary(added, skipped, platforms) { export function formatApplySummary(results) { const { submitted, failed, needs_answer, total, skipped_recruiter, skipped_external, skipped_no_apply, - skipped_other, already_applied, atsCounts } = results; + skipped_other, already_applied, closed, atsCounts } = results; const lines = [ `✅ *Apply Run Complete* — ${total} jobs processed`, @@ -106,6 +106,7 @@ export function formatApplySummary(results) { // Only show non-zero categories to keep the summary clean if (needs_answer) lines.push(`đŸ’Ŧ Needs your answer: ${needs_answer}`); if (failed) lines.push(`❌ Failed: ${failed}`); + if (closed) lines.push(`đŸšĢ Closed: ${closed}`); if (skipped_no_apply) lines.push(`â­ī¸ No apply button: ${skipped_no_apply}`); if (skipped_recruiter) lines.push(`đŸšĢ Recruiter-only: ${skipped_recruiter}`); if (already_applied) lines.push(`🔁 Already applied: ${already_applied}`);