Commit Graph

167 Commits

Author SHA1 Message Date
6e0f212515 Add GitHub link to top of SKILL.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:09:40 -08:00
f248e8573f Auto-create claw-apply proxy if it doesn't exist
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:06:47 -08:00
df9c790a0e Look up proxy by name 'claw-apply' instead of stored ID
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:06:14 -08:00
80d2323a37 Dynamic profile lookup from auth connection
Profile name is returned by ensureAuth() from the auth connection
(looked up by domain). No more storing profile names in settings.json
for the applier flow. createBrowser() still supports legacy platform
keys as fallback for searcher/setup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:02:19 -08:00
0e18bbf481 Update docs: domain-based auth lookup, no connection IDs needed
Connection IDs are no longer stored in settings.json. The applier
finds auth connections by domain (linkedin.com, wellfound.com) at
runtime via the Kernel SDK. Updated SKILL.md, README.md, and bumped
to 0.1.4.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:57:55 -08:00
668a40a51a Look up auth connections by domain instead of stored ID
Connection IDs change when re-authing. Instead of storing IDs in
settings.json (which go stale), look up connections by domain at
runtime via kernel.auth.connections.list({ domain }). This keeps
the applier in sync regardless of connection recreation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:55:26 -08:00
561e666323 Document LinkedIn rate limit and 1-job-per-run pacing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:49:35 -08:00
59e410b9c4 Add auth health check before browser creation
- Rewrite session.mjs: check connection status via SDK before creating
  browser. If NEEDS_AUTH + can_reauth, auto re-auth with stored creds.
  If can't re-auth, send Telegram alert and skip platform.
