terminalhire 0.4.4 → 0.4.6
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-bounties.js +27 -3
- package/dist/bin/jpi-claim.js +88 -25
- package/dist/bin/jpi-dispatch.js +166 -50
- package/dist/bin/jpi-jobs.js +27 -3
- package/dist/bin/jpi-learn.js +8 -0
- package/dist/bin/jpi-login.js +71 -3
- package/dist/bin/jpi-profile.js +8 -0
- package/dist/bin/jpi-refresh.js +27 -3
- package/dist/bin/jpi-save.js +8 -0
- package/dist/bin/jpi-sync.js +33 -21
- package/dist/src/acceptance-score.js +49 -0
- package/package.json +2 -1
package/dist/bin/jpi-bounties.js
CHANGED
|
@@ -1640,6 +1640,28 @@ var init_bounty_gate = __esm({
|
|
|
1640
1640
|
}
|
|
1641
1641
|
});
|
|
1642
1642
|
|
|
1643
|
+
// ../../packages/core/src/concurrency.ts
|
|
1644
|
+
async function mapWithConcurrency(items, limit, fn) {
|
|
1645
|
+
const results = new Array(items.length);
|
|
1646
|
+
if (items.length === 0) return results;
|
|
1647
|
+
const workers = Math.max(1, Math.min(Math.floor(limit) || 1, items.length));
|
|
1648
|
+
let next = 0;
|
|
1649
|
+
async function run2() {
|
|
1650
|
+
for (; ; ) {
|
|
1651
|
+
const i = next++;
|
|
1652
|
+
if (i >= items.length) return;
|
|
1653
|
+
results[i] = await fn(items[i], i);
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
await Promise.all(Array.from({ length: workers }, run2));
|
|
1657
|
+
return results;
|
|
1658
|
+
}
|
|
1659
|
+
var init_concurrency = __esm({
|
|
1660
|
+
"../../packages/core/src/concurrency.ts"() {
|
|
1661
|
+
"use strict";
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
|
|
1643
1665
|
// ../../packages/core/src/feeds/github-bounties.ts
|
|
1644
1666
|
function authHeaders() {
|
|
1645
1667
|
const token = process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"];
|
|
@@ -1731,7 +1753,7 @@ async function fetchRepoBounties(repoFullName) {
|
|
|
1731
1753
|
if (!issues) return [];
|
|
1732
1754
|
const bounties = issues.filter(isBountyIssue).slice(0, MAX_BOUNTIES_PER_REPO);
|
|
1733
1755
|
const owner = repo.owner.login;
|
|
1734
|
-
return
|
|
1756
|
+
return mapWithConcurrency(bounties, BOUNTY_FETCH_CONCURRENCY, async (issue) => {
|
|
1735
1757
|
const title = decodeEntities(issue.title).trim();
|
|
1736
1758
|
const body = issue.body ? decodeEntities(issue.body) : "";
|
|
1737
1759
|
const amountUSD = parseAmountUSD(title) ?? parseAmountUSD(body) ?? await fetchCommentAmount(repoFullName, issue.number);
|
|
@@ -1760,7 +1782,7 @@ async function fetchRepoBounties(repoFullName) {
|
|
|
1760
1782
|
},
|
|
1761
1783
|
raw: issue
|
|
1762
1784
|
};
|
|
1763
|
-
})
|
|
1785
|
+
});
|
|
1764
1786
|
}
|
|
1765
1787
|
function repoFullNameFromApiUrl(url) {
|
|
1766
1788
|
const m = url.match(/\/repos\/([^/]+)\/([^/]+)\/?$/);
|
|
@@ -1902,7 +1924,7 @@ async function fetchSearchBounties() {
|
|
|
1902
1924
|
}
|
|
1903
1925
|
return jobs;
|
|
1904
1926
|
}
|
|
1905
|
-
var GITHUB_API, BOUNTY_LABEL_RE, SEARCH_QUERIES, SEARCH_PER_PAGE, MAX_SEARCH_BOUNTIES, MAX_SEARCH_ISSUES_SCANNED, REPO_META_CONCURRENCY, repoMetaCache, MAX_PR_PAGES, repoOpenPRRefsCache, issueStateCache, githubBounties;
|
|
1927
|
+
var GITHUB_API, BOUNTY_LABEL_RE, SEARCH_QUERIES, SEARCH_PER_PAGE, MAX_SEARCH_BOUNTIES, MAX_SEARCH_ISSUES_SCANNED, REPO_META_CONCURRENCY, BOUNTY_FETCH_CONCURRENCY, repoMetaCache, MAX_PR_PAGES, repoOpenPRRefsCache, issueStateCache, githubBounties;
|
|
1906
1928
|
var init_github_bounties = __esm({
|
|
1907
1929
|
"../../packages/core/src/feeds/github-bounties.ts"() {
|
|
1908
1930
|
"use strict";
|
|
@@ -1910,6 +1932,7 @@ var init_github_bounties = __esm({
|
|
|
1910
1932
|
init_entities();
|
|
1911
1933
|
init_bounty_gate();
|
|
1912
1934
|
init_http();
|
|
1935
|
+
init_concurrency();
|
|
1913
1936
|
GITHUB_API = "https://api.github.com";
|
|
1914
1937
|
BOUNTY_LABEL_RE = /bounty|reward|funded|💎|💰/i;
|
|
1915
1938
|
SEARCH_QUERIES = [
|
|
@@ -1922,6 +1945,7 @@ var init_github_bounties = __esm({
|
|
|
1922
1945
|
MAX_SEARCH_BOUNTIES = 150;
|
|
1923
1946
|
MAX_SEARCH_ISSUES_SCANNED = 300;
|
|
1924
1947
|
REPO_META_CONCURRENCY = 15;
|
|
1948
|
+
BOUNTY_FETCH_CONCURRENCY = 6;
|
|
1925
1949
|
repoMetaCache = /* @__PURE__ */ new Map();
|
|
1926
1950
|
MAX_PR_PAGES = 3;
|
|
1927
1951
|
repoOpenPRRefsCache = /* @__PURE__ */ new Map();
|
package/dist/bin/jpi-claim.js
CHANGED
|
@@ -143,7 +143,7 @@ ${p.body ?? ""}`)).length;
|
|
|
143
143
|
return null;
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
|
-
async function
|
|
146
|
+
async function fetchIssue(repoFullName, issueNumber) {
|
|
147
147
|
try {
|
|
148
148
|
const res = await fetch(`${GH_API}/repos/${repoFullName}/issues/${issueNumber}`, {
|
|
149
149
|
headers: GH_HEADERS,
|
|
@@ -151,7 +151,8 @@ async function fetchIssueState(repoFullName, issueNumber) {
|
|
|
151
151
|
});
|
|
152
152
|
if (!res.ok) return null;
|
|
153
153
|
const issue = await res.json();
|
|
154
|
-
|
|
154
|
+
const state = issue.state === "open" ? "open" : issue.state === "closed" ? "closed" : null;
|
|
155
|
+
return { state, title: typeof issue.title === "string" ? issue.title : null };
|
|
155
156
|
} catch {
|
|
156
157
|
return null;
|
|
157
158
|
}
|
|
@@ -179,14 +180,7 @@ function printMetric(rate) {
|
|
|
179
180
|
console.log(`
|
|
180
181
|
\u{1F4CA} Accepted-PR rate: ${rate.merged}/${rate.total} claims merged (${pct}%)`);
|
|
181
182
|
}
|
|
182
|
-
async function
|
|
183
|
-
const claims = await Promise.resolve().then(() => (init_claims(), claims_exports));
|
|
184
|
-
if (!arg) {
|
|
185
|
-
console.error("Usage: terminalhire claim record <bountyId|issueUrl>");
|
|
186
|
-
console.error(" Run `terminalhire bounties` first to populate the local index cache,");
|
|
187
|
-
console.error(" then pass the id shown in its output \u2014 or pass a GitHub issue URL directly.");
|
|
188
|
-
process.exit(1);
|
|
189
|
-
}
|
|
183
|
+
async function resolveBounty(arg) {
|
|
190
184
|
let bountyId, title, repoFullName, issueUrl, amountUSD;
|
|
191
185
|
const job = findBountyInCache(arg);
|
|
192
186
|
if (job) {
|
|
@@ -198,11 +192,7 @@ async function cmdRecord(arg) {
|
|
|
198
192
|
amountUSD = b.amountUSD ?? null;
|
|
199
193
|
} else {
|
|
200
194
|
const parsed = parseGitHubUrl(arg);
|
|
201
|
-
if (!parsed)
|
|
202
|
-
console.error(`terminalhire claim: '${arg}' is not in the index cache and is not a GitHub issue URL.`);
|
|
203
|
-
console.error(" Run `terminalhire bounties` to populate the cache, or pass a full issue URL.");
|
|
204
|
-
process.exit(1);
|
|
205
|
-
}
|
|
195
|
+
if (!parsed) return null;
|
|
206
196
|
bountyId = `gh:${parsed.repoFullName}#${parsed.number}`;
|
|
207
197
|
title = `${parsed.repoFullName}#${parsed.number}`;
|
|
208
198
|
repoFullName = parsed.repoFullName;
|
|
@@ -210,14 +200,40 @@ async function cmdRecord(arg) {
|
|
|
210
200
|
amountUSD = null;
|
|
211
201
|
}
|
|
212
202
|
const ghIssue = parseGitHubUrl(issueUrl);
|
|
213
|
-
const [
|
|
214
|
-
|
|
203
|
+
const [issue, openPRs] = ghIssue ? await Promise.all([
|
|
204
|
+
fetchIssue(repoFullName, ghIssue.number),
|
|
215
205
|
countOpenPRsReferencingIssue(repoFullName, ghIssue.number)
|
|
216
|
-
// Guardrail #5
|
|
217
206
|
]) : [null, null];
|
|
218
|
-
|
|
207
|
+
const issueState = issue ? issue.state : null;
|
|
208
|
+
if (!job && issue && issue.title) title = issue.title;
|
|
209
|
+
return {
|
|
210
|
+
bountyId,
|
|
211
|
+
title,
|
|
212
|
+
repoFullName,
|
|
213
|
+
issueUrl,
|
|
214
|
+
amountUSD,
|
|
215
|
+
issueState,
|
|
216
|
+
openPRs,
|
|
217
|
+
issueNumber: ghIssue ? ghIssue.number : null
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
async function cmdRecord(arg) {
|
|
221
|
+
const claims = await Promise.resolve().then(() => (init_claims(), claims_exports));
|
|
222
|
+
if (!arg) {
|
|
223
|
+
console.error("Usage: terminalhire claim record <bountyId|issueUrl>");
|
|
224
|
+
console.error(" Run `terminalhire bounties` first to populate the local index cache,");
|
|
225
|
+
console.error(" then pass the id shown in its output \u2014 or pass a GitHub issue URL directly.");
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
const b = await resolveBounty(arg);
|
|
229
|
+
if (!b) {
|
|
230
|
+
console.error(`terminalhire claim: '${arg}' is not in the index cache and is not a GitHub issue URL.`);
|
|
231
|
+
console.error(" Run `terminalhire bounties` to populate the cache, or pass a full issue URL.");
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
if (b.issueState === "closed") {
|
|
219
235
|
console.error(
|
|
220
|
-
`terminalhire claim: ${repoFullName}#${
|
|
236
|
+
`terminalhire claim: ${b.repoFullName}#${b.issueNumber} is CLOSED \u2014 not claimable.
|
|
221
237
|
The bounty index drops closed issues; this one is likely a stale cache entry.
|
|
222
238
|
Run \`terminalhire bounties\` for the current open pool.`
|
|
223
239
|
);
|
|
@@ -225,7 +241,7 @@ async function cmdRecord(arg) {
|
|
|
225
241
|
}
|
|
226
242
|
let claim;
|
|
227
243
|
try {
|
|
228
|
-
claim = claims.recordClaim({ id: bountyId, bountyId, title, repoFullName, issueUrl, amountUSD, openPRsAtClaim: openPRs });
|
|
244
|
+
claim = claims.recordClaim({ id: b.bountyId, bountyId: b.bountyId, title: b.title, repoFullName: b.repoFullName, issueUrl: b.issueUrl, amountUSD: b.amountUSD, openPRsAtClaim: b.openPRs });
|
|
229
245
|
} catch (err) {
|
|
230
246
|
console.error(`terminalhire claim: ${err.message ?? err}`);
|
|
231
247
|
process.exit(1);
|
|
@@ -236,10 +252,10 @@ async function cmdRecord(arg) {
|
|
|
236
252
|
console.log(` repo: ${claim.repoFullName}`);
|
|
237
253
|
console.log(` amount: ${fmtAmount(claim.amountUSD)}`);
|
|
238
254
|
console.log(` issue: ${claim.issueUrl}`);
|
|
239
|
-
if (openPRs == null) {
|
|
255
|
+
if (b.openPRs == null) {
|
|
240
256
|
console.log(" open PRs: unknown (GitHub read unavailable \u2014 check the issue manually before working)");
|
|
241
|
-
} else if (openPRs > 0) {
|
|
242
|
-
console.log(` \u26A0 open PRs referencing this issue: ${openPRs} \u2014 someone may already be on it. Check before working.`);
|
|
257
|
+
} else if (b.openPRs > 0) {
|
|
258
|
+
console.log(` \u26A0 open PRs referencing this issue: ${b.openPRs} \u2014 someone may already be on it. Check before working.`);
|
|
243
259
|
} else {
|
|
244
260
|
console.log(" open PRs referencing this issue: 0");
|
|
245
261
|
}
|
|
@@ -250,6 +266,49 @@ async function cmdRecord(arg) {
|
|
|
250
266
|
console.log(" \u2022 no access to ~/.terminalhire (the executor never needs your profile)");
|
|
251
267
|
console.log("\n Next: do the work, then `terminalhire claim update " + claim.id + " <state>` as you progress.");
|
|
252
268
|
}
|
|
269
|
+
async function cmdPreview(arg, { json } = {}) {
|
|
270
|
+
if (!arg) {
|
|
271
|
+
console.error("Usage: terminalhire claim preview <bountyId|issueUrl> [--json]");
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
const b = await resolveBounty(arg);
|
|
275
|
+
if (!b) {
|
|
276
|
+
console.error(`terminalhire claim: '${arg}' is not in the index cache and is not a GitHub issue URL.`);
|
|
277
|
+
console.error(" Run `terminalhire bounties` to populate the cache, or pass a full issue URL.");
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
280
|
+
if (json) {
|
|
281
|
+
process.stdout.write(
|
|
282
|
+
JSON.stringify({
|
|
283
|
+
bountyId: b.bountyId,
|
|
284
|
+
title: b.title,
|
|
285
|
+
amountUSD: b.amountUSD,
|
|
286
|
+
repoFullName: b.repoFullName,
|
|
287
|
+
issueUrl: b.issueUrl,
|
|
288
|
+
issueState: b.issueState,
|
|
289
|
+
openPRs: b.openPRs
|
|
290
|
+
}) + "\n"
|
|
291
|
+
);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
console.log(`
|
|
295
|
+
BOUNTY \xB7 ${b.title}`);
|
|
296
|
+
console.log(` id: ${b.bountyId}`);
|
|
297
|
+
console.log(` repo: ${b.repoFullName}`);
|
|
298
|
+
console.log(` amount: ${fmtAmount(b.amountUSD)}`);
|
|
299
|
+
console.log(` issue: ${b.issueUrl}`);
|
|
300
|
+
if (b.issueState === "closed") {
|
|
301
|
+
console.log(" \u2717 CLOSED \u2014 not claimable (the pool drops closed issues; likely a stale cache entry)");
|
|
302
|
+
}
|
|
303
|
+
if (b.openPRs == null) {
|
|
304
|
+
console.log(" open PRs: unknown (GitHub read unavailable \u2014 check the issue manually before working)");
|
|
305
|
+
} else if (b.openPRs > 0) {
|
|
306
|
+
console.log(` \u26A0 open PRs referencing this issue: ${b.openPRs} \u2014 someone may already be on it. Check before working.`);
|
|
307
|
+
} else {
|
|
308
|
+
console.log(" open PRs referencing this issue: 0");
|
|
309
|
+
}
|
|
310
|
+
console.log("\n Preview only \u2014 NOT claimed. Run `terminalhire claim record " + arg + "` to claim it.");
|
|
311
|
+
}
|
|
253
312
|
async function cmdList(active) {
|
|
254
313
|
const claims = await Promise.resolve().then(() => (init_claims(), claims_exports));
|
|
255
314
|
const list = claims.listClaims({ active });
|
|
@@ -335,8 +394,12 @@ async function run() {
|
|
|
335
394
|
const verb = process.argv[2];
|
|
336
395
|
const rest = process.argv.slice(3).filter((a) => !a.startsWith("--"));
|
|
337
396
|
const active = process.argv.includes("--active");
|
|
397
|
+
const json = process.argv.includes("--json");
|
|
338
398
|
try {
|
|
339
399
|
switch (verb) {
|
|
400
|
+
case "preview":
|
|
401
|
+
await cmdPreview(rest[0], { json });
|
|
402
|
+
break;
|
|
340
403
|
case "record":
|
|
341
404
|
await cmdRecord(rest[0]);
|
|
342
405
|
break;
|
|
@@ -353,7 +416,7 @@ async function run() {
|
|
|
353
416
|
await cmdRelease(rest[0]);
|
|
354
417
|
break;
|
|
355
418
|
default:
|
|
356
|
-
console.error(`terminalhire claim: unknown verb '${verb ?? ""}'. Expected: record | list | status | update | release`);
|
|
419
|
+
console.error(`terminalhire claim: unknown verb '${verb ?? ""}'. Expected: preview | record | list | status | update | release`);
|
|
357
420
|
process.exit(1);
|
|
358
421
|
}
|
|
359
422
|
} catch (err) {
|
package/dist/bin/jpi-dispatch.js
CHANGED
|
@@ -9,6 +9,35 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// src/open-url.js
|
|
13
|
+
import { spawn } from "child_process";
|
|
14
|
+
function openInBrowser(url) {
|
|
15
|
+
let cmd;
|
|
16
|
+
let args3;
|
|
17
|
+
if (process.platform === "darwin") {
|
|
18
|
+
cmd = "open";
|
|
19
|
+
args3 = [url];
|
|
20
|
+
} else if (process.platform === "win32") {
|
|
21
|
+
cmd = "cmd";
|
|
22
|
+
args3 = ["/c", "start", "", url];
|
|
23
|
+
} else {
|
|
24
|
+
cmd = "xdg-open";
|
|
25
|
+
args3 = [url];
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const child = spawn(cmd, args3, { stdio: "ignore", detached: true });
|
|
29
|
+
child.on("error", () => {
|
|
30
|
+
});
|
|
31
|
+
child.unref();
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
var init_open_url = __esm({
|
|
36
|
+
"src/open-url.js"() {
|
|
37
|
+
"use strict";
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
12
41
|
// src/github-auth.ts
|
|
13
42
|
var github_auth_exports = {};
|
|
14
43
|
__export(github_auth_exports, {
|
|
@@ -1854,6 +1883,28 @@ var init_bounty_gate = __esm({
|
|
|
1854
1883
|
}
|
|
1855
1884
|
});
|
|
1856
1885
|
|
|
1886
|
+
// ../../packages/core/src/concurrency.ts
|
|
1887
|
+
async function mapWithConcurrency(items, limit, fn) {
|
|
1888
|
+
const results = new Array(items.length);
|
|
1889
|
+
if (items.length === 0) return results;
|
|
1890
|
+
const workers = Math.max(1, Math.min(Math.floor(limit) || 1, items.length));
|
|
1891
|
+
let next = 0;
|
|
1892
|
+
async function run13() {
|
|
1893
|
+
for (; ; ) {
|
|
1894
|
+
const i = next++;
|
|
1895
|
+
if (i >= items.length) return;
|
|
1896
|
+
results[i] = await fn(items[i], i);
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
await Promise.all(Array.from({ length: workers }, run13));
|
|
1900
|
+
return results;
|
|
1901
|
+
}
|
|
1902
|
+
var init_concurrency = __esm({
|
|
1903
|
+
"../../packages/core/src/concurrency.ts"() {
|
|
1904
|
+
"use strict";
|
|
1905
|
+
}
|
|
1906
|
+
});
|
|
1907
|
+
|
|
1857
1908
|
// ../../packages/core/src/feeds/github-bounties.ts
|
|
1858
1909
|
function authHeaders() {
|
|
1859
1910
|
const token = process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"];
|
|
@@ -1945,7 +1996,7 @@ async function fetchRepoBounties(repoFullName) {
|
|
|
1945
1996
|
if (!issues) return [];
|
|
1946
1997
|
const bounties = issues.filter(isBountyIssue).slice(0, MAX_BOUNTIES_PER_REPO);
|
|
1947
1998
|
const owner = repo.owner.login;
|
|
1948
|
-
return
|
|
1999
|
+
return mapWithConcurrency(bounties, BOUNTY_FETCH_CONCURRENCY, async (issue) => {
|
|
1949
2000
|
const title = decodeEntities(issue.title).trim();
|
|
1950
2001
|
const body = issue.body ? decodeEntities(issue.body) : "";
|
|
1951
2002
|
const amountUSD = parseAmountUSD(title) ?? parseAmountUSD(body) ?? await fetchCommentAmount(repoFullName, issue.number);
|
|
@@ -1974,7 +2025,7 @@ async function fetchRepoBounties(repoFullName) {
|
|
|
1974
2025
|
},
|
|
1975
2026
|
raw: issue
|
|
1976
2027
|
};
|
|
1977
|
-
})
|
|
2028
|
+
});
|
|
1978
2029
|
}
|
|
1979
2030
|
function repoFullNameFromApiUrl(url) {
|
|
1980
2031
|
const m = url.match(/\/repos\/([^/]+)\/([^/]+)\/?$/);
|
|
@@ -2116,7 +2167,7 @@ async function fetchSearchBounties() {
|
|
|
2116
2167
|
}
|
|
2117
2168
|
return jobs;
|
|
2118
2169
|
}
|
|
2119
|
-
var GITHUB_API, BOUNTY_LABEL_RE, SEARCH_QUERIES, SEARCH_PER_PAGE, MAX_SEARCH_BOUNTIES, MAX_SEARCH_ISSUES_SCANNED, REPO_META_CONCURRENCY, repoMetaCache, MAX_PR_PAGES, repoOpenPRRefsCache, issueStateCache, githubBounties;
|
|
2170
|
+
var GITHUB_API, BOUNTY_LABEL_RE, SEARCH_QUERIES, SEARCH_PER_PAGE, MAX_SEARCH_BOUNTIES, MAX_SEARCH_ISSUES_SCANNED, REPO_META_CONCURRENCY, BOUNTY_FETCH_CONCURRENCY, repoMetaCache, MAX_PR_PAGES, repoOpenPRRefsCache, issueStateCache, githubBounties;
|
|
2120
2171
|
var init_github_bounties = __esm({
|
|
2121
2172
|
"../../packages/core/src/feeds/github-bounties.ts"() {
|
|
2122
2173
|
"use strict";
|
|
@@ -2124,6 +2175,7 @@ var init_github_bounties = __esm({
|
|
|
2124
2175
|
init_entities();
|
|
2125
2176
|
init_bounty_gate();
|
|
2126
2177
|
init_http();
|
|
2178
|
+
init_concurrency();
|
|
2127
2179
|
GITHUB_API = "https://api.github.com";
|
|
2128
2180
|
BOUNTY_LABEL_RE = /bounty|reward|funded|💎|💰/i;
|
|
2129
2181
|
SEARCH_QUERIES = [
|
|
@@ -2136,6 +2188,7 @@ var init_github_bounties = __esm({
|
|
|
2136
2188
|
MAX_SEARCH_BOUNTIES = 150;
|
|
2137
2189
|
MAX_SEARCH_ISSUES_SCANNED = 300;
|
|
2138
2190
|
REPO_META_CONCURRENCY = 15;
|
|
2191
|
+
BOUNTY_FETCH_CONCURRENCY = 6;
|
|
2139
2192
|
repoMetaCache = /* @__PURE__ */ new Map();
|
|
2140
2193
|
MAX_PR_PAGES = 3;
|
|
2141
2194
|
repoOpenPRRefsCache = /* @__PURE__ */ new Map();
|
|
@@ -3124,6 +3177,26 @@ async function runLogin() {
|
|
|
3124
3177
|
console.log(" Profile updated at ~/.terminalhire/profile.enc (encrypted at rest)");
|
|
3125
3178
|
console.log(" GitHub data stays on your machine unless you consent to share it in a lead.");
|
|
3126
3179
|
console.log("");
|
|
3180
|
+
const skipWeb = process.argv.includes("--no-web");
|
|
3181
|
+
if (!isMock && !skipWeb) {
|
|
3182
|
+
try {
|
|
3183
|
+
const OAUTH_BASE = "https://www.terminalhire.com";
|
|
3184
|
+
const webUrl = `${OAUTH_BASE}/api/auth/github?next=/dashboard`;
|
|
3185
|
+
console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
3186
|
+
console.log(" Your web profile & r\xE9sum\xE9 \u2014 public GitHub data only,");
|
|
3187
|
+
console.log(" your local profile is NOT uploaded.");
|
|
3188
|
+
console.log(` \u2192 ${webUrl}`);
|
|
3189
|
+
if (process.stdout.isTTY) {
|
|
3190
|
+
console.log(" Opening it now to sign you in at terminalhire.com\u2026");
|
|
3191
|
+
openInBrowser(webUrl);
|
|
3192
|
+
} else {
|
|
3193
|
+
console.log(" Open the link above to sign in & view your r\xE9sum\xE9.");
|
|
3194
|
+
}
|
|
3195
|
+
console.log(" (skip next time with: terminalhire login --no-web)");
|
|
3196
|
+
console.log("");
|
|
3197
|
+
} catch {
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3127
3200
|
console.log(" Run `terminalhire jobs` to see matching roles using your enriched profile.");
|
|
3128
3201
|
console.log("");
|
|
3129
3202
|
} catch (err) {
|
|
@@ -3161,6 +3234,7 @@ async function runLogout() {
|
|
|
3161
3234
|
var init_jpi_login = __esm({
|
|
3162
3235
|
"bin/jpi-login.js"() {
|
|
3163
3236
|
"use strict";
|
|
3237
|
+
init_open_url();
|
|
3164
3238
|
}
|
|
3165
3239
|
});
|
|
3166
3240
|
|
|
@@ -3694,7 +3768,7 @@ ${p.body ?? ""}`)).length;
|
|
|
3694
3768
|
return null;
|
|
3695
3769
|
}
|
|
3696
3770
|
}
|
|
3697
|
-
async function
|
|
3771
|
+
async function fetchIssue(repoFullName, issueNumber) {
|
|
3698
3772
|
try {
|
|
3699
3773
|
const res = await fetch(`${GH_API}/repos/${repoFullName}/issues/${issueNumber}`, {
|
|
3700
3774
|
headers: GH_HEADERS,
|
|
@@ -3702,7 +3776,8 @@ async function fetchIssueState2(repoFullName, issueNumber) {
|
|
|
3702
3776
|
});
|
|
3703
3777
|
if (!res.ok) return null;
|
|
3704
3778
|
const issue = await res.json();
|
|
3705
|
-
|
|
3779
|
+
const state = issue.state === "open" ? "open" : issue.state === "closed" ? "closed" : null;
|
|
3780
|
+
return { state, title: typeof issue.title === "string" ? issue.title : null };
|
|
3706
3781
|
} catch {
|
|
3707
3782
|
return null;
|
|
3708
3783
|
}
|
|
@@ -3730,14 +3805,7 @@ function printMetric(rate) {
|
|
|
3730
3805
|
console.log(`
|
|
3731
3806
|
\u{1F4CA} Accepted-PR rate: ${rate.merged}/${rate.total} claims merged (${pct}%)`);
|
|
3732
3807
|
}
|
|
3733
|
-
async function
|
|
3734
|
-
const claims = await Promise.resolve().then(() => (init_claims(), claims_exports));
|
|
3735
|
-
if (!arg) {
|
|
3736
|
-
console.error("Usage: terminalhire claim record <bountyId|issueUrl>");
|
|
3737
|
-
console.error(" Run `terminalhire bounties` first to populate the local index cache,");
|
|
3738
|
-
console.error(" then pass the id shown in its output \u2014 or pass a GitHub issue URL directly.");
|
|
3739
|
-
process.exit(1);
|
|
3740
|
-
}
|
|
3808
|
+
async function resolveBounty(arg) {
|
|
3741
3809
|
let bountyId, title, repoFullName, issueUrl, amountUSD;
|
|
3742
3810
|
const job = findBountyInCache(arg);
|
|
3743
3811
|
if (job) {
|
|
@@ -3749,11 +3817,7 @@ async function cmdRecord(arg) {
|
|
|
3749
3817
|
amountUSD = b.amountUSD ?? null;
|
|
3750
3818
|
} else {
|
|
3751
3819
|
const parsed = parseGitHubUrl(arg);
|
|
3752
|
-
if (!parsed)
|
|
3753
|
-
console.error(`terminalhire claim: '${arg}' is not in the index cache and is not a GitHub issue URL.`);
|
|
3754
|
-
console.error(" Run `terminalhire bounties` to populate the cache, or pass a full issue URL.");
|
|
3755
|
-
process.exit(1);
|
|
3756
|
-
}
|
|
3820
|
+
if (!parsed) return null;
|
|
3757
3821
|
bountyId = `gh:${parsed.repoFullName}#${parsed.number}`;
|
|
3758
3822
|
title = `${parsed.repoFullName}#${parsed.number}`;
|
|
3759
3823
|
repoFullName = parsed.repoFullName;
|
|
@@ -3761,14 +3825,40 @@ async function cmdRecord(arg) {
|
|
|
3761
3825
|
amountUSD = null;
|
|
3762
3826
|
}
|
|
3763
3827
|
const ghIssue = parseGitHubUrl(issueUrl);
|
|
3764
|
-
const [
|
|
3765
|
-
|
|
3828
|
+
const [issue, openPRs] = ghIssue ? await Promise.all([
|
|
3829
|
+
fetchIssue(repoFullName, ghIssue.number),
|
|
3766
3830
|
countOpenPRsReferencingIssue(repoFullName, ghIssue.number)
|
|
3767
|
-
// Guardrail #5
|
|
3768
3831
|
]) : [null, null];
|
|
3769
|
-
|
|
3832
|
+
const issueState = issue ? issue.state : null;
|
|
3833
|
+
if (!job && issue && issue.title) title = issue.title;
|
|
3834
|
+
return {
|
|
3835
|
+
bountyId,
|
|
3836
|
+
title,
|
|
3837
|
+
repoFullName,
|
|
3838
|
+
issueUrl,
|
|
3839
|
+
amountUSD,
|
|
3840
|
+
issueState,
|
|
3841
|
+
openPRs,
|
|
3842
|
+
issueNumber: ghIssue ? ghIssue.number : null
|
|
3843
|
+
};
|
|
3844
|
+
}
|
|
3845
|
+
async function cmdRecord(arg) {
|
|
3846
|
+
const claims = await Promise.resolve().then(() => (init_claims(), claims_exports));
|
|
3847
|
+
if (!arg) {
|
|
3848
|
+
console.error("Usage: terminalhire claim record <bountyId|issueUrl>");
|
|
3849
|
+
console.error(" Run `terminalhire bounties` first to populate the local index cache,");
|
|
3850
|
+
console.error(" then pass the id shown in its output \u2014 or pass a GitHub issue URL directly.");
|
|
3851
|
+
process.exit(1);
|
|
3852
|
+
}
|
|
3853
|
+
const b = await resolveBounty(arg);
|
|
3854
|
+
if (!b) {
|
|
3855
|
+
console.error(`terminalhire claim: '${arg}' is not in the index cache and is not a GitHub issue URL.`);
|
|
3856
|
+
console.error(" Run `terminalhire bounties` to populate the cache, or pass a full issue URL.");
|
|
3857
|
+
process.exit(1);
|
|
3858
|
+
}
|
|
3859
|
+
if (b.issueState === "closed") {
|
|
3770
3860
|
console.error(
|
|
3771
|
-
`terminalhire claim: ${repoFullName}#${
|
|
3861
|
+
`terminalhire claim: ${b.repoFullName}#${b.issueNumber} is CLOSED \u2014 not claimable.
|
|
3772
3862
|
The bounty index drops closed issues; this one is likely a stale cache entry.
|
|
3773
3863
|
Run \`terminalhire bounties\` for the current open pool.`
|
|
3774
3864
|
);
|
|
@@ -3776,7 +3866,7 @@ async function cmdRecord(arg) {
|
|
|
3776
3866
|
}
|
|
3777
3867
|
let claim;
|
|
3778
3868
|
try {
|
|
3779
|
-
claim = claims.recordClaim({ id: bountyId, bountyId, title, repoFullName, issueUrl, amountUSD, openPRsAtClaim: openPRs });
|
|
3869
|
+
claim = claims.recordClaim({ id: b.bountyId, bountyId: b.bountyId, title: b.title, repoFullName: b.repoFullName, issueUrl: b.issueUrl, amountUSD: b.amountUSD, openPRsAtClaim: b.openPRs });
|
|
3780
3870
|
} catch (err) {
|
|
3781
3871
|
console.error(`terminalhire claim: ${err.message ?? err}`);
|
|
3782
3872
|
process.exit(1);
|
|
@@ -3787,10 +3877,10 @@ async function cmdRecord(arg) {
|
|
|
3787
3877
|
console.log(` repo: ${claim.repoFullName}`);
|
|
3788
3878
|
console.log(` amount: ${fmtAmount(claim.amountUSD)}`);
|
|
3789
3879
|
console.log(` issue: ${claim.issueUrl}`);
|
|
3790
|
-
if (openPRs == null) {
|
|
3880
|
+
if (b.openPRs == null) {
|
|
3791
3881
|
console.log(" open PRs: unknown (GitHub read unavailable \u2014 check the issue manually before working)");
|
|
3792
|
-
} else if (openPRs > 0) {
|
|
3793
|
-
console.log(` \u26A0 open PRs referencing this issue: ${openPRs} \u2014 someone may already be on it. Check before working.`);
|
|
3882
|
+
} else if (b.openPRs > 0) {
|
|
3883
|
+
console.log(` \u26A0 open PRs referencing this issue: ${b.openPRs} \u2014 someone may already be on it. Check before working.`);
|
|
3794
3884
|
} else {
|
|
3795
3885
|
console.log(" open PRs referencing this issue: 0");
|
|
3796
3886
|
}
|
|
@@ -3801,6 +3891,49 @@ async function cmdRecord(arg) {
|
|
|
3801
3891
|
console.log(" \u2022 no access to ~/.terminalhire (the executor never needs your profile)");
|
|
3802
3892
|
console.log("\n Next: do the work, then `terminalhire claim update " + claim.id + " <state>` as you progress.");
|
|
3803
3893
|
}
|
|
3894
|
+
async function cmdPreview(arg, { json } = {}) {
|
|
3895
|
+
if (!arg) {
|
|
3896
|
+
console.error("Usage: terminalhire claim preview <bountyId|issueUrl> [--json]");
|
|
3897
|
+
process.exit(1);
|
|
3898
|
+
}
|
|
3899
|
+
const b = await resolveBounty(arg);
|
|
3900
|
+
if (!b) {
|
|
3901
|
+
console.error(`terminalhire claim: '${arg}' is not in the index cache and is not a GitHub issue URL.`);
|
|
3902
|
+
console.error(" Run `terminalhire bounties` to populate the cache, or pass a full issue URL.");
|
|
3903
|
+
process.exit(1);
|
|
3904
|
+
}
|
|
3905
|
+
if (json) {
|
|
3906
|
+
process.stdout.write(
|
|
3907
|
+
JSON.stringify({
|
|
3908
|
+
bountyId: b.bountyId,
|
|
3909
|
+
title: b.title,
|
|
3910
|
+
amountUSD: b.amountUSD,
|
|
3911
|
+
repoFullName: b.repoFullName,
|
|
3912
|
+
issueUrl: b.issueUrl,
|
|
3913
|
+
issueState: b.issueState,
|
|
3914
|
+
openPRs: b.openPRs
|
|
3915
|
+
}) + "\n"
|
|
3916
|
+
);
|
|
3917
|
+
return;
|
|
3918
|
+
}
|
|
3919
|
+
console.log(`
|
|
3920
|
+
BOUNTY \xB7 ${b.title}`);
|
|
3921
|
+
console.log(` id: ${b.bountyId}`);
|
|
3922
|
+
console.log(` repo: ${b.repoFullName}`);
|
|
3923
|
+
console.log(` amount: ${fmtAmount(b.amountUSD)}`);
|
|
3924
|
+
console.log(` issue: ${b.issueUrl}`);
|
|
3925
|
+
if (b.issueState === "closed") {
|
|
3926
|
+
console.log(" \u2717 CLOSED \u2014 not claimable (the pool drops closed issues; likely a stale cache entry)");
|
|
3927
|
+
}
|
|
3928
|
+
if (b.openPRs == null) {
|
|
3929
|
+
console.log(" open PRs: unknown (GitHub read unavailable \u2014 check the issue manually before working)");
|
|
3930
|
+
} else if (b.openPRs > 0) {
|
|
3931
|
+
console.log(` \u26A0 open PRs referencing this issue: ${b.openPRs} \u2014 someone may already be on it. Check before working.`);
|
|
3932
|
+
} else {
|
|
3933
|
+
console.log(" open PRs referencing this issue: 0");
|
|
3934
|
+
}
|
|
3935
|
+
console.log("\n Preview only \u2014 NOT claimed. Run `terminalhire claim record " + arg + "` to claim it.");
|
|
3936
|
+
}
|
|
3804
3937
|
async function cmdList(active) {
|
|
3805
3938
|
const claims = await Promise.resolve().then(() => (init_claims(), claims_exports));
|
|
3806
3939
|
const list = claims.listClaims({ active });
|
|
@@ -3886,8 +4019,12 @@ async function run4() {
|
|
|
3886
4019
|
const verb = process.argv[2];
|
|
3887
4020
|
const rest = process.argv.slice(3).filter((a) => !a.startsWith("--"));
|
|
3888
4021
|
const active = process.argv.includes("--active");
|
|
4022
|
+
const json = process.argv.includes("--json");
|
|
3889
4023
|
try {
|
|
3890
4024
|
switch (verb) {
|
|
4025
|
+
case "preview":
|
|
4026
|
+
await cmdPreview(rest[0], { json });
|
|
4027
|
+
break;
|
|
3891
4028
|
case "record":
|
|
3892
4029
|
await cmdRecord(rest[0]);
|
|
3893
4030
|
break;
|
|
@@ -3904,7 +4041,7 @@ async function run4() {
|
|
|
3904
4041
|
await cmdRelease(rest[0]);
|
|
3905
4042
|
break;
|
|
3906
4043
|
default:
|
|
3907
|
-
console.error(`terminalhire claim: unknown verb '${verb ?? ""}'. Expected: record | list | status | update | release`);
|
|
4044
|
+
console.error(`terminalhire claim: unknown verb '${verb ?? ""}'. Expected: preview | record | list | status | update | release`);
|
|
3908
4045
|
process.exit(1);
|
|
3909
4046
|
}
|
|
3910
4047
|
} catch (err) {
|
|
@@ -4886,7 +5023,6 @@ import { readFileSync as readFileSync12, writeFileSync as writeFileSync9, mkdirS
|
|
|
4886
5023
|
import { join as join12 } from "path";
|
|
4887
5024
|
import { homedir as homedir10, hostname as osHostname } from "os";
|
|
4888
5025
|
import { createInterface as createInterface5 } from "readline";
|
|
4889
|
-
import { spawn } from "child_process";
|
|
4890
5026
|
function ask2(question) {
|
|
4891
5027
|
const rl = createInterface5({ input: process.stdin, output: process.stdout });
|
|
4892
5028
|
return new Promise((res) => {
|
|
@@ -4955,27 +5091,6 @@ function renderPreview(fields) {
|
|
|
4955
5091
|
console.log(" This is NOT required to use terminalhire.");
|
|
4956
5092
|
console.log("");
|
|
4957
5093
|
}
|
|
4958
|
-
function openInBrowser(url) {
|
|
4959
|
-
let cmd;
|
|
4960
|
-
let args3;
|
|
4961
|
-
if (process.platform === "darwin") {
|
|
4962
|
-
cmd = "open";
|
|
4963
|
-
args3 = [url];
|
|
4964
|
-
} else if (process.platform === "win32") {
|
|
4965
|
-
cmd = "cmd";
|
|
4966
|
-
args3 = ["/c", "start", "", url];
|
|
4967
|
-
} else {
|
|
4968
|
-
cmd = "xdg-open";
|
|
4969
|
-
args3 = [url];
|
|
4970
|
-
}
|
|
4971
|
-
try {
|
|
4972
|
-
const child = spawn(cmd, args3, { stdio: "ignore", detached: true });
|
|
4973
|
-
child.on("error", () => {
|
|
4974
|
-
});
|
|
4975
|
-
child.unref();
|
|
4976
|
-
} catch {
|
|
4977
|
-
}
|
|
4978
|
-
}
|
|
4979
5094
|
function sleep2(ms) {
|
|
4980
5095
|
return new Promise((res) => setTimeout(res, ms));
|
|
4981
5096
|
}
|
|
@@ -5244,6 +5359,7 @@ var TH_DIR3, TIER1_MARKER, API_URL3, SYNC_BASE, POLL_INTERVAL_MS, POLL_TIMEOUT_M
|
|
|
5244
5359
|
var init_jpi_sync = __esm({
|
|
5245
5360
|
"bin/jpi-sync.js"() {
|
|
5246
5361
|
"use strict";
|
|
5362
|
+
init_open_url();
|
|
5247
5363
|
TH_DIR3 = process.env["TERMINALHIRE_DIR"] || join12(homedir10(), ".terminalhire");
|
|
5248
5364
|
TIER1_MARKER = join12(TH_DIR3, "tier1.json");
|
|
5249
5365
|
API_URL3 = process.env["TERMINALHIRE_API_URL"] || process.env["JPI_API_URL"] || "https://terminalhire.com";
|
package/dist/bin/jpi-jobs.js
CHANGED
|
@@ -1640,6 +1640,28 @@ var init_bounty_gate = __esm({
|
|
|
1640
1640
|
}
|
|
1641
1641
|
});
|
|
1642
1642
|
|
|
1643
|
+
// ../../packages/core/src/concurrency.ts
|
|
1644
|
+
async function mapWithConcurrency(items, limit, fn) {
|
|
1645
|
+
const results = new Array(items.length);
|
|
1646
|
+
if (items.length === 0) return results;
|
|
1647
|
+
const workers = Math.max(1, Math.min(Math.floor(limit) || 1, items.length));
|
|
1648
|
+
let next = 0;
|
|
1649
|
+
async function run2() {
|
|
1650
|
+
for (; ; ) {
|
|
1651
|
+
const i = next++;
|
|
1652
|
+
if (i >= items.length) return;
|
|
1653
|
+
results[i] = await fn(items[i], i);
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
await Promise.all(Array.from({ length: workers }, run2));
|
|
1657
|
+
return results;
|
|
1658
|
+
}
|
|
1659
|
+
var init_concurrency = __esm({
|
|
1660
|
+
"../../packages/core/src/concurrency.ts"() {
|
|
1661
|
+
"use strict";
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
|
|
1643
1665
|
// ../../packages/core/src/feeds/github-bounties.ts
|
|
1644
1666
|
function authHeaders() {
|
|
1645
1667
|
const token = process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"];
|
|
@@ -1731,7 +1753,7 @@ async function fetchRepoBounties(repoFullName) {
|
|
|
1731
1753
|
if (!issues) return [];
|
|
1732
1754
|
const bounties = issues.filter(isBountyIssue).slice(0, MAX_BOUNTIES_PER_REPO);
|
|
1733
1755
|
const owner = repo.owner.login;
|
|
1734
|
-
return
|
|
1756
|
+
return mapWithConcurrency(bounties, BOUNTY_FETCH_CONCURRENCY, async (issue) => {
|
|
1735
1757
|
const title = decodeEntities(issue.title).trim();
|
|
1736
1758
|
const body = issue.body ? decodeEntities(issue.body) : "";
|
|
1737
1759
|
const amountUSD = parseAmountUSD(title) ?? parseAmountUSD(body) ?? await fetchCommentAmount(repoFullName, issue.number);
|
|
@@ -1760,7 +1782,7 @@ async function fetchRepoBounties(repoFullName) {
|
|
|
1760
1782
|
},
|
|
1761
1783
|
raw: issue
|
|
1762
1784
|
};
|
|
1763
|
-
})
|
|
1785
|
+
});
|
|
1764
1786
|
}
|
|
1765
1787
|
function repoFullNameFromApiUrl(url) {
|
|
1766
1788
|
const m = url.match(/\/repos\/([^/]+)\/([^/]+)\/?$/);
|
|
@@ -1902,7 +1924,7 @@ async function fetchSearchBounties() {
|
|
|
1902
1924
|
}
|
|
1903
1925
|
return jobs;
|
|
1904
1926
|
}
|
|
1905
|
-
var GITHUB_API, BOUNTY_LABEL_RE, SEARCH_QUERIES, SEARCH_PER_PAGE, MAX_SEARCH_BOUNTIES, MAX_SEARCH_ISSUES_SCANNED, REPO_META_CONCURRENCY, repoMetaCache, MAX_PR_PAGES, repoOpenPRRefsCache, issueStateCache, githubBounties;
|
|
1927
|
+
var GITHUB_API, BOUNTY_LABEL_RE, SEARCH_QUERIES, SEARCH_PER_PAGE, MAX_SEARCH_BOUNTIES, MAX_SEARCH_ISSUES_SCANNED, REPO_META_CONCURRENCY, BOUNTY_FETCH_CONCURRENCY, repoMetaCache, MAX_PR_PAGES, repoOpenPRRefsCache, issueStateCache, githubBounties;
|
|
1906
1928
|
var init_github_bounties = __esm({
|
|
1907
1929
|
"../../packages/core/src/feeds/github-bounties.ts"() {
|
|
1908
1930
|
"use strict";
|
|
@@ -1910,6 +1932,7 @@ var init_github_bounties = __esm({
|
|
|
1910
1932
|
init_entities();
|
|
1911
1933
|
init_bounty_gate();
|
|
1912
1934
|
init_http();
|
|
1935
|
+
init_concurrency();
|
|
1913
1936
|
GITHUB_API = "https://api.github.com";
|
|
1914
1937
|
BOUNTY_LABEL_RE = /bounty|reward|funded|💎|💰/i;
|
|
1915
1938
|
SEARCH_QUERIES = [
|
|
@@ -1922,6 +1945,7 @@ var init_github_bounties = __esm({
|
|
|
1922
1945
|
MAX_SEARCH_BOUNTIES = 150;
|
|
1923
1946
|
MAX_SEARCH_ISSUES_SCANNED = 300;
|
|
1924
1947
|
REPO_META_CONCURRENCY = 15;
|
|
1948
|
+
BOUNTY_FETCH_CONCURRENCY = 6;
|
|
1925
1949
|
repoMetaCache = /* @__PURE__ */ new Map();
|
|
1926
1950
|
MAX_PR_PAGES = 3;
|
|
1927
1951
|
repoOpenPRRefsCache = /* @__PURE__ */ new Map();
|
package/dist/bin/jpi-learn.js
CHANGED
|
@@ -509,6 +509,13 @@ var init_bounty_gate = __esm({
|
|
|
509
509
|
}
|
|
510
510
|
});
|
|
511
511
|
|
|
512
|
+
// ../../packages/core/src/concurrency.ts
|
|
513
|
+
var init_concurrency = __esm({
|
|
514
|
+
"../../packages/core/src/concurrency.ts"() {
|
|
515
|
+
"use strict";
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
|
|
512
519
|
// ../../packages/core/src/feeds/github-bounties.ts
|
|
513
520
|
var init_github_bounties = __esm({
|
|
514
521
|
"../../packages/core/src/feeds/github-bounties.ts"() {
|
|
@@ -517,6 +524,7 @@ var init_github_bounties = __esm({
|
|
|
517
524
|
init_entities();
|
|
518
525
|
init_bounty_gate();
|
|
519
526
|
init_http();
|
|
527
|
+
init_concurrency();
|
|
520
528
|
}
|
|
521
529
|
});
|
|
522
530
|
|
package/dist/bin/jpi-login.js
CHANGED
|
@@ -1854,6 +1854,28 @@ var init_bounty_gate = __esm({
|
|
|
1854
1854
|
}
|
|
1855
1855
|
});
|
|
1856
1856
|
|
|
1857
|
+
// ../../packages/core/src/concurrency.ts
|
|
1858
|
+
async function mapWithConcurrency(items, limit, fn) {
|
|
1859
|
+
const results = new Array(items.length);
|
|
1860
|
+
if (items.length === 0) return results;
|
|
1861
|
+
const workers = Math.max(1, Math.min(Math.floor(limit) || 1, items.length));
|
|
1862
|
+
let next = 0;
|
|
1863
|
+
async function run2() {
|
|
1864
|
+
for (; ; ) {
|
|
1865
|
+
const i = next++;
|
|
1866
|
+
if (i >= items.length) return;
|
|
1867
|
+
results[i] = await fn(items[i], i);
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
await Promise.all(Array.from({ length: workers }, run2));
|
|
1871
|
+
return results;
|
|
1872
|
+
}
|
|
1873
|
+
var init_concurrency = __esm({
|
|
1874
|
+
"../../packages/core/src/concurrency.ts"() {
|
|
1875
|
+
"use strict";
|
|
1876
|
+
}
|
|
1877
|
+
});
|
|
1878
|
+
|
|
1857
1879
|
// ../../packages/core/src/feeds/github-bounties.ts
|
|
1858
1880
|
function authHeaders() {
|
|
1859
1881
|
const token = process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"];
|
|
@@ -1945,7 +1967,7 @@ async function fetchRepoBounties(repoFullName) {
|
|
|
1945
1967
|
if (!issues) return [];
|
|
1946
1968
|
const bounties = issues.filter(isBountyIssue).slice(0, MAX_BOUNTIES_PER_REPO);
|
|
1947
1969
|
const owner = repo.owner.login;
|
|
1948
|
-
return
|
|
1970
|
+
return mapWithConcurrency(bounties, BOUNTY_FETCH_CONCURRENCY, async (issue) => {
|
|
1949
1971
|
const title = decodeEntities(issue.title).trim();
|
|
1950
1972
|
const body = issue.body ? decodeEntities(issue.body) : "";
|
|
1951
1973
|
const amountUSD = parseAmountUSD(title) ?? parseAmountUSD(body) ?? await fetchCommentAmount(repoFullName, issue.number);
|
|
@@ -1974,7 +1996,7 @@ async function fetchRepoBounties(repoFullName) {
|
|
|
1974
1996
|
},
|
|
1975
1997
|
raw: issue
|
|
1976
1998
|
};
|
|
1977
|
-
})
|
|
1999
|
+
});
|
|
1978
2000
|
}
|
|
1979
2001
|
function repoFullNameFromApiUrl(url) {
|
|
1980
2002
|
const m = url.match(/\/repos\/([^/]+)\/([^/]+)\/?$/);
|
|
@@ -2116,7 +2138,7 @@ async function fetchSearchBounties() {
|
|
|
2116
2138
|
}
|
|
2117
2139
|
return jobs;
|
|
2118
2140
|
}
|
|
2119
|
-
var GITHUB_API, BOUNTY_LABEL_RE, SEARCH_QUERIES, SEARCH_PER_PAGE, MAX_SEARCH_BOUNTIES, MAX_SEARCH_ISSUES_SCANNED, REPO_META_CONCURRENCY, repoMetaCache, MAX_PR_PAGES, repoOpenPRRefsCache, issueStateCache, githubBounties;
|
|
2141
|
+
var GITHUB_API, BOUNTY_LABEL_RE, SEARCH_QUERIES, SEARCH_PER_PAGE, MAX_SEARCH_BOUNTIES, MAX_SEARCH_ISSUES_SCANNED, REPO_META_CONCURRENCY, BOUNTY_FETCH_CONCURRENCY, repoMetaCache, MAX_PR_PAGES, repoOpenPRRefsCache, issueStateCache, githubBounties;
|
|
2120
2142
|
var init_github_bounties = __esm({
|
|
2121
2143
|
"../../packages/core/src/feeds/github-bounties.ts"() {
|
|
2122
2144
|
"use strict";
|
|
@@ -2124,6 +2146,7 @@ var init_github_bounties = __esm({
|
|
|
2124
2146
|
init_entities();
|
|
2125
2147
|
init_bounty_gate();
|
|
2126
2148
|
init_http();
|
|
2149
|
+
init_concurrency();
|
|
2127
2150
|
GITHUB_API = "https://api.github.com";
|
|
2128
2151
|
BOUNTY_LABEL_RE = /bounty|reward|funded|💎|💰/i;
|
|
2129
2152
|
SEARCH_QUERIES = [
|
|
@@ -2136,6 +2159,7 @@ var init_github_bounties = __esm({
|
|
|
2136
2159
|
MAX_SEARCH_BOUNTIES = 150;
|
|
2137
2160
|
MAX_SEARCH_ISSUES_SCANNED = 300;
|
|
2138
2161
|
REPO_META_CONCURRENCY = 15;
|
|
2162
|
+
BOUNTY_FETCH_CONCURRENCY = 6;
|
|
2139
2163
|
repoMetaCache = /* @__PURE__ */ new Map();
|
|
2140
2164
|
MAX_PR_PAGES = 3;
|
|
2141
2165
|
repoOpenPRRefsCache = /* @__PURE__ */ new Map();
|
|
@@ -3035,6 +3059,30 @@ var init_profile = __esm({
|
|
|
3035
3059
|
}
|
|
3036
3060
|
});
|
|
3037
3061
|
|
|
3062
|
+
// src/open-url.js
|
|
3063
|
+
import { spawn } from "child_process";
|
|
3064
|
+
function openInBrowser(url) {
|
|
3065
|
+
let cmd;
|
|
3066
|
+
let args;
|
|
3067
|
+
if (process.platform === "darwin") {
|
|
3068
|
+
cmd = "open";
|
|
3069
|
+
args = [url];
|
|
3070
|
+
} else if (process.platform === "win32") {
|
|
3071
|
+
cmd = "cmd";
|
|
3072
|
+
args = ["/c", "start", "", url];
|
|
3073
|
+
} else {
|
|
3074
|
+
cmd = "xdg-open";
|
|
3075
|
+
args = [url];
|
|
3076
|
+
}
|
|
3077
|
+
try {
|
|
3078
|
+
const child = spawn(cmd, args, { stdio: "ignore", detached: true });
|
|
3079
|
+
child.on("error", () => {
|
|
3080
|
+
});
|
|
3081
|
+
child.unref();
|
|
3082
|
+
} catch {
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
|
|
3038
3086
|
// bin/jpi-login.js
|
|
3039
3087
|
async function run() {
|
|
3040
3088
|
const subcommand = process.argv[2];
|
|
@@ -3120,6 +3168,26 @@ async function runLogin() {
|
|
|
3120
3168
|
console.log(" Profile updated at ~/.terminalhire/profile.enc (encrypted at rest)");
|
|
3121
3169
|
console.log(" GitHub data stays on your machine unless you consent to share it in a lead.");
|
|
3122
3170
|
console.log("");
|
|
3171
|
+
const skipWeb = process.argv.includes("--no-web");
|
|
3172
|
+
if (!isMock && !skipWeb) {
|
|
3173
|
+
try {
|
|
3174
|
+
const OAUTH_BASE = "https://www.terminalhire.com";
|
|
3175
|
+
const webUrl = `${OAUTH_BASE}/api/auth/github?next=/dashboard`;
|
|
3176
|
+
console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
3177
|
+
console.log(" Your web profile & r\xE9sum\xE9 \u2014 public GitHub data only,");
|
|
3178
|
+
console.log(" your local profile is NOT uploaded.");
|
|
3179
|
+
console.log(` \u2192 ${webUrl}`);
|
|
3180
|
+
if (process.stdout.isTTY) {
|
|
3181
|
+
console.log(" Opening it now to sign you in at terminalhire.com\u2026");
|
|
3182
|
+
openInBrowser(webUrl);
|
|
3183
|
+
} else {
|
|
3184
|
+
console.log(" Open the link above to sign in & view your r\xE9sum\xE9.");
|
|
3185
|
+
}
|
|
3186
|
+
console.log(" (skip next time with: terminalhire login --no-web)");
|
|
3187
|
+
console.log("");
|
|
3188
|
+
} catch {
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3123
3191
|
console.log(" Run `terminalhire jobs` to see matching roles using your enriched profile.");
|
|
3124
3192
|
console.log("");
|
|
3125
3193
|
} catch (err) {
|
package/dist/bin/jpi-profile.js
CHANGED
|
@@ -509,6 +509,13 @@ var init_bounty_gate = __esm({
|
|
|
509
509
|
}
|
|
510
510
|
});
|
|
511
511
|
|
|
512
|
+
// ../../packages/core/src/concurrency.ts
|
|
513
|
+
var init_concurrency = __esm({
|
|
514
|
+
"../../packages/core/src/concurrency.ts"() {
|
|
515
|
+
"use strict";
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
|
|
512
519
|
// ../../packages/core/src/feeds/github-bounties.ts
|
|
513
520
|
var init_github_bounties = __esm({
|
|
514
521
|
"../../packages/core/src/feeds/github-bounties.ts"() {
|
|
@@ -517,6 +524,7 @@ var init_github_bounties = __esm({
|
|
|
517
524
|
init_entities();
|
|
518
525
|
init_bounty_gate();
|
|
519
526
|
init_http();
|
|
527
|
+
init_concurrency();
|
|
520
528
|
}
|
|
521
529
|
});
|
|
522
530
|
|
package/dist/bin/jpi-refresh.js
CHANGED
|
@@ -1640,6 +1640,28 @@ var init_bounty_gate = __esm({
|
|
|
1640
1640
|
}
|
|
1641
1641
|
});
|
|
1642
1642
|
|
|
1643
|
+
// ../../packages/core/src/concurrency.ts
|
|
1644
|
+
async function mapWithConcurrency(items, limit, fn) {
|
|
1645
|
+
const results = new Array(items.length);
|
|
1646
|
+
if (items.length === 0) return results;
|
|
1647
|
+
const workers = Math.max(1, Math.min(Math.floor(limit) || 1, items.length));
|
|
1648
|
+
let next = 0;
|
|
1649
|
+
async function run2() {
|
|
1650
|
+
for (; ; ) {
|
|
1651
|
+
const i = next++;
|
|
1652
|
+
if (i >= items.length) return;
|
|
1653
|
+
results[i] = await fn(items[i], i);
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
await Promise.all(Array.from({ length: workers }, run2));
|
|
1657
|
+
return results;
|
|
1658
|
+
}
|
|
1659
|
+
var init_concurrency = __esm({
|
|
1660
|
+
"../../packages/core/src/concurrency.ts"() {
|
|
1661
|
+
"use strict";
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
|
|
1643
1665
|
// ../../packages/core/src/feeds/github-bounties.ts
|
|
1644
1666
|
function authHeaders() {
|
|
1645
1667
|
const token = process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"];
|
|
@@ -1731,7 +1753,7 @@ async function fetchRepoBounties(repoFullName) {
|
|
|
1731
1753
|
if (!issues) return [];
|
|
1732
1754
|
const bounties = issues.filter(isBountyIssue).slice(0, MAX_BOUNTIES_PER_REPO);
|
|
1733
1755
|
const owner = repo.owner.login;
|
|
1734
|
-
return
|
|
1756
|
+
return mapWithConcurrency(bounties, BOUNTY_FETCH_CONCURRENCY, async (issue) => {
|
|
1735
1757
|
const title = decodeEntities(issue.title).trim();
|
|
1736
1758
|
const body = issue.body ? decodeEntities(issue.body) : "";
|
|
1737
1759
|
const amountUSD = parseAmountUSD(title) ?? parseAmountUSD(body) ?? await fetchCommentAmount(repoFullName, issue.number);
|
|
@@ -1760,7 +1782,7 @@ async function fetchRepoBounties(repoFullName) {
|
|
|
1760
1782
|
},
|
|
1761
1783
|
raw: issue
|
|
1762
1784
|
};
|
|
1763
|
-
})
|
|
1785
|
+
});
|
|
1764
1786
|
}
|
|
1765
1787
|
function repoFullNameFromApiUrl(url) {
|
|
1766
1788
|
const m = url.match(/\/repos\/([^/]+)\/([^/]+)\/?$/);
|
|
@@ -1902,7 +1924,7 @@ async function fetchSearchBounties() {
|
|
|
1902
1924
|
}
|
|
1903
1925
|
return jobs;
|
|
1904
1926
|
}
|
|
1905
|
-
var GITHUB_API, BOUNTY_LABEL_RE, SEARCH_QUERIES, SEARCH_PER_PAGE, MAX_SEARCH_BOUNTIES, MAX_SEARCH_ISSUES_SCANNED, REPO_META_CONCURRENCY, repoMetaCache, MAX_PR_PAGES, repoOpenPRRefsCache, issueStateCache, githubBounties;
|
|
1927
|
+
var GITHUB_API, BOUNTY_LABEL_RE, SEARCH_QUERIES, SEARCH_PER_PAGE, MAX_SEARCH_BOUNTIES, MAX_SEARCH_ISSUES_SCANNED, REPO_META_CONCURRENCY, BOUNTY_FETCH_CONCURRENCY, repoMetaCache, MAX_PR_PAGES, repoOpenPRRefsCache, issueStateCache, githubBounties;
|
|
1906
1928
|
var init_github_bounties = __esm({
|
|
1907
1929
|
"../../packages/core/src/feeds/github-bounties.ts"() {
|
|
1908
1930
|
"use strict";
|
|
@@ -1910,6 +1932,7 @@ var init_github_bounties = __esm({
|
|
|
1910
1932
|
init_entities();
|
|
1911
1933
|
init_bounty_gate();
|
|
1912
1934
|
init_http();
|
|
1935
|
+
init_concurrency();
|
|
1913
1936
|
GITHUB_API = "https://api.github.com";
|
|
1914
1937
|
BOUNTY_LABEL_RE = /bounty|reward|funded|💎|💰/i;
|
|
1915
1938
|
SEARCH_QUERIES = [
|
|
@@ -1922,6 +1945,7 @@ var init_github_bounties = __esm({
|
|
|
1922
1945
|
MAX_SEARCH_BOUNTIES = 150;
|
|
1923
1946
|
MAX_SEARCH_ISSUES_SCANNED = 300;
|
|
1924
1947
|
REPO_META_CONCURRENCY = 15;
|
|
1948
|
+
BOUNTY_FETCH_CONCURRENCY = 6;
|
|
1925
1949
|
repoMetaCache = /* @__PURE__ */ new Map();
|
|
1926
1950
|
MAX_PR_PAGES = 3;
|
|
1927
1951
|
repoOpenPRRefsCache = /* @__PURE__ */ new Map();
|
package/dist/bin/jpi-save.js
CHANGED
|
@@ -509,6 +509,13 @@ var init_bounty_gate = __esm({
|
|
|
509
509
|
}
|
|
510
510
|
});
|
|
511
511
|
|
|
512
|
+
// ../../packages/core/src/concurrency.ts
|
|
513
|
+
var init_concurrency = __esm({
|
|
514
|
+
"../../packages/core/src/concurrency.ts"() {
|
|
515
|
+
"use strict";
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
|
|
512
519
|
// ../../packages/core/src/feeds/github-bounties.ts
|
|
513
520
|
var init_github_bounties = __esm({
|
|
514
521
|
"../../packages/core/src/feeds/github-bounties.ts"() {
|
|
@@ -517,6 +524,7 @@ var init_github_bounties = __esm({
|
|
|
517
524
|
init_entities();
|
|
518
525
|
init_bounty_gate();
|
|
519
526
|
init_http();
|
|
527
|
+
init_concurrency();
|
|
520
528
|
}
|
|
521
529
|
});
|
|
522
530
|
|
package/dist/bin/jpi-sync.js
CHANGED
|
@@ -509,6 +509,13 @@ var init_bounty_gate = __esm({
|
|
|
509
509
|
}
|
|
510
510
|
});
|
|
511
511
|
|
|
512
|
+
// ../../packages/core/src/concurrency.ts
|
|
513
|
+
var init_concurrency = __esm({
|
|
514
|
+
"../../packages/core/src/concurrency.ts"() {
|
|
515
|
+
"use strict";
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
|
|
512
519
|
// ../../packages/core/src/feeds/github-bounties.ts
|
|
513
520
|
var init_github_bounties = __esm({
|
|
514
521
|
"../../packages/core/src/feeds/github-bounties.ts"() {
|
|
@@ -517,6 +524,7 @@ var init_github_bounties = __esm({
|
|
|
517
524
|
init_entities();
|
|
518
525
|
init_bounty_gate();
|
|
519
526
|
init_http();
|
|
527
|
+
init_concurrency();
|
|
520
528
|
}
|
|
521
529
|
});
|
|
522
530
|
|
|
@@ -954,7 +962,32 @@ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSy
|
|
|
954
962
|
import { join as join3 } from "path";
|
|
955
963
|
import { homedir as homedir2, hostname as osHostname } from "os";
|
|
956
964
|
import { createInterface } from "readline";
|
|
965
|
+
|
|
966
|
+
// src/open-url.js
|
|
957
967
|
import { spawn } from "child_process";
|
|
968
|
+
function openInBrowser(url) {
|
|
969
|
+
let cmd;
|
|
970
|
+
let args;
|
|
971
|
+
if (process.platform === "darwin") {
|
|
972
|
+
cmd = "open";
|
|
973
|
+
args = [url];
|
|
974
|
+
} else if (process.platform === "win32") {
|
|
975
|
+
cmd = "cmd";
|
|
976
|
+
args = ["/c", "start", "", url];
|
|
977
|
+
} else {
|
|
978
|
+
cmd = "xdg-open";
|
|
979
|
+
args = [url];
|
|
980
|
+
}
|
|
981
|
+
try {
|
|
982
|
+
const child = spawn(cmd, args, { stdio: "ignore", detached: true });
|
|
983
|
+
child.on("error", () => {
|
|
984
|
+
});
|
|
985
|
+
child.unref();
|
|
986
|
+
} catch {
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
// bin/jpi-sync.js
|
|
958
991
|
var TH_DIR = process.env["TERMINALHIRE_DIR"] || join3(homedir2(), ".terminalhire");
|
|
959
992
|
var TIER1_MARKER = join3(TH_DIR, "tier1.json");
|
|
960
993
|
var API_URL = process.env["TERMINALHIRE_API_URL"] || process.env["JPI_API_URL"] || "https://terminalhire.com";
|
|
@@ -1030,27 +1063,6 @@ function renderPreview(fields) {
|
|
|
1030
1063
|
console.log(" This is NOT required to use terminalhire.");
|
|
1031
1064
|
console.log("");
|
|
1032
1065
|
}
|
|
1033
|
-
function openInBrowser(url) {
|
|
1034
|
-
let cmd;
|
|
1035
|
-
let args;
|
|
1036
|
-
if (process.platform === "darwin") {
|
|
1037
|
-
cmd = "open";
|
|
1038
|
-
args = [url];
|
|
1039
|
-
} else if (process.platform === "win32") {
|
|
1040
|
-
cmd = "cmd";
|
|
1041
|
-
args = ["/c", "start", "", url];
|
|
1042
|
-
} else {
|
|
1043
|
-
cmd = "xdg-open";
|
|
1044
|
-
args = [url];
|
|
1045
|
-
}
|
|
1046
|
-
try {
|
|
1047
|
-
const child = spawn(cmd, args, { stdio: "ignore", detached: true });
|
|
1048
|
-
child.on("error", () => {
|
|
1049
|
-
});
|
|
1050
|
-
child.unref();
|
|
1051
|
-
} catch {
|
|
1052
|
-
}
|
|
1053
|
-
}
|
|
1054
1066
|
function sleep(ms) {
|
|
1055
1067
|
return new Promise((res) => setTimeout(res, ms));
|
|
1056
1068
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// src/acceptance-score.ts
|
|
2
|
+
var clamp01 = (n) => Math.max(0, Math.min(1, n));
|
|
3
|
+
function scoreDiffAcceptance(input) {
|
|
4
|
+
const reasons = [];
|
|
5
|
+
let score = 0.5;
|
|
6
|
+
const prs = Math.max(0, Math.floor(input.competingOpenPRs));
|
|
7
|
+
if (prs === 0) {
|
|
8
|
+
score += 0.2;
|
|
9
|
+
reasons.push("no competing open PRs (+0.20)");
|
|
10
|
+
} else if (prs === 1) {
|
|
11
|
+
score -= 0.05;
|
|
12
|
+
reasons.push("1 competing open PR (-0.05)");
|
|
13
|
+
} else if (prs === 2) {
|
|
14
|
+
score -= 0.2;
|
|
15
|
+
reasons.push("2 competing open PRs (-0.20)");
|
|
16
|
+
} else {
|
|
17
|
+
score -= 0.35;
|
|
18
|
+
reasons.push(`${prs} competing open PRs \u2014 heavily contested (-0.35)`);
|
|
19
|
+
}
|
|
20
|
+
if (input.filesChanged <= 3 && input.linesChanged <= 150) {
|
|
21
|
+
score += 0.15;
|
|
22
|
+
reasons.push("small, focused diff (+0.15)");
|
|
23
|
+
} else if (input.filesChanged > 15 || input.linesChanged > 800) {
|
|
24
|
+
score -= 0.2;
|
|
25
|
+
reasons.push("large diff \u2014 harder to review/merge (-0.20)");
|
|
26
|
+
} else {
|
|
27
|
+
reasons.push("moderate diff size (0)");
|
|
28
|
+
}
|
|
29
|
+
if (input.touchesTests) {
|
|
30
|
+
score += 0.1;
|
|
31
|
+
reasons.push("includes test changes (+0.10)");
|
|
32
|
+
} else {
|
|
33
|
+
score -= 0.05;
|
|
34
|
+
reasons.push("no test changes (-0.05)");
|
|
35
|
+
}
|
|
36
|
+
if (input.matchesIssueArea === true) {
|
|
37
|
+
score += 0.1;
|
|
38
|
+
reasons.push("touches the issue's referenced files (+0.10)");
|
|
39
|
+
} else if (input.matchesIssueArea === false) {
|
|
40
|
+
score -= 0.1;
|
|
41
|
+
reasons.push("does not touch the issue's referenced files (-0.10)");
|
|
42
|
+
} else {
|
|
43
|
+
reasons.push("issue-area match unknown (0)");
|
|
44
|
+
}
|
|
45
|
+
return { score: Math.round(clamp01(score) * 100) / 100, reasons };
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
scoreDiffAcceptance
|
|
49
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "terminalhire",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.6",
|
|
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",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"README.md"
|
|
27
27
|
],
|
|
28
28
|
"scripts": {
|
|
29
|
+
"test": "for f in test/*.test.js; do echo \"# $f\"; node \"$f\" || exit 1; done",
|
|
29
30
|
"build": "tsup",
|
|
30
31
|
"bundle:plugin": "npm run build && rm -rf ../../plugins/terminalhire/dist && cp -R dist ../../plugins/terminalhire/dist && cp package.json ../../plugins/terminalhire/dist/package.json && cp install.js ../../plugins/terminalhire/dist/install.js && cp postinstall.js ../../plugins/terminalhire/dist/postinstall.js",
|
|
31
32
|
"prepublishOnly": "npm run build",
|