terminalhire 0.3.0 → 0.3.2
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/dist/bin/jpi-dispatch.js +32 -8
- package/dist/bin/jpi-refresh.js +32 -8
- package/dist/bin/jpi-spinner.js +15 -5
- package/dist/bin/spinner.js +22 -6
- package/package.json +1 -1
package/dist/bin/jpi-dispatch.js
CHANGED
|
@@ -3177,16 +3177,26 @@ function buildContextVerbs(topMatches, sessionTags) {
|
|
|
3177
3177
|
for (const t of sess) {
|
|
3178
3178
|
if (roleTags.has(t) && !overlap.includes(t)) overlap.push(t);
|
|
3179
3179
|
}
|
|
3180
|
+
let headers;
|
|
3180
3181
|
if (overlap.length >= 2) {
|
|
3181
3182
|
const a = titleCase(overlap[0]);
|
|
3182
3183
|
const b = titleCase(overlap[1]);
|
|
3183
|
-
|
|
3184
|
-
}
|
|
3185
|
-
if (overlap.length === 1) {
|
|
3184
|
+
headers = [`\u2726 Fits your ${a} + ${b} work`, `\u2726 A role matching what you're building`];
|
|
3185
|
+
} else if (overlap.length === 1) {
|
|
3186
3186
|
const a = titleCase(overlap[0]);
|
|
3187
|
-
|
|
3187
|
+
headers = [`\u2726 A role matching your ${a} work`, `\u2726 Your ${a} work \u2014 link in the tip below`];
|
|
3188
|
+
} else {
|
|
3189
|
+
headers = [`\u2726 A role that fits your work`, `\u2726 Job match for you \u2014 link in the tip below`];
|
|
3190
|
+
}
|
|
3191
|
+
const list = Array.isArray(topMatches) ? topMatches : [];
|
|
3192
|
+
const bounty = list.find((m) => m && m.source === "bounty" && m.amountUSD != null) || list.find((m) => m && m.source === "bounty");
|
|
3193
|
+
if (bounty) {
|
|
3194
|
+
const money = bounty.amountUSD != null ? `$${bounty.amountUSD.toLocaleString()} ` : "";
|
|
3195
|
+
const bountyHeader = `\u2726 \u{1F48E} A ${money}bounty in your stack \u2014 link below`;
|
|
3196
|
+
if (list[0] && list[0].source === "bounty") headers.unshift(bountyHeader);
|
|
3197
|
+
else headers.push(bountyHeader);
|
|
3188
3198
|
}
|
|
3189
|
-
return
|
|
3199
|
+
return headers;
|
|
3190
3200
|
}
|
|
3191
3201
|
function buildSpinnerPool(topMatches, max = 6, opts = {}) {
|
|
3192
3202
|
const { sessionTags, frequency = "always" } = opts;
|
|
@@ -3291,7 +3301,13 @@ function buildTips(topMatches, baseUrl, max = 8) {
|
|
|
3291
3301
|
const pct = Math.max(1, Math.min(99, Math.round((Number(m.score) || 0) * 100)));
|
|
3292
3302
|
const token = Buffer.from(String(m.id)).toString("base64url");
|
|
3293
3303
|
const url = `${base}/j/${token}`;
|
|
3294
|
-
|
|
3304
|
+
if (source === "bounty") {
|
|
3305
|
+
const money = m.amountUSD != null ? `$${Number(m.amountUSD).toLocaleString()}` : "$\u2014";
|
|
3306
|
+
const repo = m.repo || companyRaw;
|
|
3307
|
+
out.push(`\u{1F48E} ${money} \xB7 ${title} \xB7 ${repo} \xB7 ${pct}% \u2014 ${url}`);
|
|
3308
|
+
} else {
|
|
3309
|
+
out.push(`\u2197 ${title} @ ${company} \xB7 ${pct}% \u2014 ${url}`);
|
|
3310
|
+
}
|
|
3295
3311
|
if (out.length >= max) break;
|
|
3296
3312
|
}
|
|
3297
3313
|
return out;
|
|
@@ -4090,13 +4106,21 @@ async function run10() {
|
|
|
4090
4106
|
const fp = profileToFingerprint2(profile);
|
|
4091
4107
|
const results = match2(fp, jobs, jobs.length);
|
|
4092
4108
|
matchCount = results.length;
|
|
4093
|
-
|
|
4109
|
+
const BOUNTY_SLOTS = 5;
|
|
4110
|
+
const bountyTop = results.filter((r) => r.job.source === "bounty").slice(0, BOUNTY_SLOTS);
|
|
4111
|
+
const roleTop = results.filter((r) => r.job.source !== "bounty").slice(0, 25 - bountyTop.length);
|
|
4112
|
+
topMatches = [...roleTop, ...bountyTop].map((r) => ({
|
|
4094
4113
|
id: r.job.id,
|
|
4095
4114
|
title: r.job.title,
|
|
4096
4115
|
company: r.job.company,
|
|
4097
4116
|
score: r.score,
|
|
4098
4117
|
remote: r.job.remote,
|
|
4099
|
-
matchedTags: r.matchedTags
|
|
4118
|
+
matchedTags: r.matchedTags,
|
|
4119
|
+
// Bounty fields so the spinner can render bounty framing ($ + 💎).
|
|
4120
|
+
// Public job text, stays LOCAL (same as the rest of topMatches).
|
|
4121
|
+
source: r.job.source,
|
|
4122
|
+
amountUSD: r.job.bounty?.amountUSD,
|
|
4123
|
+
repo: r.job.bounty?.repoFullName
|
|
4100
4124
|
}));
|
|
4101
4125
|
}
|
|
4102
4126
|
} catch {
|
package/dist/bin/jpi-refresh.js
CHANGED
|
@@ -2006,16 +2006,26 @@ function buildContextVerbs(topMatches, sessionTags) {
|
|
|
2006
2006
|
for (const t of sess) {
|
|
2007
2007
|
if (roleTags.has(t) && !overlap.includes(t)) overlap.push(t);
|
|
2008
2008
|
}
|
|
2009
|
+
let headers;
|
|
2009
2010
|
if (overlap.length >= 2) {
|
|
2010
2011
|
const a = titleCase(overlap[0]);
|
|
2011
2012
|
const b = titleCase(overlap[1]);
|
|
2012
|
-
|
|
2013
|
-
}
|
|
2014
|
-
if (overlap.length === 1) {
|
|
2013
|
+
headers = [`\u2726 Fits your ${a} + ${b} work`, `\u2726 A role matching what you're building`];
|
|
2014
|
+
} else if (overlap.length === 1) {
|
|
2015
2015
|
const a = titleCase(overlap[0]);
|
|
2016
|
-
|
|
2016
|
+
headers = [`\u2726 A role matching your ${a} work`, `\u2726 Your ${a} work \u2014 link in the tip below`];
|
|
2017
|
+
} else {
|
|
2018
|
+
headers = [`\u2726 A role that fits your work`, `\u2726 Job match for you \u2014 link in the tip below`];
|
|
2019
|
+
}
|
|
2020
|
+
const list = Array.isArray(topMatches) ? topMatches : [];
|
|
2021
|
+
const bounty = list.find((m) => m && m.source === "bounty" && m.amountUSD != null) || list.find((m) => m && m.source === "bounty");
|
|
2022
|
+
if (bounty) {
|
|
2023
|
+
const money = bounty.amountUSD != null ? `$${bounty.amountUSD.toLocaleString()} ` : "";
|
|
2024
|
+
const bountyHeader = `\u2726 \u{1F48E} A ${money}bounty in your stack \u2014 link below`;
|
|
2025
|
+
if (list[0] && list[0].source === "bounty") headers.unshift(bountyHeader);
|
|
2026
|
+
else headers.push(bountyHeader);
|
|
2017
2027
|
}
|
|
2018
|
-
return
|
|
2028
|
+
return headers;
|
|
2019
2029
|
}
|
|
2020
2030
|
function buildSpinnerPool(topMatches, max = 6, opts = {}) {
|
|
2021
2031
|
const { sessionTags, frequency = "always" } = opts;
|
|
@@ -2120,7 +2130,13 @@ function buildTips(topMatches, baseUrl, max = 8) {
|
|
|
2120
2130
|
const pct = Math.max(1, Math.min(99, Math.round((Number(m.score) || 0) * 100)));
|
|
2121
2131
|
const token = Buffer.from(String(m.id)).toString("base64url");
|
|
2122
2132
|
const url = `${base}/j/${token}`;
|
|
2123
|
-
|
|
2133
|
+
if (source === "bounty") {
|
|
2134
|
+
const money = m.amountUSD != null ? `$${Number(m.amountUSD).toLocaleString()}` : "$\u2014";
|
|
2135
|
+
const repo = m.repo || companyRaw;
|
|
2136
|
+
out.push(`\u{1F48E} ${money} \xB7 ${title} \xB7 ${repo} \xB7 ${pct}% \u2014 ${url}`);
|
|
2137
|
+
} else {
|
|
2138
|
+
out.push(`\u2197 ${title} @ ${company} \xB7 ${pct}% \u2014 ${url}`);
|
|
2139
|
+
}
|
|
2124
2140
|
if (out.length >= max) break;
|
|
2125
2141
|
}
|
|
2126
2142
|
return out;
|
|
@@ -2477,13 +2493,21 @@ async function run() {
|
|
|
2477
2493
|
const fp = profileToFingerprint2(profile);
|
|
2478
2494
|
const results = match2(fp, jobs, jobs.length);
|
|
2479
2495
|
matchCount = results.length;
|
|
2480
|
-
|
|
2496
|
+
const BOUNTY_SLOTS = 5;
|
|
2497
|
+
const bountyTop = results.filter((r) => r.job.source === "bounty").slice(0, BOUNTY_SLOTS);
|
|
2498
|
+
const roleTop = results.filter((r) => r.job.source !== "bounty").slice(0, 25 - bountyTop.length);
|
|
2499
|
+
topMatches = [...roleTop, ...bountyTop].map((r) => ({
|
|
2481
2500
|
id: r.job.id,
|
|
2482
2501
|
title: r.job.title,
|
|
2483
2502
|
company: r.job.company,
|
|
2484
2503
|
score: r.score,
|
|
2485
2504
|
remote: r.job.remote,
|
|
2486
|
-
matchedTags: r.matchedTags
|
|
2505
|
+
matchedTags: r.matchedTags,
|
|
2506
|
+
// Bounty fields so the spinner can render bounty framing ($ + 💎).
|
|
2507
|
+
// Public job text, stays LOCAL (same as the rest of topMatches).
|
|
2508
|
+
source: r.job.source,
|
|
2509
|
+
amountUSD: r.job.bounty?.amountUSD,
|
|
2510
|
+
repo: r.job.bounty?.repoFullName
|
|
2487
2511
|
}));
|
|
2488
2512
|
}
|
|
2489
2513
|
} catch {
|
package/dist/bin/jpi-spinner.js
CHANGED
|
@@ -90,16 +90,26 @@ function buildContextVerbs(topMatches, sessionTags) {
|
|
|
90
90
|
for (const t of sess) {
|
|
91
91
|
if (roleTags.has(t) && !overlap.includes(t)) overlap.push(t);
|
|
92
92
|
}
|
|
93
|
+
let headers;
|
|
93
94
|
if (overlap.length >= 2) {
|
|
94
95
|
const a = titleCase(overlap[0]);
|
|
95
96
|
const b = titleCase(overlap[1]);
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
if (overlap.length === 1) {
|
|
97
|
+
headers = [`\u2726 Fits your ${a} + ${b} work`, `\u2726 A role matching what you're building`];
|
|
98
|
+
} else if (overlap.length === 1) {
|
|
99
99
|
const a = titleCase(overlap[0]);
|
|
100
|
-
|
|
100
|
+
headers = [`\u2726 A role matching your ${a} work`, `\u2726 Your ${a} work \u2014 link in the tip below`];
|
|
101
|
+
} else {
|
|
102
|
+
headers = [`\u2726 A role that fits your work`, `\u2726 Job match for you \u2014 link in the tip below`];
|
|
103
|
+
}
|
|
104
|
+
const list = Array.isArray(topMatches) ? topMatches : [];
|
|
105
|
+
const bounty = list.find((m) => m && m.source === "bounty" && m.amountUSD != null) || list.find((m) => m && m.source === "bounty");
|
|
106
|
+
if (bounty) {
|
|
107
|
+
const money = bounty.amountUSD != null ? `$${bounty.amountUSD.toLocaleString()} ` : "";
|
|
108
|
+
const bountyHeader = `\u2726 \u{1F48E} A ${money}bounty in your stack \u2014 link below`;
|
|
109
|
+
if (list[0] && list[0].source === "bounty") headers.unshift(bountyHeader);
|
|
110
|
+
else headers.push(bountyHeader);
|
|
101
111
|
}
|
|
102
|
-
return
|
|
112
|
+
return headers;
|
|
103
113
|
}
|
|
104
114
|
function buildSpinnerPool(topMatches, max = 6, opts = {}) {
|
|
105
115
|
const { sessionTags, frequency = "always" } = opts;
|
package/dist/bin/spinner.js
CHANGED
|
@@ -97,16 +97,26 @@ function buildContextVerbs(topMatches, sessionTags) {
|
|
|
97
97
|
for (const t of sess) {
|
|
98
98
|
if (roleTags.has(t) && !overlap.includes(t)) overlap.push(t);
|
|
99
99
|
}
|
|
100
|
+
let headers;
|
|
100
101
|
if (overlap.length >= 2) {
|
|
101
102
|
const a = titleCase(overlap[0]);
|
|
102
103
|
const b = titleCase(overlap[1]);
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
if (overlap.length === 1) {
|
|
104
|
+
headers = [`\u2726 Fits your ${a} + ${b} work`, `\u2726 A role matching what you're building`];
|
|
105
|
+
} else if (overlap.length === 1) {
|
|
106
106
|
const a = titleCase(overlap[0]);
|
|
107
|
-
|
|
107
|
+
headers = [`\u2726 A role matching your ${a} work`, `\u2726 Your ${a} work \u2014 link in the tip below`];
|
|
108
|
+
} else {
|
|
109
|
+
headers = [`\u2726 A role that fits your work`, `\u2726 Job match for you \u2014 link in the tip below`];
|
|
110
|
+
}
|
|
111
|
+
const list = Array.isArray(topMatches) ? topMatches : [];
|
|
112
|
+
const bounty = list.find((m) => m && m.source === "bounty" && m.amountUSD != null) || list.find((m) => m && m.source === "bounty");
|
|
113
|
+
if (bounty) {
|
|
114
|
+
const money = bounty.amountUSD != null ? `$${bounty.amountUSD.toLocaleString()} ` : "";
|
|
115
|
+
const bountyHeader = `\u2726 \u{1F48E} A ${money}bounty in your stack \u2014 link below`;
|
|
116
|
+
if (list[0] && list[0].source === "bounty") headers.unshift(bountyHeader);
|
|
117
|
+
else headers.push(bountyHeader);
|
|
108
118
|
}
|
|
109
|
-
return
|
|
119
|
+
return headers;
|
|
110
120
|
}
|
|
111
121
|
function buildSpinnerPool(topMatches, max = 6, opts = {}) {
|
|
112
122
|
const { sessionTags, frequency = "always" } = opts;
|
|
@@ -211,7 +221,13 @@ function buildTips(topMatches, baseUrl, max = 8) {
|
|
|
211
221
|
const pct = Math.max(1, Math.min(99, Math.round((Number(m.score) || 0) * 100)));
|
|
212
222
|
const token = Buffer.from(String(m.id)).toString("base64url");
|
|
213
223
|
const url = `${base}/j/${token}`;
|
|
214
|
-
|
|
224
|
+
if (source === "bounty") {
|
|
225
|
+
const money = m.amountUSD != null ? `$${Number(m.amountUSD).toLocaleString()}` : "$\u2014";
|
|
226
|
+
const repo = m.repo || companyRaw;
|
|
227
|
+
out.push(`\u{1F48E} ${money} \xB7 ${title} \xB7 ${repo} \xB7 ${pct}% \u2014 ${url}`);
|
|
228
|
+
} else {
|
|
229
|
+
out.push(`\u2197 ${title} @ ${company} \xB7 ${pct}% \u2014 ${url}`);
|
|
230
|
+
}
|
|
215
231
|
if (out.length >= max) break;
|
|
216
232
|
}
|
|
217
233
|
return out;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "terminalhire",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Local-first job matching for developers — ambient job matches in the Claude Code spinner. Matching runs on your machine; your profile never leaves it.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|