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.
@@ -1122,6 +1122,187 @@ var init_rigor = __esm({
1122
1122
  }
1123
1123
  });
1124
1124
 
1125
+ // ../../packages/core/src/gh-governor.ts
1126
+ function readReqGapMs() {
1127
+ const raw = process.env["CONTRIB_REQ_GAP_MS"];
1128
+ if (raw == null) return DEFAULT_REQ_GAP_MS;
1129
+ const n = Number.parseInt(raw, 10);
1130
+ if (Number.isNaN(n)) return DEFAULT_REQ_GAP_MS;
1131
+ return Math.min(Math.max(n, 0), 1e3);
1132
+ }
1133
+ function readBuildBudgetMs() {
1134
+ const raw = process.env["CONTRIB_BUILD_BUDGET_MS"];
1135
+ if (raw == null) return DEFAULT_BUILD_BUDGET_MS;
1136
+ const n = Number.parseInt(raw, 10);
1137
+ if (Number.isNaN(n)) return DEFAULT_BUILD_BUDGET_MS;
1138
+ return Math.min(Math.max(n, MIN_BUILD_BUDGET_MS), MAX_BUILD_BUDGET_MS);
1139
+ }
1140
+ function makeDefaultGovernorConfig(o) {
1141
+ return {
1142
+ paceEnabled: o.paceEnabled,
1143
+ gapMs: readReqGapMs(),
1144
+ budgetMs: readBuildBudgetMs(),
1145
+ sleep: o.sleep ?? realSleep,
1146
+ now: o.now ?? Date.now,
1147
+ probeTimeoutMs: o.probeTimeoutMs ?? (o.paceEnabled ? PROBE_TIMEOUT_MS : null)
1148
+ };
1149
+ }
1150
+ function makeGitHubGovernor(fetchImpl, cfg) {
1151
+ const startedAt = cfg.now();
1152
+ let lastRequestAt = 0;
1153
+ let pacedMs = 0;
1154
+ let secondaryHits = 0;
1155
+ let aborted2 = false;
1156
+ let secondaryAborted = false;
1157
+ let budgetAborted = false;
1158
+ let gqlCost = 0;
1159
+ let gqlRemaining = null;
1160
+ let coreHealthyAtStart = false;
1161
+ async function noteAndMaybeBackOff(res) {
1162
+ if (res.status !== 403) return;
1163
+ const remaining = res.headers.get("x-ratelimit-remaining");
1164
+ const retryAfter = res.headers.get("retry-after");
1165
+ const positiveSecondary = retryAfter != null || remaining != null && remaining !== "0";
1166
+ const isSecondary = positiveSecondary || coreHealthyAtStart;
1167
+ if (!isSecondary) return;
1168
+ await recordSecondaryStrike(retryAfter);
1169
+ }
1170
+ async function recordSecondaryStrike(retryAfter) {
1171
+ secondaryHits++;
1172
+ if (secondaryHits >= 2) {
1173
+ aborted2 = true;
1174
+ secondaryAborted = true;
1175
+ return;
1176
+ }
1177
+ if (cfg.paceEnabled) {
1178
+ const trimmed = (retryAfter ?? "").trim();
1179
+ const parsed = trimmed.length === 0 ? Number.NaN : Number(trimmed);
1180
+ const sec = Number.isNaN(parsed) ? SECONDARY_BACKOFF_CAP_S : Math.min(Math.max(parsed, 0), SECONDARY_BACKOFF_CAP_S);
1181
+ const remainingBudget = Math.max(0, cfg.budgetMs - (cfg.now() - startedAt));
1182
+ await cfg.sleep(Math.min(sec * 1e3, remainingBudget));
1183
+ }
1184
+ }
1185
+ async function noteGraphQLAndMaybeBackOff(res, body) {
1186
+ const b = body ?? {};
1187
+ const rl = b.data?.rateLimit;
1188
+ if (rl) {
1189
+ if (typeof rl.cost === "number") gqlCost += rl.cost;
1190
+ if (typeof rl.remaining === "number") gqlRemaining = rl.remaining;
1191
+ }
1192
+ const remainingHdr = res.headers?.get("x-ratelimit-remaining") ?? null;
1193
+ const retryAfter = res.headers?.get("retry-after") ?? null;
1194
+ const headerRate = retryAfter != null || remainingHdr === "0";
1195
+ const errs = Array.isArray(b.errors) ? b.errors : [];
1196
+ const bodyRate = errs.some((e) => e?.type === "RATE_LIMITED" || /rate limit/i.test(String(e?.message ?? ""))) || typeof rl?.remaining === "number" && rl.remaining <= 0;
1197
+ if (headerRate || bodyRate) await recordSecondaryStrike(retryAfter);
1198
+ }
1199
+ async function preflight() {
1200
+ if (aborted2) return false;
1201
+ if (cfg.now() - startedAt >= cfg.budgetMs) {
1202
+ aborted2 = true;
1203
+ budgetAborted = true;
1204
+ return false;
1205
+ }
1206
+ if (cfg.paceEnabled && cfg.gapMs > 0) {
1207
+ const wait = cfg.gapMs - (cfg.now() - lastRequestAt);
1208
+ if (wait > 0) {
1209
+ await cfg.sleep(wait);
1210
+ pacedMs += wait;
1211
+ if (cfg.now() - startedAt >= cfg.budgetMs) {
1212
+ aborted2 = true;
1213
+ budgetAborted = true;
1214
+ return false;
1215
+ }
1216
+ }
1217
+ lastRequestAt = cfg.now();
1218
+ }
1219
+ return true;
1220
+ }
1221
+ async function get(url, init) {
1222
+ if (!await preflight()) return null;
1223
+ try {
1224
+ const res = await fetchImpl(url, init);
1225
+ await noteAndMaybeBackOff(res);
1226
+ return res;
1227
+ } catch {
1228
+ return null;
1229
+ }
1230
+ }
1231
+ async function graphql(url, init) {
1232
+ if (!await preflight()) return null;
1233
+ let res;
1234
+ try {
1235
+ res = await fetchImpl(url, init);
1236
+ } catch {
1237
+ return null;
1238
+ }
1239
+ let body;
1240
+ try {
1241
+ body = await res.json();
1242
+ } catch {
1243
+ return null;
1244
+ }
1245
+ await noteGraphQLAndMaybeBackOff(res, body);
1246
+ if (!res.ok) return null;
1247
+ return body;
1248
+ }
1249
+ async function probe(url, init) {
1250
+ const bound = cfg.probeTimeoutMs;
1251
+ let timer;
1252
+ const fetchP = fetchImpl(url, init).then(
1253
+ (r) => r,
1254
+ () => null
1255
+ );
1256
+ try {
1257
+ const res = bound == null ? await fetchP : await Promise.race([
1258
+ fetchP,
1259
+ new Promise((resolve2) => {
1260
+ timer = setTimeout(() => resolve2(null), bound);
1261
+ })
1262
+ ]);
1263
+ if (!res || !res.ok) return null;
1264
+ return await res.json();
1265
+ } catch {
1266
+ return null;
1267
+ } finally {
1268
+ if (timer) clearTimeout(timer);
1269
+ }
1270
+ }
1271
+ function setSecondaryHint(coreHealthy) {
1272
+ coreHealthyAtStart = coreHealthy;
1273
+ }
1274
+ function getStats() {
1275
+ return {
1276
+ pacedMs,
1277
+ secondaryAborted: secondaryAborted ? 1 : 0,
1278
+ budgetAborted: budgetAborted ? 1 : 0,
1279
+ elapsedMs: cfg.now() - startedAt,
1280
+ gqlCost,
1281
+ gqlRemaining
1282
+ };
1283
+ }
1284
+ function tripped() {
1285
+ return secondaryAborted;
1286
+ }
1287
+ function budgetExhausted() {
1288
+ return budgetAborted || cfg.now() - startedAt >= cfg.budgetMs;
1289
+ }
1290
+ return { get, graphql, probe, setSecondaryHint, getStats, tripped, budgetExhausted };
1291
+ }
1292
+ 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;
1293
+ var init_gh_governor = __esm({
1294
+ "../../packages/core/src/gh-governor.ts"() {
1295
+ "use strict";
1296
+ DEFAULT_REQ_GAP_MS = 75;
1297
+ SECONDARY_BACKOFF_CAP_S = 30;
1298
+ DEFAULT_BUILD_BUDGET_MS = 9e4;
1299
+ MIN_BUILD_BUDGET_MS = 1e4;
1300
+ MAX_BUILD_BUDGET_MS = 9e4;
1301
+ PROBE_TIMEOUT_MS = 3e3;
1302
+ realSleep = (ms) => new Promise((r) => setTimeout(r, ms));
1303
+ }
1304
+ });
1305
+
1125
1306
  // ../../packages/core/src/github.ts
