npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

job-form-filler

v1.3.0

Published

Chrome Extension and Bridge/MCP Server for 0-token and AI-assisted job application form filling

Readme

⚡ Job Form Filler (0-Token & AI Hybrid)

Розширення для Google Chrome + опційний локальний міст (Local Bridge & MCP Server) для заповнення форм вакансій (Ashby, Greenhouse, Lever, Workable, LinkedIn Easy Apply, Djinni та будь-які інші).

Замість того щоб віддавати ШІ весь DOM або скріншоти, розширення ділить поля на рівні:

  1. Tier 1 (0 токенів): стандартні поля (ім'я, контакти, адреса, лінки, дозвіл на роботу, віза, релокація, notice period, зарплата, EEO, файл резюме) заповнюються локально з вашого профілю.
  2. Tier 2 (мінімум токенів): ШІ отримує лише незаповнені питання (зі стабільними fieldId та варіантами відповідей) і стислий текст вакансії.
  3. Tier 3 (людина): мотиваційні/поведінкові питання ШІ ніколи не пише — вони повертаються вам.

🚀 Швидкий старт (без мосту, без ШІ)

  1. chrome://extensions/ → увімкніть Developer mode → Load unpacked → оберіть папку extension/.

  2. Відкрийте попап → вкладка 👤 Профіль → заповніть дані → 💾 Зберегти. Там же завантажте файл резюме (PDF/DOCX до 5 МБ).

    • Або ⬆️ Імпорт готового profile.json (формат — як у ⬇️ Експорт; поля описані в extension/shared/default-profile.js).
    • Або заповніть одну форму вручну й натисніть 🧠 Запам'ятати з цієї форми: розпізнані стандартні поля потраплять у профіль.
    • Або попросіть агента через MCP: «заповни мій профіль у job-form-filler з мого резюме» (тул update_candidate_profile).

    Обидва автоматичні шляхи заповнюють лише порожні поля профілю. Розбіжності з уже збереженими значеннями показуються, але не застосовуються.

  3. Відкрийте форму вакансії → ⚡ Заповнити стандартні поля. Попап покаже, яких даних бракує в профілі та які поля не вдалося заповнити.

Профіль і резюме зберігаються лише локально в chrome.storage.local. Розширення ніколи не перезаписує поля, які ви вже заповнили.

Формат профілю

{
  "personal": { "firstName": "", "lastName": "", "email": "", "phoneCountryCode": "+380", "phone": "", "city": "", "country": "" },
  "links": { "linkedin": "", "github": "", "website": "" },
  "work": { "currentCompany": "", "currentTitle": "", "yearsOfExperience": "", "noticePeriod": "", "salaryExpectation": "" },
  "legal": { "authorizedToWork": "Yes", "requiresSponsorship": "No", "willingToRelocate": "" },
  "eeo": {},
  "profiles": { "frontend-developer": { "title": "Senior Frontend Developer", "summary": "..." } },
  "localized": { "uk": { "personal": { "firstName": "Дмитро", "city": "Вінниця" }, "work": { "noticePeriod": "2 тижні" } } }
}

Порожні EEO-поля (gender, ethnicity, veteran, disability) заповнюються варіантом «Decline to self-identify» мовою форми. profiles — необов'язкові варіанти ролі (обираються в попапі).

Щоб додати нове стандартне поле: рядок у PROFILE_FIELDS (extension/shared/default-profile.js), правило в FIELD_RULES та значення в profileValue (extension/content/content.js).

🌍 Мови

Підтримувані мови: English, Українська, Polski, Deutsch, Français, Español, Italiano, Português, Nederlands. Російська свідомо не підтримується.

  • Форми розпізнаються всіма цими мовами. Мова форми визначається за підписами полів (кирилиця → uk, польські літери → pl), а <html lang> використовується як запасний варіант. ATS часто лишають там en.
  • Значення: основний профіль заповнюється однією мовою, а для інших мов можна задати переклади (вкладка «Профіль» → «Переклади для форм іншими мовами», у JSON це localized.<lang>). На формі цією мовою спершу береться переклад. Назви країн («Ukraine» ⇄ «Україна» ⇄ «Ucraina») і «Так/Ні» перекладаються автоматично.
  • «Запам'ятати з цієї форми» на неанглійській формі записує значення, що відрізняються від профілю, як переклади цієї мови.
  • ШІ відповідає мовою форми (get_active_job_form.language). Tier 3 (особисті питання) розпізнається всіма цими мовами.
  • Інтерфейс перекладено тими самими мовами (португальська — pt_BR і pt_PT). Мова обирається за мовою браузера, за замовчуванням англійська (extension/_locales/). Щоб додати мову інтерфейсу, створіть _locales/<lang>/messages.json з тими самими ключами, що й в uk.
  • Щоб додати мову форм: по рядку в кожному правилі FIELD_RULES (content.js), мову в FORM_LANGUAGES (default-profile.js) і шаблони в HUMAN_PATTERNS (server/human-questions.js).

🔌 Міст і MCP (для Claude Code / AGY)

npm install
npm run bridge            # http://127.0.0.1:8765, ws://127.0.0.1:8765/ws

Підключіть MCP-сервер (~/.claude/mcp.json або claude mcp add):

{
  "mcpServers": {
    "job-form-filler": {
      "command": "node",
      "args": ["/path/to/job-form-filler/bin/mcp.js"],
      "env": { "RESUME_REPO_PATH": "/path/to/your/resume-repo" }
    }
  }
}

Агент отримує інструкції робочого циклу від самого MCP-сервера: autofill_static_fields → get_active_job_form → get_candidate_profile → fill_job_form → ви перевіряєте й натискаєте Submit → get_submission_status.

Змінні оточення (усі опційні)

| Змінна | Що робить | |---|---| | RESUME_REPO_PATH | Папка з варіантами резюме: <repo>/resume/<role>/*.md, *.pdf або <repo>/<role>/.... За замовчуванням не задано (функція вимкнена). Дає варіанти ролей у попапі, PDF для завантаження і markdown-факти для ШІ. Назви файлів довільні (перевага resume*/cv*). | | BRIDGE_PORT | Порт мосту (за замовчуванням 8765). | | JFF_DATA_DIR | Куди зберігати learned answers і заявки без репо (за замовчуванням ~/.job-form-filler). |


