qiksy 1.3.0 → 1.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qiksy",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Qiksy \u2014 one local engine for every Qiksy tool (Work Finder, Travel Assistant, Client Finder). Runs on your own Claude; nothing leaves your machine.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -54,7 +54,16 @@ export function searchPrompt(position, profile, excludeCompanies, settings, pass
54
54
  POSITION: ${position.title}
55
55
  KEYWORDS / STACK: ${position.keywords || '—'}
56
56
  ENGAGEMENT: ${ENGAGEMENT_TEXT[position.engagement] || ENGAGEMENT_TEXT.both}
57
- CANDIDATE LOCATION: ${profile?.location || 'Ukraine'} — works remotely from there (or B2B contract)
57
+ CANDIDATE LOCATION: ${profile?.location || 'Ukraine'}
58
+ WHERE THEY CAN WORK: ${
59
+ settings.workMode === 'onsite'
60
+ ? `ON SITE, in or near ${profile?.location || 'Ukraine'}. Look for office roles there — commuting distance, not another country. A remote-only posting is NOT a match unless it also offers an office in that area.`
61
+ : settings.workMode === 'hybrid'
62
+ ? `HYBRID — an office in or near ${profile?.location || 'Ukraine'} with some days from home. Fully remote is acceptable only if the company also has an office there.`
63
+ : settings.workMode === 'any'
64
+ ? `EITHER — remote from ${profile?.location || 'Ukraine'} (or B2B contract), or an office role in or near ${profile?.location || 'Ukraine'}. Both count; say which one each posting is.`
65
+ : `REMOTELY from ${profile?.location || 'Ukraine'} (or B2B contract).`
66
+ }
58
67
  ${settings.searchExtra ? `EXTRA INSTRUCTIONS FROM USER: ${settings.searchExtra}\n` : ''}
59
68
  CANDIDATE (for relevance filtering):
60
69
  ${resumeExcerpt(profile, 1200)}
@@ -78,11 +87,12 @@ RULES:
78
87
  - Skip these companies (already found earlier): ${excludeCompanies.length ? excludeCompanies.join(', ') : 'none'}.
79
88
  - Find AT LEAST ${n} distinct openings at distinct companies — more is better. There is no upper limit: return every match you can confirm in this pass.
80
89
  - SCORE THE FIT: for every vacancy set "match" to an INTEGER 0-100 — how well THIS role fits the candidate above (stack & seniority overlap, remote eligibility from ${profile?.location || 'Ukraine'}, engagement type). Be honest and discriminating: reserve 90+ for a strong direct match, 60-75 for a plausible partial fit, below 50 for a stretch. The "notes" field should justify the number in one line.
90
+ - FIRST FIVE, ONE AT A TIME. Do not gather a batch before reporting. Take the first promising link, WebFetch it, and the MOMENT it checks out print its VACANCY line — before you open the next one. Repeat until five are out. Only after that may you work in parallel and report in groups. The person is watching an empty screen until the first line appears, and five minutes of nothing reads as broken (measured 2026-07-26: first results at ~7 min).
81
91
  - WORK FAST but do not stop early: broad WebSearch queries first, then WebFetch the promising pages. Streaming a confirmed find costs nothing extra, so stream as you go.
82
92
  - TIME BUDGET: up to ~12 minutes for this pass. Stop when you genuinely run out of NEW companies, not when you reach a number.
83
93
  ${wave > 1 ? `- THIS IS SWEEP #${wave}. Everything the earlier sweeps found is in the exclusion list above and must not come back. Asking the same question again returns the same answers, so change the ANGLE: different search phrasings and role synonyms, different ATS hosts, different regions and countries, smaller and less-known companies, older-but-still-open postings, adjacent titles the candidate also fits. If a whole angle turns up nothing new, say so and finish the pass — an honest empty sweep ends the search cleanly.` : ''}
84
94
 
85
- PROGRESS STREAMING: the user watches results arrive live. As soon as you have CONFIRMED one vacancy (page fetched, fresh, geography checked), immediately print a single line:
95
+ PROGRESS STREAMING — THIS IS NOT OPTIONAL AND NOT A SUMMARY STEP: the user is watching a live screen and sees nothing until you print. Never hold findings back to report them together at the end; a vacancy you confirmed but have not printed is invisible to them. As soon as you have CONFIRMED one vacancy (page fetched, fresh, geography checked), immediately print a single line:
86
96
  VACANCY: {"company":...} ← one-line JSON, exact same fields as the array items below
87
97
  …then continue searching. Stream every confirmed finding this way.
88
98
 
@@ -22,6 +22,11 @@ function defaults() {
22
22
  model: 'sonnet',
23
23
  autoSubmit: false,
24
24
  searchViaBrowser: false,
25
+ /* Where the person can actually work: 'remote' (default, what the agent always
26
+ silently assumed) | 'onsite' | 'hybrid' | 'any'. Not everyone can work from
27
+ home — some need an office in their own city, and until now the product had
28
+ nothing to offer them (owner, 2026-07-26). */
29
+ workMode: 'remote',
25
30
  searchExtra: '',
26
31
  /* Per SWEEP, and a FLOOR, not a ceiling — the search runs sweep after sweep
27
32
  until one turns up nothing new (server.mjs startSearch). It used to be a