1126
1307
  function ghHeaders(token) {
1127
1308
  const headers = {
@@ -1602,11 +1783,9 @@ async function fetchRepoReceptivity(fullName, opts = {}) {
1602
1783
  const doFetch = opts.fetchImpl ?? fetch;
1603
1784
  const now = opts.now ?? Date.now();
1604
1785
  try {
1605
- const res = await doFetch(
1606
- `https://api.github.com/repos/${fullName}/pulls?state=closed&per_page=50&sort=updated&direction=desc`,
1607
- { headers: ghHeaders(opts.token) }
1608
- );
1609
- if (!res.ok) return null;
1786
+ const url = `https://api.github.com/repos/${fullName}/pulls?state=closed&per_page=50&sort=updated&direction=desc`;
1787
+ const res = opts.governor ? await opts.governor.get(url, { headers: ghHeaders(opts.token) }) : await doFetch(url, { headers: ghHeaders(opts.token) });
1788
+ if (!res || !res.ok) return null;
1610
1789
  const prs = await res.json();
1611
1790
  if (!Array.isArray(prs)) return null;
1612
1791
  const external = prs.filter(isExternalAuthor);
@@ -1691,25 +1870,34 @@ function parseGitHubRef(url) {
1691
1870
  if (!m) return null;
1692
1871
  return { owner: m[1], repo: m[2], number: parseInt(m[4], 10), kind: m[3] === "pull" ? "pull" : "issue" };
1693
1872
  }
1694
- async function ghGraphQL(query, variables, token, signal) {
1695
- const res = await fetch("https://api.github.com/graphql", {
1873
+ async function ghGraphQL(query, variables, token, signal, governor) {
1874
+ const init = {
1696
1875
  method: "POST",
1697
1876
  headers: { ...ghHeaders(token), "Content-Type": "application/json" },
1698
1877
  body: JSON.stringify({ query, variables }),
1699
1878
  signal
1700
- });
1879
+ };
1880
+ if (governor) {
1881
+ const json2 = await governor.graphql(GITHUB_GRAPHQL_URL, init);
1882
+ if (json2 === null) return null;
1883
+ if (json2.errors?.length) throw new Error("GitHub GraphQL errors: " + JSON.stringify(json2.errors));
1884
+ return json2;
1885
+ }
1886
+ const res = await fetch(GITHUB_GRAPHQL_URL, init);
1701
1887
  if (!res.ok) throw new Error(`GitHub GraphQL: HTTP ${res.status}`);
1702
1888
  const json = await res.json();
1703
1889
  if (json.errors?.length) throw new Error("GitHub GraphQL errors: " + JSON.stringify(json.errors));
1704
1890
  return json;
1705
1891
  }
1706
- async function resolveClosingIssues(owner, name, number3, body, token, signal) {
1892
+ async function resolveClosingIssues(owner, name, number3, body, token, signal, governor) {
1707
1893
  if (token) {
1708
1894
  try {
1709
- const q = `query($o:String!,$n:String!,$p:Int!){repository(owner:$o,name:$n){pullRequest(number:$p){closingIssuesReferences(first:20){nodes{number}}}}}`;
1710
- const r = await ghGraphQL(q, { o: owner, n: name, p: number3 }, token, signal);
1711
- const nodes = r.data?.repository?.pullRequest?.closingIssuesReferences?.nodes ?? [];
1712
- return { closesIssues: nodes.map((x) => x.number), linkageSource: "graphql" };
1895
+ 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}}`;
1896
+ const r = await ghGraphQL(q, { o: owner, n: name, p: number3 }, token, signal, governor);
1897
+ if (r) {
1898
+ const nodes = r.data?.repository?.pullRequest?.closingIssuesReferences?.nodes ?? [];
1899
+ return { closesIssues: nodes.map((x) => x.number), linkageSource: "graphql" };
1900
+ }
1713
1901
  } catch {
1714
1902
  }
1715
1903
  }
@@ -1719,11 +1907,19 @@ async function resolveClosingIssues(owner, name, number3, body, token, signal) {
1719
1907
  while ((m = re.exec(body)) !== null) nums.add(parseInt(m[1], 10));
1720
1908
  return { closesIssues: [...nums], linkageSource: nums.size ? "body-keyword" : "none" };
1721
1909
  }
1722
- async function fetchPRScoringFacts(prUrl, token, signal) {
1910
+ function makeScoringGovernor(governor) {
1911
+ return governor ?? makeGitHubGovernor(
1912
+ ((url, init) => fetch(url, init)),
1913
+ makeDefaultGovernorConfig({ paceEnabled: false })
1914
+ );
1915
+ }
1916
+ async function fetchPRScoringFacts(prUrl, token, signal, governor) {
1723
1917
  const ref = parseGitHubRef(prUrl);
1724
1918
  if (!ref || ref.kind !== "pull") return null;
1725
1919
  const { owner, repo, number: number3 } = ref;
1726
1920
  const sig = signal ?? AbortSignal.timeout(1e4);
1921
+ const gov = makeScoringGovernor(governor);
1922
+ if (gov.tripped() || gov.budgetExhausted()) return null;
1727
1923
  let pr;
1728
1924
  try {
1729
1925
  pr = await ghFetch(`/repos/${owner}/${repo}/pulls/${number3}`, token, sig);
@@ -1731,22 +1927,26 @@ async function fetchPRScoringFacts(prUrl, token, signal) {
1731
1927
  return null;
1732
1928
  }
1733
1929
  let repoMeta = null;
1734
- try {
1735
- repoMeta = await ghFetch(`/repos/${owner}/${repo}`, token, sig);
1736
- } catch {
1930
+ if (!gov.tripped() && !gov.budgetExhausted()) {
1931
+ try {
1932
+ repoMeta = await ghFetch(`/repos/${owner}/${repo}`, token, sig);
1933
+ } catch {
1934
+ }
1737
1935
  }
1738
- const contributors = await repoContributorCount(owner, repo, token, sig);
1739
- const { closesIssues, linkageSource } = await resolveClosingIssues(owner, repo, number3, pr.body ?? "", token, sig);
1936
+ const contributors = gov.tripped() || gov.budgetExhausted() ? null : await repoContributorCount(owner, repo, token, sig);
1937
+ const { closesIssues, linkageSource } = await resolveClosingIssues(owner, repo, number3, pr.body ?? "", token, sig, gov);
1740
1938
  let reviewerAssociations;
1741
- try {
1742
- const reviews = await ghFetch(
1743
- `/repos/${owner}/${repo}/pulls/${number3}/reviews?per_page=100`,
1744
- token,
1745
- sig
1746
- );
1747
- reviewerAssociations = reviews.map((r) => r.author_association);
1748
- } catch {
1749
- reviewerAssociations = void 0;
1939
+ if (!gov.tripped() && !gov.budgetExhausted()) {
1940
+ try {
1941
+ const reviews = await ghFetch(
1942
+ `/repos/${owner}/${repo}/pulls/${number3}/reviews?per_page=100`,
1943
+ token,
1944
+ sig
1945
+ );
1946
+ reviewerAssociations = reviews.map((r) => r.author_association);
1947
+ } catch {
1948
+ reviewerAssociations = void 0;
1949
+ }
1750
1950
  }
1751
1951
  return {
1752
1952
  repo: `${owner}/${repo}`,
@@ -1773,7 +1973,7 @@ async function fetchPRScoringFacts(prUrl, token, signal) {
1773
1973
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
1774
1974
  };
1775
1975
  }
1776
- 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;
1976
+ 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;
1777
1977
  var init_github = __esm({
1778
1978
  "../../packages/core/src/github.ts"() {
1779
1979
  "use strict";
@@ -1781,6 +1981,7 @@ var init_github = __esm({
1781
1981
  init_contribution_gate();
1782
1982
  init_contribution_gate();
1783
1983
  init_rigor();
1984
+ init_gh_governor();
1784
1985
  TRACTION_TOP_N = 6;
1785
1986
  MAINTAINER_ENRICH_MAX = 25;
1786
1987
  CANDIDATE_PR_PAGE = 50;
@@ -1791,6 +1992,7 @@ var init_github = __esm({
1791
1992
  RESUME_MIN_SCORE = 0.05;
1792
1993
  RECEPTIVITY_RECENCY_DAYS = 180;
1793
1994
  RECEPTIVITY_RECENCY_FLOOR = 0.1;
1995
+ GITHUB_GRAPHQL_URL = "https://api.github.com/graphql";
1794
1996
  }
1795
1997
  });
1796
1998
 
@@ -1871,34 +2073,45 @@ function mergeSoftCoverage(covMap, softTags, cap) {
1871
2073
  }
1872
2074
  return covMap;
1873
2075
  }
2076
+ function tagKernel(job, ctx) {
2077
+ const { expanded, covMap, maxDevScore, skillTags } = ctx;
2078
+ const details = [];
2079
+ let jobMatchScore = 0;
2080
+ let jobMaxScore = 0;
2081
+ const devCovByTag = /* @__PURE__ */ new Map();
2082
+ for (const tag of job.tags) {
2083
+ const w = backgroundIdf(tag);
2084
+ jobMaxScore += w;
2085
+ const covHit = covMap.get(tag);
2086
+ if (covHit) jobMatchScore += w * Math.pow(covHit.weight, SHARPEN);
2087
+ const fpHit = expanded.get(tag);
2088
+ if (fpHit) {
2089
+ const credit = Math.pow(fpHit.weight, SHARPEN);
2090
+ details.push({ tag, weight: fpHit.weight, via: fpHit.via });
2091
+ if (credit > (devCovByTag.get(fpHit.via) ?? 0)) devCovByTag.set(fpHit.via, credit);
2092
+ }
2093
+ }
2094
+ let devScore = 0;
2095
+ for (const t of skillTags) devScore += backgroundIdf(t) * (devCovByTag.get(t) ?? 0);
2096
+ const devCov = maxDevScore > 0 ? Math.min(1, devScore / maxDevScore) : 0;
2097
+ const jobCov = jobMaxScore > 0 ? Math.min(1, jobMatchScore / jobMaxScore) : 0;
2098
+ return { tagComponent: harmonicMean(devCov, jobCov), details };
2099
+ }
2100
+ function relevanceScore(fp, job, softTags = []) {
2101
+ const expanded = expandWeighted(fp.skillTags);
2102
+ const covMap = softTags.length > 0 ? mergeSoftCoverage(new Map(expanded), softTags, INTEREST_CAP) : expanded;
2103
+ const maxDevScore = fp.skillTags.reduce((acc, t) => acc + backgroundIdf(t), 0);
2104
+ return tagKernel(job, { expanded, covMap, maxDevScore, skillTags: fp.skillTags }).tagComponent;
2105
+ }
1874
2106
  function match(fp, jobs, limit = 5, now = Date.now(), opts = {}) {
1875
2107
  const idfOf = backgroundIdf;
1876
2108
  const expanded = expandWeighted(fp.skillTags);
1877
2109
  const covMap = opts.softTags && opts.softTags.length > 0 ? mergeSoftCoverage(new Map(expanded), opts.softTags, INTEREST_CAP) : expanded;
1878
2110
  const maxDevScore = fp.skillTags.reduce((acc, t) => acc + idfOf(t), 0);
2111
+ const ctx = { expanded, covMap, maxDevScore, skillTags: fp.skillTags };
1879
2112
  const candidates = jobs.filter((j) => passesFilters(fp, j));
1880
2113
  const scored = candidates.map((job) => {
1881
- const details = [];
1882
- let jobMatchScore = 0;
1883
- let jobMaxScore = 0;
1884
- const devCovByTag = /* @__PURE__ */ new Map();
1885
- for (const tag of job.tags) {
1886
- const w = idfOf(tag);
1887
- jobMaxScore += w;
1888
- const covHit = covMap.get(tag);
1889
- if (covHit) jobMatchScore += w * Math.pow(covHit.weight, SHARPEN);
1890
- const fpHit = expanded.get(tag);
1891
- if (fpHit) {
1892
- const credit = Math.pow(fpHit.weight, SHARPEN);
1893
- details.push({ tag, weight: fpHit.weight, via: fpHit.via });
1894
- if (credit > (devCovByTag.get(fpHit.via) ?? 0)) devCovByTag.set(fpHit.via, credit);
1895
- }
1896
- }
1897
- let devScore = 0;
1898
- for (const t of fp.skillTags) devScore += idfOf(t) * (devCovByTag.get(t) ?? 0);
1899
- const devCov = maxDevScore > 0 ? Math.min(1, devScore / maxDevScore) : 0;
1900
- const jobCov = jobMaxScore > 0 ? Math.min(1, jobMatchScore / jobMaxScore) : 0;
1901
- const tagComponent = harmonicMean(devCov, jobCov);
2114
+ const { tagComponent, details } = tagKernel(job, ctx);
1902
2115
  if (tagComponent === 0) return null;
1903
2116
  const coreTags = job.coreTags ?? coreTagsFromTitle(job.title);
1904
2117
  let coreComponent = tagComponent;
@@ -3433,6 +3646,7 @@ function hasContentSignal(title, body, labels) {
3433
3646
  ${body}`;
3434
3647
  if (CONTENT_ADD_RE.test(text)) return true;
3435
3648
  if (ADD_TO_CORPUS_RE.test(text)) return true;
3649
+ if (NUMBERED_SEED_RE.test(title)) return true;
3436
3650
  if (TRANSLATE_RE.test(text)) return true;
3437
3651
  if (TYPO_RE.test(text)) return true;
3438
3652
  return false;
@@ -3448,7 +3662,7 @@ function classifyContributionKind(input) {
3448
3662
  function looksLikeContentTask(input) {
3449
3663
  return classifyContributionKind(input) === "content";
3450
3664
  }
3451
- 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;
3665
+ 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;
3452
3666
  var init_contribution_classify = __esm({
3453
3667
  "../../packages/core/src/feeds/contribution-classify.ts"() {
3454
3668
  "use strict";
@@ -3458,7 +3672,16 @@ var init_contribution_classify = __esm({
3458
3672
  CODE_EXCEPTION_RE = /exception|stacktrace|segfault|traceback/i;
3459
3673
  CODE_FENCE_RE = /```|(?:^|\n)\s{4,}\S/;
3460
3674
  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;
3461
- CONTENT_ADD_RE = /\badd(?:ing|s)?\s+(?:\w+\s+){0,4}?(?:proverbs?|words?|phrases?|sayings?|quotes?|quotations?|translations?|entry|entries|definitions?|terms?|idioms?|synonyms?|antonyms?|acronyms?|abbreviations?)\b/i;
3675
+ CONTENT_NOUN_STRONG = String.raw`proverbs?|words?|phrases?|sayings?|quotes?|quotations?|translations?|entry|entries|definitions?|terms?|idioms?|synonyms?|antonyms?|acronyms?|abbreviations?`;
3676
+ CONTENT_NOUN_BROAD = String.raw`trivia\s+questions?|grammar\s+points?|trivia|facts?|quiz(?:zes)?|flash\s?cards?|vocab(?:ulary)?|lessons?|kanji`;
3677
+ CONTENT_ADD_RE = new RegExp(
3678
+ String.raw`\badd(?:ing|s)?\s+(?:\w+\s+){0,4}?(?:${CONTENT_NOUN_STRONG})\b`,
3679
+ "i"
3680
+ );
3681
+ NUMBERED_SEED_RE = new RegExp(
3682
+ String.raw`\badd(?:ing|s)?\s+(?:\w+\s+){0,4}?(?:${CONTENT_NOUN_STRONG}|${CONTENT_NOUN_BROAD})\s*#?\s*\d{1,3}\s*$`,
3683
+ "i"
3684
+ );
3462
3685
  ADD_TO_CORPUS_RE = /\badd\b[\s\S]*?\bto\s+(?:the\s+)?(?:word\s?list|dictionary|glossary|phrasebook)\b/i;
3463
3686
  TRANSLATE_RE = /\b(?:translate|translating|translation|localize|localise|localization|localisation)\b/i;
3464
3687
  TYPO_RE = /\bfix(?:ing)?\s+(?:a\s+|the\s+|some\s+)?typos?\b/i;
@@ -3466,20 +3689,6 @@ var init_contribution_classify = __esm({
3466
3689
  });
3467
3690
 
3468
3691
  // ../../packages/core/src/feeds/contributions.ts
3469
- function readReqGapMs() {
3470
- const raw = process.env["CONTRIB_REQ_GAP_MS"];
3471
- if (raw == null) return DEFAULT_REQ_GAP_MS;
3472
- const n = Number.parseInt(raw, 10);
3473
- if (Number.isNaN(n)) return DEFAULT_REQ_GAP_MS;
3474
- return Math.min(Math.max(n, 0), 1e3);
3475
- }
3476
- function readBuildBudgetMs() {
3477
- const raw = process.env["CONTRIB_BUILD_BUDGET_MS"];
3478
- if (raw == null) return DEFAULT_BUILD_BUDGET_MS;
3479
- const n = Number.parseInt(raw, 10);
3480
- if (Number.isNaN(n)) return DEFAULT_BUILD_BUDGET_MS;
3481
- return Math.min(Math.max(n, MIN_BUILD_BUDGET_MS), MAX_BUILD_BUDGET_MS);
3482
- }
3483
3692
  function authHeaders2() {
3484
3693
  const token = process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"];
3485
3694
  const h = {
@@ -3501,57 +3710,9 @@ function repoFullNameFromApiUrl2(url) {
3501
3710
  return m ? `${m[1]}/${m[2]}` : null;
3502
3711
  }
3503
3712
  function makeClient(fetchImpl, cfg) {
3504
- const startedAt = cfg.now();
3505
- let lastRequestAt = 0;
3506
- let pacedMs = 0;
3507
- let secondaryHits = 0;
3508
- let aborted2 = false;
3509
- let secondaryAborted = false;
3510
- let budgetAborted = false;
3511
- let coreHealthyAtStart = false;
3512
- async function noteAndMaybeBackOff(res) {
3513
- if (res.status !== 403) return;
3514
- const remaining = res.headers.get("x-ratelimit-remaining");
3515
- const retryAfter = res.headers.get("retry-after");
3516
- const positiveSecondary = retryAfter != null || remaining != null && remaining !== "0";
3517
- const isSecondary = positiveSecondary || coreHealthyAtStart;
3518
- if (!isSecondary) return;
3519
- secondaryHits++;
3520
- if (secondaryHits >= 2) {
3521
- aborted2 = true;
3522
- secondaryAborted = true;
3523
- return;
3524
- }
3525
- if (cfg.paceEnabled) {
3526
- const trimmed = (retryAfter ?? "").trim();
3527
- const parsed = trimmed.length === 0 ? Number.NaN : Number(trimmed);
3528
- const sec = Number.isNaN(parsed) ? SECONDARY_BACKOFF_CAP_S : Math.min(Math.max(parsed, 0), SECONDARY_BACKOFF_CAP_S);
3529
- const remaining2 = Math.max(0, cfg.budgetMs - (cfg.now() - startedAt));
3530
- await cfg.sleep(Math.min(sec * 1e3, remaining2));
3531
- }
3532
- }
3713
+ const gov = makeGitHubGovernor(fetchImpl, cfg);
3533
3714
  async function raw(path) {
3534
- if (aborted2) return null;
3535
- if (cfg.now() - startedAt > cfg.budgetMs) {
3536
- aborted2 = true;
3537
- budgetAborted = true;
3538
- return null;
3539
- }
3540
- if (cfg.paceEnabled && cfg.gapMs > 0) {
3541
- const wait = cfg.gapMs - (cfg.now() - lastRequestAt);
3542
- if (wait > 0) {
3543
- await cfg.sleep(wait);
3544
- pacedMs += wait;
3545
- }
3546
- lastRequestAt = cfg.now();
3547
- }
3548
- try {
3549
- const res = await fetchImpl(`${GITHUB_API2}${path}`, { headers: authHeaders2() });
3550
- await noteAndMaybeBackOff(res);
3551
- return res;
3552
- } catch {
3553
- return null;
3554
- }
3715
+ return gov.get(`${GITHUB_API2}${path}`, { headers: authHeaders2() });
3555
3716
  }
3556
3717
  async function json(path) {
3557
3718
  const res = await raw(path);
@@ -3565,41 +3726,9 @@ function makeClient(fetchImpl, cfg) {
3565
3726
  }
3566
3727
  }
3567
3728
  async function probe(path) {
3568
- const bound = cfg.probeTimeoutMs;
3569
- let timer;
3570
- const fetchP = fetchImpl(`${GITHUB_API2}${path}`, {
3571
- headers: authHeaders2()
3572
- }).then(
3573
- (r) => r,
3574
- () => null
3575
- );
3576
- try {
3577
- const res = bound == null ? await fetchP : await Promise.race([
3578
- fetchP,
3579
- new Promise((resolve2) => {
3580
- timer = setTimeout(() => resolve2(null), bound);
3581
- })
3582
- ]);
3583
- if (!res || !res.ok) return null;
3584
- return await res.json();
3585
- } catch {
3586
- return null;
3587
- } finally {
3588
- if (timer) clearTimeout(timer);
3589
- }
3590
- }
3591
- function setSecondaryHint(coreHealthy) {
3592
- coreHealthyAtStart = coreHealthy;
3593
- }
3594
- function getStats() {
3595
- return {
3596
- pacedMs,
3597
- secondaryAborted: secondaryAborted ? 1 : 0,
3598
- budgetAborted: budgetAborted ? 1 : 0,
3599
- elapsedMs: cfg.now() - startedAt
3600
- };
3729
+ return gov.probe(`${GITHUB_API2}${path}`, { headers: authHeaders2() });
3601
3730
  }
3602
- return { raw, json, probe, setSecondaryHint, getStats };
3731
+ return { raw, json, probe, setSecondaryHint: gov.setSecondaryHint, getStats: gov.getStats };
3603
3732
  }
3604
3733
  async function contributorCount(client, fullName) {
3605
3734
  const res = await client.raw(`/repos/${fullName}/contributors?per_page=1&anon=false`);
@@ -3698,10 +3827,63 @@ async function aggregateContributions(opts = {}) {
3698
3827
  const repoCache = /* @__PURE__ */ new Map();
3699
3828
  const contribCache = /* @__PURE__ */ new Map();
3700
3829
  const prRefsCache = /* @__PURE__ */ new Map();
3830
+ const xbuild = opts.repoMetaCache;
3831
+ const servedFromXbuild = /* @__PURE__ */ new Set();
3832
+ const persistedXbuild = /* @__PURE__ */ new Set();
3833
+ const xbuildTried = /* @__PURE__ */ new Set();
3834
+ async function primeFromXbuild(key, fullName) {
3835
+ if (!xbuild || xbuildTried.has(key)) return;
3836
+ xbuildTried.add(key);
3837
+ if (repoCache.has(key) && contribCache.has(key)) return;
3838
+ let cached2 = null;
3839
+ try {
3840
+ cached2 = await xbuild.get(key);
3841
+ } catch {
3842
+ return;
3843
+ }
3844
+ if (!cached2) return;
3845
+ if (!repoCache.has(key)) {
3846
+ const owner = fullName.split("/")[0] ?? "";
3847
+ repoCache.set(key, {
3848
+ full_name: fullName,
3849
+ stargazers_count: cached2.stars,
3850
+ archived: cached2.archived,
3851
+ disabled: cached2.disabled,
3852
+ fork: cached2.fork,
3853
+ language: cached2.language,
3854
+ owner: { login: owner }
3855
+ });
3856
+ }
3857
+ if (!contribCache.has(key)) {
3858
+ contribCache.set(key, cached2.contributors);
3859
+ servedFromXbuild.add(key);
3860
+ }
3861
+ }
3862
+ async function persistRepoMeta(fullName, repo, contributors) {
3863
+ if (!xbuild) return;
3864
+ const key = repoKey(fullName);
3865
+ if (servedFromXbuild.has(key) || persistedXbuild.has(key)) return;
3866
+ if (contributors === void 0) return;
3867
+ persistedXbuild.add(key);
3868
+ try {
3869
+ await xbuild.set(key, {
3870
+ stars: repo.stargazers_count,
3871
+ contributors,
3872
+ language: repo.language,
3873
+ archived: repo.archived,
3874
+ fork: repo.fork,
3875
+ disabled: repo.disabled
3876
+ });
3877
+ } catch {
3878
+ }
3879
+ }
3701
3880
  async function repoMeta(fullName) {
3702
3881
  const key = repoKey(fullName);
3703
3882
  const hit = repoCache.get(key);
3704
3883
  if (hit !== void 0) return hit;
3884
+ await primeFromXbuild(key, fullName);
3885
+ const primed = repoCache.get(key);
3886
+ if (primed !== void 0) return primed;
3705
3887
  const r = await client.json(`/repos/${fullName}`) ?? null;
3706
3888
  repoCache.set(key, r);
3707
3889
  return r;
@@ -3709,6 +3891,8 @@ async function aggregateContributions(opts = {}) {
3709
3891
  async function repoContribCount(fullName) {
3710
3892
  const key = repoKey(fullName);
3711
3893
  if (contribCache.has(key)) return contribCache.get(key);
3894
+ await primeFromXbuild(key, fullName);
3895
+ if (contribCache.has(key)) return contribCache.get(key);
3712
3896
  const n = await contributorCount(client, fullName);
3713
3897
  contribCache.set(key, n);
3714
3898
  return n;
@@ -3735,14 +3919,18 @@ async function aggregateContributions(opts = {}) {
3735
3919
  if (isDenylistedRepo(fullName)) continue;
3736
3920
  if (isAssigned(issue2)) continue;
3737
3921
  if ((perRepo.get(repoKey(fullName)) ?? 0) >= MAX_BOUNTIES_PER_DISCOVERED_REPO) continue;
3922
+ const title = decodeEntities(issue2.title).trim();
3923
+ const body = issue2.body ? decodeEntities(issue2.body) : "";
3924
+ const labels = labelNames2(issue2.labels);
3925
+ if (looksLikeContentTask({ title, body, labels })) continue;
3738
3926
  const repo = await repoMeta(fullName);
3739
3927
  if (!repo) {
3740
3928
  metaNull++;
3741
3929
  continue;
3742
3930
  }
3743
- const title = decodeEntities(issue2.title).trim();
3744
3931
  const contributors = await repoContribCount(fullName);
3745
3932
  if (contributors === void 0) contribUndefined++;
3933
+ await persistRepoMeta(fullName, repo, contributors);
3746
3934
  if (!passesContributionGate({
3747
3935
  fullName,
3748
3936
  stars: repo.stargazers_count,
@@ -3754,13 +3942,9 @@ async function aggregateContributions(opts = {}) {
3754
3942
  continue;
3755
3943
  }
3756
3944
  if (repo.disabled) continue;
3757
- const body = issue2.body ? decodeEntities(issue2.body) : "";
3758
- const labels = labelNames2(issue2.labels);
3759
- if (looksLikeContentTask({ title, body, labels })) continue;
3760
3945
  const prRefs = await repoPRRefs(fullName);
3761
3946
  if (prRefs === null) prRefsNull++;
3762
- if (prRefs && prRefs.has(issue2.number)) continue;
3763
- const openPRsAtDiscovery = prRefs ? 0 : void 0;
3947
+ const openPRsAtDiscovery = prRefs ? prRefs.has(issue2.number) ? 1 : 0 : void 0;
3764
3948
  const tags = normalize(
3765
3949
  tokenize4([title, repo.language ?? "", labels.join(" "), body.slice(0, 2e3)].join(" "))
3766
3950
  );
@@ -3851,6 +4035,7 @@ async function aggregateContributions(opts = {}) {
3851
4035
  if (repo.disabled) continue;
3852
4036
  const contributors = await repoContribCount(fullName);
3853
4037
  if (contributors === void 0) contribUndefined++;
4038
+ await persistRepoMeta(fullName, repo, contributors);
3854
4039
  if (repo.archived || repo.fork || repo.stargazers_count < MIN_STARS || contributors === void 0 || contributors < MIN_CONTRIBUTORS) {
3855
4040
  continue;
3856
4041
  }
@@ -3883,8 +4068,7 @@ async function aggregateContributions(opts = {}) {
3883
4068
  if (looksLikeContentTask({ title, body, labels })) continue;
3884
4069
  const prRefs = await repoPRRefs(fullName);
3885
4070
  if (prRefs === null) prRefsNull++;
3886
- if (prRefs && prRefs.has(issue2.number)) continue;
3887
- const openPRsAtDiscovery = prRefs ? 0 : void 0;
4071
+ const openPRsAtDiscovery = prRefs ? prRefs.has(issue2.number) ? 1 : 0 : void 0;
3888
4072
  const tags = normalize(
3889
4073
  tokenize4([title, repo.language ?? "", labels.join(" "), body.slice(0, 2e3)].join(" "))
3890
4074
  );
@@ -3915,9 +4099,9 @@ async function aggregateContributions(opts = {}) {
3915
4099
  const core = rl?.core ? `${rl.core.remaining}/${rl.core.limit}` : "n/a";
3916
4100
  const search = rl?.search ? `${rl.search.remaining}/${rl.search.limit}` : "n/a";
3917
4101
  const noToken = !(process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"]);
3918
- const { pacedMs, secondaryAborted, budgetAborted, elapsedMs } = client.getStats();
4102
+ const { pacedMs, secondaryAborted, budgetAborted, elapsedMs, gqlCost, gqlRemaining } = client.getStats();
3919
4103
  console.info(
3920
- `[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)" : "")
4104
+ `[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)" : "")
3921
4105
  );
3922
4106
  if (discoveryBudgetStopped) {
3923
4107
  console.warn(
@@ -3927,7 +4111,7 @@ async function aggregateContributions(opts = {}) {
3927
4111
  }
3928
4112
  return jobs;
3929
4113
  }
3930
- var GITHUB_API2, DEFAULT_REQ_GAP_MS, SECONDARY_BACKOFF_CAP_S, DEFAULT_BUILD_BUDGET_MS, MIN_BUILD_BUDGET_MS, MAX_BUILD_BUDGET_MS, PROBE_TIMEOUT_MS, realSleep, 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;
4114
+ 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;
3931
4115
  var init_contributions = __esm({
3932
4116
  "../../packages/core/src/feeds/contributions.ts"() {
3933
4117
  "use strict";
@@ -3938,14 +4122,8 @@ var init_contributions = __esm({
3938
4122
  init_contribution_classify();
3939
4123
  init_github_bounties();
3940
4124
  init_http();
4125
+ init_gh_governor();
3941
4126
  GITHUB_API2 = "https://api.github.com";
3942
- DEFAULT_REQ_GAP_MS = 75;
3943
- SECONDARY_BACKOFF_CAP_S = 30;
3944
- DEFAULT_BUILD_BUDGET_MS = 9e4;
3945
- MIN_BUILD_BUDGET_MS = 1e4;
3946
- MAX_BUILD_BUDGET_MS = 9e4;
3947
- PROBE_TIMEOUT_MS = 3e3;
3948
- realSleep = (ms) => new Promise((r) => setTimeout(r, ms));
3949
4127
  CONTRIB_LABEL_QUERIES = [
3950
4128
  'label:"good first issue" type:issue state:open',
3951
4129
  'label:"good-first-issue" type:issue state:open',
@@ -4163,12 +4341,22 @@ async function enrichWinnability(jobs, contribute, w) {
4163
4341
  const repos = [...byRepo.keys()].sort((a, b) => starsOf(b) - starsOf(a));
4164
4342
  const scored = repos.slice(0, maxRepos);
4165
4343
  const cappedOut = repos.length - scored.length;
4344
+ const gov = w.governor ?? makeGitHubGovernor(
4345
+ w.fetchImpl ?? fetch,
4346
+ makeDefaultGovernorConfig({ paceEnabled: !w.fetchImpl })
4347
+ );
4348
+ let stoppedEarly = false;
4166
4349
  for (const repo of scored) {
4350
+ if (gov.tripped() || gov.budgetExhausted()) {
4351
+ stoppedEarly = true;
4352
+ break;
4353
+ }
4167
4354
  const targets = byRepo.get(repo) ?? [];
4168
4355
  const receptivity = await fetchRepoReceptivity(repo, {
4169
4356
  token: w.token,
4170
4357
  fetchImpl: w.fetchImpl,
4171
- now
4358
+ now,
4359
+ governor: gov
4172
4360
  });
4173
4361
  const stars = starsOf(repo);
4174
4362
  const prev = priorStars[repo];
@@ -4197,6 +4385,12 @@ async function enrichWinnability(jobs, contribute, w) {
4197
4385
  }
4198
4386
  }
4199
4387
  }
4388
+ if (stoppedEarly) {
4389
+ const reason = gov.tripped() ? "secondary-abuse breaker" : "wall-clock budget";
4390
+ console.warn(
4391
+ `[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.`
4392
+ );
4393
+ }
4200
4394
  if (cappedOut > 0) {
4201
4395
  console.warn(
4202
4396
  `[winnability] receptivity cap hit \u2014 scored ${scored.length}/${repos.length} repos (${cappedOut} beyond maxRepos=${maxRepos} left un-scored, legacy ranking)`
@@ -4239,6 +4433,7 @@ var init_indexer = __esm({
4239
4433
  init_contributions();
4240
4434
  init_partners();
4241
4435
  init_github();
4436
+ init_gh_governor();
4242
4437
  init_winnability();
4243
4438
  }
4244
4439
  });
@@ -8126,6 +8321,7 @@ __export(src_exports, {
8126
8321
  MERGE_PROBABILITY: () => MERGE_PROBABILITY,
8127
8322
  MIN_CONTRIBUTORS: () => MIN_CONTRIBUTORS,
8128
8323
  MIN_STARS: () => MIN_STARS,
8324
+ PROBE_TIMEOUT_MS: () => PROBE_TIMEOUT_MS,
8129
8325
  RIGOR: () => RIGOR,
8130
8326
  STRONG_MATCH_THRESHOLD: () => STRONG_MATCH_THRESHOLD,
8131
8327
  SYNONYMS: () => SYNONYMS,
@@ -8197,6 +8393,9 @@ __export(src_exports, {
8197
8393
  lever: () => lever,
8198
8394
  loadPartnerRoles: () => loadPartnerRoles,
8199
8395
  looksLikeEngRole: () => looksLikeEngRole,
8396
+ makeDefaultGovernorConfig: () => makeDefaultGovernorConfig,
8397
+ makeGitHubGovernor: () => makeGitHubGovernor,
8398
+ makeScoringGovernor: () => makeScoringGovernor,
8200
8399
  match: () => match,
8201
8400
  mergeProbability: () => mergeProbability,
8202
8401
  mmrRerank: () => mmrRerank,
@@ -8209,8 +8408,12 @@ __export(src_exports, {
8209
8408
  passesMaturityGate: () => passesMaturityGate,
8210
8409
  personCardToJob: () => personCardToJob,
8211
8410
  projectCardToJob: () => projectCardToJob,
8411
+ readBuildBudgetMs: () => readBuildBudgetMs,
8412
+ readReqGapMs: () => readReqGapMs,
8413
+ realSleep: () => realSleep,
8212
8414
  recordClick: () => recordClick,
8213
8415
  rejectExtraIntroFields: () => rejectExtraIntroFields,
8416
+ relevanceScore: () => relevanceScore,
8214
8417
  revealIntroContacts: () => revealIntroContacts,
8215
8418
  safetyNumber: () => safetyNumber,
8216
8419
  sameLogin: () => sameLogin,
@@ -8237,6 +8440,7 @@ var init_src = __esm({
8237
8440
  init_winnability();
8238
8441
  init_partners();
8239
8442
  init_github();
8443
+ init_gh_governor();
8240
8444
  init_credit();
8241
8445
  init_intro();
8242
8446
  init_directoryThreshold();
@@ -8412,9 +8616,9 @@ var init_keytar = __esm({
8412
8616
  }
8413
8617
  });
8414
8618
 
8415
- // node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/agent-a4d8b1364e2f66adc/node_modules/keytar/build/Release/keytar.node
8619
+ // node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node
8416
8620
  var require_keytar = __commonJS({
8417
- "node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/agent-a4d8b1364e2f66adc/node_modules/keytar/build/Release/keytar.node"(exports, module) {
8621
+ "node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node"(exports, module) {
8418
8622
  "use strict";
8419
8623
  init_keytar();
8420
8624
  try {
@@ -10341,7 +10545,13 @@ function defaultPrompt(question) {
10341
10545
  }
10342
10546
  function rankContributions(fp, items) {
10343
10547
  if (!fp || !Array.isArray(items) || items.length === 0) return [];
10344
- return match(fp, items, items.length);
10548
+ const ranked = match(fp, items, items.length);
10549
+ const rel = new Map(ranked.map((r) => [r, relevanceScore(fp, r.job)]));
10550
+ ranked.sort((a, b) => (rel.get(b) ?? 0) - (rel.get(a) ?? 0));
10551
+ return ranked.filter((r) => {
10552
+ const contested = (r.job.contribution?.openPRsAtDiscovery ?? 0) > 0;
10553
+ return !contested || (rel.get(r) ?? 0) >= STRONG_THRESHOLD;
10554
+ });
10345
10555
  }
10346
10556
  async function rankLocally(items, injectedFp) {
10347
10557
  if (!Array.isArray(items) || items.length === 0) return [];
@@ -10412,7 +10622,7 @@ async function run6(opts = {}) {
10412
10622
  process.exit(1);
10413
10623
  }
10414
10624
  }
10415
- var TERMINALHIRE_DIR10, INDEX_CACHE_FILE4, INDEX_TTL_MS4, API_URL5, HEADER, OPT_IN_PROMPT, EMPTY_STATE, LANGUAGES;
10625
+ var TERMINALHIRE_DIR10, INDEX_CACHE_FILE4, INDEX_TTL_MS4, API_URL5, HEADER, OPT_IN_PROMPT, EMPTY_STATE, STRONG_THRESHOLD, LANGUAGES;
10416
10626
  var init_jpi_contribute = __esm({
10417
10627
  "bin/jpi-contribute.js"() {
10418
10628
  "use strict";
@@ -10427,6 +10637,10 @@ var init_jpi_contribute = __esm({
10427
10637
  HEADER = "Contribution opportunities \u2014 open issues where a merged PR actually counts toward your r\xE9sum\xE9.\nRepos \u226550\u2605 / \u226510 contributors \xB7 unassigned \xB7 merit-merge \xB7 matched locally to your stack.";
10428
10638
  OPT_IN_PROMPT = "Contribute is off. Turn it on to see open issues where a merged PR would count toward your r\xE9sum\xE9 \u2014\nmatched to your stack. Matching runs locally; your profile never leaves this machine. Enable? [y/N]";
10429
10639
  EMPTY_STATE = "Nothing clears the bar right now. We only list issues where a merged PR actually counts toward\nyour r\xE9sum\xE9 \u2014 so the list stays honest. Try again after the next refresh.";
10640
+ STRONG_THRESHOLD = 0.5;
10641
+ if (STRONG_THRESHOLD <= 0) {
10642
+ throw new Error("STRONG_THRESHOLD must be > 0 or the contested-issue fail-safe breaks");
10643
+ }
10430
10644
  LANGUAGES = /* @__PURE__ */ new Set([
10431
10645
  "typescript",
10432
10646
  "javascript",
@@ -10830,6 +11044,8 @@ __export(jpi_claim_exports, {
10830
11044
  fmtAge: () => fmtAge,
10831
11045
  fmtContestedWarning: () => fmtContestedWarning,
10832
11046
  isContested: () => isContested,
11047
+ isStrayArgShortRefClaim: () => isStrayArgShortRefClaim,
11048
+ isVerblessShortRefClaim: () => isVerblessShortRefClaim,
10833
11049
  listOpenPRsReferencingIssue: () => listOpenPRsReferencingIssue,
10834
11050
  matchReferencingPrs: () => matchReferencingPrs,
10835
11051
  pickBodySource: () => pickBodySource,
@@ -10980,6 +11196,12 @@ function findClaimableInCache(id) {
10980
11196
  function looksLikeShortRef(arg) {
10981
11197
  return typeof arg === "string" && /^[A-Za-z0-9_-]{8}$/.test(arg);
10982
11198
  }
11199
+ function isVerblessShortRefClaim(verb, positional) {
11200
+ return looksLikeShortRef(verb) && positional.length === 0;
11201
+ }
11202
+ function isStrayArgShortRefClaim(verb, positional) {
11203
+ return looksLikeShortRef(verb) && positional.length > 0;
11204
+ }
10983
11205
  function findClaimableByShortRef(ref) {
10984
11206
  try {
10985
11207
  return findByShortRefInPool(readClaimablePool(), ref);
@@ -11019,9 +11241,12 @@ function extractClaimableFields(job) {
11019
11241
  issueUrl: c.issueUrl ?? job.url ?? "",
11020
11242
  amountUSD: null,
11021
11243
  source: "contribute",
11022
- // Fix 2: the aggregator proved 0 open PRs at discovery (it only admits an
11023
- // uncontested issue). Carry it through so resolveBounty can prefer it over
11024
- // a live re-count that degrades to null under a rate limit / >100-PR page.
11244
+ // Fix 2: the aggregator persists a discovery-time open-PR presence flag
11245
+ // (0 = verified-uncontested, 1 = contested kept and flagged, not dropped,
11246
+ // undefined = the PR check couldn't run). Carry it through so resolveBounty
11247
+ // can prefer it over a live re-count that degrades to null under a rate limit
11248
+ // / >100-PR page. Display/fallback ONLY — the contention gate still forces a
11249
+ // LIVE recount (see resolveBounty); the snapshot never decides contention.
11025
11250
  openPRsAtDiscovery: c.openPRsAtDiscovery
11026
11251
  };
11027
11252
  }
@@ -12131,6 +12356,16 @@ async function run7() {
12131
12356
  else await cmdPush({ keepUpdated: Boolean(flags["keep-updated"]) });
12132
12357
  return;
12133
12358
  }
12359
+ if (isVerblessShortRefClaim(verb, positional)) {
12360
+ await cmdRecord(verb, flags);
12361
+ return;
12362
+ }
12363
+ if (isStrayArgShortRefClaim(verb, positional)) {
12364
+ console.error(
12365
+ `terminalhire claim: '${verb}' is a short ref and takes no extra arguments (got: ${positional.join(" ")}). Did you mean \`terminalhire claim ${verb}\`?`
12366
+ );
12367
+ process.exit(1);
12368
+ }
12134
12369
  try {
12135
12370
  switch (verb) {
12136
12371
  case "preview":