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-refresh.js
CHANGED
|
@@ -945,6 +945,187 @@ var init_rigor = __esm({
|
|
|
945
945
|
}
|
|
946
946
|
});
|
|
947
947
|
|
|
948
|
+
// ../../packages/core/src/gh-governor.ts
|
|
949
|
+
function readReqGapMs() {
|
|
950
|
+
const raw = process.env["CONTRIB_REQ_GAP_MS"];
|
|
951
|
+
if (raw == null) return DEFAULT_REQ_GAP_MS;
|
|
952
|
+
const n = Number.parseInt(raw, 10);
|
|
953
|
+
if (Number.isNaN(n)) return DEFAULT_REQ_GAP_MS;
|
|
954
|
+
return Math.min(Math.max(n, 0), 1e3);
|
|
955
|
+
}
|
|
956
|
+
function readBuildBudgetMs() {
|
|
957
|
+
const raw = process.env["CONTRIB_BUILD_BUDGET_MS"];
|
|
958
|
+
if (raw == null) return DEFAULT_BUILD_BUDGET_MS;
|
|
959
|
+
const n = Number.parseInt(raw, 10);
|
|
960
|
+
if (Number.isNaN(n)) return DEFAULT_BUILD_BUDGET_MS;
|
|
961
|
+
return Math.min(Math.max(n, MIN_BUILD_BUDGET_MS), MAX_BUILD_BUDGET_MS);
|
|
962
|
+
}
|
|
963
|
+
function makeDefaultGovernorConfig(o) {
|
|
964
|
+
return {
|
|
965
|
+
paceEnabled: o.paceEnabled,
|
|
966
|
+
gapMs: readReqGapMs(),
|
|
967
|
+
budgetMs: readBuildBudgetMs(),
|
|
968
|
+
sleep: o.sleep ?? realSleep,
|
|
969
|
+
now: o.now ?? Date.now,
|
|
970
|
+
probeTimeoutMs: o.probeTimeoutMs ?? (o.paceEnabled ? PROBE_TIMEOUT_MS : null)
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
function makeGitHubGovernor(fetchImpl, cfg) {
|
|
974
|
+
const startedAt = cfg.now();
|
|
975
|
+
let lastRequestAt = 0;
|
|
976
|
+
let pacedMs = 0;
|
|
977
|
+
let secondaryHits = 0;
|
|
978
|
+
let aborted = false;
|
|
979
|
+
let secondaryAborted = false;
|
|
980
|
+
let budgetAborted = false;
|
|
981
|
+
let gqlCost = 0;
|
|
982
|
+
let gqlRemaining = null;
|
|
983
|
+
let coreHealthyAtStart = false;
|
|
984
|
+
async function noteAndMaybeBackOff(res) {
|
|
985
|
+
if (res.status !== 403) return;
|
|
986
|
+
const remaining = res.headers.get("x-ratelimit-remaining");
|
|
987
|
+
const retryAfter = res.headers.get("retry-after");
|
|
988
|
+
const positiveSecondary = retryAfter != null || remaining != null && remaining !== "0";
|
|
989
|
+
const isSecondary = positiveSecondary || coreHealthyAtStart;
|
|
990
|
+
if (!isSecondary) return;
|
|
991
|
+
await recordSecondaryStrike(retryAfter);
|
|
992
|
+
}
|
|
993
|
+
async function recordSecondaryStrike(retryAfter) {
|
|
994
|
+
secondaryHits++;
|
|
995
|
+
if (secondaryHits >= 2) {
|
|
996
|
+
aborted = true;
|
|
997
|
+
secondaryAborted = true;
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
if (cfg.paceEnabled) {
|
|
1001
|
+
const trimmed = (retryAfter ?? "").trim();
|
|
1002
|
+
const parsed = trimmed.length === 0 ? Number.NaN : Number(trimmed);
|
|
1003
|
+
const sec = Number.isNaN(parsed) ? SECONDARY_BACKOFF_CAP_S : Math.min(Math.max(parsed, 0), SECONDARY_BACKOFF_CAP_S);
|
|
1004
|
+
const remainingBudget = Math.max(0, cfg.budgetMs - (cfg.now() - startedAt));
|
|
1005
|
+
await cfg.sleep(Math.min(sec * 1e3, remainingBudget));
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
async function noteGraphQLAndMaybeBackOff(res, body) {
|
|
1009
|
+
const b = body ?? {};
|
|
1010
|
+
const rl = b.data?.rateLimit;
|
|
1011
|
+
if (rl) {
|
|
1012
|
+
if (typeof rl.cost === "number") gqlCost += rl.cost;
|
|
1013
|
+
if (typeof rl.remaining === "number") gqlRemaining = rl.remaining;
|
|
1014
|
+
}
|
|
1015
|
+
const remainingHdr = res.headers?.get("x-ratelimit-remaining") ?? null;
|
|
1016
|
+
const retryAfter = res.headers?.get("retry-after") ?? null;
|
|
1017
|
+
const headerRate = retryAfter != null || remainingHdr === "0";
|
|
1018
|
+
const errs = Array.isArray(b.errors) ? b.errors : [];
|
|
1019
|
+
const bodyRate = errs.some((e) => e?.type === "RATE_LIMITED" || /rate limit/i.test(String(e?.message ?? ""))) || typeof rl?.remaining === "number" && rl.remaining <= 0;
|
|
1020
|
+
if (headerRate || bodyRate) await recordSecondaryStrike(retryAfter);
|
|
1021
|
+
}
|
|
1022
|
+
async function preflight() {
|
|
1023
|
+
if (aborted) return false;
|
|
1024
|
+
if (cfg.now() - startedAt >= cfg.budgetMs) {
|
|
1025
|
+
aborted = true;
|
|
1026
|
+
budgetAborted = true;
|
|
1027
|
+
return false;
|
|
1028
|
+
}
|
|
1029
|
+
if (cfg.paceEnabled && cfg.gapMs > 0) {
|
|
1030
|
+
const wait = cfg.gapMs - (cfg.now() - lastRequestAt);
|
|
1031
|
+
if (wait > 0) {
|
|
1032
|
+
await cfg.sleep(wait);
|
|
1033
|
+
pacedMs += wait;
|
|
1034
|
+
if (cfg.now() - startedAt >= cfg.budgetMs) {
|
|
1035
|
+
aborted = true;
|
|
1036
|
+
budgetAborted = true;
|
|
1037
|
+
return false;
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
lastRequestAt = cfg.now();
|
|
1041
|
+
}
|
|
1042
|
+
return true;
|
|
1043
|
+
}
|
|
1044
|
+
async function get(url, init) {
|
|
1045
|
+
if (!await preflight()) return null;
|
|
1046
|
+
try {
|
|
1047
|
+
const res = await fetchImpl(url, init);
|
|
1048
|
+
await noteAndMaybeBackOff(res);
|
|
1049
|
+
return res;
|
|
1050
|
+
} catch {
|
|
1051
|
+
return null;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
async function graphql(url, init) {
|
|
1055
|
+
if (!await preflight()) return null;
|
|
1056
|
+
let res;
|
|
1057
|
+
try {
|
|
1058
|
+
res = await fetchImpl(url, init);
|
|
1059
|
+
} catch {
|
|
1060
|
+
return null;
|
|
1061
|
+
}
|
|
1062
|
+
let body;
|
|
1063
|
+
try {
|
|
1064
|
+
body = await res.json();
|
|
1065
|
+
} catch {
|
|
1066
|
+
return null;
|
|
1067
|
+
}
|
|
1068
|
+
await noteGraphQLAndMaybeBackOff(res, body);
|
|
1069
|
+
if (!res.ok) return null;
|
|
1070
|
+
return body;
|
|
1071
|
+
}
|
|
1072
|
+
async function probe(url, init) {
|
|
1073
|
+
const bound = cfg.probeTimeoutMs;
|
|
1074
|
+
let timer;
|
|
1075
|
+
const fetchP = fetchImpl(url, init).then(
|
|
1076
|
+
(r) => r,
|
|
1077
|
+
() => null
|
|
1078
|
+
);
|
|
1079
|
+
try {
|
|
1080
|
+
const res = bound == null ? await fetchP : await Promise.race([
|
|
1081
|
+
fetchP,
|
|
1082
|
+
new Promise((resolve) => {
|
|
1083
|
+
timer = setTimeout(() => resolve(null), bound);
|
|
1084
|
+
})
|
|
1085
|
+
]);
|
|
1086
|
+
if (!res || !res.ok) return null;
|
|
1087
|
+
return await res.json();
|
|
1088
|
+
} catch {
|
|
1089
|
+
return null;
|
|
1090
|
+
} finally {
|
|
1091
|
+
if (timer) clearTimeout(timer);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
function setSecondaryHint(coreHealthy) {
|
|
1095
|
+
coreHealthyAtStart = coreHealthy;
|
|
1096
|
+
}
|
|
1097
|
+
function getStats() {
|
|
1098
|
+
return {
|
|
1099
|
+
pacedMs,
|
|
1100
|
+
secondaryAborted: secondaryAborted ? 1 : 0,
|
|
1101
|
+
budgetAborted: budgetAborted ? 1 : 0,
|
|
1102
|
+
elapsedMs: cfg.now() - startedAt,
|
|
1103
|
+
gqlCost,
|
|
1104
|
+
gqlRemaining
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
1107
|
+
function tripped() {
|
|
1108
|
+
return secondaryAborted;
|
|
1109
|
+
}
|
|
1110
|
+
function budgetExhausted() {
|
|
1111
|
+
return budgetAborted || cfg.now() - startedAt >= cfg.budgetMs;
|
|
1112
|
+
}
|
|
1113
|
+
return { get, graphql, probe, setSecondaryHint, getStats, tripped, budgetExhausted };
|
|
1114
|
+
}
|
|
1115
|
+
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;
|
|
1116
|
+
var init_gh_governor = __esm({
|
|
1117
|
+
"../../packages/core/src/gh-governor.ts"() {
|
|
1118
|
+
"use strict";
|
|
1119
|
+
DEFAULT_REQ_GAP_MS = 75;
|
|
1120
|
+
SECONDARY_BACKOFF_CAP_S = 30;
|
|
1121
|
+
DEFAULT_BUILD_BUDGET_MS = 9e4;
|
|
1122
|
+
MIN_BUILD_BUDGET_MS = 1e4;
|
|
1123
|
+
MAX_BUILD_BUDGET_MS = 9e4;
|
|
1124
|
+
PROBE_TIMEOUT_MS = 3e3;
|
|
1125
|
+
realSleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
1126
|
+
}
|
|
1127
|
+
});
|
|
1128
|
+
|
|
948
1129
|
// ../../packages/core/src/github.ts
|
|
949
1130
|
function ghHeaders(token) {
|
|
950
1131
|
const headers = {
|
|
@@ -1425,11 +1606,9 @@ async function fetchRepoReceptivity(fullName, opts = {}) {
|
|
|
1425
1606
|
const doFetch = opts.fetchImpl ?? fetch;
|
|
1426
1607
|
const now = opts.now ?? Date.now();
|
|
1427
1608
|
try {
|
|
1428
|
-
const
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
);
|
|
1432
|
-
if (!res.ok) return null;
|
|
1609
|
+
const url = `https://api.github.com/repos/${fullName}/pulls?state=closed&per_page=50&sort=updated&direction=desc`;
|
|
1610
|
+
const res = opts.governor ? await opts.governor.get(url, { headers: ghHeaders(opts.token) }) : await doFetch(url, { headers: ghHeaders(opts.token) });
|
|
1611
|
+
if (!res || !res.ok) return null;
|
|
1433
1612
|
const prs = await res.json();
|
|
1434
1613
|
if (!Array.isArray(prs)) return null;
|
|
1435
1614
|
const external = prs.filter(isExternalAuthor);
|
|
@@ -1514,25 +1693,34 @@ function parseGitHubRef(url) {
|
|
|
1514
1693
|
if (!m) return null;
|
|
1515
1694
|
return { owner: m[1], repo: m[2], number: parseInt(m[4], 10), kind: m[3] === "pull" ? "pull" : "issue" };
|
|
1516
1695
|
}
|
|
1517
|
-
async function ghGraphQL(query, variables, token, signal) {
|
|
1518
|
-
const
|
|
1696
|
+
async function ghGraphQL(query, variables, token, signal, governor) {
|
|
1697
|
+
const init = {
|
|
1519
1698
|
method: "POST",
|
|
1520
1699
|
headers: { ...ghHeaders(token), "Content-Type": "application/json" },
|
|
1521
1700
|
body: JSON.stringify({ query, variables }),
|
|
1522
1701
|
signal
|
|
1523
|
-
}
|
|
1702
|
+
};
|
|
1703
|
+
if (governor) {
|
|
1704
|
+
const json2 = await governor.graphql(GITHUB_GRAPHQL_URL, init);
|
|
1705
|
+
if (json2 === null) return null;
|
|
1706
|
+
if (json2.errors?.length) throw new Error("GitHub GraphQL errors: " + JSON.stringify(json2.errors));
|
|
1707
|
+
return json2;
|
|
1708
|
+
}
|
|
1709
|
+
const res = await fetch(GITHUB_GRAPHQL_URL, init);
|
|
1524
1710
|
if (!res.ok) throw new Error(`GitHub GraphQL: HTTP ${res.status}`);
|
|
1525
1711
|
const json = await res.json();
|
|
1526
1712
|
if (json.errors?.length) throw new Error("GitHub GraphQL errors: " + JSON.stringify(json.errors));
|
|
1527
1713
|
return json;
|
|
1528
1714
|
}
|
|
1529
|
-
async function resolveClosingIssues(owner, name, number, body, token, signal) {
|
|
1715
|
+
async function resolveClosingIssues(owner, name, number, body, token, signal, governor) {
|
|
1530
1716
|
if (token) {
|
|
1531
1717
|
try {
|
|
1532
|
-
const q = `query($o:String!,$n:String!,$p:Int!){repository(owner:$o,name:$n){pullRequest(number:$p){closingIssuesReferences(first:20){nodes{number}}}}}`;
|
|
1533
|
-
const r = await ghGraphQL(q, { o: owner, n: name, p: number }, token, signal);
|
|
1534
|
-
|
|
1535
|
-
|
|
1718
|
+
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}}`;
|
|
1719
|
+
const r = await ghGraphQL(q, { o: owner, n: name, p: number }, token, signal, governor);
|
|
1720
|
+
if (r) {
|
|
1721
|
+
const nodes = r.data?.repository?.pullRequest?.closingIssuesReferences?.nodes ?? [];
|
|
1722
|
+
return { closesIssues: nodes.map((x) => x.number), linkageSource: "graphql" };
|
|
1723
|
+
}
|
|
1536
1724
|
} catch {
|
|
1537
1725
|
}
|
|
1538
1726
|
}
|
|
@@ -1542,11 +1730,19 @@ async function resolveClosingIssues(owner, name, number, body, token, signal) {
|
|
|
1542
1730
|
while ((m = re.exec(body)) !== null) nums.add(parseInt(m[1], 10));
|
|
1543
1731
|
return { closesIssues: [...nums], linkageSource: nums.size ? "body-keyword" : "none" };
|
|
1544
1732
|
}
|
|
1545
|
-
|
|
1733
|
+
function makeScoringGovernor(governor) {
|
|
1734
|
+
return governor ?? makeGitHubGovernor(
|
|
1735
|
+
((url, init) => fetch(url, init)),
|
|
1736
|
+
makeDefaultGovernorConfig({ paceEnabled: false })
|
|
1737
|
+
);
|
|
1738
|
+
}
|
|
1739
|
+
async function fetchPRScoringFacts(prUrl, token, signal, governor) {
|
|
1546
1740
|
const ref = parseGitHubRef(prUrl);
|
|
1547
1741
|
if (!ref || ref.kind !== "pull") return null;
|
|
1548
1742
|
const { owner, repo, number } = ref;
|
|
1549
1743
|
const sig = signal ?? AbortSignal.timeout(1e4);
|
|
1744
|
+
const gov = makeScoringGovernor(governor);
|
|
1745
|
+
if (gov.tripped() || gov.budgetExhausted()) return null;
|
|
1550
1746
|
let pr;
|
|
1551
1747
|
try {
|
|
1552
1748
|
pr = await ghFetch(`/repos/${owner}/${repo}/pulls/${number}`, token, sig);
|
|
@@ -1554,22 +1750,26 @@ async function fetchPRScoringFacts(prUrl, token, signal) {
|
|
|
1554
1750
|
return null;
|
|
1555
1751
|
}
|
|
1556
1752
|
let repoMeta = null;
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1753
|
+
if (!gov.tripped() && !gov.budgetExhausted()) {
|
|
1754
|
+
try {
|
|
1755
|
+
repoMeta = await ghFetch(`/repos/${owner}/${repo}`, token, sig);
|
|
1756
|
+
} catch {
|
|
1757
|
+
}
|
|
1560
1758
|
}
|
|
1561
|
-
const contributors = await repoContributorCount(owner, repo, token, sig);
|
|
1562
|
-
const { closesIssues, linkageSource } = await resolveClosingIssues(owner, repo, number, pr.body ?? "", token, sig);
|
|
1759
|
+
const contributors = gov.tripped() || gov.budgetExhausted() ? null : await repoContributorCount(owner, repo, token, sig);
|
|
1760
|
+
const { closesIssues, linkageSource } = await resolveClosingIssues(owner, repo, number, pr.body ?? "", token, sig, gov);
|
|
1563
1761
|
let reviewerAssociations;
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1762
|
+
if (!gov.tripped() && !gov.budgetExhausted()) {
|
|
1763
|
+
try {
|
|
1764
|
+
const reviews = await ghFetch(
|
|
1765
|
+
`/repos/${owner}/${repo}/pulls/${number}/reviews?per_page=100`,
|
|
1766
|
+
token,
|
|
1767
|
+
sig
|
|
1768
|
+
);
|
|
1769
|
+
reviewerAssociations = reviews.map((r) => r.author_association);
|
|
1770
|
+
} catch {
|
|
1771
|
+
reviewerAssociations = void 0;
|
|
1772
|
+
}
|
|
1573
1773
|
}
|
|
1574
1774
|
return {
|
|
1575
1775
|
repo: `${owner}/${repo}`,
|
|
@@ -1596,7 +1796,7 @@ async function fetchPRScoringFacts(prUrl, token, signal) {
|
|
|
1596
1796
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1597
1797
|
};
|
|
1598
1798
|
}
|
|
1599
|
-
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;
|
|
1799
|
+
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;
|
|
1600
1800
|
var init_github = __esm({
|
|
1601
1801
|
"../../packages/core/src/github.ts"() {
|
|
1602
1802
|
"use strict";
|
|
@@ -1604,6 +1804,7 @@ var init_github = __esm({
|
|
|
1604
1804
|
init_contribution_gate();
|
|
1605
1805
|
init_contribution_gate();
|
|
1606
1806
|
init_rigor();
|
|
1807
|
+
init_gh_governor();
|
|
1607
1808
|
TRACTION_TOP_N = 6;
|
|
1608
1809
|
MAINTAINER_ENRICH_MAX = 25;
|
|
1609
1810
|
CANDIDATE_PR_PAGE = 50;
|
|
@@ -1614,6 +1815,7 @@ var init_github = __esm({
|
|
|
1614
1815
|
RESUME_MIN_SCORE = 0.05;
|
|
1615
1816
|
RECEPTIVITY_RECENCY_DAYS = 180;
|
|
1616
1817
|
RECEPTIVITY_RECENCY_FLOOR = 0.1;
|
|
1818
|
+
GITHUB_GRAPHQL_URL = "https://api.github.com/graphql";
|
|
1617
1819
|
}
|
|
1618
1820
|
});
|
|
1619
1821
|
|
|
@@ -1694,34 +1896,45 @@ function mergeSoftCoverage(covMap, softTags, cap) {
|
|
|
1694
1896
|
}
|
|
1695
1897
|
return covMap;
|
|
1696
1898
|
}
|
|
1899
|
+
function tagKernel(job, ctx) {
|
|
1900
|
+
const { expanded, covMap, maxDevScore, skillTags } = ctx;
|
|
1901
|
+
const details = [];
|
|
1902
|
+
let jobMatchScore = 0;
|
|
1903
|
+
let jobMaxScore = 0;
|
|
1904
|
+
const devCovByTag = /* @__PURE__ */ new Map();
|
|
1905
|
+
for (const tag of job.tags) {
|
|
1906
|
+
const w = backgroundIdf(tag);
|
|
1907
|
+
jobMaxScore += w;
|
|
1908
|
+
const covHit = covMap.get(tag);
|
|
1909
|
+
if (covHit) jobMatchScore += w * Math.pow(covHit.weight, SHARPEN);
|
|
1910
|
+
const fpHit = expanded.get(tag);
|
|
1911
|
+
if (fpHit) {
|
|
1912
|
+
const credit = Math.pow(fpHit.weight, SHARPEN);
|
|
1913
|
+
details.push({ tag, weight: fpHit.weight, via: fpHit.via });
|
|
1914
|
+
if (credit > (devCovByTag.get(fpHit.via) ?? 0)) devCovByTag.set(fpHit.via, credit);
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
let devScore = 0;
|
|
1918
|
+
for (const t of skillTags) devScore += backgroundIdf(t) * (devCovByTag.get(t) ?? 0);
|
|
1919
|
+
const devCov = maxDevScore > 0 ? Math.min(1, devScore / maxDevScore) : 0;
|
|
1920
|
+
const jobCov = jobMaxScore > 0 ? Math.min(1, jobMatchScore / jobMaxScore) : 0;
|
|
1921
|
+
return { tagComponent: harmonicMean(devCov, jobCov), details };
|
|
1922
|
+
}
|
|
1923
|
+
function relevanceScore(fp, job, softTags = []) {
|
|
1924
|
+
const expanded = expandWeighted(fp.skillTags);
|
|
1925
|
+
const covMap = softTags.length > 0 ? mergeSoftCoverage(new Map(expanded), softTags, INTEREST_CAP) : expanded;
|
|
1926
|
+
const maxDevScore = fp.skillTags.reduce((acc, t) => acc + backgroundIdf(t), 0);
|
|
1927
|
+
return tagKernel(job, { expanded, covMap, maxDevScore, skillTags: fp.skillTags }).tagComponent;
|
|
1928
|
+
}
|
|
1697
1929
|
function match(fp, jobs, limit = 5, now = Date.now(), opts = {}) {
|
|
1698
1930
|
const idfOf = backgroundIdf;
|
|
1699
1931
|
const expanded = expandWeighted(fp.skillTags);
|
|
1700
1932
|
const covMap = opts.softTags && opts.softTags.length > 0 ? mergeSoftCoverage(new Map(expanded), opts.softTags, INTEREST_CAP) : expanded;
|
|
1701
1933
|
const maxDevScore = fp.skillTags.reduce((acc, t) => acc + idfOf(t), 0);
|
|
1934
|
+
const ctx = { expanded, covMap, maxDevScore, skillTags: fp.skillTags };
|
|
1702
1935
|
const candidates = jobs.filter((j) => passesFilters(fp, j));
|
|
1703
1936
|
const scored = candidates.map((job) => {
|
|
1704
|
-
const details =
|
|
1705
|
-
let jobMatchScore = 0;
|
|
1706
|
-
let jobMaxScore = 0;
|
|
1707
|
-
const devCovByTag = /* @__PURE__ */ new Map();
|
|
1708
|
-
for (const tag of job.tags) {
|
|
1709
|
-
const w = idfOf(tag);
|
|
1710
|
-
jobMaxScore += w;
|
|
1711
|
-
const covHit = covMap.get(tag);
|
|
1712
|
-
if (covHit) jobMatchScore += w * Math.pow(covHit.weight, SHARPEN);
|
|
1713
|
-
const fpHit = expanded.get(tag);
|
|
1714
|
-
if (fpHit) {
|
|
1715
|
-
const credit = Math.pow(fpHit.weight, SHARPEN);
|
|
1716
|
-
details.push({ tag, weight: fpHit.weight, via: fpHit.via });
|
|
1717
|
-
if (credit > (devCovByTag.get(fpHit.via) ?? 0)) devCovByTag.set(fpHit.via, credit);
|
|
1718
|
-
}
|
|
1719
|
-
}
|
|
1720
|
-
let devScore = 0;
|
|
1721
|
-
for (const t of fp.skillTags) devScore += idfOf(t) * (devCovByTag.get(t) ?? 0);
|
|
1722
|
-
const devCov = maxDevScore > 0 ? Math.min(1, devScore / maxDevScore) : 0;
|
|
1723
|
-
const jobCov = jobMaxScore > 0 ? Math.min(1, jobMatchScore / jobMaxScore) : 0;
|
|
1724
|
-
const tagComponent = harmonicMean(devCov, jobCov);
|
|
1937
|
+
const { tagComponent, details } = tagKernel(job, ctx);
|
|
1725
1938
|
if (tagComponent === 0) return null;
|
|
1726
1939
|
const coreTags = job.coreTags ?? coreTagsFromTitle(job.title);
|
|
1727
1940
|
let coreComponent = tagComponent;
|
|
@@ -3256,6 +3469,7 @@ function hasContentSignal(title, body, labels) {
|
|
|
3256
3469
|
${body}`;
|
|
3257
3470
|
if (CONTENT_ADD_RE.test(text)) return true;
|
|
3258
3471
|
if (ADD_TO_CORPUS_RE.test(text)) return true;
|
|
3472
|
+
if (NUMBERED_SEED_RE.test(title)) return true;
|
|
3259
3473
|
if (TRANSLATE_RE.test(text)) return true;
|
|
3260
3474
|
if (TYPO_RE.test(text)) return true;
|
|
3261
3475
|
return false;
|
|
@@ -3271,7 +3485,7 @@ function classifyContributionKind(input) {
|
|
|
3271
3485
|
function looksLikeContentTask(input) {
|
|
3272
3486
|
return classifyContributionKind(input) === "content";
|
|
3273
3487
|
}
|
|
3274
|
-
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;
|
|
3488
|
+
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;
|
|
3275
3489
|
var init_contribution_classify = __esm({
|
|
3276
3490
|
"../../packages/core/src/feeds/contribution-classify.ts"() {
|
|
3277
3491
|
"use strict";
|
|
@@ -3281,7 +3495,16 @@ var init_contribution_classify = __esm({
|
|
|
3281
3495
|
CODE_EXCEPTION_RE = /exception|stacktrace|segfault|traceback/i;
|
|
3282
3496
|
CODE_FENCE_RE = /```|(?:^|\n)\s{4,}\S/;
|
|
3283
3497
|
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;
|
|
3284
|
-
|
|
3498
|
+
CONTENT_NOUN_STRONG = String.raw`proverbs?|words?|phrases?|sayings?|quotes?|quotations?|translations?|entry|entries|definitions?|terms?|idioms?|synonyms?|antonyms?|acronyms?|abbreviations?`;
|
|
3499
|
+
CONTENT_NOUN_BROAD = String.raw`trivia\s+questions?|grammar\s+points?|trivia|facts?|quiz(?:zes)?|flash\s?cards?|vocab(?:ulary)?|lessons?|kanji`;
|
|
3500
|
+
CONTENT_ADD_RE = new RegExp(
|
|
3501
|
+
String.raw`\badd(?:ing|s)?\s+(?:\w+\s+){0,4}?(?:${CONTENT_NOUN_STRONG})\b`,
|
|
3502
|
+
"i"
|
|
3503
|
+
);
|
|
3504
|
+
NUMBERED_SEED_RE = new RegExp(
|
|
3505
|
+
String.raw`\badd(?:ing|s)?\s+(?:\w+\s+){0,4}?(?:${CONTENT_NOUN_STRONG}|${CONTENT_NOUN_BROAD})\s*#?\s*\d{1,3}\s*$`,
|
|
3506
|
+
"i"
|
|
3507
|
+
);
|
|
3285
3508
|
ADD_TO_CORPUS_RE = /\badd\b[\s\S]*?\bto\s+(?:the\s+)?(?:word\s?list|dictionary|glossary|phrasebook)\b/i;
|
|
3286
3509
|
TRANSLATE_RE = /\b(?:translate|translating|translation|localize|localise|localization|localisation)\b/i;
|
|
3287
3510
|
TYPO_RE = /\bfix(?:ing)?\s+(?:a\s+|the\s+|some\s+)?typos?\b/i;
|
|
@@ -3289,20 +3512,6 @@ var init_contribution_classify = __esm({
|
|
|
3289
3512
|
});
|
|
3290
3513
|
|
|
3291
3514
|
// ../../packages/core/src/feeds/contributions.ts
|
|
3292
|
-
function readReqGapMs() {
|
|
3293
|
-
const raw = process.env["CONTRIB_REQ_GAP_MS"];
|
|
3294
|
-
if (raw == null) return DEFAULT_REQ_GAP_MS;
|
|
3295
|
-
const n = Number.parseInt(raw, 10);
|
|
3296
|
-
if (Number.isNaN(n)) return DEFAULT_REQ_GAP_MS;
|
|
3297
|
-
return Math.min(Math.max(n, 0), 1e3);
|
|
3298
|
-
}
|
|
3299
|
-
function readBuildBudgetMs() {
|
|
3300
|
-
const raw = process.env["CONTRIB_BUILD_BUDGET_MS"];
|
|
3301
|
-
if (raw == null) return DEFAULT_BUILD_BUDGET_MS;
|
|
3302
|
-
const n = Number.parseInt(raw, 10);
|
|
3303
|
-
if (Number.isNaN(n)) return DEFAULT_BUILD_BUDGET_MS;
|
|
3304
|
-
return Math.min(Math.max(n, MIN_BUILD_BUDGET_MS), MAX_BUILD_BUDGET_MS);
|
|
3305
|
-
}
|
|
3306
3515
|
function authHeaders2() {
|
|
3307
3516
|
const token = process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"];
|
|
3308
3517
|
const h = {
|
|
@@ -3324,57 +3533,9 @@ function repoFullNameFromApiUrl2(url) {
|
|
|
3324
3533
|
return m ? `${m[1]}/${m[2]}` : null;
|
|
3325
3534
|
}
|
|
3326
3535
|
function makeClient(fetchImpl, cfg) {
|
|
3327
|
-
const
|
|
3328
|
-
let lastRequestAt = 0;
|
|
3329
|
-
let pacedMs = 0;
|
|
3330
|
-
let secondaryHits = 0;
|
|
3331
|
-
let aborted = false;
|
|
3332
|
-
let secondaryAborted = false;
|
|
3333
|
-
let budgetAborted = false;
|
|
3334
|
-
let coreHealthyAtStart = false;
|
|
3335
|
-
async function noteAndMaybeBackOff(res) {
|
|
3336
|
-
if (res.status !== 403) return;
|
|
3337
|
-
const remaining = res.headers.get("x-ratelimit-remaining");
|
|
3338
|
-
const retryAfter = res.headers.get("retry-after");
|
|
3339
|
-
const positiveSecondary = retryAfter != null || remaining != null && remaining !== "0";
|
|
3340
|
-
const isSecondary = positiveSecondary || coreHealthyAtStart;
|
|
3341
|
-
if (!isSecondary) return;
|
|
3342
|
-
secondaryHits++;
|
|
3343
|
-
if (secondaryHits >= 2) {
|
|
3344
|
-
aborted = true;
|
|
3345
|
-
secondaryAborted = true;
|
|
3346
|
-
return;
|
|
3347
|
-
}
|
|
3348
|
-
if (cfg.paceEnabled) {
|
|
3349
|
-
const trimmed = (retryAfter ?? "").trim();
|
|
3350
|
-
const parsed = trimmed.length === 0 ? Number.NaN : Number(trimmed);
|
|
3351
|
-
const sec = Number.isNaN(parsed) ? SECONDARY_BACKOFF_CAP_S : Math.min(Math.max(parsed, 0), SECONDARY_BACKOFF_CAP_S);
|
|
3352
|
-
const remaining2 = Math.max(0, cfg.budgetMs - (cfg.now() - startedAt));
|
|
3353
|
-
await cfg.sleep(Math.min(sec * 1e3, remaining2));
|
|
3354
|
-
}
|
|
3355
|
-
}
|
|
3536
|
+
const gov = makeGitHubGovernor(fetchImpl, cfg);
|
|
3356
3537
|
async function raw(path) {
|
|
3357
|
-
|
|
3358
|
-
if (cfg.now() - startedAt > cfg.budgetMs) {
|
|
3359
|
-
aborted = true;
|
|
3360
|
-
budgetAborted = true;
|
|
3361
|
-
return null;
|
|
3362
|
-
}
|
|
3363
|
-
if (cfg.paceEnabled && cfg.gapMs > 0) {
|
|
3364
|
-
const wait = cfg.gapMs - (cfg.now() - lastRequestAt);
|
|
3365
|
-
if (wait > 0) {
|
|
3366
|
-
await cfg.sleep(wait);
|
|
3367
|
-
pacedMs += wait;
|
|
3368
|
-
}
|
|
3369
|
-
lastRequestAt = cfg.now();
|
|
3370
|
-
}
|
|
3371
|
-
try {
|
|
3372
|
-
const res = await fetchImpl(`${GITHUB_API2}${path}`, { headers: authHeaders2() });
|
|
3373
|
-
await noteAndMaybeBackOff(res);
|
|
3374
|
-
return res;
|
|
3375
|
-
} catch {
|
|
3376
|
-
return null;
|
|
3377
|
-
}
|
|
3538
|
+
return gov.get(`${GITHUB_API2}${path}`, { headers: authHeaders2() });
|
|
3378
3539
|
}
|
|
3379
3540
|
async function json(path) {
|
|
3380
3541
|
const res = await raw(path);
|
|
@@ -3388,41 +3549,9 @@ function makeClient(fetchImpl, cfg) {
|
|
|
3388
3549
|
}
|
|
3389
3550
|
}
|
|
3390
3551
|
async function probe(path) {
|
|
3391
|
-
|
|
3392
|
-
let timer;
|
|
3393
|
-
const fetchP = fetchImpl(`${GITHUB_API2}${path}`, {
|
|
3394
|
-
headers: authHeaders2()
|
|
3395
|
-
}).then(
|
|
3396
|
-
(r) => r,
|
|
3397
|
-
() => null
|
|
3398
|
-
);
|
|
3399
|
-
try {
|
|
3400
|
-
const res = bound == null ? await fetchP : await Promise.race([
|
|
3401
|
-
fetchP,
|
|
3402
|
-
new Promise((resolve) => {
|
|
3403
|
-
timer = setTimeout(() => resolve(null), bound);
|
|
3404
|
-
})
|
|
3405
|
-
]);
|
|
3406
|
-
if (!res || !res.ok) return null;
|
|
3407
|
-
return await res.json();
|
|
3408
|
-
} catch {
|
|
3409
|
-
return null;
|
|
3410
|
-
} finally {
|
|
3411
|
-
if (timer) clearTimeout(timer);
|
|
3412
|
-
}
|
|
3552
|
+
return gov.probe(`${GITHUB_API2}${path}`, { headers: authHeaders2() });
|
|
3413
3553
|
}
|
|
3414
|
-
|
|
3415
|
-
coreHealthyAtStart = coreHealthy;
|
|
3416
|
-
}
|
|
3417
|
-
function getStats() {
|
|
3418
|
-
return {
|
|
3419
|
-
pacedMs,
|
|
3420
|
-
secondaryAborted: secondaryAborted ? 1 : 0,
|
|
3421
|
-
budgetAborted: budgetAborted ? 1 : 0,
|
|
3422
|
-
elapsedMs: cfg.now() - startedAt
|
|
3423
|
-
};
|
|
3424
|
-
}
|
|
3425
|
-
return { raw, json, probe, setSecondaryHint, getStats };
|
|
3554
|
+
return { raw, json, probe, setSecondaryHint: gov.setSecondaryHint, getStats: gov.getStats };
|
|
3426
3555
|
}
|
|
3427
3556
|
async function contributorCount(client, fullName) {
|
|
3428
3557
|
const res = await client.raw(`/repos/${fullName}/contributors?per_page=1&anon=false`);
|
|
@@ -3521,10 +3650,63 @@ async function aggregateContributions(opts = {}) {
|
|
|
3521
3650
|
const repoCache = /* @__PURE__ */ new Map();
|
|
3522
3651
|
const contribCache = /* @__PURE__ */ new Map();
|
|
3523
3652
|
const prRefsCache = /* @__PURE__ */ new Map();
|
|
3653
|
+
const xbuild = opts.repoMetaCache;
|
|
3654
|
+
const servedFromXbuild = /* @__PURE__ */ new Set();
|
|
3655
|
+
const persistedXbuild = /* @__PURE__ */ new Set();
|
|
3656
|
+
const xbuildTried = /* @__PURE__ */ new Set();
|
|
3657
|
+
async function primeFromXbuild(key, fullName) {
|
|
3658
|
+
if (!xbuild || xbuildTried.has(key)) return;
|
|
3659
|
+
xbuildTried.add(key);
|
|
3660
|
+
if (repoCache.has(key) && contribCache.has(key)) return;
|
|
3661
|
+
let cached = null;
|
|
3662
|
+
try {
|
|
3663
|
+
cached = await xbuild.get(key);
|
|
3664
|
+
} catch {
|
|
3665
|
+
return;
|
|
3666
|
+
}
|
|
3667
|
+
if (!cached) return;
|
|
3668
|
+
if (!repoCache.has(key)) {
|
|
3669
|
+
const owner = fullName.split("/")[0] ?? "";
|
|
3670
|
+
repoCache.set(key, {
|
|
3671
|
+
full_name: fullName,
|
|
3672
|
+
stargazers_count: cached.stars,
|
|
3673
|
+
archived: cached.archived,
|
|
3674
|
+
disabled: cached.disabled,
|
|
3675
|
+
fork: cached.fork,
|
|
3676
|
+
language: cached.language,
|
|
3677
|
+
owner: { login: owner }
|
|
3678
|
+
});
|
|
3679
|
+
}
|
|
3680
|
+
if (!contribCache.has(key)) {
|
|
3681
|
+
contribCache.set(key, cached.contributors);
|
|
3682
|
+
servedFromXbuild.add(key);
|
|
3683
|
+
}
|
|
3684
|
+
}
|
|
3685
|
+
async function persistRepoMeta(fullName, repo, contributors) {
|
|
3686
|
+
if (!xbuild) return;
|
|
3687
|
+
const key = repoKey(fullName);
|
|
3688
|
+
if (servedFromXbuild.has(key) || persistedXbuild.has(key)) return;
|
|
3689
|
+
if (contributors === void 0) return;
|
|
3690
|
+
persistedXbuild.add(key);
|
|
3691
|
+
try {
|
|
3692
|
+
await xbuild.set(key, {
|
|
3693
|
+
stars: repo.stargazers_count,
|
|
3694
|
+
contributors,
|
|
3695
|
+
language: repo.language,
|
|
3696
|
+
archived: repo.archived,
|
|
3697
|
+
fork: repo.fork,
|
|
3698
|
+
disabled: repo.disabled
|
|
3699
|
+
});
|
|
3700
|
+
} catch {
|
|
3701
|
+
}
|
|
3702
|
+
}
|
|
3524
3703
|
async function repoMeta(fullName) {
|
|
3525
3704
|
const key = repoKey(fullName);
|
|
3526
3705
|
const hit = repoCache.get(key);
|
|
3527
3706
|
if (hit !== void 0) return hit;
|
|
3707
|
+
await primeFromXbuild(key, fullName);
|
|
3708
|
+
const primed = repoCache.get(key);
|
|
3709
|
+
if (primed !== void 0) return primed;
|
|
3528
3710
|
const r = await client.json(`/repos/${fullName}`) ?? null;
|
|
3529
3711
|
repoCache.set(key, r);
|
|
3530
3712
|
return r;
|
|
@@ -3532,6 +3714,8 @@ async function aggregateContributions(opts = {}) {
|
|
|
3532
3714
|
async function repoContribCount(fullName) {
|
|
3533
3715
|
const key = repoKey(fullName);
|
|
3534
3716
|
if (contribCache.has(key)) return contribCache.get(key);
|
|
3717
|
+
await primeFromXbuild(key, fullName);
|
|
3718
|
+
if (contribCache.has(key)) return contribCache.get(key);
|
|
3535
3719
|
const n = await contributorCount(client, fullName);
|
|
3536
3720
|
contribCache.set(key, n);
|
|
3537
3721
|
return n;
|
|
@@ -3558,14 +3742,18 @@ async function aggregateContributions(opts = {}) {
|
|
|
3558
3742
|
if (isDenylistedRepo(fullName)) continue;
|
|
3559
3743
|
if (isAssigned(issue)) continue;
|
|
3560
3744
|
if ((perRepo.get(repoKey(fullName)) ?? 0) >= MAX_BOUNTIES_PER_DISCOVERED_REPO) continue;
|
|
3745
|
+
const title = decodeEntities(issue.title).trim();
|
|
3746
|
+
const body = issue.body ? decodeEntities(issue.body) : "";
|
|
3747
|
+
const labels = labelNames2(issue.labels);
|
|
3748
|
+
if (looksLikeContentTask({ title, body, labels })) continue;
|
|
3561
3749
|
const repo = await repoMeta(fullName);
|
|
3562
3750
|
if (!repo) {
|
|
3563
3751
|
metaNull++;
|
|
3564
3752
|
continue;
|
|
3565
3753
|
}
|
|
3566
|
-
const title = decodeEntities(issue.title).trim();
|
|
3567
3754
|
const contributors = await repoContribCount(fullName);
|
|
3568
3755
|
if (contributors === void 0) contribUndefined++;
|
|
3756
|
+
await persistRepoMeta(fullName, repo, contributors);
|
|
3569
3757
|
if (!passesContributionGate({
|
|
3570
3758
|
fullName,
|
|
3571
3759
|
stars: repo.stargazers_count,
|
|
@@ -3577,13 +3765,9 @@ async function aggregateContributions(opts = {}) {
|
|
|
3577
3765
|
continue;
|
|
3578
3766
|
}
|
|
3579
3767
|
if (repo.disabled) continue;
|
|
3580
|
-
const body = issue.body ? decodeEntities(issue.body) : "";
|
|
3581
|
-
const labels = labelNames2(issue.labels);
|
|
3582
|
-
if (looksLikeContentTask({ title, body, labels })) continue;
|
|
3583
3768
|
const prRefs = await repoPRRefs(fullName);
|
|
3584
3769
|
if (prRefs === null) prRefsNull++;
|
|
3585
|
-
|
|
3586
|
-
const openPRsAtDiscovery = prRefs ? 0 : void 0;
|
|
3770
|
+
const openPRsAtDiscovery = prRefs ? prRefs.has(issue.number) ? 1 : 0 : void 0;
|
|
3587
3771
|
const tags = normalize(
|
|
3588
3772
|
tokenize4([title, repo.language ?? "", labels.join(" "), body.slice(0, 2e3)].join(" "))
|
|
3589
3773
|
);
|
|
@@ -3674,6 +3858,7 @@ async function aggregateContributions(opts = {}) {
|
|
|
3674
3858
|
if (repo.disabled) continue;
|
|
3675
3859
|
const contributors = await repoContribCount(fullName);
|
|
3676
3860
|
if (contributors === void 0) contribUndefined++;
|
|
3861
|
+
await persistRepoMeta(fullName, repo, contributors);
|
|
3677
3862
|
if (repo.archived || repo.fork || repo.stargazers_count < MIN_STARS || contributors === void 0 || contributors < MIN_CONTRIBUTORS) {
|
|
3678
3863
|
continue;
|
|
3679
3864
|
}
|
|
@@ -3706,8 +3891,7 @@ async function aggregateContributions(opts = {}) {
|
|
|
3706
3891
|
if (looksLikeContentTask({ title, body, labels })) continue;
|
|
3707
3892
|
const prRefs = await repoPRRefs(fullName);
|
|
3708
3893
|
if (prRefs === null) prRefsNull++;
|
|
3709
|
-
|
|
3710
|
-
const openPRsAtDiscovery = prRefs ? 0 : void 0;
|
|
3894
|
+
const openPRsAtDiscovery = prRefs ? prRefs.has(issue.number) ? 1 : 0 : void 0;
|
|
3711
3895
|
const tags = normalize(
|
|
3712
3896
|
tokenize4([title, repo.language ?? "", labels.join(" "), body.slice(0, 2e3)].join(" "))
|
|
3713
3897
|
);
|
|
@@ -3738,9 +3922,9 @@ async function aggregateContributions(opts = {}) {
|
|
|
3738
3922
|
const core = rl?.core ? `${rl.core.remaining}/${rl.core.limit}` : "n/a";
|
|
3739
3923
|
const search = rl?.search ? `${rl.search.remaining}/${rl.search.limit}` : "n/a";
|
|
3740
3924
|
const noToken = !(process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"]);
|
|
3741
|
-
const { pacedMs, secondaryAborted, budgetAborted, elapsedMs } = client.getStats();
|
|
3925
|
+
const { pacedMs, secondaryAborted, budgetAborted, elapsedMs, gqlCost, gqlRemaining } = client.getStats();
|
|
3742
3926
|
console.info(
|
|
3743
|
-
`[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)" : "")
|
|
3927
|
+
`[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)" : "")
|
|
3744
3928
|
);
|
|
3745
3929
|
if (discoveryBudgetStopped) {
|
|
3746
3930
|
console.warn(
|
|
@@ -3750,7 +3934,7 @@ async function aggregateContributions(opts = {}) {
|
|
|
3750
3934
|
}
|
|
3751
3935
|
return jobs;
|
|
3752
3936
|
}
|
|
3753
|
-
var GITHUB_API2,
|
|
3937
|
+
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;
|
|
3754
3938
|
var init_contributions = __esm({
|
|
3755
3939
|
"../../packages/core/src/feeds/contributions.ts"() {
|
|
3756
3940
|
"use strict";
|
|
@@ -3761,14 +3945,8 @@ var init_contributions = __esm({
|
|
|
3761
3945
|
init_contribution_classify();
|
|
3762
3946
|
init_github_bounties();
|
|
3763
3947
|
init_http();
|
|
3948
|
+
init_gh_governor();
|
|
3764
3949
|
GITHUB_API2 = "https://api.github.com";
|
|
3765
|
-
DEFAULT_REQ_GAP_MS = 75;
|
|
3766
|
-
SECONDARY_BACKOFF_CAP_S = 30;
|
|
3767
|
-
DEFAULT_BUILD_BUDGET_MS = 9e4;
|
|
3768
|
-
MIN_BUILD_BUDGET_MS = 1e4;
|
|
3769
|
-
MAX_BUILD_BUDGET_MS = 9e4;
|
|
3770
|
-
PROBE_TIMEOUT_MS = 3e3;
|
|
3771
|
-
realSleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
3772
3950
|
CONTRIB_LABEL_QUERIES = [
|
|
3773
3951
|
'label:"good first issue" type:issue state:open',
|
|
3774
3952
|
'label:"good-first-issue" type:issue state:open',
|
|
@@ -3986,12 +4164,22 @@ async function enrichWinnability(jobs, contribute, w) {
|
|
|
3986
4164
|
const repos = [...byRepo.keys()].sort((a, b) => starsOf(b) - starsOf(a));
|
|
3987
4165
|
const scored = repos.slice(0, maxRepos);
|
|
3988
4166
|
const cappedOut = repos.length - scored.length;
|
|
4167
|
+
const gov = w.governor ?? makeGitHubGovernor(
|
|
4168
|
+
w.fetchImpl ?? fetch,
|
|
4169
|
+
makeDefaultGovernorConfig({ paceEnabled: !w.fetchImpl })
|
|
4170
|
+
);
|
|
4171
|
+
let stoppedEarly = false;
|
|
3989
4172
|
for (const repo of scored) {
|
|
4173
|
+
if (gov.tripped() || gov.budgetExhausted()) {
|
|
4174
|
+
stoppedEarly = true;
|
|
4175
|
+
break;
|
|
4176
|
+
}
|
|
3990
4177
|
const targets = byRepo.get(repo) ?? [];
|
|
3991
4178
|
const receptivity = await fetchRepoReceptivity(repo, {
|
|
3992
4179
|
token: w.token,
|
|
3993
4180
|
fetchImpl: w.fetchImpl,
|
|
3994
|
-
now
|
|
4181
|
+
now,
|
|
4182
|
+
governor: gov
|
|
3995
4183
|
});
|
|
3996
4184
|
const stars = starsOf(repo);
|
|
3997
4185
|
const prev = priorStars[repo];
|
|
@@ -4020,6 +4208,12 @@ async function enrichWinnability(jobs, contribute, w) {
|
|
|
4020
4208
|
}
|
|
4021
4209
|
}
|
|
4022
4210
|
}
|
|
4211
|
+
if (stoppedEarly) {
|
|
4212
|
+
const reason = gov.tripped() ? "secondary-abuse breaker" : "wall-clock budget";
|
|
4213
|
+
console.warn(
|
|
4214
|
+
`[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.`
|
|
4215
|
+
);
|
|
4216
|
+
}
|
|
4023
4217
|
if (cappedOut > 0) {
|
|
4024
4218
|
console.warn(
|
|
4025
4219
|
`[winnability] receptivity cap hit \u2014 scored ${scored.length}/${repos.length} repos (${cappedOut} beyond maxRepos=${maxRepos} left un-scored, legacy ranking)`
|
|
@@ -4062,6 +4256,7 @@ var init_indexer = __esm({
|
|
|
4062
4256
|
init_contributions();
|
|
4063
4257
|
init_partners();
|
|
4064
4258
|
init_github();
|
|
4259
|
+
init_gh_governor();
|
|
4065
4260
|
init_winnability();
|
|
4066
4261
|
}
|
|
4067
4262
|
});
|
|
@@ -7657,6 +7852,7 @@ __export(src_exports, {
|
|
|
7657
7852
|
MERGE_PROBABILITY: () => MERGE_PROBABILITY,
|
|
7658
7853
|
MIN_CONTRIBUTORS: () => MIN_CONTRIBUTORS,
|
|
7659
7854
|
MIN_STARS: () => MIN_STARS,
|
|
7855
|
+
PROBE_TIMEOUT_MS: () => PROBE_TIMEOUT_MS,
|
|
7660
7856
|
RIGOR: () => RIGOR,
|
|
7661
7857
|
STRONG_MATCH_THRESHOLD: () => STRONG_MATCH_THRESHOLD,
|
|
7662
7858
|
SYNONYMS: () => SYNONYMS,
|
|
@@ -7728,6 +7924,9 @@ __export(src_exports, {
|
|
|
7728
7924
|
lever: () => lever,
|
|
7729
7925
|
loadPartnerRoles: () => loadPartnerRoles,
|
|
7730
7926
|
looksLikeEngRole: () => looksLikeEngRole,
|
|
7927
|
+
makeDefaultGovernorConfig: () => makeDefaultGovernorConfig,
|
|
7928
|
+
makeGitHubGovernor: () => makeGitHubGovernor,
|
|
7929
|
+
makeScoringGovernor: () => makeScoringGovernor,
|
|
7731
7930
|
match: () => match,
|
|
7732
7931
|
mergeProbability: () => mergeProbability,
|
|
7733
7932
|
mmrRerank: () => mmrRerank,
|
|
@@ -7740,8 +7939,12 @@ __export(src_exports, {
|
|
|
7740
7939
|
passesMaturityGate: () => passesMaturityGate,
|
|
7741
7940
|
personCardToJob: () => personCardToJob,
|
|
7742
7941
|
projectCardToJob: () => projectCardToJob,
|
|
7942
|
+
readBuildBudgetMs: () => readBuildBudgetMs,
|
|
7943
|
+
readReqGapMs: () => readReqGapMs,
|
|
7944
|
+
realSleep: () => realSleep,
|
|
7743
7945
|
recordClick: () => recordClick,
|
|
7744
7946
|
rejectExtraIntroFields: () => rejectExtraIntroFields,
|
|
7947
|
+
relevanceScore: () => relevanceScore,
|
|
7745
7948
|
revealIntroContacts: () => revealIntroContacts,
|
|
7746
7949
|
safetyNumber: () => safetyNumber,
|
|
7747
7950
|
sameLogin: () => sameLogin,
|
|
@@ -7768,6 +7971,7 @@ var init_src = __esm({
|
|
|
7768
7971
|
init_winnability();
|
|
7769
7972
|
init_partners();
|
|
7770
7973
|
init_github();
|
|
7974
|
+
init_gh_governor();
|
|
7771
7975
|
init_credit();
|
|
7772
7976
|
init_intro();
|
|
7773
7977
|
init_directoryThreshold();
|
|
@@ -7788,9 +7992,9 @@ var init_keytar = __esm({
|
|
|
7788
7992
|
}
|
|
7789
7993
|
});
|
|
7790
7994
|
|
|
7791
|
-
// node-file:/Users/ericgang/job-placement-inline
|
|
7995
|
+
// node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node
|
|
7792
7996
|
var require_keytar = __commonJS({
|
|
7793
|
-
"node-file:/Users/ericgang/job-placement-inline
|
|
7997
|
+
"node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
7794
7998
|
"use strict";
|
|
7795
7999
|
init_keytar();
|
|
7796
8000
|
try {
|