{"_id":"@andy-toolforge/jobscan","_rev":"5-5dcda19a184149ae21f5f49a0f9b38f0","name":"@andy-toolforge/jobscan","dist-tags":{"latest":"0.3.4"},"versions":{"0.1.0":{"name":"@andy-toolforge/jobscan","version":"0.1.0","_id":"@andy-toolforge/jobscan@0.1.0","maintainers":[{"name":"andy_pham","email":"phamlehoaian@gmail.com"}],"homepage":"https://github.com/andy-pham-it/toolforge#readme","bugs":{"url":"https://github.com/andy-pham-it/toolforge/issues"},"bin":{"jobscan":"bin/jobscan.js"},"dist":{"shasum":"0372c78124e646eaf1a0eb8cdacde9441bf12d5a","tarball":"https://registry.npmjs.org/@andy-toolforge/jobscan/-/jobscan-0.1.0.tgz","fileCount":33,"integrity":"sha512-TcUcKYZxnReQivEfvyoGOCKzufR+6T5mDQ7l2TjQrLGXTtfz6+3yOCL+h0bQzAn3vp3BcXqUBkXUDQSLCi/E1Q==","signatures":[{"sig":"MEUCIAHT21/l482PF2S3oZsKQJGZf5ZQ7oKLzfz+Qv3RtywhAiEAkqgSdsBGr/WtB+c6PT/JwsjocALQv78ttXNGG8ry9DE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":95041},"main":"lib/index.js","gitHead":"75b9f07859d84bf1d2f74786515775ab70c65563","scripts":{"test":"node --test lib/*.test.js","postinstall":"node skills/postinstall.js"},"_npmUser":{"name":"andy_pham","email":"phamlehoaian@gmail.com"},"repository":{"url":"git+https://github.com/andy-pham-it/toolforge.git","type":"git"},"_npmVersion":"10.8.2","description":"Toolforge domain: freemium job-scan CLI","directories":{},"_nodeVersion":"20.20.2","dependencies":{"js-yaml":"^5.4.1","commander":"^12.0.0","@andy-toolforge/core":"^1.3.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jobscan_0.1.0_1788608850314_0.6676532219312132","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@andy-toolforge/jobscan","version":"0.3.0","_id":"@andy-toolforge/jobscan@0.3.0","maintainers":[{"name":"andy_pham","email":"phamlehoaian@gmail.com"}],"homepage":"https://github.com/andy-pham-it/toolforge#readme","bugs":{"url":"https://github.com/andy-pham-it/toolforge/issues"},"bin":{"jobscan":"bin/jobscan.js"},"dist":{"shasum":"7e0d40db40fb94c37472be55b98c840b81cd8db8","tarball":"https://registry.npmjs.org/@andy-toolforge/jobscan/-/jobscan-0.3.0.tgz","fileCount":39,"integrity":"sha512-eA1BJZfnZfTh499OiMC6m44HtLmDfX0Aj1e0ePr38G6/arJdirJhgC0dpVIUdk1SMXYZBwWr8ijsFbVcim/L+g==","signatures":[{"sig":"MEYCIQDH1ddlqDOZ7miEkrQA4TCADOZTzPm+LDo4J1NhQzyLbgIhAJtQhyBpFclXdYml1sVakrJcwdrl5yz01nwrVgu2uys6","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCheZcxmJBlenxdXLyG8QS4H80m5EzcAFbT6q8tJ9o5fQIhAOwiFP5gdlwt3JAlHcVSV3QBOVvpUxyOX0z7yK1zWhwc","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":127288},"main":"lib/index.js","gitHead":"c25554fc7b0b322ce14ee61fd56060b6506afdfc","scripts":{"test":"node --test lib/*.test.js","postinstall":"node skills/postinstall.js"},"_npmUser":{"name":"andy_pham","email":"phamlehoaian@gmail.com"},"repository":{"url":"git+https://github.com/andy-pham-it/toolforge.git","type":"git"},"_npmVersion":"10.8.2","description":"Toolforge domain: freemium job-scan CLI","directories":{},"_nodeVersion":"20.20.2","dependencies":{"js-yaml":"^5.4.1","commander":"^12.0.0","@andy-toolforge/core":"^1.3.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jobscan_0.3.0_1788619169214_0.7896190559831018","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@andy-toolforge/jobscan","version":"0.3.2","_id":"@andy-toolforge/jobscan@0.3.2","maintainers":[{"name":"andy_pham","email":"phamlehoaian@gmail.com"}],"homepage":"https://github.com/andy-pham-it/toolforge#readme","bugs":{"url":"https://github.com/andy-pham-it/toolforge/issues"},"bin":{"jobscan":"bin/jobscan.js"},"dist":{"shasum":"ddc1cbd0c52ea219596ac2659374d64564cfe6ff","tarball":"https://registry.npmjs.org/@andy-toolforge/jobscan/-/jobscan-0.3.2.tgz","fileCount":39,"integrity":"sha512-GnEYkq7QtS5bQSzJx+T1uFELReCkap+EQClLdj1PN16LlzLL1E/BDqkl/mtQcsspzXd6/3HFvDTCpjZccwflFA==","signatures":[{"sig":"MEQCIEzeyhz8Shxxq9/iUI3HwlalW0NyGUjfzZr04+mXq62oAiA5yej3/oL1JfgYJCWVg44WpHArMr7BReGyUYgiD64oOA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCDBELbwhp3Anr2h9MzrpHJfGpg9KYPfQL8P8j+X+N+lgIgalAE2GmxEFhrcv5sUvijotQK5k/a8rGMcwdkmQixMQ0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":133715},"main":"lib/index.js","gitHead":"0e08d6377e2e3c96a72d89fcb2874a70896a91b2","scripts":{"test":"node --test lib/*.test.js","postinstall":"node skills/postinstall.js"},"_npmUser":{"name":"andy_pham","email":"phamlehoaian@gmail.com"},"repository":{"url":"git+https://github.com/andy-pham-it/toolforge.git","type":"git"},"_npmVersion":"10.8.2","description":"Toolforge domain: freemium job-scan CLI","directories":{},"_nodeVersion":"20.20.2","dependencies":{"js-yaml":"^5.4.1","commander":"^12.0.0","@andy-toolforge/core":"^1.3.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jobscan_0.3.2_1788625821089_0.839504749278976","host":"s3://npm-registry-packages-npm-production"}},"0.3.3":{"name":"@andy-toolforge/jobscan","version":"0.3.3","_id":"@andy-toolforge/jobscan@0.3.3","maintainers":[{"name":"andy_pham","email":"phamlehoaian@gmail.com"}],"homepage":"https://github.com/andy-pham-it/toolforge#readme","bugs":{"url":"https://github.com/andy-pham-it/toolforge/issues"},"bin":{"jobscan":"bin/jobscan.js"},"dist":{"shasum":"1ed71843fa4c8da577610b058a174b0dbaaf1f7c","tarball":"https://registry.npmjs.org/@andy-toolforge/jobscan/-/jobscan-0.3.3.tgz","fileCount":41,"integrity":"sha512-CrjorhO2f6tnIXpZ3/Tw7hC9YhKKcjtJT0+Yed4fkBsWdj1F26L9bSe0FAyzGollcSJ01Yw2/fZt9/xeXEJmmg==","signatures":[{"sig":"MEQCIHhrXoYhKXfhn+5nfYhAEgs5VJxAroCS69j4qgICQeFxAiBp9Qw2GWJVZWCHnTuX7CcJ3F0/nHYnE8x4md0HlxbvGA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQC8mvM4mIHI0vG2QJ7kcZlxyYqqlt6a0JlkNyqnZL16EAIgS8mFXRx8FWUG6qzsNwJxOQw8vJJTtD+zogdi45JO6ko=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":145360},"main":"lib/index.js","gitHead":"6976bb1d5cd13f3bba71cc36554ea11a34c72fd3","scripts":{"test":"node --test lib/*.test.js","postinstall":"node skills/postinstall.js"},"_npmUser":{"name":"andy_pham","email":"phamlehoaian@gmail.com"},"repository":{"url":"git+https://github.com/andy-pham-it/toolforge.git","type":"git"},"_npmVersion":"10.8.2","description":"Toolforge domain: freemium job-scan CLI","directories":{},"_nodeVersion":"20.20.2","dependencies":{"js-yaml":"^5.4.1","commander":"^12.0.0","@andy-toolforge/core":"^1.3.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jobscan_0.3.3_1788626214297_0.5716635899954479","host":"s3://npm-registry-packages-npm-production"}},"0.3.4":{"_id":"@andy-toolforge/jobscan@0.3.4","bin":{"jobscan":"bin/jobscan.js"},"bugs":{"url":"https://github.com/andy-pham-it/toolforge/issues"},"dist":{"shasum":"462f1e64beabdb9835a536a36b7e47c2bfd9694c","tarball":"https://registry.npmjs.org/@andy-toolforge/jobscan/-/jobscan-0.3.4.tgz","fileCount":41,"integrity":"sha512-PuWchxNMkGPSEb87v/ST9ZVCoPNU4WfVC3lueC/BrXlvj6l9TK8U+aPYd+oK1KPmoCDvZTebo5eeeOP6yGinGA==","signatures":[{"sig":"MEUCIGUbXA2UTNHp8Pw2bdCpz/c6ytOjmRZU1Ez2WfqHuBruAiEA+4DIeg4zqBCiUjpWAN4SmZwpMOYYopkRfASja0Rg8ig=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGdCU7IDA4w3w+s4HDcrfYqWNhr0KZpQECxLDj32pzF1AiAiv37pUU9/qgHmPlmMh74EjtGGF9h9URoWHPoXpWy8BQ=="}],"unpackedSize":146076},"main":"lib/index.js","name":"@andy-toolforge/jobscan","gitHead":"a8eff2b7bc3d1d06d2045be79a7ed3d827e2003e","scripts":{"test":"node --test lib/*.test.js","postinstall":"node skills/postinstall.js"},"version":"0.3.4","_npmUser":{"name":"andy_pham","email":"phamlehoaian@gmail.com"},"homepage":"https://github.com/andy-pham-it/toolforge#readme","repository":{"url":"git+https://github.com/andy-pham-it/toolforge.git","type":"git"},"_npmVersion":"10.8.2","description":"Toolforge domain: freemium job-scan CLI","directories":{},"maintainers":[{"name":"andy_pham","email":"phamlehoaian@gmail.com"}],"_nodeVersion":"20.20.2","dependencies":{"js-yaml":"^5.4.1","commander":"^12.0.0","@andy-toolforge/core":"^1.3.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/jobscan_0.3.4_1788627574387_0.7855577399252824"}}},"time":{"created":"2026-09-05T11:47:30.173Z","modified":"2026-09-05T16:59:34.642Z","0.1.0":"2026-09-05T11:47:30.470Z","0.3.0":"2026-09-05T14:39:29.290Z","0.3.2":"2026-09-05T16:30:21.175Z","0.3.3":"2026-09-05T16:36:54.397Z","0.3.4":"2026-09-05T16:59:34.468Z"},"bugs":{"url":"https://github.com/andy-pham-it/toolforge/issues"},"homepage":"https://github.com/andy-pham-it/toolforge#readme","repository":{"url":"git+https://github.com/andy-pham-it/toolforge.git","type":"git"},"description":"Toolforge domain: freemium job-scan CLI","maintainers":[{"name":"andy_pham","email":"phamlehoaian@gmail.com"}],"readme":"# @andy-toolforge/jobscan\n\nFreemium job-scan CLI — scan ATS boards (Greenhouse / Lever / Ashby / SmartRecruiters / Workable / Recruitee / Pinpoint / Personio / RemoteOK) against a local resume, report keyword gaps. Local heuristic in free, LLM-tuned bullets in pro.\n\n## Install\n\n```bash\nnpm i -g @andy-toolforge/jobscan\n# or inside monorepo\nnpm install\n```\n\n## Quick start (no slug needed)\n\n```bash\n# example resume\ncp packages/jobscan/templates/resume.example.json ./resume.json\n\n# 1. save your companies once (paste careers page URLs — provider inferred)\njobscan init\njobscan companies --add https://boards.greenhouse.io/datadog\njobscan companies --list\n\n# 2. scan everything with no args (uses jobscan.yml; no file → RemoteOK board)\njobscan scan --resume ./resume.json\n\n# one-off scan from a URL, no config needed\njobscan scan --url https://jobs.lever.co/lever --resume ./resume.json\n\n# power users: explicit provider + slug still works\njobscan scan --provider greenhouse --company datadog --resume ./resume.json\n\n# pro (single company, valid license)\nexport JOBSCAN_LICENSE_PUBLIC_KEY=\"your-server-hmac-secret\"\njobscan license verify <key> --sig <hmac> --tier pro --expires 2026-12-31T00:00:00.000Z\njobscan scan --url https://boards.greenhouse.io/datadog --resume ./resume.json --pro\n```\n\n## Free vs Pro\n\n| Feature | Free | Pro (`--pro` + valid license) |\n|---------|------|-------------------------------|\n| Heuristic match (score, matched/missing, suggestions) | ✓ | ✓ |\n| `tailoredBullets`, `coverLetterHint`, `llmSuggestions` | — (placeholder) | ✓ via `@andy-toolforge/core` LLMClient |\n| `export --format md` pro section | stripped | included |\n| Batch (`jobscan batch`) | ✓ | ✓ (pro adds LLM fields when licensed) |\n\nPro uses Groq/Gemini via `@andy-toolforge/core` `LLMClient` adapter chain. Cost ~$0.01–0.03 per scan (depends on provider/model). Free never calls LLM — verified by `lib/llm.test.js` spy.\n\n## Providers (9 real, verified live — no stubs)\n\n- Greenhouse (`boards-api.greenhouse.io`)\n- Lever (`api.lever.co`)\n- Ashby (`api.ashbyhq.com`)\n- SmartRecruiters (`api.smartrecruiters.com` — list + N+1 detail fetch; IDs case-sensitive, e.g. `BoschGroup`)\n- Workable (`apply.workable.com` widget API, `?details=true` for inline descriptions)\n- Recruitee (`{company}.recruitee.com/api/offers/` — no-auth Careers Site API)\n- Pinpoint (`{slug}.pinpointhq.com/postings.json` — e.g. `workwithus`)\n- Personio (`{company}.jobs.personio.de/xml` — official XML feed, regex-parsed with zero new deps)\n- RemoteOK (`remoteok.com/api` — board-wide feed, no company slug; `--company` acts as optional company-name filter, use `all` for newest)\n\nEach honors `User-Agent: jobscan/0.3.4`, ≥2s gap + `Retry-After` / exponential backoff (3 retries). Greenhouse additionally checks `robots.txt` (best-effort). Research notes for the remaining ATS platforms live in `ROADMAP.md` — no stub files shipped. Workday and Jobvite are deferred (see ROADMAP).\n\n## Data attribution\n\nRemoteOK data requires a dofollow backlink attribution when displayed publicly. CLI matching and local reports are fine, but any public rendering of RemoteOK job descriptions (exported dashboard, website) must credit RemoteOK with a link.\n\n## Commands\n\n```\njobscan init                                        # create jobscan.yml\njobscan companies --add <careers-url>               # add company (provider inferred)\njobscan companies --list                            # list saved companies\njobscan scan [--resume <path>]                      # no args: jobscan.yml or RemoteOK board\njobscan scan --url <careers-url> [--resume <path>]  # one-off URL scan\njobscan scan --provider <name> --company <slug> [--resume <path>] [--pro]\njobscan license verify <key> [--sig <sig>] [--tier pro|free] [--expires <iso>]\njobscan license status\njobscan dashboard [--last]\njobscan batch <file>        # CSV (provider,company) or NDJSON {provider, company}\njobscan update --resume <path>   # 3-way merge, preserves custom, writes *.merge-conflict on conflict\njobscan export --format json|md  # tier-gated via DATA_CONTRACT\n```\n\nBatch is pure Node (no `batch-runner.sh`) — works on Windows/macOS/Linux.\n\nDashboard is Ink-style plain renderer (`lib/dashboard.js`); fallback when Ink ESM not installed.\n\n## Data contract\n\n`schemas/data-contract.v1.json` splits `core` (always) vs `pro` (gated):\n\n- core: `score`, `matchedKeywords`, `missingKeywords`, `suggestions`, `provider`, `url`, `fetchedAt`, `jobTitle`, `jobId`\n- pro: `llmSuggestions`, `tailoredBullets`, `coverLetterHint`\n\n`scanner.serialize(result, tier)` strips `pro` keys when `tier !== 'pro'`.\n\n## License grace\n\n`~/.config/jobscan/license.json` (0600, gitignored) is cache only — signature verified with `JOBSCAN_LICENSE_PUBLIC_KEY` (HMAC-SHA256 `tier|expiresAt|key`). Expired within 7 days + valid sig → still pro with warning; expired + 8 days → free. `XDG_CONFIG_HOME` overrides path for tests. Never commit `license.json` or plaintext secrets — hygiene check: `grep -r JOBSCAN_LICENSE_KEY packages/jobscan --include=\"*.json\" --include=\"*.md\"` must be empty (tested in CI).\n\n## Update / 3-way merge\n\n```\njobscan update --resume ./resume.json\n```\n\n- base = `resume.base.json` (last pulled)\n- local = current `resume.json` (user edits, `custom` preserved)\n- remote = latest scan suggestions\n\nOn conflict writes `resume.json.merge-conflict` (`<<<<<<<` markers) + `resume.json.merge-conflict.json` sidecar, does not overwrite original.\n\n## Roadmap\n\nSee `ROADMAP.md` — provider research notes, deferred Workday/Jobvite, rejected Breezy (HTML-scrape), + Next.js dashboard v2 (deferred).\n\n## Publish\n\nRoot `.github/workflows/publish.yml` checks `npm view @andy-toolforge/jobscan version` and publishes only on version bump. No per-package workflow.\n\n## Testing\n\n```bash\nnpm test -w @andy-toolforge/jobscan   # node --test lib/*.test.js\n```\n","readmeFilename":"README.md"}