qiksy 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +78 -0
- package/INSTALL-PROMPT.md +53 -0
- package/bin/qiksy.mjs +302 -0
- package/package.json +32 -0
- package/tools/client-finder/vendor/README.md +70 -0
- package/tools/client-finder/vendor/find.mjs +121 -0
- package/tools/client-finder/vendor/icp/assist-pl-shops.json +30 -0
- package/tools/client-finder/vendor/icp/assist-ua-shops.json +30 -0
- package/tools/client-finder/vendor/knowledge/assist.md +68 -0
- package/tools/client-finder/vendor/knowledge/custom.md +36 -0
- package/tools/client-finder/vendor/knowledge/multilogin.md +29 -0
- package/tools/client-finder/vendor/knowledge/pay.md +26 -0
- package/tools/client-finder/vendor/knowledge/qa-copilot.md +43 -0
- package/tools/client-finder/vendor/knowledge/travel.md +43 -0
- package/tools/client-finder/vendor/knowledge/work-finder.md +52 -0
- package/tools/client-finder/vendor/lib/access.mjs +108 -0
- package/tools/client-finder/vendor/lib/agent.mjs +204 -0
- package/tools/client-finder/vendor/lib/approver-mcp.mjs +78 -0
- package/tools/client-finder/vendor/lib/browser.mjs +108 -0
- package/tools/client-finder/vendor/lib/catalog.mjs +86 -0
- package/tools/client-finder/vendor/lib/channels.mjs +54 -0
- package/tools/client-finder/vendor/lib/deliver.mjs +89 -0
- package/tools/client-finder/vendor/lib/engine.mjs +283 -0
- package/tools/client-finder/vendor/lib/formats.mjs +108 -0
- package/tools/client-finder/vendor/lib/jobs.mjs +75 -0
- package/tools/client-finder/vendor/lib/knowledge.mjs +26 -0
- package/tools/client-finder/vendor/lib/prompts.mjs +183 -0
- package/tools/client-finder/vendor/lib/report.mjs +75 -0
- package/tools/client-finder/vendor/lib/scope.mjs +162 -0
- package/tools/client-finder/vendor/lib/spawn-claude.mjs +44 -0
- package/tools/client-finder/vendor/lib/verify.mjs +96 -0
- package/tools/client-finder/vendor/package.json +8 -0
- package/tools/client-finder/vendor/server.mjs +390 -0
- package/tools/travel/vendor/README.md +58 -0
- package/tools/travel/vendor/docs/CONTRACT.md +174 -0
- package/tools/travel/vendor/docs/ENGINE-MIGRATION.md +33 -0
- package/tools/travel/vendor/lib/agent.mjs +190 -0
- package/tools/travel/vendor/lib/engine.mjs +283 -0
- package/tools/travel/vendor/lib/jobs.mjs +125 -0
- package/tools/travel/vendor/lib/license.mjs +41 -0
- package/tools/travel/vendor/lib/plans.mjs +28 -0
- package/tools/travel/vendor/lib/prompts.mjs +394 -0
- package/tools/travel/vendor/lib/proposal.mjs +207 -0
- package/tools/travel/vendor/lib/spawn-claude.mjs +44 -0
- package/tools/travel/vendor/lib/store.mjs +75 -0
- package/tools/travel/vendor/package.json +12 -0
- package/tools/travel/vendor/public/app.js +996 -0
- package/tools/travel/vendor/public/index.html +112 -0
- package/tools/travel/vendor/public/styles.css +760 -0
- package/tools/travel/vendor/scripts/approver-mcp.mjs +80 -0
- package/tools/travel/vendor/scripts/launch-browser.mjs +77 -0
- package/tools/travel/vendor/server.mjs +755 -0
- package/tools/work-finder/vendor/.claude/settings.local.json +27 -0
- package/tools/work-finder/vendor/.mcp.json +9 -0
- package/tools/work-finder/vendor/CLAUDE.md +24 -0
- package/tools/work-finder/vendor/README.md +44 -0
- package/tools/work-finder/vendor/bin/qiksy-work-finder.mjs +127 -0
- package/tools/work-finder/vendor/lib/agent.mjs +159 -0
- package/tools/work-finder/vendor/lib/catalog.mjs +41 -0
- package/tools/work-finder/vendor/lib/channels.mjs +73 -0
- package/tools/work-finder/vendor/lib/engine.mjs +283 -0
- package/tools/work-finder/vendor/lib/jobs.mjs +127 -0
- package/tools/work-finder/vendor/lib/license.mjs +60 -0
- package/tools/work-finder/vendor/lib/linkcheck.mjs +72 -0
- package/tools/work-finder/vendor/lib/linkedin.mjs +22 -0
- package/tools/work-finder/vendor/lib/plans.mjs +33 -0
- package/tools/work-finder/vendor/lib/prompts.mjs +217 -0
- package/tools/work-finder/vendor/lib/spawn-claude.mjs +44 -0
- package/tools/work-finder/vendor/lib/store.mjs +125 -0
- package/tools/work-finder/vendor/package.json +41 -0
- package/tools/work-finder/vendor/public/app.js +1863 -0
- package/tools/work-finder/vendor/public/index.html +518 -0
- package/tools/work-finder/vendor/public/styles.css +930 -0
- package/tools/work-finder/vendor/scripts/approver-mcp.mjs +69 -0
- package/tools/work-finder/vendor/scripts/extract-linkedin.mjs +81 -0
- package/tools/work-finder/vendor/scripts/launch-browser.mjs +78 -0
- package/tools/work-finder/vendor/scripts/screenshot.mjs +17 -0
- package/tools/work-finder/vendor/server.mjs +1006 -0
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>Work Finder</title>
|
|
7
|
+
<link rel="stylesheet" href="styles.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<script>
|
|
11
|
+
/* Pre-paint gate: set body.gated BEFORE the app views parse, so a no-key visitor never
|
|
12
|
+
flashes the app before app.js runs (the gate CSS hides app views while .gated). */
|
|
13
|
+
try {
|
|
14
|
+
var _k = localStorage.getItem('workFinder_anthropicKey');
|
|
15
|
+
if (!_k || !_k.trim()) document.body.classList.add('gated');
|
|
16
|
+
} catch (e) {}
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<header class="topbar">
|
|
20
|
+
<div class="brand">
|
|
21
|
+
<span class="brand-mark" aria-hidden="true">
|
|
22
|
+
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
23
|
+
<rect width="20" height="14" x="2" y="7" rx="2" ry="2"/>
|
|
24
|
+
<path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/>
|
|
25
|
+
</svg>
|
|
26
|
+
</span>
|
|
27
|
+
<b>Work Finder</b>
|
|
28
|
+
</div>
|
|
29
|
+
<nav class="nav">
|
|
30
|
+
<button class="nav-tab active" data-tab="jobs" data-i18n="nav.jobs">Jobs</button>
|
|
31
|
+
<button class="nav-tab" data-tab="leads"><span data-i18n="nav.leads">Leads</span> <span id="leads-count" class="nav-badge"></span></button>
|
|
32
|
+
<button class="nav-tab" data-tab="profiles" data-i18n="nav.profiles">Profiles</button>
|
|
33
|
+
<button class="nav-tab" data-tab="settings" data-i18n="nav.settings">Settings</button>
|
|
34
|
+
</nav>
|
|
35
|
+
<div class="topbar-right">
|
|
36
|
+
<span id="credits-pill" class="pill" hidden></span>
|
|
37
|
+
<span id="browser-status" class="pill">…</span>
|
|
38
|
+
<div class="lang-switch" role="group" aria-label="Language">
|
|
39
|
+
<button type="button" class="lang-btn active" data-lang="en">EN</button>
|
|
40
|
+
<button type="button" class="lang-btn" data-lang="ru">RU</button>
|
|
41
|
+
</div>
|
|
42
|
+
<button id="theme-toggle" class="pill theme-btn" data-i18n-title="topbar.themeToggle" title="Toggle theme">🌙</button>
|
|
43
|
+
</div>
|
|
44
|
+
</header>
|
|
45
|
+
|
|
46
|
+
<!-- ══════════ LANDING (key gate) ══════════ -->
|
|
47
|
+
<main id="view-landing" class="view landing" hidden>
|
|
48
|
+
|
|
49
|
+
<div class="lp-topline">
|
|
50
|
+
<span class="lp-badge"><span class="lp-badge-dot"></span><span data-i18n="landing.badge">AI job-hunt agents</span></span>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<!-- HERO -->
|
|
54
|
+
<section class="lp-hero">
|
|
55
|
+
<div class="lp-hero-copy">
|
|
56
|
+
<h1 class="lp-title" data-i18n="landing.heroTitle">Your job hunt, on autopilot.</h1>
|
|
57
|
+
<p class="lp-sub" data-i18n="landing.heroSub">Work Finder runs Claude agents that scan the whole market, match roles to your profile, and prepare tailored applications — while you get on with your day.</p>
|
|
58
|
+
<div class="lp-hero-cta">
|
|
59
|
+
<button class="btn primary big" id="landing-cta" data-i18n="landing.heroCta">Connect your key & start</button>
|
|
60
|
+
<span class="lp-hero-note" data-i18n="landing.heroNote">Bring your own Anthropic key · runs locally in your browser</span>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
<div class="lp-hero-art" aria-hidden="true">
|
|
64
|
+
<div class="lp-run">
|
|
65
|
+
<div class="lp-run-head"><span class="lp-run-dot"></span><b data-i18n="widget.working">Agents working…</b></div>
|
|
66
|
+
<div class="lp-run-row"><span class="spin">⏳</span><span data-i18n="landing.pipeScan">Scanning companies that are hiring</span></div>
|
|
67
|
+
<div class="lp-run-row"><span class="spin">⏳</span><span data-i18n="landing.pipeMatch">Matching roles to the profile</span></div>
|
|
68
|
+
<div class="lp-run-row done"><span>✅</span><span data-i18n="landing.pipeDraft">12 roles found · 4 letters drafted</span></div>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</section>
|
|
72
|
+
|
|
73
|
+
<!-- HOW IT WORKS -->
|
|
74
|
+
<section class="lp-section">
|
|
75
|
+
<h2 class="lp-h2" data-i18n="landing.howTitle">How it works</h2>
|
|
76
|
+
<div class="lp-steps">
|
|
77
|
+
|
|
78
|
+
<article class="lp-step">
|
|
79
|
+
<div class="lp-step-n">1</div>
|
|
80
|
+
<h3 class="lp-step-title" data-i18n="landing.step1Title">Add a candidate</h3>
|
|
81
|
+
<p class="lp-step-text" data-i18n="landing.step1Text">Drop in a name and a LinkedIn — the resume imports itself and roles are picked automatically.</p>
|
|
82
|
+
<div class="lp-mock lp-mock-profile" aria-hidden="true">
|
|
83
|
+
<div class="lp-pc-head">
|
|
84
|
+
<span class="lp-ava" style="background:hsl(210,58%,52%)">A</span>
|
|
85
|
+
<div><div class="lp-pc-name">Alex Carter</div><div class="lp-pc-sub">Kyiv · remote</div></div>
|
|
86
|
+
</div>
|
|
87
|
+
<div class="lp-chips">
|
|
88
|
+
<span class="lp-chip on" data-i18n="landing.roleBackend">Senior Backend Engineer</span>
|
|
89
|
+
<span class="lp-chip" data-i18n="landing.roleDevops">DevOps Engineer</span>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
</article>
|
|
93
|
+
|
|
94
|
+
<article class="lp-step">
|
|
95
|
+
<div class="lp-step-n">2</div>
|
|
96
|
+
<h3 class="lp-step-title" data-i18n="landing.step2Title">Agents scan the market</h3>
|
|
97
|
+
<p class="lp-step-text" data-i18n="landing.step2Text">Claude agents comb company career pages, ATS systems and job boards for fresh, matching openings.</p>
|
|
98
|
+
<div class="lp-mock lp-mock-scan" aria-hidden="true">
|
|
99
|
+
<div class="lp-scan-row"><span class="spin">⏳</span><span data-i18n="landing.step2Mock">Scanning 1,240 sources…</span></div>
|
|
100
|
+
<div class="lp-scan-bars"><i style="width:82%"></i><i style="width:64%"></i><i style="width:91%"></i></div>
|
|
101
|
+
</div>
|
|
102
|
+
</article>
|
|
103
|
+
|
|
104
|
+
<article class="lp-step">
|
|
105
|
+
<div class="lp-step-n">3</div>
|
|
106
|
+
<h3 class="lp-step-title" data-i18n="landing.step3Title">Review matched roles</h3>
|
|
107
|
+
<p class="lp-step-text" data-i18n="landing.step3Text">Every hit lands as a card with why-it-fits notes, salary, location and freshness — filter to taste.</p>
|
|
108
|
+
<div class="lp-mock lp-mock-grid" aria-hidden="true">
|
|
109
|
+
<div class="lp-vcard">
|
|
110
|
+
<span class="lp-ava" style="background:hsl(150,55%,45%)">N</span>
|
|
111
|
+
<div class="lp-vc-body">
|
|
112
|
+
<div class="lp-vc-title" data-i18n="landing.roleBackend">Senior Backend Engineer</div>
|
|
113
|
+
<div class="lp-vc-co">Northwind Labs · remote</div>
|
|
114
|
+
<div class="lp-vc-tags"><span class="lp-tag remote">🌍 worldwide</span><span class="lp-tag sal">$6k–8k</span></div>
|
|
115
|
+
</div>
|
|
116
|
+
<span class="lp-st st-new" data-i18n="status.new">new</span>
|
|
117
|
+
</div>
|
|
118
|
+
<div class="lp-vcard">
|
|
119
|
+
<span class="lp-ava" style="background:hsl(24,72%,52%)">A</span>
|
|
120
|
+
<div class="lp-vc-body">
|
|
121
|
+
<div class="lp-vc-title" data-i18n="landing.roleData">Data Engineer</div>
|
|
122
|
+
<div class="lp-vc-co">Acme Cloud · EU remote</div>
|
|
123
|
+
<div class="lp-vc-tags"><span class="lp-tag remote">remote · region</span></div>
|
|
124
|
+
</div>
|
|
125
|
+
<span class="lp-st st-prepared" data-i18n="status.prepared">reply ready</span>
|
|
126
|
+
</div>
|
|
127
|
+
<div class="lp-vcard">
|
|
128
|
+
<span class="lp-ava" style="background:hsl(276,52%,55%)">O</span>
|
|
129
|
+
<div class="lp-vc-body">
|
|
130
|
+
<div class="lp-vc-title" data-i18n="landing.roleDesigner">Product Designer</div>
|
|
131
|
+
<div class="lp-vc-co">Orbit AI · London / hybrid</div>
|
|
132
|
+
<div class="lp-vc-tags"><span class="lp-tag sal">£70k–85k</span></div>
|
|
133
|
+
</div>
|
|
134
|
+
<span class="lp-st st-sent" data-i18n="status.sent">sent</span>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
</article>
|
|
138
|
+
|
|
139
|
+
<article class="lp-step">
|
|
140
|
+
<div class="lp-step-n">4</div>
|
|
141
|
+
<h3 class="lp-step-title" data-i18n="landing.step4Title">Apply on autopilot</h3>
|
|
142
|
+
<p class="lp-step-text" data-i18n="landing.step4Text">The agent writes a tailored cover letter and can fill and submit the application form for you.</p>
|
|
143
|
+
<div class="lp-mock lp-mock-letter" aria-hidden="true">
|
|
144
|
+
<div class="lp-lbl" data-i18n="card.coverLetter">Cover letter</div>
|
|
145
|
+
<div class="lp-letter-lines"><i style="width:94%"></i><i style="width:100%"></i><i style="width:80%"></i><i style="width:90%"></i></div>
|
|
146
|
+
<div class="lp-letter-actions">
|
|
147
|
+
<span class="lp-btn ghost" data-i18n="card.openJob">Open job ↗</span>
|
|
148
|
+
<span class="lp-btn primary" data-i18n="card.autoApply">🤖 Auto-apply</span>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
</article>
|
|
152
|
+
|
|
153
|
+
</div>
|
|
154
|
+
</section>
|
|
155
|
+
|
|
156
|
+
<!-- SEARCH PRINCIPLE -->
|
|
157
|
+
<section class="lp-section lp-principle">
|
|
158
|
+
<h2 class="lp-h2" data-i18n="landing.searchTitle">How the search works</h2>
|
|
159
|
+
<p class="lp-lead" data-i18n="landing.searchLead">Work Finder does not stop at one job board. Agents sweep the entire market and fold everything into a single, filterable list.</p>
|
|
160
|
+
<div class="lp-principle-grid">
|
|
161
|
+
<div class="lp-pcol">
|
|
162
|
+
<div class="lp-pcol-icon">🏢</div>
|
|
163
|
+
<h3 data-i18n="landing.searchCol1Title">Every company that is hiring</h3>
|
|
164
|
+
<p data-i18n="landing.searchCol1Text">Career pages and ATS systems (Greenhouse, Lever, Ashby and the like) — direct openings straight from the source, including roles that never reach the big boards.</p>
|
|
165
|
+
</div>
|
|
166
|
+
<div class="lp-pcol">
|
|
167
|
+
<div class="lp-pcol-icon">🌐</div>
|
|
168
|
+
<h3 data-i18n="landing.searchCol2Title">Independent boards & aggregators</h3>
|
|
169
|
+
<p data-i18n="landing.searchCol2Text">Public job boards and aggregators are scanned in parallel, then de-duplicated against the direct hits so you never see the same role twice.</p>
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
<div class="lp-filters">
|
|
173
|
+
<span class="lp-filters-lbl" data-i18n="landing.searchFiltersTitle">Filter everything by</span>
|
|
174
|
+
<span class="lp-fchip" data-i18n="landing.filterCompany">Company</span>
|
|
175
|
+
<span class="lp-fchip" data-i18n="landing.filterGeo">Geography</span>
|
|
176
|
+
<span class="lp-fchip" data-i18n="landing.filterFormat">Format</span>
|
|
177
|
+
<span class="lp-fchip" data-i18n="landing.filterFreshness">Freshness</span>
|
|
178
|
+
</div>
|
|
179
|
+
</section>
|
|
180
|
+
|
|
181
|
+
<!-- BENEFITS -->
|
|
182
|
+
<section class="lp-section">
|
|
183
|
+
<h2 class="lp-h2" data-i18n="landing.benefitsTitle">Why Work Finder</h2>
|
|
184
|
+
<div class="lp-benefits">
|
|
185
|
+
<div class="lp-benefit"><div class="lp-benefit-icon">🤖</div><h3 data-i18n="landing.benefit1Title">Autopilot agents</h3><p data-i18n="landing.benefit1Text">Kick off a search and walk away — agents keep working and results drop in as they are confirmed.</p></div>
|
|
186
|
+
<div class="lp-benefit"><div class="lp-benefit-icon">✍️</div><h3 data-i18n="landing.benefit2Title">Tailored applications</h3><p data-i18n="landing.benefit2Text">Cover letters are written per role from the candidate profile — no copy-paste, no generic templates.</p></div>
|
|
187
|
+
<div class="lp-benefit"><div class="lp-benefit-icon">📁</div><h3 data-i18n="landing.benefit3Title">One place for everything</h3><p data-i18n="landing.benefit3Text">Candidates, roles, letters and application status live together in a single pipeline.</p></div>
|
|
188
|
+
<div class="lp-benefit"><div class="lp-benefit-icon">🔒</div><h3 data-i18n="landing.benefit4Title">Your key, your data</h3><p data-i18n="landing.benefit4Text">Runs on your own Anthropic key and stays on your machine — nothing is sent to us.</p></div>
|
|
189
|
+
</div>
|
|
190
|
+
</section>
|
|
191
|
+
|
|
192
|
+
<!-- CONNECT KEY -->
|
|
193
|
+
<section class="lp-section" id="lp-connect">
|
|
194
|
+
<div class="lp-connect-card">
|
|
195
|
+
<h2 class="lp-h2" data-i18n="landing.connectTitle">Connect your Anthropic API key</h2>
|
|
196
|
+
<p class="lp-lead" data-i18n="landing.connectLead">Work Finder runs on your own Anthropic key, so you pay Anthropic directly for exactly what the agents use.</p>
|
|
197
|
+
<ol class="lp-inst">
|
|
198
|
+
<li data-i18n="landing.connectStep1">Sign in to the Anthropic Console.</li>
|
|
199
|
+
<li data-i18n="landing.connectStep2">Open API Keys and click Create key.</li>
|
|
200
|
+
<li data-i18n="landing.connectStep3">Copy the key (it starts with sk-ant-) and paste it below.</li>
|
|
201
|
+
</ol>
|
|
202
|
+
<a class="btn ghost sm lp-console" href="https://console.anthropic.com/settings/keys" target="_blank" rel="noopener" data-i18n="landing.consoleLink">Open Anthropic Console ↗</a>
|
|
203
|
+
<div class="lp-key-row">
|
|
204
|
+
<input id="landing-key" type="password" autocomplete="off" spellcheck="false" data-i18n-ph="landing.keyPlaceholder" placeholder="sk-ant-…">
|
|
205
|
+
<button class="btn primary" id="landing-connect" data-i18n="landing.connectBtn">Connect</button>
|
|
206
|
+
</div>
|
|
207
|
+
<p class="lp-key-note" data-i18n="landing.keyNote">The key is stored only in this browser (localStorage) and is never sent to our servers.</p>
|
|
208
|
+
</div>
|
|
209
|
+
</section>
|
|
210
|
+
|
|
211
|
+
</main>
|
|
212
|
+
|
|
213
|
+
<!-- ══════════ JOBS ══════════ -->
|
|
214
|
+
<main id="view-jobs" class="view">
|
|
215
|
+
|
|
216
|
+
<!-- zero-profile onboarding: one focused step -->
|
|
217
|
+
<div id="jobs-onboard" class="jobs-onboard" hidden>
|
|
218
|
+
<div class="jo-card">
|
|
219
|
+
<div class="jo-icon" aria-hidden="true">👤</div>
|
|
220
|
+
<h2 data-i18n="jobsonb.title">Create your profile to start</h2>
|
|
221
|
+
<p class="jo-sub" data-i18n="jobsonb.sub">Add a candidate and the agents start scanning the market right away — one step, then the results roll in.</p>
|
|
222
|
+
<form id="jobs-onboard-form" class="jo-form" autocomplete="off">
|
|
223
|
+
<input name="name" data-i18n-ph="jobsonb.namePlaceholder" placeholder="First and last name *" required>
|
|
224
|
+
<input name="linkedin" data-i18n-ph="jobsonb.linkedinPlaceholder" placeholder="LinkedIn URL — https://www.linkedin.com/in/…">
|
|
225
|
+
<button type="submit" class="btn primary big" data-i18n="jobsonb.submit">🚀 Add and find jobs</button>
|
|
226
|
+
</form>
|
|
227
|
+
<button type="button" class="btn ghost" id="jobs-onboard-builder" data-i18n="jobsonb.builderLink">🧩 Build a full resume instead</button>
|
|
228
|
+
</div>
|
|
229
|
+
</div>
|
|
230
|
+
|
|
231
|
+
<div class="search-panel" id="search-panel">
|
|
232
|
+
<div id="profile-chips" class="prof-chips"></div>
|
|
233
|
+
<div class="search-row">
|
|
234
|
+
<div id="position-chips" class="pos-chips"></div>
|
|
235
|
+
<button class="chip-add" id="show-add-position" data-i18n="search.addPosition" data-i18n-title="search.addPositionTitle" title="Add position">+ position</button>
|
|
236
|
+
</div>
|
|
237
|
+
<form id="position-form" class="add-form" hidden>
|
|
238
|
+
<select name="role" id="position-role"></select>
|
|
239
|
+
<select name="seniority" id="position-seniority"></select>
|
|
240
|
+
<input name="title" data-i18n-ph="posform.titlePlaceholder" placeholder="Custom position wording" hidden>
|
|
241
|
+
<input name="keywords" data-i18n-ph="posform.keywordsPlaceholder" placeholder="Keywords" hidden>
|
|
242
|
+
<select name="profileId" id="position-profile"></select>
|
|
243
|
+
<select name="engagement">
|
|
244
|
+
<option value="both" data-i18n="engagement.opt.both">staff or contract</option>
|
|
245
|
+
<option value="staff" data-i18n="engagement.opt.staff">staff only</option>
|
|
246
|
+
<option value="contract" data-i18n="engagement.opt.contract">contract only</option>
|
|
247
|
+
</select>
|
|
248
|
+
<button class="btn primary" data-i18n="common.add">Add</button>
|
|
249
|
+
<button class="btn ghost" type="button" id="hide-add-position" data-i18n="common.cancel">Cancel</button>
|
|
250
|
+
</form>
|
|
251
|
+
<div class="search-actions">
|
|
252
|
+
<button class="btn primary big" id="search-all" data-i18n="search.findJobs">🔎 Find jobs</button>
|
|
253
|
+
<select id="freshness" data-i18n-title="search.freshnessTitle" title="The agent will only take jobs published within this period">
|
|
254
|
+
<option value="1" data-i18n="search.freshness.1">no older than 1 day</option>
|
|
255
|
+
<option value="2" data-i18n="search.freshness.2">no older than 2 days</option>
|
|
256
|
+
<option value="3" data-i18n="search.freshness.3">no older than 3 days</option>
|
|
257
|
+
<option value="5" data-i18n="search.freshness.5">no older than 5 days</option>
|
|
258
|
+
</select>
|
|
259
|
+
<input id="text-filter" class="text-filter" data-i18n-ph="search.textFilterPlaceholder" placeholder="Filter: company, role, stack…">
|
|
260
|
+
</div>
|
|
261
|
+
</div>
|
|
262
|
+
|
|
263
|
+
<div id="status-tabs" class="status-tabs"></div>
|
|
264
|
+
|
|
265
|
+
<div class="filter-bar" id="filter-bar">
|
|
266
|
+
<select data-flt="geo">
|
|
267
|
+
<option value="" data-i18n="filter.geo.all">Geography: all</option>
|
|
268
|
+
<option value="global" data-i18n="filter.geo.global">🌍 Global — worldwide</option>
|
|
269
|
+
<option value="remote" data-i18n="filter.geo.remote">🏠 Remote — any</option>
|
|
270
|
+
<option value="region" data-i18n="filter.geo.region">Remote — region (EU/EMEA…)</option>
|
|
271
|
+
<option value="country" data-i18n="filter.geo.country">Remote — single country</option>
|
|
272
|
+
<option value="onsite" data-i18n="filter.geo.onsite">🏢 Office / hybrid</option>
|
|
273
|
+
</select>
|
|
274
|
+
<select data-flt="eng">
|
|
275
|
+
<option value="" data-i18n="filter.eng.all">Format: all</option>
|
|
276
|
+
<option value="staff" data-i18n="filter.eng.staff">Staff</option>
|
|
277
|
+
<option value="contract" data-i18n="filter.eng.contract">Contract / B2B</option>
|
|
278
|
+
</select>
|
|
279
|
+
<select data-flt="apply">
|
|
280
|
+
<option value="" data-i18n="filter.apply.all">Apply: all</option>
|
|
281
|
+
<option value="form" data-i18n="filter.apply.form">Form on site</option>
|
|
282
|
+
<option value="email">Email</option>
|
|
283
|
+
<option value="linkedin">LinkedIn</option>
|
|
284
|
+
</select>
|
|
285
|
+
<select data-flt="salary">
|
|
286
|
+
<option value="" data-i18n="filter.salary.all">Salary: all</option>
|
|
287
|
+
<option value="yes" data-i18n="filter.salary.yes">With a range only</option>
|
|
288
|
+
</select>
|
|
289
|
+
<select data-flt="fresh">
|
|
290
|
+
<option value="" data-i18n="filter.fresh.any">Freshness: any</option>
|
|
291
|
+
<option value="1" data-i18n="filter.fresh.1">past 1 day</option>
|
|
292
|
+
<option value="2" data-i18n="filter.fresh.2">past 2 days</option>
|
|
293
|
+
<option value="3" data-i18n="filter.fresh.3">past 3 days</option>
|
|
294
|
+
<option value="5" data-i18n="filter.fresh.5">past 5 days</option>
|
|
295
|
+
</select>
|
|
296
|
+
<button class="btn ghost sm" id="reset-filters" data-i18n="filter.reset">Reset</button>
|
|
297
|
+
<button class="btn ghost sm" id="validate-links" data-i18n="filter.validateLinks" data-i18n-title="filter.validateLinksTitle" title="Scan the database and hide jobs with dead links (free, no tokens)">🧹 Check links</button>
|
|
298
|
+
</div>
|
|
299
|
+
|
|
300
|
+
<div id="history-row" class="history-row" hidden></div>
|
|
301
|
+
|
|
302
|
+
<div id="vacancy-list" class="vlist"></div>
|
|
303
|
+
</main>
|
|
304
|
+
|
|
305
|
+
<!-- ══════════ LEADS ══════════ -->
|
|
306
|
+
<main id="view-leads" class="view" hidden>
|
|
307
|
+
<div class="view-head">
|
|
308
|
+
<h2 data-i18n="leads.heading">Leads — companies with a hiring signal</h2>
|
|
309
|
+
<button class="btn primary" id="search-leads" data-i18n="leads.findLeads">🔎 Find leads (funding rounds)</button>
|
|
310
|
+
</div>
|
|
311
|
+
<p class="hint" data-i18n="leads.hint">Product companies that raised a round in the last ~60 days — they are hiring (or will be soon), even without public openings. The agent finds the founder/CTO contact, and “Pitch” writes a cold email tailored to the candidate profile.</p>
|
|
312
|
+
<div id="leads-list"></div>
|
|
313
|
+
</main>
|
|
314
|
+
|
|
315
|
+
<!-- ══════════ PROFILES ══════════ -->
|
|
316
|
+
<main id="view-profiles" class="view" hidden>
|
|
317
|
+
<div class="view-head">
|
|
318
|
+
<h2 data-i18n="profiles.heading">Profiles and resumes</h2>
|
|
319
|
+
<div class="view-head-actions">
|
|
320
|
+
<span id="plan-badge" class="plan-badge free"></span>
|
|
321
|
+
<button class="btn ghost" id="open-builder" data-i18n="builder.open">🧩 Resume builder</button>
|
|
322
|
+
<button class="btn primary" id="add-profile" data-i18n="profiles.addCandidate">+ Add candidate</button>
|
|
323
|
+
</div>
|
|
324
|
+
</div>
|
|
325
|
+
<p class="hint" data-i18n="profiles.hint">A name and LinkedIn are enough: the resume imports itself, roles are picked automatically, and the search starts right away.</p>
|
|
326
|
+
|
|
327
|
+
<form id="onboard-form" class="profile-card onboard" hidden>
|
|
328
|
+
<h3 style="margin:0 0 12px" data-i18n="onboard.title">New candidate</h3>
|
|
329
|
+
<div class="row">
|
|
330
|
+
<input name="name" data-i18n-ph="onboard.namePlaceholder" placeholder="First and last name *" required>
|
|
331
|
+
<input name="linkedin" data-i18n-ph="onboard.linkedinPlaceholder" placeholder="LinkedIn URL — https://www.linkedin.com/in/…">
|
|
332
|
+
<select name="location" id="onb-location"></select>
|
|
333
|
+
</div>
|
|
334
|
+
<div class="row" style="margin-top:8px">
|
|
335
|
+
<select name="seniority" id="onb-seniority"></select>
|
|
336
|
+
<select name="engagement">
|
|
337
|
+
<option value="both" data-i18n="engagement.opt.both">staff or contract</option>
|
|
338
|
+
<option value="staff" data-i18n="engagement.opt.staff">staff only</option>
|
|
339
|
+
<option value="contract" data-i18n="engagement.opt.contract">contract only</option>
|
|
340
|
+
</select>
|
|
341
|
+
</div>
|
|
342
|
+
<div class="lbl" style="margin:12px 0 6px" data-i18n="onboard.rolesLabel">Roles — optional, they’ll be picked from the resume automatically:</div>
|
|
343
|
+
<div id="onb-roles" class="role-grid"></div>
|
|
344
|
+
<details style="margin-top:10px">
|
|
345
|
+
<summary class="hint" style="margin:0" data-i18n="onboard.noLinkedin">No LinkedIn — paste resume as text</summary>
|
|
346
|
+
<textarea name="resumeText" rows="8" data-i18n-ph="onboard.resumePlaceholder" placeholder="Resume in any form — the agent will tidy it up"></textarea>
|
|
347
|
+
</details>
|
|
348
|
+
<div class="row" style="margin-top:12px">
|
|
349
|
+
<button class="btn primary" data-i18n="onboard.submit">🚀 Add and find jobs</button>
|
|
350
|
+
<button class="btn ghost" type="button" id="onboard-cancel" data-i18n="common.cancel">Cancel</button>
|
|
351
|
+
</div>
|
|
352
|
+
</form>
|
|
353
|
+
|
|
354
|
+
<div id="profiles-list"></div>
|
|
355
|
+
</main>
|
|
356
|
+
|
|
357
|
+
<!-- ══════════ SETTINGS ══════════ -->
|
|
358
|
+
<main id="view-settings" class="view" hidden>
|
|
359
|
+
<div class="view-head"><h2 data-i18n="nav.settings">Settings</h2></div>
|
|
360
|
+
<form id="settings-form" class="settings-card">
|
|
361
|
+
<label><span data-i18n="settings.apiKey">Anthropic API key</span>
|
|
362
|
+
<div class="row" style="align-items:center;gap:8px">
|
|
363
|
+
<input name="anthropicKey" type="password" autocomplete="off" spellcheck="false" style="flex:1;min-width:200px" data-i18n-ph="settings.keyPlaceholder" placeholder="Paste a new key to replace (sk-ant-…)">
|
|
364
|
+
<button type="button" class="btn ghost sm" id="disconnect-key" data-i18n="settings.disconnect">Disconnect</button>
|
|
365
|
+
</div>
|
|
366
|
+
<span id="key-status" class="hint" style="margin:2px 0 0"></span>
|
|
367
|
+
</label>
|
|
368
|
+
<label><span data-i18n="settings.plan">Plan</span>
|
|
369
|
+
<select name="plan">
|
|
370
|
+
<option value="free" data-i18n="settings.plan.free">Free — 1 candidate</option>
|
|
371
|
+
<option value="dev" data-i18n="settings.plan.dev">Dev — no limits (self-hosted instance)</option>
|
|
372
|
+
</select>
|
|
373
|
+
<span id="usage-line" class="hint" style="margin:2px 0 0"></span>
|
|
374
|
+
</label>
|
|
375
|
+
<label><span data-i18n="settings.license">License key</span>
|
|
376
|
+
<div class="row" style="align-items:center;gap:8px">
|
|
377
|
+
<input name="licenseKey" autocomplete="off" spellcheck="false" style="flex:1;min-width:200px" data-i18n-ph="settings.licensePlaceholder" placeholder="wf_… — paste the key from your purchase email">
|
|
378
|
+
<button type="button" class="btn ghost sm" id="license-apply" data-i18n="settings.licenseApply">Apply</button>
|
|
379
|
+
</div>
|
|
380
|
+
<span id="license-status" class="hint" style="margin:4px 0 0"></span>
|
|
381
|
+
<div class="row" style="margin-top:8px;gap:8px">
|
|
382
|
+
<button type="button" class="btn ghost sm" id="buy-pro" data-i18n="settings.buyPro">Get Pro — $99/yr</button>
|
|
383
|
+
</div>
|
|
384
|
+
</label>
|
|
385
|
+
<label><span data-i18n="settings.model">Agent model</span>
|
|
386
|
+
<select name="model">
|
|
387
|
+
<option value="haiku" data-i18n="settings.model.haiku">haiku — fast and cheap</option>
|
|
388
|
+
<option value="sonnet" data-i18n="settings.model.sonnet">sonnet — balanced (recommended)</option>
|
|
389
|
+
<option value="opus" data-i18n="settings.model.opus">opus — top quality</option>
|
|
390
|
+
</select>
|
|
391
|
+
</label>
|
|
392
|
+
<label><span data-i18n="settings.resultsPerSearch">Jobs per search</span>
|
|
393
|
+
<input type="number" name="resultsPerSearch" min="3" max="20">
|
|
394
|
+
</label>
|
|
395
|
+
<label class="checkbox">
|
|
396
|
+
<input type="checkbox" name="autoSubmit">
|
|
397
|
+
<span data-i18n="settings.autoSubmit">Auto-submit applications — the agent submits the form itself, without your review</span>
|
|
398
|
+
</label>
|
|
399
|
+
<label class="checkbox">
|
|
400
|
+
<input type="checkbox" name="searchViaBrowser">
|
|
401
|
+
<span data-i18n="settings.searchViaBrowser">Search via browser — deeper (djinni/DOU while logged in), but slower</span>
|
|
402
|
+
</label>
|
|
403
|
+
<label class="checkbox">
|
|
404
|
+
<input type="checkbox" name="excludeBoards">
|
|
405
|
+
<span data-i18n="settings.excludeBoards">No job boards (djinni, DOU, RemoteOK…) — only direct jobs from company sites and ATS</span>
|
|
406
|
+
</label>
|
|
407
|
+
<label><span data-i18n="settings.searchExtra">Extra search preferences (salary, countries, exclusions…)</span>
|
|
408
|
+
<textarea name="searchExtra" rows="3" data-i18n-ph="settings.searchExtraPlaceholder" placeholder="e.g.: only companies paying $4000+, no gambling"></textarea>
|
|
409
|
+
</label>
|
|
410
|
+
<button class="btn primary" data-i18n="common.save">Save</button>
|
|
411
|
+
</form>
|
|
412
|
+
</main>
|
|
413
|
+
|
|
414
|
+
<!-- ══════════ RESUME BUILDER ══════════ -->
|
|
415
|
+
<div id="builder-overlay" class="modal-overlay" hidden>
|
|
416
|
+
<div class="builder-panel" role="dialog" aria-modal="true">
|
|
417
|
+
<div class="builder-head">
|
|
418
|
+
<h3 id="builder-title">Resume builder</h3>
|
|
419
|
+
<button type="button" class="modal-x" id="builder-close" data-i18n-title="builder.cancel" title="Cancel">✕</button>
|
|
420
|
+
</div>
|
|
421
|
+
<div class="builder-body">
|
|
422
|
+
<div id="builder-form" class="builder-form">
|
|
423
|
+
|
|
424
|
+
<details class="bld-import">
|
|
425
|
+
<summary data-i18n="builder.import">Import an existing resume</summary>
|
|
426
|
+
<textarea id="builder-import" rows="5" data-i18n-ph="builder.importPh" placeholder="Paste an existing resume here, then Parse with Claude — or keep it as-is."></textarea>
|
|
427
|
+
<div class="bld-import-actions">
|
|
428
|
+
<button type="button" class="btn primary sm" id="builder-parse" data-i18n="builder.parseImport">✨ Parse with Claude</button>
|
|
429
|
+
<label class="btn ghost sm bld-file-lbl">
|
|
430
|
+
<span data-i18n="builder.importFile">Load .txt file</span>
|
|
431
|
+
<input type="file" id="builder-file" accept=".txt,.md,text/plain" hidden>
|
|
432
|
+
</label>
|
|
433
|
+
</div>
|
|
434
|
+
</details>
|
|
435
|
+
|
|
436
|
+
<div class="bld-sec">
|
|
437
|
+
<div class="bld-lbl" data-i18n="builder.contact">Contact</div>
|
|
438
|
+
<div class="bld-grid">
|
|
439
|
+
<input data-bf="name" data-i18n-ph="builder.namePh" placeholder="First and last name *">
|
|
440
|
+
<input data-bf="location" data-i18n-ph="builder.locationPh" placeholder="Location, e.g. Ukraine">
|
|
441
|
+
<input data-bf="email" data-i18n-ph="builder.emailPh" placeholder="Email">
|
|
442
|
+
<input data-bf="linkedin" data-i18n-ph="builder.linkedinPh" placeholder="LinkedIn URL">
|
|
443
|
+
</div>
|
|
444
|
+
</div>
|
|
445
|
+
|
|
446
|
+
<div class="bld-sec">
|
|
447
|
+
<div class="bld-lbl" data-i18n="builder.headlineLabel">Headline & summary</div>
|
|
448
|
+
<input data-bf="headline" data-i18n-ph="builder.headlinePh" placeholder="Headline, e.g. Senior Backend Engineer">
|
|
449
|
+
<textarea data-bf="summary" rows="4" data-i18n-ph="builder.summaryPh" placeholder="A short professional summary"></textarea>
|
|
450
|
+
<div class="bld-ai-row">
|
|
451
|
+
<button type="button" class="btn ghost sm" id="builder-gen-summary" data-i18n="builder.genSummary">✨ Generate summary</button>
|
|
452
|
+
<button type="button" class="btn ghost sm" id="builder-polish" data-i18n="builder.polishSummary">✨ Polish</button>
|
|
453
|
+
</div>
|
|
454
|
+
</div>
|
|
455
|
+
|
|
456
|
+
<div class="bld-sec">
|
|
457
|
+
<div class="bld-lbl" data-i18n="builder.experience">Experience</div>
|
|
458
|
+
<div id="builder-exp"></div>
|
|
459
|
+
<button type="button" class="btn ghost sm" id="builder-add-exp" data-i18n="builder.addExp">+ Add role</button>
|
|
460
|
+
</div>
|
|
461
|
+
|
|
462
|
+
<div class="bld-sec">
|
|
463
|
+
<div class="bld-lbl" data-i18n="builder.skillsLabel">Skills</div>
|
|
464
|
+
<textarea data-bf="skills" rows="2" data-i18n-ph="builder.skillsPh" placeholder="Skills, comma-separated"></textarea>
|
|
465
|
+
</div>
|
|
466
|
+
|
|
467
|
+
<div class="bld-sec">
|
|
468
|
+
<div class="bld-lbl" data-i18n="builder.education">Education</div>
|
|
469
|
+
<div id="builder-edu"></div>
|
|
470
|
+
<button type="button" class="btn ghost sm" id="builder-add-edu" data-i18n="builder.addEdu">+ Add education</button>
|
|
471
|
+
</div>
|
|
472
|
+
|
|
473
|
+
</div>
|
|
474
|
+
<div class="builder-preview-wrap">
|
|
475
|
+
<div class="bld-lbl" data-i18n="builder.preview">Preview</div>
|
|
476
|
+
<div id="builder-preview" class="builder-preview"></div>
|
|
477
|
+
</div>
|
|
478
|
+
</div>
|
|
479
|
+
<div class="builder-foot">
|
|
480
|
+
<button type="button" class="btn primary" id="builder-save">💾 Save</button>
|
|
481
|
+
<button type="button" class="btn ghost" id="builder-cancel" data-i18n="builder.cancel">Cancel</button>
|
|
482
|
+
</div>
|
|
483
|
+
</div>
|
|
484
|
+
</div>
|
|
485
|
+
|
|
486
|
+
<!-- ══════════ PRO UPSELL ══════════ -->
|
|
487
|
+
<div id="upsell-overlay" class="modal-overlay" hidden>
|
|
488
|
+
<div class="upsell-card" role="dialog" aria-modal="true">
|
|
489
|
+
<button type="button" class="modal-x" id="upsell-close" data-i18n-title="upsell.later" title="Close">✕</button>
|
|
490
|
+
<div class="upsell-badge" data-i18n="plan.pro">Pro</div>
|
|
491
|
+
<h3 data-i18n="upsell.title">Manage more than one candidate with Pro</h3>
|
|
492
|
+
<p class="upsell-sub" data-i18n="upsell.sub">Free covers a single candidate — perfect for your own job hunt. Recruiters and headhunters run several candidates at once, each with its own searches and pipeline.</p>
|
|
493
|
+
<div class="upsell-price"><b data-i18n="upsell.price">$99/yr</b> <span data-i18n="upsell.priceNote">secure card payment</span></div>
|
|
494
|
+
<ul class="upsell-benefits">
|
|
495
|
+
<li data-i18n="upsell.benefit1">Unlimited candidate profiles</li>
|
|
496
|
+
<li data-i18n="upsell.benefit2">A separate search pipeline for each person</li>
|
|
497
|
+
<li data-i18n="upsell.benefit3">Auto-apply and funding-round leads</li>
|
|
498
|
+
</ul>
|
|
499
|
+
<div class="upsell-actions">
|
|
500
|
+
<button type="button" class="btn primary big" id="upsell-upgrade" data-i18n="upsell.upgrade">Upgrade to Pro</button>
|
|
501
|
+
<button type="button" class="btn ghost" id="upsell-later" data-i18n="upsell.later">Maybe later</button>
|
|
502
|
+
</div>
|
|
503
|
+
</div>
|
|
504
|
+
</div>
|
|
505
|
+
|
|
506
|
+
<!-- floating agent-tasks widget -->
|
|
507
|
+
<div id="jobs-widget" class="jobs-widget" hidden>
|
|
508
|
+
<div class="jobs-widget-head" id="jobs-widget-toggle">
|
|
509
|
+
<span id="jobs-widget-title" data-i18n="widget.working">Agents working…</span>
|
|
510
|
+
<span id="jobs-widget-arrow">▾</span>
|
|
511
|
+
</div>
|
|
512
|
+
<div class="wprogress" id="jobs-widget-progress" hidden><div></div></div>
|
|
513
|
+
<div id="jobs-widget-body"></div>
|
|
514
|
+
</div>
|
|
515
|
+
|
|
516
|
+
<script src="app.js"></script>
|
|
517
|
+
</body>
|
|
518
|
+
</html>
|