- Wire ensureAuth() into job_applier.mjs before createBrowser()
- Jobs are returned to queue (not failed) when auth is down

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:45:24 -08:00
a133202e1b Bump to 0.1.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:27:17 -08:00
82db9658c2 Add security note to SKILL.md addressing prompt-injection false positive
The ClawHub scanner flags systemPrompt variables in lib/*.mjs as
potential prompt injection. These are legitimate Claude API prompts
for job scoring, answer generation, and keyword generation. Added
explicit note clarifying their purpose.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:26:47 -08:00
c767c7e30e Bump version to 0.1.2 for ClawHub republish
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:25:03 -08:00
7083e1bc77 Fix ClawHub scan findings: declare env vars, remove git-pull cron
- claw.json: declare KERNEL_API_KEY (required) and ANTHROPIC_API_KEY
  (optional) so registry metadata matches actual requirements
- claw.json: add telegram credentials declaration
- SKILL.md: remove frontmatter block (triggered prompt-injection scanner)
- SKILL.md: remove Git Pull cron row (ops detail, not part of skill)
- Bump version to 0.1.1

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:22:23 -08:00
6d69443f51 Pass placeholder format hints to AI for inputs and textareas
Captures placeholder from textareas in snapshot. When AI fallback is
used, includes placeholder as a format hint so the AI knows expected
format (dates, phone numbers, URLs, etc).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:12:35 -08:00
7bd91a19a0 Fix maxRetries not defined crash in handleResult
The stuck/incomplete retry logic referenced maxRetries which was only
defined in main() scope, not in handleResult(). Compute it locally.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:11:32 -08:00
3bf1786895 Detect date format from placeholder (MM/DD/YYYY) instead of label matching
Reads input placeholder in snapshot. If it contains MM/DD/YYYY pattern,
auto-fills with today's date in the correct format. Generic — works
regardless of the field label.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:05:41 -08:00
7d81d59cb5 Broaden date field detection — match any label containing 'date'
Catches 'Date of Application', 'Available Start Date', and other
date fields that expect mm/dd/yyyy format.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:04:10 -08:00
fdb0224226 Fix date inputs and dismiss date picker/sub-form popups
- Start date fields now return mm/dd/yyyy format instead of "Immediately"
- Cancel any open sub-forms or date pickers before filling (handles
  stacked popups with double-cancel check)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:02:35 -08:00
029360b118 Dismiss LinkedIn education/experience sub-forms before filling
LinkedIn sometimes opens an Add Education/Experience sub-form with
Save/Cancel buttons that blocks the main Next button. Detect and
cancel these before attempting to fill the step.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:54:40 -08:00
ad281d1a9f Retry stuck/incomplete jobs instead of marking permanently failed
Stuck and incomplete jobs now get retried up to max_retries (default 2)
before being permanently marked. Honeypots are still permanent.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:51:20 -08:00
d0a40e4654 Batch CDP calls: single-evaluate debug info, data-claw-idx tagging, field count logging
- getModalDebugInfo: one evaluate() for heading, buttons, errors (was N+2 calls)
- selectOptionFuzzy: batch-read option texts in one evaluate (was N calls)
- Tag elements with data-claw-idx during snapshot, query by attribute in fill()
  (fixes fragile positional index matching for checkboxes/inputs)
- Log field counts per fill step for debugging

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:50:47 -08:00
a956b98941 Stop auto-checking 'top choice' and 'interested' checkboxes
Only auto-check confirm/agree/consent checkboxes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:46:03 -08:00
23eb5284fa Fix snapshot evaluate: scope queries to container element, handle Page fallback
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:42:41 -08:00
aeb41b42c2 Optimize form_filler: batch DOM reads into single evaluate() call
Instead of 60+ sequential CDP round-trips per step (isVisible, getLabel,
inputValue, isRequired for each element), snapshot all form state in one
evaluate() call, do answer matching locally, then only make CDP calls to
fill/click elements that need action.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:39:18 -08:00
d2de496d27 Track apply_started_at per job and log duration on success
Adds timing data to queue entries and shows seconds in the apply log.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:30:11 -08:00
dc7113907b Fix Anthropic API 404 — correct model ID to claude-sonnet-4-6
The dated model ID claude-sonnet-4-6-20251101 doesn't exist, causing
keyword generation to fall back to static keywords.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:24:38 -08:00
6d325cf931 Add timestamps to searcher start/finish logs for run tracking
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:22:48 -08:00
d5e595475c fix: 6h cooldown guard on searcher — prevents accidental re-runs 2026-03-06 22:18:25 +00:00
c4e5dbc32a Fix Telegram code block rendering — remove leading spaces from messages
Telegram Markdown treats lines starting with spaces as preformatted code
blocks. Replaced leading spaces with bullet points and arrows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:14:47 -08:00
ba4bc9ac03 Fix status Telegram: keep markdown in console output for agent relay
When --telegram, send directly and don't print. Otherwise keep * in
console output so agents capturing stdout can relay with formatting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:13:01 -08:00
199175f5f6 Add --telegram flag to status report, fix missing duplicate/closed counts
status.mjs --telegram sends the report to Telegram with proper bold formatting.
Console output strips markdown. Queue total now accounts for duplicates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:09:19 -08:00
cd454f8cc2 Clean up status report and apply summary
Status: only show non-zero queue counts, compact breakdown line,
remove emoji clutter
Apply summary: remove misleading green check on header, show applied/total

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:05:45 -08:00
b0a2eb3746 Fix fieldset radios: validate answers against options, fix checkbox skip, fix authorization match
Tested against Webflow (4311307116) and Scout Global (4378934058):
- Webflow: reaches Review page with all radios checked and checkbox group selected
- Scout Global: already applied successfully with select fix

Three fixes:
1. Fieldset radio answers validated against available options - prevents
   experience pattern returning "7" when options are Yes/No
2. Checkbox groups no longer skipped when one checkbox already checked -
   was preventing multi-select from working on retry
3. "authoriz" pattern matches both "authorized" and "authorization"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:05:02 -08:00
053c0b1242 Fix select answer mismatch: validate answer against available options
Built-in answerFor() could return a number (e.g. "7" for years experience)
when the select only has Yes/No options, causing selectOptionFuzzy to fail
silently. Now checks if the answer matches any available option before using
it, falling through to AI with actual options if not.

Also added "right to work" to work authorization pattern matching.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 13:44:49 -08:00
87cfce8eca Filter: stop spamming Telegram on submit, collect+submit in one run
- Removed Telegram notification on batch submit (only notify on collect
  when results are ready)
- After collecting, immediately submit remaining unscored jobs in the
  same run instead of waiting for next cron cycle

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 13:39:19 -08:00
c99ea10585 Richer search and filter summaries
Search: show per-track breakdown (found/added per track name)
Filter: show top 5 scoring jobs with score, title, company and cost

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 13:34:21 -08:00
82fa2b3697 Rich apply summary with per-job details (title, company, link)
Each job now shows title @ company with a clickable link, grouped by
status category. Only non-empty categories are shown.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 13:30:58 -08:00
615899e9a9 Normalize fieldset legend text same as getLabel (dedup, strip Required)
Legend text was saved to answers.json with duplicated text and "Required"
suffix, causing pattern mismatches on future runs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 13:27:45 -08:00
4048d8e5c4 docs: all crons silent — scripts send own Telegram summaries 2026-03-06 21:27:15 +00:00
50be273d9d docs: update cron defaults — applier silent, add git pull cron 2026-03-06 21:26:45 +00:00
094824abb2 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 <noreply@anthropic.com>
2026-03-06 13:23:39 -08:00
97aa8472aa Fix radio selection: verify click worked, fallback to input/select
LinkedIn radio clicks via label can silently fail. Now verifies input:checked
after label click, falls back to clicking radio input directly by value match,
and tries <select> within fieldset as last resort.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 13:16:30 -08:00
bb0c96dd3d 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>
2026-03-06 12:48:03 -08:00
3e367687b2 Fix checkbox group (multi-select) handling in form filler
LinkedIn forms with "Select all that apply" questions use checkbox groups
inside fieldsets. The fieldset handler only clicked one label (radio behavior).
Now detects checkbox vs radio fieldsets and splits comma-separated AI answers
to click multiple labels. Also added "consent" to auto-check keyword list.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:43:58 -08:00
26afc803a5 Navigate directly to apply URL instead of finding/clicking Easy Apply button
LinkedIn's apply URL pattern is {jobUrl}/apply/?openSDUIApplyFlow=true
which opens the modal directly. This eliminates:
- Button finding with waitForSelector (flaky on slow loads)
- Click retry logic
- "Continue" link fallback for draft applications
- Shadow DOM piercing for button detection

Tested: modal opens reliably, meta readable from background page,
form + progress bar present, 3.4s total navigation time.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:32:34 -08:00
7a730f689e Use networkidle for job page navigation to fix intermittent button miss
domcontentloaded fires before JS renders the Easy Apply button,
causing flaky "No Easy Apply button found" failures on valid listings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:28:50 -08:00
c5ebdc9362 Fix answer saving: normalize answers format, improve label dedup
- normalizeAnswers() handles both object {"q":"a"} and array [{pattern,answer}]
  formats — prevents silent failures when answers.json format varies
- getLabel() now strips "Required" suffix before dedup, uses smarter
  prefix-repeat detection instead of simple half-split
- telegram_answers.mjs also normalizes on load
- Cleaned existing answers.json on AWS: removed duplicated text in patterns,
  fixed bad AI answer for "Current company", generalized Geotab-specific patterns

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:24:10 -08:00
4419363b3c Fix process exit: use process.exit() directly instead of logStream.end callback
logStream.end() callback wasn't firing reliably, leaving processes hanging.
process.exit() is synchronous and forces exit regardless of open handles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:21:55 -08:00
d43e2025b2 Fix process not exiting after run, detect closed job listings
- All entry points with log tee now call logStream.end() + process.exit()
  (log stream kept event loop alive, blocking next cron run)
- easy_apply: detect "no longer accepting applications" and similar closed
  listing text before reporting as unsupported

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:19:00 -08:00
a498f49b95 Fix critical import bugs in linkedin.mjs and wellfound.mjs, clean up status/setup
- linkedin.mjs: LINKEDIN_LINKEDIN_MAX_SEARCH_PAGES → LINKEDIN_MAX_SEARCH_PAGES
  (typo would crash searcher at module load — constant doesn't exist)
- wellfound.mjs: WELLFOUND_WELLFOUND_MAX_INFINITE_SCROLL → WELLFOUND_MAX_INFINITE_SCROLL
  (same — doubled prefix crashes at import)
- status.mjs: remove double-counting ATS from both queue and log
- setup.mjs: replace PM2 instructions with OpenClaw crons

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:15:52 -08:00
51ca354c52 Audit fixes: remove dead code, fix run timeout bug, add log tee to all entry points
- Remove unused APPLY_PRIORITY array (replaced by score-based sort)
- Fix run timeout only breaking inner loop — now breaks outer platform loop too
- Remove dead lastProgress variable in easy_apply step loop
- Add stdout/stderr log tee to job_searcher, job_filter, telegram_poller

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:13:01 -08:00