Enable Wellfound apply: fix missing apply_type, add submit verification

- Search now sets apply_type: 'wellfound' on discovered jobs (was missing,
  so applier silently skipped all Wellfound jobs)
- Add Wellfound to DEFAULT_ENABLED_APPLY_TYPES (LinkedIn first, then Wellfound)
- Sort platform processing order: linkedin → wellfound → external
- Apply handler: add closed listing detection, submit verification,
  error handling on meta extraction

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 12:48:03 -08:00
parent 3e367687b2
commit bb0c96dd3d
3 changed files with 35 additions and 5 deletions

View File

@@ -32,7 +32,7 @@ import {
APPLY_RUN_TIMEOUT_MS, PER_JOB_TIMEOUT_MS APPLY_RUN_TIMEOUT_MS, PER_JOB_TIMEOUT_MS
} from './lib/constants.mjs'; } from './lib/constants.mjs';
const DEFAULT_ENABLED_APPLY_TYPES = ['easy_apply']; const DEFAULT_ENABLED_APPLY_TYPES = ['easy_apply', 'wellfound'];
const isPreview = process.argv.includes('--preview'); const isPreview = process.argv.includes('--preview');
@@ -120,9 +120,12 @@ async function main() {
byPlatform[platform].push(job); byPlatform[platform].push(job);
} }
// Process each platform group // Process each platform group — LinkedIn first, then Wellfound, then external
const platformOrder = ['linkedin', 'wellfound', 'external'];
const sortedPlatforms = Object.entries(byPlatform)
.sort((a, b) => (platformOrder.indexOf(a[0]) ?? 99) - (platformOrder.indexOf(b[0]) ?? 99));
let timedOut = false; let timedOut = false;
for (const [platform, platformJobs] of Object.entries(byPlatform)) { for (const [platform, platformJobs] of sortedPlatforms) {
if (timedOut) break; if (timedOut) break;
console.log(`\n--- ${platform.toUpperCase()} (${platformJobs.length} jobs) ---\n`); console.log(`\n--- ${platform.toUpperCase()} (${platformJobs.length} jobs) ---\n`);
let browser; let browser;

View File

@@ -14,7 +14,18 @@ export async function apply(page, job, formFiller) {
const meta = await page.evaluate(() => ({ const meta = await page.evaluate(() => ({
title: document.querySelector('h1')?.textContent?.trim(), title: document.querySelector('h1')?.textContent?.trim(),
company: document.querySelector('[class*="company"] h2, [class*="startup"] h2, h2')?.textContent?.trim(), company: document.querySelector('[class*="company"] h2, [class*="startup"] h2, h2')?.textContent?.trim(),
})); })).catch(() => ({}));
// Check if listing is closed/unavailable
const closed = await page.evaluate(() => {
const text = (document.body.innerText || '').toLowerCase();
return text.includes('no longer accepting') || text.includes('position has been filled') ||
text.includes('this job is no longer') || text.includes('job not found');
}).catch(() => false);
if (closed) {
console.log(` Job closed — no longer available`);
return { status: 'skipped_no_apply', meta };
}
const applyBtn = page.locator('a:has-text("Apply"), button:has-text("Apply Now"), a:has-text("Apply Now")').first(); const applyBtn = page.locator('a:has-text("Apply"), button:has-text("Apply Now"), a:has-text("Apply Now")').first();
if (await applyBtn.count() === 0) return { status: 'no_button', meta }; if (await applyBtn.count() === 0) return { status: 'no_button', meta };
@@ -33,5 +44,20 @@ export async function apply(page, job, formFiller) {
await submitBtn.click(); await submitBtn.click();
await page.waitForTimeout(SUBMIT_WAIT); await page.waitForTimeout(SUBMIT_WAIT);
// Verify submission — check for success indicators or form gone
const postSubmit = await page.evaluate(() => {
const text = (document.body.innerText || '').toLowerCase();
return {
hasSuccess: text.includes('application submitted') || text.includes('successfully applied') ||
text.includes('thank you') || text.includes('application received'),
hasForm: !!document.querySelector('form button[type="submit"]:not([disabled])'),
};
}).catch(() => ({ hasSuccess: false, hasForm: false }));
if (postSubmit.hasSuccess || !postSubmit.hasForm) {
return { status: 'submitted', meta }; return { status: 'submitted', meta };
} }
console.log(` ⚠️ Submit clicked but form still present — may not have submitted`);
return { status: 'incomplete', meta };
}

View File

@@ -69,6 +69,7 @@ export async function searchWellfound(page, search, { onPage } = {}) {
results.push({ results.push({
id: `wf_${slug}`, id: `wf_${slug}`,
platform: 'wellfound', platform: 'wellfound',
apply_type: 'wellfound',
track, track,
title, title,
company, company,