terminalhire 0.26.0 → 0.26.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/claim-push-bg.js +2 -2
- package/dist/bin/jpi-bounties.js +375 -171
- package/dist/bin/jpi-chat-read.js +24 -2
- package/dist/bin/jpi-chat.js +24 -2
- package/dist/bin/jpi-claim.js +399 -174
- package/dist/bin/jpi-contribute.js +67 -24
- package/dist/bin/jpi-devs.js +375 -171
- package/dist/bin/jpi-dispatch.js +411 -176
- package/dist/bin/jpi-hub.js +375 -171
- package/dist/bin/jpi-inbox.js +24 -2
- package/dist/bin/jpi-init.js +373 -169
- package/dist/bin/jpi-intro.js +24 -2
- package/dist/bin/jpi-jobs.js +375 -171
- package/dist/bin/jpi-learn.js +24 -2
- package/dist/bin/jpi-login.js +375 -171
- package/dist/bin/jpi-profile.js +24 -2
- package/dist/bin/jpi-project.js +373 -169
- package/dist/bin/jpi-refresh.js +375 -171
- package/dist/bin/jpi-save.js +24 -2
- package/dist/bin/jpi-spinner.js +12 -0
- package/dist/bin/jpi-sync.js +24 -2
- package/dist/bin/jpi-trajectory.js +24 -2
- package/dist/bin/spinner.js +12 -0
- package/dist/src/chat-client.js +14 -2
- package/dist/src/chat-keystore.js +14 -2
- package/dist/src/github-auth.js +2 -2
- package/dist/src/intro.js +24 -2
- package/dist/src/profile.js +14 -2
- package/dist/src/signal.js +12 -0
- package/dist/src/trajectory.js +24 -2
- package/package.json +1 -1
package/dist/bin/jpi-hub.js
CHANGED
|
@@ -1226,6 +1226,187 @@ var init_rigor = __esm({
|
|
|
1226
1226
|
}
|
|
1227
1227
|
});
|
|
1228
1228
|
|
|
1229
|
+
// ../../packages/core/src/gh-governor.ts
|
|
1230
|
+
function readReqGapMs() {
|
|
1231
|
+
const raw = process.env["CONTRIB_REQ_GAP_MS"];
|
|
1232
|
+
if (raw == null) return DEFAULT_REQ_GAP_MS;
|
|
1233
|
+
const n = Number.parseInt(raw, 10);
|
|
1234
|
+
if (Number.isNaN(n)) return DEFAULT_REQ_GAP_MS;
|
|
1235
|
+
return Math.min(Math.max(n, 0), 1e3);
|
|
1236
|
+
}
|
|
1237
|
+
function readBuildBudgetMs() {
|
|
1238
|
+
const raw = process.env["CONTRIB_BUILD_BUDGET_MS"];
|
|
1239
|
+
if (raw == null) return DEFAULT_BUILD_BUDGET_MS;
|
|
1240
|
+
const n = Number.parseInt(raw, 10);
|
|
1241
|
+
if (Number.isNaN(n)) return DEFAULT_BUILD_BUDGET_MS;
|
|
1242
|
+
return Math.min(Math.max(n, MIN_BUILD_BUDGET_MS), MAX_BUILD_BUDGET_MS);
|
|
1243
|
+
}
|
|
1244
|
+
function makeDefaultGovernorConfig(o) {
|
|
1245
|
+
return {
|
|
1246
|
+
paceEnabled: o.paceEnabled,
|
|
1247
|
+
gapMs: readReqGapMs(),
|
|
1248
|
+
budgetMs: readBuildBudgetMs(),
|
|
1249
|
+
sleep: o.sleep ?? realSleep,
|
|
1250
|
+
now: o.now ?? Date.now,
|
|
1251
|
+
probeTimeoutMs: o.probeTimeoutMs ?? (o.paceEnabled ? PROBE_TIMEOUT_MS : null)
|
|
1252
|
+
};
|
|
1253
|
+
}
|
|
1254
|
+
function makeGitHubGovernor(fetchImpl, cfg) {
|
|
1255
|
+
const startedAt = cfg.now();
|
|
1256
|
+
let lastRequestAt = 0;
|
|
1257
|
+
let pacedMs = 0;
|
|
1258
|
+
let secondaryHits = 0;
|
|
1259
|
+
let aborted = false;
|
|
1260
|
+
let secondaryAborted = false;
|
|
1261
|
+
let budgetAborted = false;
|
|
1262
|
+
let gqlCost = 0;
|
|
1263
|
+
let gqlRemaining = null;
|
|
1264
|
+
let coreHealthyAtStart = false;
|
|
1265
|
+
async function noteAndMaybeBackOff(res) {
|
|
1266
|
+
if (res.status !== 403) return;
|
|
1267
|
+
const remaining = res.headers.get("x-ratelimit-remaining");
|
|
1268
|
+
const retryAfter = res.headers.get("retry-after");
|
|
1269
|
+
const positiveSecondary = retryAfter != null || remaining != null && remaining !== "0";
|
|
1270
|
+
const isSecondary = positiveSecondary || coreHealthyAtStart;
|
|
1271
|
+
if (!isSecondary) return;
|
|
1272
|
+
await recordSecondaryStrike(retryAfter);
|
|
1273
|
+
}
|
|
1274
|
+
async function recordSecondaryStrike(retryAfter) {
|
|
1275
|
+
secondaryHits++;
|
|
1276
|
+
if (secondaryHits >= 2) {
|
|
1277
|
+
aborted = true;
|
|
1278
|
+
secondaryAborted = true;
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
if (cfg.paceEnabled) {
|
|
1282
|
+
const trimmed = (retryAfter ?? "").trim();
|
|
1283
|
+
const parsed = trimmed.length === 0 ? Number.NaN : Number(trimmed);
|
|
1284
|
+
const sec = Number.isNaN(parsed) ? SECONDARY_BACKOFF_CAP_S : Math.min(Math.max(parsed, 0), SECONDARY_BACKOFF_CAP_S);
|
|
1285
|
+
const remainingBudget = Math.max(0, cfg.budgetMs - (cfg.now() - startedAt));
|
|
1286
|
+
await cfg.sleep(Math.min(sec * 1e3, remainingBudget));
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
async function noteGraphQLAndMaybeBackOff(res, body) {
|
|
1290
|
+
const b = body ?? {};
|
|
1291
|
+
const rl = b.data?.rateLimit;
|
|
1292
|
+
if (rl) {
|
|
1293
|
+
if (typeof rl.cost === "number") gqlCost += rl.cost;
|
|
1294
|
+
if (typeof rl.remaining === "number") gqlRemaining = rl.remaining;
|
|
1295
|
+
}
|
|
1296
|
+
const remainingHdr = res.headers?.get("x-ratelimit-remaining") ?? null;
|
|
1297
|
+
const retryAfter = res.headers?.get("retry-after") ?? null;
|
|
1298
|
+
const headerRate = retryAfter != null || remainingHdr === "0";
|
|
1299
|
+
const errs = Array.isArray(b.errors) ? b.errors : [];
|
|
1300
|
+
const bodyRate = errs.some((e) => e?.type === "RATE_LIMITED" || /rate limit/i.test(String(e?.message ?? ""))) || typeof rl?.remaining === "number" && rl.remaining <= 0;
|
|
1301
|
+
if (headerRate || bodyRate) await recordSecondaryStrike(retryAfter);
|
|
1302
|
+
}
|
|
1303
|
+
async function preflight() {
|
|
1304
|
+
if (aborted) return false;
|
|
1305
|
+
if (cfg.now() - startedAt >= cfg.budgetMs) {
|
|
1306
|
+
aborted = true;
|
|
1307
|
+
budgetAborted = true;
|
|
1308
|
+
return false;
|
|
1309
|
+
}
|
|
1310
|
+
if (cfg.paceEnabled && cfg.gapMs > 0) {
|
|
1311
|
+
const wait = cfg.gapMs - (cfg.now() - lastRequestAt);
|
|
1312
|
+
if (wait > 0) {
|
|
1313
|
+
await cfg.sleep(wait);
|
|
1314
|
+
pacedMs += wait;
|
|
1315
|
+
if (cfg.now() - startedAt >= cfg.budgetMs) {
|
|
1316
|
+
aborted = true;
|
|
1317
|
+
budgetAborted = true;
|
|
1318
|
+
return false;
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
lastRequestAt = cfg.now();
|
|
1322
|
+
}
|
|
1323
|
+
return true;
|
|
1324
|
+
}
|
|
1325
|
+
async function get(url, init) {
|
|
1326
|
+
if (!await preflight()) return null;
|
|
1327
|
+
try {
|
|
1328
|
+
const res = await fetchImpl(url, init);
|
|
1329
|
+
await noteAndMaybeBackOff(res);
|
|
1330
|
+
return res;
|
|
1331
|
+
} catch {
|
|
1332
|
+
return null;
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
async function graphql(url, init) {
|
|
1336
|
+
if (!await preflight()) return null;
|
|
1337
|
+
let res;
|
|
1338
|
+
try {
|
|
1339
|
+
res = await fetchImpl(url, init);
|
|
1340
|
+
} catch {
|
|
1341
|
+
return null;
|
|
1342
|
+
}
|
|
1343
|
+
let body;
|
|
1344
|
+
try {
|
|
1345
|
+
body = await res.json();
|
|
1346
|
+
} catch {
|
|
1347
|
+
return null;
|
|
1348
|
+
}
|
|
1349
|
+
await noteGraphQLAndMaybeBackOff(res, body);
|
|
1350
|
+
if (!res.ok) return null;
|
|
1351
|
+
return body;
|
|
1352
|
+
}
|
|
1353
|
+
async function probe(url, init) {
|
|
1354
|
+
const bound = cfg.probeTimeoutMs;
|
|
1355
|
+
let timer;
|
|
1356
|
+
const fetchP = fetchImpl(url, init).then(
|
|
1357
|
+
(r) => r,
|
|
1358
|
+
() => null
|
|
1359
|
+
);
|
|
1360
|
+
try {
|
|
1361
|
+
const res = bound == null ? await fetchP : await Promise.race([
|
|
1362
|
+
fetchP,
|
|
1363
|
+
new Promise((resolve) => {
|
|
1364
|
+
timer = setTimeout(() => resolve(null), bound);
|
|
1365
|
+
})
|
|
1366
|
+
]);
|
|
1367
|
+
if (!res || !res.ok) return null;
|
|
1368
|
+
return await res.json();
|
|
1369
|
+
} catch {
|
|
1370
|
+
return null;
|
|
1371
|
+
} finally {
|
|
1372
|
+
if (timer) clearTimeout(timer);
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
function setSecondaryHint(coreHealthy) {
|
|
1376
|
+
coreHealthyAtStart = coreHealthy;
|
|
1377
|
+
}
|
|
1378
|
+
function getStats() {
|
|
1379
|
+
return {
|
|
1380
|
+
pacedMs,
|
|
1381
|
+
secondaryAborted: secondaryAborted ? 1 : 0,
|
|
1382
|
+
budgetAborted: budgetAborted ? 1 : 0,
|
|
1383
|
+
elapsedMs: cfg.now() - startedAt,
|
|
1384
|
+
gqlCost,
|
|
1385
|
+
gqlRemaining
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
function tripped() {
|
|
1389
|
+
return secondaryAborted;
|
|
1390
|
+
}
|
|
1391
|
+
function budgetExhausted() {
|
|
1392
|
+
return budgetAborted || cfg.now() - startedAt >= cfg.budgetMs;
|
|
1393
|
+
}
|
|
1394
|
+
return { get, graphql, probe, setSecondaryHint, getStats, tripped, budgetExhausted };
|
|
1395
|
+
}
|
|
1396
|
+
var DEFAULT_REQ_GAP_MS, SECONDARY_BACKOFF_CAP_S, DEFAULT_BUILD_BUDGET_MS, MIN_BUILD_BUDGET_MS, MAX_BUILD_BUDGET_MS, PROBE_TIMEOUT_MS, realSleep;
|
|
1397
|
+
var init_gh_governor = __esm({
|
|
1398
|
+
"../../packages/core/src/gh-governor.ts"() {
|
|
1399
|
+
"use strict";
|
|
1400
|
+
DEFAULT_REQ_GAP_MS = 75;
|
|
1401
|
+
SECONDARY_BACKOFF_CAP_S = 30;
|
|
1402
|
+
DEFAULT_BUILD_BUDGET_MS = 9e4;
|
|
1403
|
+
MIN_BUILD_BUDGET_MS = 1e4;
|
|
1404
|
+
MAX_BUILD_BUDGET_MS = 9e4;
|
|
1405
|
+
PROBE_TIMEOUT_MS = 3e3;
|
|
1406
|
+
realSleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
1407
|
+
}
|
|
1408
|
+
});
|
|
1409
|
+
|
|
1229
1410
|
// ../../packages/core/src/github.ts
|
|
1230
1411
|
function ghHeaders(token) {
|
|
1231
1412
|
const headers = {
|
|
@@ -1706,11 +1887,9 @@ async function fetchRepoReceptivity(fullName, opts = {}) {
|
|
|
1706
1887
|
const doFetch = opts.fetchImpl ?? fetch;
|
|
1707
1888
|
const now = opts.now ?? Date.now();
|
|
1708
1889
|
try {
|
|
1709
|
-
const
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
);
|
|
1713
|
-
if (!res.ok) return null;
|
|
1890
|
+
const url = `https://api.github.com/repos/${fullName}/pulls?state=closed&per_page=50&sort=updated&direction=desc`;
|
|
1891
|
+
const res = opts.governor ? await opts.governor.get(url, { headers: ghHeaders(opts.token) }) : await doFetch(url, { headers: ghHeaders(opts.token) });
|
|
1892
|
+
if (!res || !res.ok) return null;
|
|
1714
1893
|
const prs = await res.json();
|
|
1715
1894
|
if (!Array.isArray(prs)) return null;
|
|
1716
1895
|
const external = prs.filter(isExternalAuthor);
|
|
@@ -1795,25 +1974,34 @@ function parseGitHubRef(url) {
|
|
|
1795
1974
|
if (!m) return null;
|
|
1796
1975
|
return { owner: m[1], repo: m[2], number: parseInt(m[4], 10), kind: m[3] === "pull" ? "pull" : "issue" };
|
|
1797
1976
|
}
|
|
1798
|
-
async function ghGraphQL(query, variables, token, signal) {
|
|
1799
|
-
const
|
|
1977
|
+
async function ghGraphQL(query, variables, token, signal, governor) {
|
|
1978
|
+
const init = {
|
|
1800
1979
|
method: "POST",
|
|
1801
1980
|
headers: { ...ghHeaders(token), "Content-Type": "application/json" },
|
|
1802
1981
|
body: JSON.stringify({ query, variables }),
|
|
1803
1982
|
signal
|
|
1804
|
-
}
|
|
1983
|
+
};
|
|
1984
|
+
if (governor) {
|
|
1985
|
+
const json2 = await governor.graphql(GITHUB_GRAPHQL_URL, init);
|
|
1986
|
+
if (json2 === null) return null;
|
|
1987
|
+
if (json2.errors?.length) throw new Error("GitHub GraphQL errors: " + JSON.stringify(json2.errors));
|
|
1988
|
+
return json2;
|
|
1989
|
+
}
|
|
1990
|
+
const res = await fetch(GITHUB_GRAPHQL_URL, init);
|
|
1805
1991
|
if (!res.ok) throw new Error(`GitHub GraphQL: HTTP ${res.status}`);
|
|
1806
1992
|
const json = await res.json();
|
|
1807
1993
|
if (json.errors?.length) throw new Error("GitHub GraphQL errors: " + JSON.stringify(json.errors));
|
|
1808
1994
|
return json;
|
|
1809
1995
|
}
|
|
1810
|
-
async function resolveClosingIssues(owner, name, number, body, token, signal) {
|
|
1996
|
+
async function resolveClosingIssues(owner, name, number, body, token, signal, governor) {
|
|
1811
1997
|
if (token) {
|
|
1812
1998
|
try {
|
|
1813
|
-
const q = `query($o:String!,$n:String!,$p:Int!){repository(owner:$o,name:$n){pullRequest(number:$p){closingIssuesReferences(first:20){nodes{number}}}}}`;
|
|
1814
|
-
const r = await ghGraphQL(q, { o: owner, n: name, p: number }, token, signal);
|
|
1815
|
-
|
|
1816
|
-
|
|
1999
|
+
const q = `query($o:String!,$n:String!,$p:Int!){repository(owner:$o,name:$n){pullRequest(number:$p){closingIssuesReferences(first:20){nodes{number}}}}rateLimit{cost remaining}}`;
|
|
2000
|
+
const r = await ghGraphQL(q, { o: owner, n: name, p: number }, token, signal, governor);
|
|
2001
|
+
if (r) {
|
|
2002
|
+
const nodes = r.data?.repository?.pullRequest?.closingIssuesReferences?.nodes ?? [];
|
|
2003
|
+
return { closesIssues: nodes.map((x) => x.number), linkageSource: "graphql" };
|
|
2004
|
+
}
|
|
1817
2005
|
} catch {
|
|
1818
2006
|
}
|
|
1819
2007
|
}
|
|
@@ -1823,11 +2011,19 @@ async function resolveClosingIssues(owner, name, number, body, token, signal) {
|
|
|
1823
2011
|
while ((m = re.exec(body)) !== null) nums.add(parseInt(m[1], 10));
|
|
1824
2012
|
return { closesIssues: [...nums], linkageSource: nums.size ? "body-keyword" : "none" };
|
|
1825
2013
|
}
|
|
1826
|
-
|
|
2014
|
+
function makeScoringGovernor(governor) {
|
|
2015
|
+
return governor ?? makeGitHubGovernor(
|
|
2016
|
+
((url, init) => fetch(url, init)),
|
|
2017
|
+
makeDefaultGovernorConfig({ paceEnabled: false })
|
|
2018
|
+
);
|
|
2019
|
+
}
|
|
2020
|
+
async function fetchPRScoringFacts(prUrl, token, signal, governor) {
|
|
1827
2021
|
const ref = parseGitHubRef(prUrl);
|
|
1828
2022
|
if (!ref || ref.kind !== "pull") return null;
|
|
1829
2023
|
const { owner, repo, number } = ref;
|
|
1830
2024
|
const sig = signal ?? AbortSignal.timeout(1e4);
|
|
2025
|
+
const gov = makeScoringGovernor(governor);
|
|
2026
|
+
if (gov.tripped() || gov.budgetExhausted()) return null;
|
|
1831
2027
|
let pr;
|
|
1832
2028
|
try {
|
|
1833
2029
|
pr = await ghFetch(`/repos/${owner}/${repo}/pulls/${number}`, token, sig);
|
|
@@ -1835,22 +2031,26 @@ async function fetchPRScoringFacts(prUrl, token, signal) {
|
|
|
1835
2031
|
return null;
|
|
1836
2032
|
}
|
|
1837
2033
|
let repoMeta = null;
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
2034
|
+
if (!gov.tripped() && !gov.budgetExhausted()) {
|
|
2035
|
+
try {
|
|
2036
|
+
repoMeta = await ghFetch(`/repos/${owner}/${repo}`, token, sig);
|
|
2037
|
+
} catch {
|
|
2038
|
+
}
|
|
1841
2039
|
}
|
|
1842
|
-
const contributors = await repoContributorCount(owner, repo, token, sig);
|
|
1843
|
-
const { closesIssues, linkageSource } = await resolveClosingIssues(owner, repo, number, pr.body ?? "", token, sig);
|
|
2040
|
+
const contributors = gov.tripped() || gov.budgetExhausted() ? null : await repoContributorCount(owner, repo, token, sig);
|
|
2041
|
+
const { closesIssues, linkageSource } = await resolveClosingIssues(owner, repo, number, pr.body ?? "", token, sig, gov);
|
|
1844
2042
|
let reviewerAssociations;
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
2043
|
+
if (!gov.tripped() && !gov.budgetExhausted()) {
|
|
2044
|
+
try {
|
|
2045
|
+
const reviews = await ghFetch(
|
|
2046
|
+
`/repos/${owner}/${repo}/pulls/${number}/reviews?per_page=100`,
|
|
2047
|
+
token,
|
|
2048
|
+
sig
|
|
2049
|
+
);
|
|
2050
|
+
reviewerAssociations = reviews.map((r) => r.author_association);
|
|
2051
|
+
} catch {
|
|
2052
|
+
reviewerAssociations = void 0;
|
|
2053
|
+
}
|
|
1854
2054
|
}
|
|
1855
2055
|
return {
|
|
1856
2056
|
repo: `${owner}/${repo}`,
|
|
@@ -1877,7 +2077,7 @@ async function fetchPRScoringFacts(prUrl, token, signal) {
|
|
|
1877
2077
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1878
2078
|
};
|
|
1879
2079
|
}
|
|
1880
|
-
var TRACTION_TOP_N, MAINTAINER_ENRICH_MAX, CANDIDATE_PR_PAGE, MAX_ENRICH_PRS, OPEN_PR_PAGE, TRANSIENT_META_ERROR, RESUME_DECAY_HALF_LIFE_MS, RESUME_MIN_SCORE, RECEPTIVITY_RECENCY_DAYS, RECEPTIVITY_RECENCY_FLOOR;
|
|
2080
|
+
var TRACTION_TOP_N, MAINTAINER_ENRICH_MAX, CANDIDATE_PR_PAGE, MAX_ENRICH_PRS, OPEN_PR_PAGE, TRANSIENT_META_ERROR, RESUME_DECAY_HALF_LIFE_MS, RESUME_MIN_SCORE, RECEPTIVITY_RECENCY_DAYS, RECEPTIVITY_RECENCY_FLOOR, GITHUB_GRAPHQL_URL;
|
|
1881
2081
|
var init_github = __esm({
|
|
1882
2082
|
"../../packages/core/src/github.ts"() {
|
|
1883
2083
|
"use strict";
|
|
@@ -1885,6 +2085,7 @@ var init_github = __esm({
|
|
|
1885
2085
|
init_contribution_gate();
|
|
1886
2086
|
init_contribution_gate();
|
|
1887
2087
|
init_rigor();
|
|
2088
|
+
init_gh_governor();
|
|
1888
2089
|
TRACTION_TOP_N = 6;
|
|
1889
2090
|
MAINTAINER_ENRICH_MAX = 25;
|
|
1890
2091
|
CANDIDATE_PR_PAGE = 50;
|
|
@@ -1895,6 +2096,7 @@ var init_github = __esm({
|
|
|
1895
2096
|
RESUME_MIN_SCORE = 0.05;
|
|
1896
2097
|
RECEPTIVITY_RECENCY_DAYS = 180;
|
|
1897
2098
|
RECEPTIVITY_RECENCY_FLOOR = 0.1;
|
|
2099
|
+
GITHUB_GRAPHQL_URL = "https://api.github.com/graphql";
|
|
1898
2100
|
}
|
|
1899
2101
|
});
|
|
1900
2102
|
|
|
@@ -1975,34 +2177,45 @@ function mergeSoftCoverage(covMap, softTags, cap) {
|
|
|
1975
2177
|
}
|
|
1976
2178
|
return covMap;
|
|
1977
2179
|
}
|
|
2180
|
+
function tagKernel(job, ctx) {
|
|
2181
|
+
const { expanded, covMap, maxDevScore, skillTags } = ctx;
|
|
2182
|
+
const details = [];
|
|
2183
|
+
let jobMatchScore = 0;
|
|
2184
|
+
let jobMaxScore = 0;
|
|
2185
|
+
const devCovByTag = /* @__PURE__ */ new Map();
|
|
2186
|
+
for (const tag of job.tags) {
|
|
2187
|
+
const w = backgroundIdf(tag);
|
|
2188
|
+
jobMaxScore += w;
|
|
2189
|
+
const covHit = covMap.get(tag);
|
|
2190
|
+
if (covHit) jobMatchScore += w * Math.pow(covHit.weight, SHARPEN);
|
|
2191
|
+
const fpHit = expanded.get(tag);
|
|
2192
|
+
if (fpHit) {
|
|
2193
|
+
const credit = Math.pow(fpHit.weight, SHARPEN);
|
|
2194
|
+
details.push({ tag, weight: fpHit.weight, via: fpHit.via });
|
|
2195
|
+
if (credit > (devCovByTag.get(fpHit.via) ?? 0)) devCovByTag.set(fpHit.via, credit);
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
let devScore = 0;
|
|
2199
|
+
for (const t of skillTags) devScore += backgroundIdf(t) * (devCovByTag.get(t) ?? 0);
|
|
2200
|
+
const devCov = maxDevScore > 0 ? Math.min(1, devScore / maxDevScore) : 0;
|
|
2201
|
+
const jobCov = jobMaxScore > 0 ? Math.min(1, jobMatchScore / jobMaxScore) : 0;
|
|
2202
|
+
return { tagComponent: harmonicMean(devCov, jobCov), details };
|
|
2203
|
+
}
|
|
2204
|
+
function relevanceScore(fp, job, softTags = []) {
|
|
2205
|
+
const expanded = expandWeighted(fp.skillTags);
|
|
2206
|
+
const covMap = softTags.length > 0 ? mergeSoftCoverage(new Map(expanded), softTags, INTEREST_CAP) : expanded;
|
|
2207
|
+
const maxDevScore = fp.skillTags.reduce((acc, t) => acc + backgroundIdf(t), 0);
|
|
2208
|
+
return tagKernel(job, { expanded, covMap, maxDevScore, skillTags: fp.skillTags }).tagComponent;
|
|
2209
|
+
}
|
|
1978
2210
|
function match(fp, jobs, limit = 5, now = Date.now(), opts = {}) {
|
|
1979
2211
|
const idfOf = backgroundIdf;
|
|
1980
2212
|
const expanded = expandWeighted(fp.skillTags);
|
|
1981
2213
|
const covMap = opts.softTags && opts.softTags.length > 0 ? mergeSoftCoverage(new Map(expanded), opts.softTags, INTEREST_CAP) : expanded;
|
|
1982
2214
|
const maxDevScore = fp.skillTags.reduce((acc, t) => acc + idfOf(t), 0);
|
|
2215
|
+
const ctx = { expanded, covMap, maxDevScore, skillTags: fp.skillTags };
|
|
1983
2216
|
const candidates = jobs.filter((j) => passesFilters(fp, j));
|
|
1984
2217
|
const scored = candidates.map((job) => {
|
|
1985
|
-
const details =
|
|
1986
|
-
let jobMatchScore = 0;
|
|
1987
|
-
let jobMaxScore = 0;
|
|
1988
|
-
const devCovByTag = /* @__PURE__ */ new Map();
|
|
1989
|
-
for (const tag of job.tags) {
|
|
1990
|
-
const w = idfOf(tag);
|
|
1991
|
-
jobMaxScore += w;
|
|
1992
|
-
const covHit = covMap.get(tag);
|
|
1993
|
-
if (covHit) jobMatchScore += w * Math.pow(covHit.weight, SHARPEN);
|
|
1994
|
-
const fpHit = expanded.get(tag);
|
|
1995
|
-
if (fpHit) {
|
|
1996
|
-
const credit = Math.pow(fpHit.weight, SHARPEN);
|
|
1997
|
-
details.push({ tag, weight: fpHit.weight, via: fpHit.via });
|
|
1998
|
-
if (credit > (devCovByTag.get(fpHit.via) ?? 0)) devCovByTag.set(fpHit.via, credit);
|
|
1999
|
-
}
|
|
2000
|
-
}
|
|
2001
|
-
let devScore = 0;
|
|
2002
|
-
for (const t of fp.skillTags) devScore += idfOf(t) * (devCovByTag.get(t) ?? 0);
|
|
2003
|
-
const devCov = maxDevScore > 0 ? Math.min(1, devScore / maxDevScore) : 0;
|
|
2004
|
-
const jobCov = jobMaxScore > 0 ? Math.min(1, jobMatchScore / jobMaxScore) : 0;
|
|
2005
|
-
const tagComponent = harmonicMean(devCov, jobCov);
|
|
2218
|
+
const { tagComponent, details } = tagKernel(job, ctx);
|
|
2006
2219
|
if (tagComponent === 0) return null;
|
|
2007
2220
|
const coreTags = job.coreTags ?? coreTagsFromTitle(job.title);
|
|
2008
2221
|
let coreComponent = tagComponent;
|
|
@@ -3537,6 +3750,7 @@ function hasContentSignal(title, body, labels) {
|
|
|
3537
3750
|
${body}`;
|
|
3538
3751
|
if (CONTENT_ADD_RE.test(text)) return true;
|
|
3539
3752
|
if (ADD_TO_CORPUS_RE.test(text)) return true;
|
|
3753
|
+
if (NUMBERED_SEED_RE.test(title)) return true;
|
|
3540
3754
|
if (TRANSLATE_RE.test(text)) return true;
|
|
3541
3755
|
if (TYPO_RE.test(text)) return true;
|
|
3542
3756
|
return false;
|
|
@@ -3552,7 +3766,7 @@ function classifyContributionKind(input) {
|
|
|
3552
3766
|
function looksLikeContentTask(input) {
|
|
3553
3767
|
return classifyContributionKind(input) === "content";
|
|
3554
3768
|
}
|
|
3555
|
-
var CONTENT_LABEL_RE, CODE_LABEL_RE, CODE_TERM_RE, CODE_EXCEPTION_RE, CODE_FENCE_RE, FILE_PATH_RE, CONTENT_ADD_RE, ADD_TO_CORPUS_RE, TRANSLATE_RE, TYPO_RE;
|
|
3769
|
+
var CONTENT_LABEL_RE, CODE_LABEL_RE, CODE_TERM_RE, CODE_EXCEPTION_RE, CODE_FENCE_RE, FILE_PATH_RE, CONTENT_NOUN_STRONG, CONTENT_NOUN_BROAD, CONTENT_ADD_RE, NUMBERED_SEED_RE, ADD_TO_CORPUS_RE, TRANSLATE_RE, TYPO_RE;
|
|
3556
3770
|
var init_contribution_classify = __esm({
|
|
3557
3771
|
"../../packages/core/src/feeds/contribution-classify.ts"() {
|
|
3558
3772
|
"use strict";
|
|
@@ -3562,7 +3776,16 @@ var init_contribution_classify = __esm({
|
|
|
3562
3776
|
CODE_EXCEPTION_RE = /exception|stacktrace|segfault|traceback/i;
|
|
3563
3777
|
CODE_FENCE_RE = /```|(?:^|\n)\s{4,}\S/;
|
|
3564
3778
|
FILE_PATH_RE = /\b[\w./-]+\.(?:ts|tsx|js|jsx|mjs|cjs|py|rb|go|rs|java|kt|scala|c|cc|cpp|cxx|h|hpp|cs|php|swift|m|mm|sh|bash|zsh|sql|graphql|proto|css|scss|sass|less|vue|svelte|toml|ini|gradle|dockerfile)\b/i;
|
|
3565
|
-
|
|
3779
|
+
CONTENT_NOUN_STRONG = String.raw`proverbs?|words?|phrases?|sayings?|quotes?|quotations?|translations?|entry|entries|definitions?|terms?|idioms?|synonyms?|antonyms?|acronyms?|abbreviations?`;
|
|
3780
|
+
CONTENT_NOUN_BROAD = String.raw`trivia\s+questions?|grammar\s+points?|trivia|facts?|quiz(?:zes)?|flash\s?cards?|vocab(?:ulary)?|lessons?|kanji`;
|
|
3781
|
+
CONTENT_ADD_RE = new RegExp(
|
|
3782
|
+
String.raw`\badd(?:ing|s)?\s+(?:\w+\s+){0,4}?(?:${CONTENT_NOUN_STRONG})\b`,
|
|
3783
|
+
"i"
|
|
3784
|
+
);
|
|
3785
|
+
NUMBERED_SEED_RE = new RegExp(
|
|
3786
|
+
String.raw`\badd(?:ing|s)?\s+(?:\w+\s+){0,4}?(?:${CONTENT_NOUN_STRONG}|${CONTENT_NOUN_BROAD})\s*#?\s*\d{1,3}\s*$`,
|
|
3787
|
+
"i"
|
|
3788
|
+
);
|
|
3566
3789
|
ADD_TO_CORPUS_RE = /\badd\b[\s\S]*?\bto\s+(?:the\s+)?(?:word\s?list|dictionary|glossary|phrasebook)\b/i;
|
|
3567
3790
|
TRANSLATE_RE = /\b(?:translate|translating|translation|localize|localise|localization|localisation)\b/i;
|
|
3568
3791
|
TYPO_RE = /\bfix(?:ing)?\s+(?:a\s+|the\s+|some\s+)?typos?\b/i;
|
|
@@ -3570,20 +3793,6 @@ var init_contribution_classify = __esm({
|
|
|
3570
3793
|
});
|
|
3571
3794
|
|
|
3572
3795
|
// ../../packages/core/src/feeds/contributions.ts
|
|
3573
|
-
function readReqGapMs() {
|
|
3574
|
-
const raw = process.env["CONTRIB_REQ_GAP_MS"];
|
|
3575
|
-
if (raw == null) return DEFAULT_REQ_GAP_MS;
|
|
3576
|
-
const n = Number.parseInt(raw, 10);
|
|
3577
|
-
if (Number.isNaN(n)) return DEFAULT_REQ_GAP_MS;
|
|
3578
|
-
return Math.min(Math.max(n, 0), 1e3);
|
|
3579
|
-
}
|
|
3580
|
-
function readBuildBudgetMs() {
|
|
3581
|
-
const raw = process.env["CONTRIB_BUILD_BUDGET_MS"];
|
|
3582
|
-
if (raw == null) return DEFAULT_BUILD_BUDGET_MS;
|
|
3583
|
-
const n = Number.parseInt(raw, 10);
|
|
3584
|
-
if (Number.isNaN(n)) return DEFAULT_BUILD_BUDGET_MS;
|
|
3585
|
-
return Math.min(Math.max(n, MIN_BUILD_BUDGET_MS), MAX_BUILD_BUDGET_MS);
|
|
3586
|
-
}
|
|
3587
3796
|
function authHeaders2() {
|
|
3588
3797
|
const token = process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"];
|
|
3589
3798
|
const h = {
|
|
@@ -3605,57 +3814,9 @@ function repoFullNameFromApiUrl2(url) {
|
|
|
3605
3814
|
return m ? `${m[1]}/${m[2]}` : null;
|
|
3606
3815
|
}
|
|
3607
3816
|
function makeClient(fetchImpl, cfg) {
|
|
3608
|
-
const
|
|
3609
|
-
let lastRequestAt = 0;
|
|
3610
|
-
let pacedMs = 0;
|
|
3611
|
-
let secondaryHits = 0;
|
|
3612
|
-
let aborted = false;
|
|
3613
|
-
let secondaryAborted = false;
|
|
3614
|
-
let budgetAborted = false;
|
|
3615
|
-
let coreHealthyAtStart = false;
|
|
3616
|
-
async function noteAndMaybeBackOff(res) {
|
|
3617
|
-
if (res.status !== 403) return;
|
|
3618
|
-
const remaining = res.headers.get("x-ratelimit-remaining");
|
|
3619
|
-
const retryAfter = res.headers.get("retry-after");
|
|
3620
|
-
const positiveSecondary = retryAfter != null || remaining != null && remaining !== "0";
|
|
3621
|
-
const isSecondary = positiveSecondary || coreHealthyAtStart;
|
|
3622
|
-
if (!isSecondary) return;
|
|
3623
|
-
secondaryHits++;
|
|
3624
|
-
if (secondaryHits >= 2) {
|
|
3625
|
-
aborted = true;
|
|
3626
|
-
secondaryAborted = true;
|
|
3627
|
-
return;
|
|
3628
|
-
}
|
|
3629
|
-
if (cfg.paceEnabled) {
|
|
3630
|
-
const trimmed = (retryAfter ?? "").trim();
|
|
3631
|
-
const parsed = trimmed.length === 0 ? Number.NaN : Number(trimmed);
|
|
3632
|
-
const sec = Number.isNaN(parsed) ? SECONDARY_BACKOFF_CAP_S : Math.min(Math.max(parsed, 0), SECONDARY_BACKOFF_CAP_S);
|
|
3633
|
-
const remaining2 = Math.max(0, cfg.budgetMs - (cfg.now() - startedAt));
|
|
3634
|
-
await cfg.sleep(Math.min(sec * 1e3, remaining2));
|
|
3635
|
-
}
|
|
3636
|
-
}
|
|
3817
|
+
const gov = makeGitHubGovernor(fetchImpl, cfg);
|
|
3637
3818
|
async function raw(path) {
|
|
3638
|
-
|
|
3639
|
-
if (cfg.now() - startedAt > cfg.budgetMs) {
|
|
3640
|
-
aborted = true;
|
|
3641
|
-
budgetAborted = true;
|
|
3642
|
-
return null;
|
|
3643
|
-
}
|
|
3644
|
-
if (cfg.paceEnabled && cfg.gapMs > 0) {
|
|
3645
|
-
const wait = cfg.gapMs - (cfg.now() - lastRequestAt);
|
|
3646
|
-
if (wait > 0) {
|
|
3647
|
-
await cfg.sleep(wait);
|
|
3648
|
-
pacedMs += wait;
|
|
3649
|
-
}
|
|
3650
|
-
lastRequestAt = cfg.now();
|
|
3651
|
-
}
|
|
3652
|
-
try {
|
|
3653
|
-
const res = await fetchImpl(`${GITHUB_API2}${path}`, { headers: authHeaders2() });
|
|
3654
|
-
await noteAndMaybeBackOff(res);
|
|
3655
|
-
return res;
|
|
3656
|
-
} catch {
|
|
3657
|
-
return null;
|
|
3658
|
-
}
|
|
3819
|
+
return gov.get(`${GITHUB_API2}${path}`, { headers: authHeaders2() });
|
|
3659
3820
|
}
|
|
3660
3821
|
async function json(path) {
|
|
3661
3822
|
const res = await raw(path);
|
|
@@ -3669,41 +3830,9 @@ function makeClient(fetchImpl, cfg) {
|
|
|
3669
3830
|
}
|
|
3670
3831
|
}
|
|
3671
3832
|
async function probe(path) {
|
|
3672
|
-
|
|
3673
|
-
let timer;
|
|
3674
|
-
const fetchP = fetchImpl(`${GITHUB_API2}${path}`, {
|
|
3675
|
-
headers: authHeaders2()
|
|
3676
|
-
}).then(
|
|
3677
|
-
(r) => r,
|
|
3678
|
-
() => null
|
|
3679
|
-
);
|
|
3680
|
-
try {
|
|
3681
|
-
const res = bound == null ? await fetchP : await Promise.race([
|
|
3682
|
-
fetchP,
|
|
3683
|
-
new Promise((resolve) => {
|
|
3684
|
-
timer = setTimeout(() => resolve(null), bound);
|
|
3685
|
-
})
|
|
3686
|
-
]);
|
|
3687
|
-
if (!res || !res.ok) return null;
|
|
3688
|
-
return await res.json();
|
|
3689
|
-
} catch {
|
|
3690
|
-
return null;
|
|
3691
|
-
} finally {
|
|
3692
|
-
if (timer) clearTimeout(timer);
|
|
3693
|
-
}
|
|
3833
|
+
return gov.probe(`${GITHUB_API2}${path}`, { headers: authHeaders2() });
|
|
3694
3834
|
}
|
|
3695
|
-
|
|
3696
|
-
coreHealthyAtStart = coreHealthy;
|
|
3697
|
-
}
|
|
3698
|
-
function getStats() {
|
|
3699
|
-
return {
|
|
3700
|
-
pacedMs,
|
|
3701
|
-
secondaryAborted: secondaryAborted ? 1 : 0,
|
|
3702
|
-
budgetAborted: budgetAborted ? 1 : 0,
|
|
3703
|
-
elapsedMs: cfg.now() - startedAt
|
|
3704
|
-
};
|
|
3705
|
-
}
|
|
3706
|
-
return { raw, json, probe, setSecondaryHint, getStats };
|
|
3835
|
+
return { raw, json, probe, setSecondaryHint: gov.setSecondaryHint, getStats: gov.getStats };
|
|
3707
3836
|
}
|
|
3708
3837
|
async function contributorCount(client, fullName) {
|
|
3709
3838
|
const res = await client.raw(`/repos/${fullName}/contributors?per_page=1&anon=false`);
|
|
@@ -3802,10 +3931,63 @@ async function aggregateContributions(opts = {}) {
|
|
|
3802
3931
|
const repoCache = /* @__PURE__ */ new Map();
|
|
3803
3932
|
const contribCache = /* @__PURE__ */ new Map();
|
|
3804
3933
|
const prRefsCache = /* @__PURE__ */ new Map();
|
|
3934
|
+
const xbuild = opts.repoMetaCache;
|
|
3935
|
+
const servedFromXbuild = /* @__PURE__ */ new Set();
|
|
3936
|
+
const persistedXbuild = /* @__PURE__ */ new Set();
|
|
3937
|
+
const xbuildTried = /* @__PURE__ */ new Set();
|
|
3938
|
+
async function primeFromXbuild(key, fullName) {
|
|
3939
|
+
if (!xbuild || xbuildTried.has(key)) return;
|
|
3940
|
+
xbuildTried.add(key);
|
|
3941
|
+
if (repoCache.has(key) && contribCache.has(key)) return;
|
|
3942
|
+
let cached = null;
|
|
3943
|
+
try {
|
|
3944
|
+
cached = await xbuild.get(key);
|
|
3945
|
+
} catch {
|
|
3946
|
+
return;
|
|
3947
|
+
}
|
|
3948
|
+
if (!cached) return;
|
|
3949
|
+
if (!repoCache.has(key)) {
|
|
3950
|
+
const owner = fullName.split("/")[0] ?? "";
|
|
3951
|
+
repoCache.set(key, {
|
|
3952
|
+
full_name: fullName,
|
|
3953
|
+
stargazers_count: cached.stars,
|
|
3954
|
+
archived: cached.archived,
|
|
3955
|
+
disabled: cached.disabled,
|
|
3956
|
+
fork: cached.fork,
|
|
3957
|
+
language: cached.language,
|
|
3958
|
+
owner: { login: owner }
|
|
3959
|
+
});
|
|
3960
|
+
}
|
|
3961
|
+
if (!contribCache.has(key)) {
|
|
3962
|
+
contribCache.set(key, cached.contributors);
|
|
3963
|
+
servedFromXbuild.add(key);
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
async function persistRepoMeta(fullName, repo, contributors) {
|
|
3967
|
+
if (!xbuild) return;
|
|
3968
|
+
const key = repoKey(fullName);
|
|
3969
|
+
if (servedFromXbuild.has(key) || persistedXbuild.has(key)) return;
|
|
3970
|
+
if (contributors === void 0) return;
|
|
3971
|
+
persistedXbuild.add(key);
|
|
3972
|
+
try {
|
|
3973
|
+
await xbuild.set(key, {
|
|
3974
|
+
stars: repo.stargazers_count,
|
|
3975
|
+
contributors,
|
|
3976
|
+
language: repo.language,
|
|
3977
|
+
archived: repo.archived,
|
|
3978
|
+
fork: repo.fork,
|
|
3979
|
+
disabled: repo.disabled
|
|
3980
|
+
});
|
|
3981
|
+
} catch {
|
|
3982
|
+
}
|
|
3983
|
+
}
|
|
3805
3984
|
async function repoMeta(fullName) {
|
|
3806
3985
|
const key = repoKey(fullName);
|
|
3807
3986
|
const hit = repoCache.get(key);
|
|
3808
3987
|
if (hit !== void 0) return hit;
|
|
3988
|
+
await primeFromXbuild(key, fullName);
|
|
3989
|
+
const primed = repoCache.get(key);
|
|
3990
|
+
if (primed !== void 0) return primed;
|
|
3809
3991
|
const r = await client.json(`/repos/${fullName}`) ?? null;
|
|
3810
3992
|
repoCache.set(key, r);
|
|
3811
3993
|
return r;
|
|
@@ -3813,6 +3995,8 @@ async function aggregateContributions(opts = {}) {
|
|
|
3813
3995
|
async function repoContribCount(fullName) {
|
|
3814
3996
|
const key = repoKey(fullName);
|
|
3815
3997
|
if (contribCache.has(key)) return contribCache.get(key);
|
|
3998
|
+
await primeFromXbuild(key, fullName);
|
|
3999
|
+
if (contribCache.has(key)) return contribCache.get(key);
|
|
3816
4000
|
const n = await contributorCount(client, fullName);
|
|
3817
4001
|
contribCache.set(key, n);
|
|
3818
4002
|
return n;
|
|
@@ -3839,14 +4023,18 @@ async function aggregateContributions(opts = {}) {
|
|
|
3839
4023
|
if (isDenylistedRepo(fullName)) continue;
|
|
3840
4024
|
if (isAssigned(issue)) continue;
|
|
3841
4025
|
if ((perRepo.get(repoKey(fullName)) ?? 0) >= MAX_BOUNTIES_PER_DISCOVERED_REPO) continue;
|
|
4026
|
+
const title = decodeEntities(issue.title).trim();
|
|
4027
|
+
const body = issue.body ? decodeEntities(issue.body) : "";
|
|
4028
|
+
const labels = labelNames2(issue.labels);
|
|
4029
|
+
if (looksLikeContentTask({ title, body, labels })) continue;
|
|
3842
4030
|
const repo = await repoMeta(fullName);
|
|
3843
4031
|
if (!repo) {
|
|
3844
4032
|
metaNull++;
|
|
3845
4033
|
continue;
|
|
3846
4034
|
}
|
|
3847
|
-
const title = decodeEntities(issue.title).trim();
|
|
3848
4035
|
const contributors = await repoContribCount(fullName);
|
|
3849
4036
|
if (contributors === void 0) contribUndefined++;
|
|
4037
|
+
await persistRepoMeta(fullName, repo, contributors);
|
|
3850
4038
|
if (!passesContributionGate({
|
|
3851
4039
|
fullName,
|
|
3852
4040
|
stars: repo.stargazers_count,
|
|
@@ -3858,13 +4046,9 @@ async function aggregateContributions(opts = {}) {
|
|
|
3858
4046
|
continue;
|
|
3859
4047
|
}
|
|
3860
4048
|
if (repo.disabled) continue;
|
|
3861
|
-
const body = issue.body ? decodeEntities(issue.body) : "";
|
|
3862
|
-
const labels = labelNames2(issue.labels);
|
|
3863
|
-
if (looksLikeContentTask({ title, body, labels })) continue;
|
|
3864
4049
|
const prRefs = await repoPRRefs(fullName);
|
|
3865
4050
|
if (prRefs === null) prRefsNull++;
|
|
3866
|
-
|
|
3867
|
-
const openPRsAtDiscovery = prRefs ? 0 : void 0;
|
|
4051
|
+
const openPRsAtDiscovery = prRefs ? prRefs.has(issue.number) ? 1 : 0 : void 0;
|
|
3868
4052
|
const tags = normalize(
|
|
3869
4053
|
tokenize4([title, repo.language ?? "", labels.join(" "), body.slice(0, 2e3)].join(" "))
|
|
3870
4054
|
);
|
|
@@ -3955,6 +4139,7 @@ async function aggregateContributions(opts = {}) {
|
|
|
3955
4139
|
if (repo.disabled) continue;
|
|
3956
4140
|
const contributors = await repoContribCount(fullName);
|
|
3957
4141
|
if (contributors === void 0) contribUndefined++;
|
|
4142
|
+
await persistRepoMeta(fullName, repo, contributors);
|
|
3958
4143
|
if (repo.archived || repo.fork || repo.stargazers_count < MIN_STARS || contributors === void 0 || contributors < MIN_CONTRIBUTORS) {
|
|
3959
4144
|
continue;
|
|
3960
4145
|
}
|
|
@@ -3987,8 +4172,7 @@ async function aggregateContributions(opts = {}) {
|
|
|
3987
4172
|
if (looksLikeContentTask({ title, body, labels })) continue;
|
|
3988
4173
|
const prRefs = await repoPRRefs(fullName);
|
|
3989
4174
|
if (prRefs === null) prRefsNull++;
|
|
3990
|
-
|
|
3991
|
-
const openPRsAtDiscovery = prRefs ? 0 : void 0;
|
|
4175
|
+
const openPRsAtDiscovery = prRefs ? prRefs.has(issue.number) ? 1 : 0 : void 0;
|
|
3992
4176
|
const tags = normalize(
|
|
3993
4177
|
tokenize4([title, repo.language ?? "", labels.join(" "), body.slice(0, 2e3)].join(" "))
|
|
3994
4178
|
);
|
|
@@ -4019,9 +4203,9 @@ async function aggregateContributions(opts = {}) {
|
|
|
4019
4203
|
const core = rl?.core ? `${rl.core.remaining}/${rl.core.limit}` : "n/a";
|
|
4020
4204
|
const search = rl?.search ? `${rl.search.remaining}/${rl.search.limit}` : "n/a";
|
|
4021
4205
|
const noToken = !(process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"]);
|
|
4022
|
-
const { pacedMs, secondaryAborted, budgetAborted, elapsedMs } = client.getStats();
|
|
4206
|
+
const { pacedMs, secondaryAborted, budgetAborted, elapsedMs, gqlCost, gqlRemaining } = client.getStats();
|
|
4023
4207
|
console.info(
|
|
4024
|
-
`[contribute] build metrics \u2014 scanned=${issues.length} reposDistinct=${repoCache.size} emitted=${jobs.length} discovered=${discoveredEmitted} metaNull=${metaNull} contribUndefined=${contribUndefined} prRefsNull=${prRefsNull} paced=${pacedMs} secondaryAborted=${secondaryAborted} budgetAborted=${budgetAborted} core=${core} search=${search} elapsed=${elapsedMs}` + (noToken ? " (NO TOKEN \u2192 60/hr)" : "")
|
|
4208
|
+
`[contribute] build metrics \u2014 scanned=${issues.length} reposDistinct=${repoCache.size} emitted=${jobs.length} discovered=${discoveredEmitted} metaNull=${metaNull} contribUndefined=${contribUndefined} prRefsNull=${prRefsNull} paced=${pacedMs} secondaryAborted=${secondaryAborted} budgetAborted=${budgetAborted} core=${core} search=${search} gqlCost=${gqlCost} gqlRemaining=${gqlRemaining ?? "n/a"} elapsed=${elapsedMs}` + (noToken ? " (NO TOKEN \u2192 60/hr)" : "")
|
|
4025
4209
|
);
|
|
4026
4210
|
if (discoveryBudgetStopped) {
|
|
4027
4211
|
console.warn(
|
|
@@ -4031,7 +4215,7 @@ async function aggregateContributions(opts = {}) {
|
|
|
4031
4215
|
}
|
|
4032
4216
|
return jobs;
|
|
4033
4217
|
}
|
|
4034
|
-
var GITHUB_API2,
|
|
4218
|
+
var GITHUB_API2, CONTRIB_LABEL_QUERIES, CONTRIB_LANGUAGE_QUERIES, CONTRIB_SEARCH_QUERIES, SEARCH_PER_PAGE2, MAX_CONTRIB_ITEMS, MAX_CONTRIB_ISSUES_SCANNED, MAX_DISCOVERED_REPOS, MAX_ISSUES_PER_DISCOVERED_REPO, DISCOVERY_REPOS_PER_TERM, DISCOVERY_VOCAB_TERMS, DISCOVERY_ISSUE_LABELS, repoKey;
|
|
4035
4219
|
var init_contributions = __esm({
|
|
4036
4220
|
"../../packages/core/src/feeds/contributions.ts"() {
|
|
4037
4221
|
"use strict";
|
|
@@ -4042,14 +4226,8 @@ var init_contributions = __esm({
|
|
|
4042
4226
|
init_contribution_classify();
|
|
4043
4227
|
init_github_bounties();
|
|
4044
4228
|
init_http();
|
|
4229
|
+
init_gh_governor();
|
|
4045
4230
|
GITHUB_API2 = "https://api.github.com";
|
|
4046
|
-
DEFAULT_REQ_GAP_MS = 75;
|
|
4047
|
-
SECONDARY_BACKOFF_CAP_S = 30;
|
|
4048
|
-
DEFAULT_BUILD_BUDGET_MS = 9e4;
|
|
4049
|
-
MIN_BUILD_BUDGET_MS = 1e4;
|
|
4050
|
-
MAX_BUILD_BUDGET_MS = 9e4;
|
|
4051
|
-
PROBE_TIMEOUT_MS = 3e3;
|
|
4052
|
-
realSleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
4053
4231
|
CONTRIB_LABEL_QUERIES = [
|
|
4054
4232
|
'label:"good first issue" type:issue state:open',
|
|
4055
4233
|
'label:"good-first-issue" type:issue state:open',
|
|
@@ -4267,12 +4445,22 @@ async function enrichWinnability(jobs, contribute, w) {
|
|
|
4267
4445
|
const repos = [...byRepo.keys()].sort((a, b) => starsOf(b) - starsOf(a));
|
|
4268
4446
|
const scored = repos.slice(0, maxRepos);
|
|
4269
4447
|
const cappedOut = repos.length - scored.length;
|
|
4448
|
+
const gov = w.governor ?? makeGitHubGovernor(
|
|
4449
|
+
w.fetchImpl ?? fetch,
|
|
4450
|
+
makeDefaultGovernorConfig({ paceEnabled: !w.fetchImpl })
|
|
4451
|
+
);
|
|
4452
|
+
let stoppedEarly = false;
|
|
4270
4453
|
for (const repo of scored) {
|
|
4454
|
+
if (gov.tripped() || gov.budgetExhausted()) {
|
|
4455
|
+
stoppedEarly = true;
|
|
4456
|
+
break;
|
|
4457
|
+
}
|
|
4271
4458
|
const targets = byRepo.get(repo) ?? [];
|
|
4272
4459
|
const receptivity = await fetchRepoReceptivity(repo, {
|
|
4273
4460
|
token: w.token,
|
|
4274
4461
|
fetchImpl: w.fetchImpl,
|
|
4275
|
-
now
|
|
4462
|
+
now,
|
|
4463
|
+
governor: gov
|
|
4276
4464
|
});
|
|
4277
4465
|
const stars = starsOf(repo);
|
|
4278
4466
|
const prev = priorStars[repo];
|
|
@@ -4301,6 +4489,12 @@ async function enrichWinnability(jobs, contribute, w) {
|
|
|
4301
4489
|
}
|
|
4302
4490
|
}
|
|
4303
4491
|
}
|
|
4492
|
+
if (stoppedEarly) {
|
|
4493
|
+
const reason = gov.tripped() ? "secondary-abuse breaker" : "wall-clock budget";
|
|
4494
|
+
console.warn(
|
|
4495
|
+
`[winnability] receptivity governor stopped the loop \u2014 ${reason} tripped; remaining repos left un-scored (legacy ranking). Governed egress halted to avoid prolonging the GitHub rate-limit window.`
|
|
4496
|
+
);
|
|
4497
|
+
}
|
|
4304
4498
|
if (cappedOut > 0) {
|
|
4305
4499
|
console.warn(
|
|
4306
4500
|
`[winnability] receptivity cap hit \u2014 scored ${scored.length}/${repos.length} repos (${cappedOut} beyond maxRepos=${maxRepos} left un-scored, legacy ranking)`
|
|
@@ -4343,6 +4537,7 @@ var init_indexer = __esm({
|
|
|
4343
4537
|
init_contributions();
|
|
4344
4538
|
init_partners();
|
|
4345
4539
|
init_github();
|
|
4540
|
+
init_gh_governor();
|
|
4346
4541
|
init_winnability();
|
|
4347
4542
|
}
|
|
4348
4543
|
});
|
|
@@ -7938,6 +8133,7 @@ __export(src_exports, {
|
|
|
7938
8133
|
MERGE_PROBABILITY: () => MERGE_PROBABILITY,
|
|
7939
8134
|
MIN_CONTRIBUTORS: () => MIN_CONTRIBUTORS,
|
|
7940
8135
|
MIN_STARS: () => MIN_STARS,
|
|
8136
|
+
PROBE_TIMEOUT_MS: () => PROBE_TIMEOUT_MS,
|
|
7941
8137
|
RIGOR: () => RIGOR,
|
|
7942
8138
|
STRONG_MATCH_THRESHOLD: () => STRONG_MATCH_THRESHOLD,
|
|
7943
8139
|
SYNONYMS: () => SYNONYMS,
|
|
@@ -8009,6 +8205,9 @@ __export(src_exports, {
|
|
|
8009
8205
|
lever: () => lever,
|
|
8010
8206
|
loadPartnerRoles: () => loadPartnerRoles,
|
|
8011
8207
|
looksLikeEngRole: () => looksLikeEngRole,
|
|
8208
|
+
makeDefaultGovernorConfig: () => makeDefaultGovernorConfig,
|
|
8209
|
+
makeGitHubGovernor: () => makeGitHubGovernor,
|
|
8210
|
+
makeScoringGovernor: () => makeScoringGovernor,
|
|
8012
8211
|
match: () => match,
|
|
8013
8212
|
mergeProbability: () => mergeProbability,
|
|
8014
8213
|
mmrRerank: () => mmrRerank,
|
|
@@ -8021,8 +8220,12 @@ __export(src_exports, {
|
|
|
8021
8220
|
passesMaturityGate: () => passesMaturityGate,
|
|
8022
8221
|
personCardToJob: () => personCardToJob,
|
|
8023
8222
|
projectCardToJob: () => projectCardToJob,
|
|
8223
|
+
readBuildBudgetMs: () => readBuildBudgetMs,
|
|
8224
|
+
readReqGapMs: () => readReqGapMs,
|
|
8225
|
+
realSleep: () => realSleep,
|
|
8024
8226
|
recordClick: () => recordClick,
|
|
8025
8227
|
rejectExtraIntroFields: () => rejectExtraIntroFields,
|
|
8228
|
+
relevanceScore: () => relevanceScore,
|
|
8026
8229
|
revealIntroContacts: () => revealIntroContacts,
|
|
8027
8230
|
safetyNumber: () => safetyNumber,
|
|
8028
8231
|
sameLogin: () => sameLogin,
|
|
@@ -8049,6 +8252,7 @@ var init_src = __esm({
|
|
|
8049
8252
|
init_winnability();
|
|
8050
8253
|
init_partners();
|
|
8051
8254
|
init_github();
|
|
8255
|
+
init_gh_governor();
|
|
8052
8256
|
init_credit();
|
|
8053
8257
|
init_intro();
|
|
8054
8258
|
init_directoryThreshold();
|
|
@@ -8069,9 +8273,9 @@ var init_keytar = __esm({
|
|
|
8069
8273
|
}
|
|
8070
8274
|
});
|
|
8071
8275
|
|
|
8072
|
-
// node-file:/Users/ericgang/job-placement-inline
|
|
8276
|
+
// node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node
|
|
8073
8277
|
var require_keytar = __commonJS({
|
|
8074
|
-
"node-file:/Users/ericgang/job-placement-inline
|
|
8278
|
+
"node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
8075
8279
|
"use strict";
|
|
8076
8280
|
init_keytar();
|
|
8077
8281
|
try {
|