🎯 Як це працює

Крок 0: навігація — ваша відповідальність

Відкрийте вкладку з формою самі (або іншим інструментом). Цей інструмент ніколи не переходить за URL.

Попап

  • ⚡ Заповнити стандартні поля — 0 токенів.
  • 📋 Скопіювати промпт для CLI — компактний промпт з fieldId і варіантами відповідей для будь-якого агента.
  • 💾 Зберегти в репо — job-posting.md у <role>/applications/<company>/ (або ~/.job-form-filler/applications/).
  • 🧠 Запам'ятати з цієї форми — стандартні поля, заповнені вручну, додаються в профіль (лише порожні слоти); відповіді на нестандартні питання зберігаються для наступних форм.

🔒 Безпека та контроль

❌ Submit — НІКОЛИ не натискається автоматично

Це навмисне архітектурне рішення безпеки, а не відсутня фіча.

  • Жоден MCP-тул, команда bridge або дія попапу не може натиснути кнопку Submit / Apply.
  • Якщо майбутній контриб'ютор захоче додати submit_form — не треба: ризик випадкової подачі резюме на небажану вакансію є неприйнятним.
  • get_submission_status лише читає заголовок сторінки після того, як ви натиснули Submit.

🧑 Tier 3 — Питання, що потребують людини

Поведінкові («Розкажіть про випадок, коли…»), мотиваційні («Чому саме зараз?») та особистісні питання ніколи не заповнюються ШІ. get_active_job_form позначає їх humanRequired: true.

Міст

  • Слухає лише 127.0.0.1; приймає запити тільки від розширення (chrome-extension://) та локальних процесів без Origin. Веб-сторінки отримують 403 (захист від читання профілю й DNS-rebinding).
  • Персональні дані (learned answers, заявки) зберігаються поза папкою проєкту.

🛠 MCP-інструменти

| Інструмент | Опис | |---|---| | autofill_static_fields | Заповнює Tier 1 поля; повертає filled, missingProfile, failed | | get_active_job_form | Незаповнені питання (fieldId, label, options, humanRequired) + метадані вакансії | | get_form_state | Поточні значення всіх полів форми (заповнених і порожніх): перевірка після автозаповнення; паролі приховані, файли — імена, групи чекбоксів — позначені опції | | click_button | Просуває багатокрокову форму кнопкою навігації (Continue/Next/Apply Now/Продовжити/Далі): точний збіг мітки; Submit/Send/Apply/Delete/Pay та кнопки з такою aria-label відхиляються; фінальний Submit завжди натискає користувач | | fill_job_form | Вписує відповіді за fieldId; повертає failed, notFound | | get_candidate_profile | Профіль з розширення + markdown резюме обраного варіанту ролі | | update_candidate_profile | Записує дані в профіль розширення (лише відомі поля; наявні значення — тільки з overwrite) | | save_job_application | Зберігає job-posting.md (+ cover letter); використовуйте log_application для запису результату | | get_job_posting | Отримує повний текст, вимоги та питання вакансії серверно без браузера | | log_application | Логує результат заявки (submitted/skipped) до info/applications-log.md, профілю резюме та job-posting.md. Ідемпотентна за URL чи company+date. Підтримує dryRun | | get_submission_status | Перевіряє URL (/confirm, /applied, /thank-you, /connect/dashboard) і текст/заголовок після Submit; повертає matchedBy |

🧪 Тести

npm test