terminalhire 0.28.0 → 0.30.0
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 +41 -0
- package/dist/bin/jpi-bounties.js +161 -1
- package/dist/bin/jpi-claim.js +453 -6
- package/dist/bin/jpi-devs.js +161 -1
- package/dist/bin/jpi-dispatch.js +475 -7
- package/dist/bin/jpi-hub.js +161 -1
- package/dist/bin/jpi-init.js +161 -1
- package/dist/bin/jpi-jobs.js +161 -1
- package/dist/bin/jpi-login.js +161 -1
- package/dist/bin/jpi-project.js +161 -1
- package/dist/bin/jpi-refresh.js +388 -169
- package/dist/bin/jpi-spinner.js +7 -0
- package/dist/bin/spinner.js +9 -0
- package/dist/src/reputation/audit.js +84 -0
- package/dist/src/reputation/fetch.js +1042 -0
- package/dist/src/reputation/identity.js +19 -0
- package/package.json +1 -1
|
@@ -285,6 +285,7 @@ function decrypt(blob, key) {
|
|
|
285
285
|
var TERMINALHIRE_DIR3 = process.env.TERMINALHIRE_DIR || join3(homedir3(), ".terminalhire");
|
|
286
286
|
var CLAIM_PUSH_AUTO_MARKER = join3(TERMINALHIRE_DIR3, "claim-push-auto.json");
|
|
287
287
|
var CLAIM_PUSH_TOKEN_FILE = join3(TERMINALHIRE_DIR3, "claim-push-token.enc");
|
|
288
|
+
var CLAIM_PUSH_MANUAL_MARKER = join3(TERMINALHIRE_DIR3, "claim-push.json");
|
|
288
289
|
var CLAIM_SYNC_BASE = "https://terminalhire.com";
|
|
289
290
|
var AUTO_CONSENT_VERSION = 2;
|
|
290
291
|
var AUTO_PUSH_THROTTLE_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -352,6 +353,43 @@ function backgroundPushGate(params) {
|
|
|
352
353
|
}
|
|
353
354
|
return { push: true, reason: "ok" };
|
|
354
355
|
}
|
|
356
|
+
function unpushedNudgeGate(params) {
|
|
357
|
+
const {
|
|
358
|
+
autoMarkerExists,
|
|
359
|
+
tokenFileExists,
|
|
360
|
+
manualMarkerExists,
|
|
361
|
+
lastSnapshotHash,
|
|
362
|
+
currentHash,
|
|
363
|
+
claimCount
|
|
364
|
+
} = params;
|
|
365
|
+
if (autoMarkerExists && tokenFileExists) return false;
|
|
366
|
+
if (!manualMarkerExists) return false;
|
|
367
|
+
if (!(claimCount > 0)) return false;
|
|
368
|
+
return lastSnapshotHash !== currentHash;
|
|
369
|
+
}
|
|
370
|
+
async function shouldNudgeUnpushed() {
|
|
371
|
+
try {
|
|
372
|
+
const { listClaims: listClaims2, toPushedClaim: toPushedClaim2 } = await Promise.resolve().then(() => (init_claims(), claims_exports));
|
|
373
|
+
const pushed = listClaims2().map((c) => toPushedClaim2(c));
|
|
374
|
+
const currentHash = computeSnapshotHash(pushed);
|
|
375
|
+
let manual = null;
|
|
376
|
+
try {
|
|
377
|
+
manual = existsSync3(CLAIM_PUSH_MANUAL_MARKER) ? JSON.parse(readFileSync3(CLAIM_PUSH_MANUAL_MARKER, "utf8")) : null;
|
|
378
|
+
} catch {
|
|
379
|
+
manual = null;
|
|
380
|
+
}
|
|
381
|
+
return unpushedNudgeGate({
|
|
382
|
+
autoMarkerExists: existsSync3(CLAIM_PUSH_AUTO_MARKER),
|
|
383
|
+
tokenFileExists: existsSync3(CLAIM_PUSH_TOKEN_FILE),
|
|
384
|
+
manualMarkerExists: !!manual,
|
|
385
|
+
lastSnapshotHash: manual?.lastSnapshotHash ?? null,
|
|
386
|
+
currentHash,
|
|
387
|
+
claimCount: pushed.length
|
|
388
|
+
});
|
|
389
|
+
} catch {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
355
393
|
async function runBackgroundClaimPush({ now = Date.now() } = {}) {
|
|
356
394
|
try {
|
|
357
395
|
if (!existsSync3(CLAIM_PUSH_AUTO_MARKER) || !existsSync3(CLAIM_PUSH_TOKEN_FILE)) return;
|
|
@@ -396,6 +434,7 @@ export {
|
|
|
396
434
|
AUTO_CONSENT_VERSION,
|
|
397
435
|
AUTO_PUSH_THROTTLE_MS,
|
|
398
436
|
CLAIM_PUSH_AUTO_MARKER,
|
|
437
|
+
CLAIM_PUSH_MANUAL_MARKER,
|
|
399
438
|
CLAIM_PUSH_TOKEN_FILE,
|
|
400
439
|
backgroundPushGate,
|
|
401
440
|
clearAutoMarker,
|
|
@@ -404,6 +443,8 @@ export {
|
|
|
404
443
|
readAutoMarker,
|
|
405
444
|
readPushTokenEnc,
|
|
406
445
|
runBackgroundClaimPush,
|
|
446
|
+
shouldNudgeUnpushed,
|
|
447
|
+
unpushedNudgeGate,
|
|
407
448
|
writeAutoMarker,
|
|
408
449
|
writePushTokenEnc
|
|
409
450
|
};
|
package/dist/bin/jpi-bounties.js
CHANGED
|
@@ -1706,7 +1706,152 @@ async function fetchPRScoringFacts(prUrl, token, signal, governor) {
|
|
|
1706
1706
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1707
1707
|
};
|
|
1708
1708
|
}
|
|
1709
|
-
|
|
1709
|
+
function isLifecycleBot(actor) {
|
|
1710
|
+
if (!actor) return false;
|
|
1711
|
+
if (actor.type === "Bot") return true;
|
|
1712
|
+
const login = String(actor.login ?? "");
|
|
1713
|
+
if (/\[bot\]$/i.test(login)) return true;
|
|
1714
|
+
return LIFECYCLE_BOT_LOGINS.has(login.toLowerCase());
|
|
1715
|
+
}
|
|
1716
|
+
async function fetchPRLifecycle(prUrl, token, signal, governor) {
|
|
1717
|
+
const ref = parseGitHubRef(prUrl);
|
|
1718
|
+
if (!ref || ref.kind !== "pull") return null;
|
|
1719
|
+
const { owner, repo, number } = ref;
|
|
1720
|
+
const sig = signal ?? AbortSignal.timeout(1e4);
|
|
1721
|
+
const gov = makeScoringGovernor(governor);
|
|
1722
|
+
if (gov.tripped() || gov.budgetExhausted()) return null;
|
|
1723
|
+
let pr;
|
|
1724
|
+
try {
|
|
1725
|
+
pr = await ghFetch(`/repos/${owner}/${repo}/pulls/${number}`, token, sig);
|
|
1726
|
+
} catch {
|
|
1727
|
+
return null;
|
|
1728
|
+
}
|
|
1729
|
+
const authorId = pr.user?.id ?? null;
|
|
1730
|
+
const events = [];
|
|
1731
|
+
const complete = { reviews: false, comments: false, commits: false };
|
|
1732
|
+
if (pr.created_at) {
|
|
1733
|
+
events.push({
|
|
1734
|
+
event_type: "pr_opened",
|
|
1735
|
+
source_id: `pr-${number}`,
|
|
1736
|
+
actor_id: authorId ?? 0,
|
|
1737
|
+
actor_assoc: "",
|
|
1738
|
+
is_author: true,
|
|
1739
|
+
is_bot: false,
|
|
1740
|
+
occurred_at: pr.created_at
|
|
1741
|
+
});
|
|
1742
|
+
}
|
|
1743
|
+
if (!gov.tripped() && !gov.budgetExhausted()) {
|
|
1744
|
+
try {
|
|
1745
|
+
const reviews = await ghFetch(
|
|
1746
|
+
`/repos/${owner}/${repo}/pulls/${number}/reviews?per_page=100`,
|
|
1747
|
+
token,
|
|
1748
|
+
sig
|
|
1749
|
+
);
|
|
1750
|
+
for (const r of reviews) {
|
|
1751
|
+
if (r.state === "PENDING" || !r.submitted_at) continue;
|
|
1752
|
+
const aid = r.user?.id ?? 0;
|
|
1753
|
+
events.push({
|
|
1754
|
+
event_type: "review_submitted",
|
|
1755
|
+
source_id: `review-${r.id}`,
|
|
1756
|
+
actor_id: aid,
|
|
1757
|
+
actor_assoc: r.author_association ?? "",
|
|
1758
|
+
is_author: authorId != null && aid === authorId,
|
|
1759
|
+
is_bot: isLifecycleBot(r.user),
|
|
1760
|
+
occurred_at: r.submitted_at
|
|
1761
|
+
});
|
|
1762
|
+
}
|
|
1763
|
+
complete.reviews = true;
|
|
1764
|
+
} catch {
|
|
1765
|
+
complete.reviews = false;
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
if (!gov.tripped() && !gov.budgetExhausted()) {
|
|
1769
|
+
try {
|
|
1770
|
+
const comments = await ghFetch(
|
|
1771
|
+
`/repos/${owner}/${repo}/issues/${number}/comments?per_page=100`,
|
|
1772
|
+
token,
|
|
1773
|
+
sig
|
|
1774
|
+
);
|
|
1775
|
+
for (const c of comments) {
|
|
1776
|
+
if (!c.created_at) continue;
|
|
1777
|
+
const aid = c.user?.id ?? 0;
|
|
1778
|
+
events.push({
|
|
1779
|
+
event_type: "issue_comment",
|
|
1780
|
+
source_id: `comment-${c.id}`,
|
|
1781
|
+
actor_id: aid,
|
|
1782
|
+
actor_assoc: c.author_association ?? "",
|
|
1783
|
+
is_author: authorId != null && aid === authorId,
|
|
1784
|
+
is_bot: isLifecycleBot(c.user),
|
|
1785
|
+
occurred_at: c.created_at
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
complete.comments = true;
|
|
1789
|
+
} catch {
|
|
1790
|
+
complete.comments = false;
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
if (!gov.tripped() && !gov.budgetExhausted()) {
|
|
1794
|
+
try {
|
|
1795
|
+
const commits = await ghFetch(
|
|
1796
|
+
`/repos/${owner}/${repo}/pulls/${number}/commits?per_page=100`,
|
|
1797
|
+
token,
|
|
1798
|
+
sig
|
|
1799
|
+
);
|
|
1800
|
+
for (const cm of commits) {
|
|
1801
|
+
const when = cm.commit?.author?.date ?? null;
|
|
1802
|
+
if (!when) continue;
|
|
1803
|
+
const aid = cm.author?.id ?? authorId ?? 0;
|
|
1804
|
+
events.push({
|
|
1805
|
+
event_type: "commit_pushed",
|
|
1806
|
+
source_id: `commit-${cm.sha}`,
|
|
1807
|
+
actor_id: aid,
|
|
1808
|
+
actor_assoc: "",
|
|
1809
|
+
is_author: authorId != null && aid === authorId,
|
|
1810
|
+
is_bot: isLifecycleBot(cm.author),
|
|
1811
|
+
occurred_at: when
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
complete.commits = true;
|
|
1815
|
+
} catch {
|
|
1816
|
+
complete.commits = false;
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
if (pr.merged && pr.merged_at) {
|
|
1820
|
+
events.push({
|
|
1821
|
+
event_type: "pr_merged",
|
|
1822
|
+
source_id: `merged-${number}`,
|
|
1823
|
+
actor_id: pr.merged_by?.id ?? 0,
|
|
1824
|
+
actor_assoc: "",
|
|
1825
|
+
is_author: authorId != null && pr.merged_by?.id === authorId,
|
|
1826
|
+
// A bot merger (mergify[bot], a merge queue, etc.) must NOT count as an
|
|
1827
|
+
// independent human counterparty. Classify it like every other actor (§4b V4).
|
|
1828
|
+
is_bot: isLifecycleBot(pr.merged_by),
|
|
1829
|
+
occurred_at: pr.merged_at
|
|
1830
|
+
});
|
|
1831
|
+
} else if (pr.state === "closed" && pr.closed_at) {
|
|
1832
|
+
events.push({
|
|
1833
|
+
event_type: "pr_closed_unmerged",
|
|
1834
|
+
source_id: `closed-${number}`,
|
|
1835
|
+
actor_id: 0,
|
|
1836
|
+
actor_assoc: "",
|
|
1837
|
+
is_author: false,
|
|
1838
|
+
is_bot: false,
|
|
1839
|
+
occurred_at: pr.closed_at
|
|
1840
|
+
});
|
|
1841
|
+
}
|
|
1842
|
+
return {
|
|
1843
|
+
prNumber: number,
|
|
1844
|
+
prUrl: pr.html_url,
|
|
1845
|
+
openedAt: pr.created_at ?? null,
|
|
1846
|
+
merged: pr.merged === true,
|
|
1847
|
+
mergedAt: pr.merged_at ?? null,
|
|
1848
|
+
closedUnmergedAt: !pr.merged && pr.state === "closed" ? pr.closed_at ?? null : null,
|
|
1849
|
+
authorId,
|
|
1850
|
+
events,
|
|
1851
|
+
complete
|
|
1852
|
+
};
|
|
1853
|
+
}
|
|
1854
|
+
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, LIFECYCLE_BOT_LOGINS;
|
|
1710
1855
|
var init_github = __esm({
|
|
1711
1856
|
"../../packages/core/src/github.ts"() {
|
|
1712
1857
|
"use strict";
|
|
@@ -1726,6 +1871,20 @@ var init_github = __esm({
|
|
|
1726
1871
|
RECEPTIVITY_RECENCY_DAYS = 180;
|
|
1727
1872
|
RECEPTIVITY_RECENCY_FLOOR = 0.1;
|
|
1728
1873
|
GITHUB_GRAPHQL_URL = "https://api.github.com/graphql";
|
|
1874
|
+
LIFECYCLE_BOT_LOGINS = /* @__PURE__ */ new Set([
|
|
1875
|
+
"mergify",
|
|
1876
|
+
"mergify[bot]",
|
|
1877
|
+
"bors",
|
|
1878
|
+
"bors[bot]",
|
|
1879
|
+
"kodiakhq",
|
|
1880
|
+
"kodiakhq[bot]",
|
|
1881
|
+
"dependabot",
|
|
1882
|
+
"dependabot[bot]",
|
|
1883
|
+
"renovate",
|
|
1884
|
+
"renovate[bot]",
|
|
1885
|
+
"github-actions",
|
|
1886
|
+
"github-actions[bot]"
|
|
1887
|
+
]);
|
|
1729
1888
|
}
|
|
1730
1889
|
});
|
|
1731
1890
|
|
|
@@ -7807,6 +7966,7 @@ __export(src_exports, {
|
|
|
7807
7966
|
fetchGitHubProfile: () => fetchGitHubProfile,
|
|
7808
7967
|
fetchOpenExternalPRs: () => fetchOpenExternalPRs,
|
|
7809
7968
|
fetchOwnedRepoTraction: () => fetchOwnedRepoTraction,
|
|
7969
|
+
fetchPRLifecycle: () => fetchPRLifecycle,
|
|
7810
7970
|
fetchPRScoringFacts: () => fetchPRScoringFacts,
|
|
7811
7971
|
fetchRepoRecency: () => fetchRepoRecency,
|
|
7812
7972
|
fetchRepoReceptivity: () => fetchRepoReceptivity,
|