terminalhire 0.35.0 → 0.35.3
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 +10 -58
- package/dist/bin/jpi-bounties.js +124 -77
- package/dist/bin/jpi-chat-read.js +29 -60
- package/dist/bin/jpi-chat.js +31 -62
- package/dist/bin/jpi-claim.js +125 -78
- package/dist/bin/jpi-config.js +51 -1
- package/dist/bin/jpi-contribute.js +30 -61
- package/dist/bin/jpi-devs.js +124 -77
- package/dist/bin/jpi-dispatch.js +682 -6167
- package/dist/bin/jpi-hub.js +127 -79
- package/dist/bin/jpi-inbox.js +31 -62
- package/dist/bin/jpi-init.js +113 -18
- package/dist/bin/jpi-intro.js +28 -60
- package/dist/bin/jpi-jobs.js +126 -78
- package/dist/bin/jpi-learn.js +28 -60
- package/dist/bin/jpi-link.js +2 -1
- package/dist/bin/jpi-login.js +127 -79
- package/dist/bin/jpi-mcp.js +148 -5827
- package/dist/bin/jpi-profile.js +28 -60
- package/dist/bin/jpi-project.js +113 -18
- package/dist/bin/jpi-protocol.js +73 -5
- package/dist/bin/jpi-refresh.js +158 -83
- package/dist/bin/jpi-repo.js +27 -59
- package/dist/bin/jpi-save.js +28 -60
- package/dist/bin/jpi-spinner.js +14 -0
- package/dist/bin/jpi-sync.js +28 -60
- package/dist/bin/jpi-trajectory.js +28 -60
- package/dist/bin/jpi-update.js +487 -5
- package/dist/bin/peer-connect-prompt.js +2 -1
- package/dist/bin/pulse-prompt.js +2 -1
- package/dist/bin/spinner.js +18 -1
- package/dist/src/chat-client.js +24 -61
- package/dist/src/chat-keystore.js +24 -61
- package/dist/src/config.js +17 -1
- package/dist/src/crypto-store.js +11 -62
- package/dist/src/github-auth.js +10 -61
- package/dist/src/intro.js +28 -60
- package/dist/src/link.js +2 -1
- package/dist/src/profile.js +25 -62
- package/dist/src/protocol.js +72 -4
- package/dist/src/repo-experience.js +24 -61
- package/dist/src/reputation/fetch.js +14 -0
- package/dist/src/signal.js +14 -0
- package/dist/src/trajectory.js +28 -60
- package/package.json +1 -1
- package/dist/keytar-KOAAH267.node +0 -0
package/dist/bin/jpi-chat.js
CHANGED
|
@@ -5,16 +5,10 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
9
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
10
|
-
}) : x)(function(x) {
|
|
11
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
12
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
13
|
-
});
|
|
14
8
|
var __esm = (fn, res) => function __init() {
|
|
15
9
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
16
10
|
};
|
|
17
|
-
var __commonJS = (cb, mod2) => function
|
|
11
|
+
var __commonJS = (cb, mod2) => function __require() {
|
|
18
12
|
return mod2 || (0, cb[__getOwnPropNames(cb)[0]])((mod2 = { exports: {} }).exports, mod2), mod2.exports;
|
|
19
13
|
};
|
|
20
14
|
var __export = (target, all) => {
|
|
@@ -724,11 +718,26 @@ var init_winnability = __esm({
|
|
|
724
718
|
});
|
|
725
719
|
|
|
726
720
|
// ../../packages/core/src/feeds/projectCuration.ts
|
|
727
|
-
var CURATION_NORM;
|
|
721
|
+
var CURATION_WEIGHTS, CURATION_NORM;
|
|
728
722
|
var init_projectCuration = __esm({
|
|
729
723
|
"../../packages/core/src/feeds/projectCuration.ts"() {
|
|
730
724
|
"use strict";
|
|
725
|
+
init_vocab();
|
|
731
726
|
init_winnability();
|
|
727
|
+
CURATION_WEIGHTS = {
|
|
728
|
+
winnableCount: 0.45,
|
|
729
|
+
vocabRelevance: 0.05,
|
|
730
|
+
skillDensity: 0.15,
|
|
731
|
+
freshness: 0.15,
|
|
732
|
+
mergeVelocity: 0.15,
|
|
733
|
+
popularity: 0.05
|
|
734
|
+
};
|
|
735
|
+
{
|
|
736
|
+
const _sum = Object.values(CURATION_WEIGHTS).reduce((a, b) => a + b, 0);
|
|
737
|
+
if (Math.abs(_sum - 1) > 1e-9) {
|
|
738
|
+
throw new Error(`CURATION_WEIGHTS must sum to 1.0, got ${_sum}`);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
732
741
|
CURATION_NORM = {
|
|
733
742
|
/** ~60 commits in the last ~30d is treated as "maxed" commit-cadence freshness. */
|
|
734
743
|
commitCadence: 60,
|
|
@@ -892,6 +901,7 @@ var init_contributions = __esm({
|
|
|
892
901
|
init_contribution_gate();
|
|
893
902
|
init_contribution_classify();
|
|
894
903
|
init_github_bounties();
|
|
904
|
+
init_github();
|
|
895
905
|
init_http();
|
|
896
906
|
init_gh_governor();
|
|
897
907
|
CONTRIB_LABEL_QUERIES = [
|
|
@@ -4125,61 +4135,19 @@ var init_src = __esm({
|
|
|
4125
4135
|
}
|
|
4126
4136
|
});
|
|
4127
4137
|
|
|
4128
|
-
// ../../node_modules/keytar/build/Release/keytar.node
|
|
4129
|
-
var keytar_default;
|
|
4130
|
-
var init_keytar = __esm({
|
|
4131
|
-
"../../node_modules/keytar/build/Release/keytar.node"() {
|
|
4132
|
-
keytar_default = "../keytar-KOAAH267.node";
|
|
4133
|
-
}
|
|
4134
|
-
});
|
|
4135
|
-
|
|
4136
|
-
// node-file:/private/tmp/claude-501/-Users-ericgang-job-placement-inline/9716ff9c-0531-4844-adf4-286763cf8ab8/scratchpad/wt-cli-update/node_modules/keytar/build/Release/keytar.node
|
|
4137
|
-
var require_keytar = __commonJS({
|
|
4138
|
-
"node-file:/private/tmp/claude-501/-Users-ericgang-job-placement-inline/9716ff9c-0531-4844-adf4-286763cf8ab8/scratchpad/wt-cli-update/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
4139
|
-
"use strict";
|
|
4140
|
-
init_keytar();
|
|
4141
|
-
try {
|
|
4142
|
-
module.exports = __require(keytar_default);
|
|
4143
|
-
} catch {
|
|
4144
|
-
}
|
|
4145
|
-
}
|
|
4146
|
-
});
|
|
4147
|
-
|
|
4148
4138
|
// ../../node_modules/keytar/lib/keytar.js
|
|
4149
|
-
var
|
|
4139
|
+
var require_keytar = __commonJS({
|
|
4150
4140
|
"../../node_modules/keytar/lib/keytar.js"(exports, module) {
|
|
4151
4141
|
"use strict";
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
if (!val || val.length <= 0) {
|
|
4155
|
-
throw new Error(name + " is required.");
|
|
4156
|
-
}
|
|
4142
|
+
function disabled() {
|
|
4143
|
+
throw new Error("keytar disabled in this dev checkout (keychain popup guard) \u2014 key-file fallback expected");
|
|
4157
4144
|
}
|
|
4158
4145
|
module.exports = {
|
|
4159
|
-
getPassword:
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
setPassword: function(service, account, password) {
|
|
4165
|
-
checkRequired(service, "Service");
|
|
4166
|
-
checkRequired(account, "Account");
|
|
4167
|
-
checkRequired(password, "Password");
|
|
4168
|
-
return keytar.setPassword(service, account, password);
|
|
4169
|
-
},
|
|
4170
|
-
deletePassword: function(service, account) {
|
|
4171
|
-
checkRequired(service, "Service");
|
|
4172
|
-
checkRequired(account, "Account");
|
|
4173
|
-
return keytar.deletePassword(service, account);
|
|
4174
|
-
},
|
|
4175
|
-
findPassword: function(service) {
|
|
4176
|
-
checkRequired(service, "Service");
|
|
4177
|
-
return keytar.findPassword(service);
|
|
4178
|
-
},
|
|
4179
|
-
findCredentials: function(service) {
|
|
4180
|
-
checkRequired(service, "Service");
|
|
4181
|
-
return keytar.findCredentials(service);
|
|
4182
|
-
}
|
|
4146
|
+
getPassword: disabled,
|
|
4147
|
+
setPassword: disabled,
|
|
4148
|
+
deletePassword: disabled,
|
|
4149
|
+
findPassword: disabled,
|
|
4150
|
+
findCredentials: disabled
|
|
4183
4151
|
};
|
|
4184
4152
|
}
|
|
4185
4153
|
});
|
|
@@ -4206,7 +4174,7 @@ function skipKeychain() {
|
|
|
4206
4174
|
async function loadKey() {
|
|
4207
4175
|
if (!skipKeychain()) {
|
|
4208
4176
|
try {
|
|
4209
|
-
const kt = await Promise.resolve().then(() => __toESM(
|
|
4177
|
+
const kt = await Promise.resolve().then(() => __toESM(require_keytar(), 1));
|
|
4210
4178
|
const stored = await kt.getPassword("terminalhire", "profile-key");
|
|
4211
4179
|
if (stored) return Buffer.from(stored, "hex");
|
|
4212
4180
|
const key2 = randomBytes3(KEY_BYTES);
|
|
@@ -4598,7 +4566,8 @@ var init_config = __esm({
|
|
|
4598
4566
|
betaOptIn: false,
|
|
4599
4567
|
lastFullFeedbackAt: null,
|
|
4600
4568
|
lastPulseAskAt: null,
|
|
4601
|
-
pulseDisclosed: false
|
|
4569
|
+
pulseDisclosed: false,
|
|
4570
|
+
mix: "balanced"
|
|
4602
4571
|
};
|
|
4603
4572
|
}
|
|
4604
4573
|
});
|
|
@@ -5104,7 +5073,7 @@ function skipKeychain2() {
|
|
|
5104
5073
|
async function tryLoadFromKeytar(policy) {
|
|
5105
5074
|
if (forceKeytarUnavailableForTests || skipKeychain2()) return null;
|
|
5106
5075
|
try {
|
|
5107
|
-
const kt = policy === "keychain-required" ? createRequire(import.meta.url)("keytar") : await Promise.resolve().then(() => __toESM(
|
|
5076
|
+
const kt = policy === "keychain-required" ? createRequire(import.meta.url)("keytar") : await Promise.resolve().then(() => __toESM(require_keytar(), 1));
|
|
5108
5077
|
const stored = await kt.getPassword(KEYTAR_SERVICE, KEYTAR_ACCOUNT);
|
|
5109
5078
|
if (stored) {
|
|
5110
5079
|
return Buffer.from(stored, "hex");
|
|
@@ -5145,7 +5114,7 @@ async function deleteKey() {
|
|
|
5145
5114
|
}
|
|
5146
5115
|
if (!forceKeytarUnavailableForTests && !skipKeychain2()) {
|
|
5147
5116
|
try {
|
|
5148
|
-
const kt = await Promise.resolve().then(() => __toESM(
|
|
5117
|
+
const kt = await Promise.resolve().then(() => __toESM(require_keytar(), 1));
|
|
5149
5118
|
await kt.deletePassword(KEYTAR_SERVICE, KEYTAR_ACCOUNT);
|
|
5150
5119
|
} catch {
|
|
5151
5120
|
}
|
package/dist/bin/jpi-claim.js
CHANGED
|
@@ -5,16 +5,10 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
9
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
10
|
-
}) : x)(function(x) {
|
|
11
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
12
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
13
|
-
});
|
|
14
8
|
var __esm = (fn, res) => function __init() {
|
|
15
9
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
16
10
|
};
|
|
17
|
-
var __commonJS = (cb, mod2) => function
|
|
11
|
+
var __commonJS = (cb, mod2) => function __require() {
|
|
18
12
|
return mod2 || (0, cb[__getOwnPropNames(cb)[0]])((mod2 = { exports: {} }).exports, mod2), mod2.exports;
|
|
19
13
|
};
|
|
20
14
|
var __export = (target, all) => {
|
|
@@ -1735,6 +1729,25 @@ async function resolveClosingIssues(owner, name, number, body, token, signal, go
|
|
|
1735
1729
|
while ((m = re.exec(body)) !== null) nums.add(parseInt(m[1], 10));
|
|
1736
1730
|
return { closesIssues: [...nums], linkageSource: nums.size ? "body-keyword" : "none" };
|
|
1737
1731
|
}
|
|
1732
|
+
async function openPRClosingRefs(owner, name, token, signal, governor) {
|
|
1733
|
+
const q = `query($o:String!,$n:String!){repository(owner:$o,name:$n){pullRequests(states:OPEN,first:100){totalCount nodes{number closingIssuesReferences(first:20){nodes{number}}}}}rateLimit{cost remaining}}`;
|
|
1734
|
+
try {
|
|
1735
|
+
const r = await ghGraphQL(q, { o: owner, n: name }, token, signal, governor);
|
|
1736
|
+
if (r === null) return null;
|
|
1737
|
+
if (!r.data?.repository) return null;
|
|
1738
|
+
const prs = r.data.repository.pullRequests;
|
|
1739
|
+
if (prs && prs.nodes !== void 0 && !Array.isArray(prs.nodes)) return null;
|
|
1740
|
+
const nodes = prs?.nodes ?? [];
|
|
1741
|
+
const refs = /* @__PURE__ */ new Set();
|
|
1742
|
+
for (const node of nodes) {
|
|
1743
|
+
for (const ref of node.closingIssuesReferences?.nodes ?? []) refs.add(ref.number);
|
|
1744
|
+
}
|
|
1745
|
+
const totalCount = prs?.totalCount ?? nodes.length;
|
|
1746
|
+
return { refs, capHit: totalCount > nodes.length, totalCount };
|
|
1747
|
+
} catch {
|
|
1748
|
+
return null;
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1738
1751
|
function makeScoringGovernor(governor) {
|
|
1739
1752
|
return governor ?? makeGitHubGovernor(
|
|
1740
1753
|
((url, init) => fetch(url, init)),
|
|
@@ -3487,7 +3500,7 @@ function firstNumber(xs) {
|
|
|
3487
3500
|
function isWinnableIssue(issue) {
|
|
3488
3501
|
const contested = (issue.contribution.openPRsAtDiscovery ?? 0) > 0;
|
|
3489
3502
|
if (contested) return false;
|
|
3490
|
-
if (issue.winnabilityScore
|
|
3503
|
+
if (issue.winnabilityScore != null && issue.winnabilityScore <= 0) return false;
|
|
3491
3504
|
return true;
|
|
3492
3505
|
}
|
|
3493
3506
|
function issueRecency(postedAt, now) {
|
|
@@ -3504,6 +3517,7 @@ function issueRecency(postedAt, now) {
|
|
|
3504
3517
|
function curateProjects(issues, opts = {}) {
|
|
3505
3518
|
const now = opts.now ?? Date.now();
|
|
3506
3519
|
const vocabSet = new Set(opts.vocabTerms ?? []);
|
|
3520
|
+
const applyFloor = opts.applySkillFloor ?? SKILL_FLOOR_ENABLED;
|
|
3507
3521
|
const groups = /* @__PURE__ */ new Map();
|
|
3508
3522
|
for (const issue of issues) {
|
|
3509
3523
|
const key = repoKeyOf(issue.contribution.repoFullName);
|
|
@@ -3531,15 +3545,21 @@ function curateProjects(issues, opts = {}) {
|
|
|
3531
3545
|
}
|
|
3532
3546
|
if (topTags.length >= 4) break;
|
|
3533
3547
|
}
|
|
3548
|
+
const repoLanguageRaw = firstNonEmptyString(
|
|
3549
|
+
winnableIssues.map((i) => i.contribution.language ?? "")
|
|
3550
|
+
);
|
|
3551
|
+
const languageIds = new Set(repoLanguageRaw ? normalize(tokenize(repoLanguageRaw)) : []);
|
|
3552
|
+
const skillTagUnion = /* @__PURE__ */ new Set();
|
|
3553
|
+
for (const iss of winnableIssues) for (const t of iss.tags ?? []) skillTagUnion.add(t);
|
|
3554
|
+
let distinctNonLanguageSkillTags = 0;
|
|
3555
|
+
for (const t of skillTagUnion) if (!languageIds.has(t)) distinctNonLanguageSkillTags++;
|
|
3556
|
+
if (applyFloor && distinctNonLanguageSkillTags < SKILL_FLOOR_MIN) continue;
|
|
3557
|
+
const skillDensity = clamp012(distinctNonLanguageSkillTags / SKILL_DENSITY_SATURATION);
|
|
3534
3558
|
let vocabRelevance = 0;
|
|
3535
|
-
if (vocabSet.size > 0) {
|
|
3536
|
-
|
|
3537
|
-
for (const
|
|
3538
|
-
|
|
3539
|
-
let matched = 0;
|
|
3540
|
-
for (const t of repoTags) if (vocabSet.has(t)) matched++;
|
|
3541
|
-
vocabRelevance = matched / repoTags.size;
|
|
3542
|
-
}
|
|
3559
|
+
if (vocabSet.size > 0 && skillTagUnion.size > 0) {
|
|
3560
|
+
let matched = 0;
|
|
3561
|
+
for (const t of skillTagUnion) if (vocabSet.has(t)) matched++;
|
|
3562
|
+
vocabRelevance = matched / skillTagUnion.size;
|
|
3543
3563
|
}
|
|
3544
3564
|
const cadence = clamp012((commitCadence ?? 0) / CURATION_NORM.commitCadence);
|
|
3545
3565
|
let recency = 0;
|
|
@@ -3558,6 +3578,8 @@ function curateProjects(issues, opts = {}) {
|
|
|
3558
3578
|
repoContributors: repoContributors ?? null,
|
|
3559
3579
|
topTags,
|
|
3560
3580
|
vocabRelevance,
|
|
3581
|
+
distinctNonLanguageSkillTags,
|
|
3582
|
+
skillDensity,
|
|
3561
3583
|
freshness,
|
|
3562
3584
|
mergeVelocity,
|
|
3563
3585
|
popularity
|
|
@@ -3567,7 +3589,7 @@ function curateProjects(issues, opts = {}) {
|
|
|
3567
3589
|
const cards = partials.map((p) => {
|
|
3568
3590
|
const winnableCount = p.winnableIssues.length;
|
|
3569
3591
|
const winnableCountNorm = maxCount > 0 ? winnableCount / maxCount : 0;
|
|
3570
|
-
const score = CURATION_WEIGHTS.winnableCount * winnableCountNorm + CURATION_WEIGHTS.vocabRelevance * p.vocabRelevance + CURATION_WEIGHTS.freshness * p.freshness + CURATION_WEIGHTS.mergeVelocity * p.mergeVelocity + CURATION_WEIGHTS.popularity * p.popularity;
|
|
3592
|
+
const score = CURATION_WEIGHTS.winnableCount * winnableCountNorm + CURATION_WEIGHTS.vocabRelevance * p.vocabRelevance + CURATION_WEIGHTS.skillDensity * p.skillDensity + CURATION_WEIGHTS.freshness * p.freshness + CURATION_WEIGHTS.mergeVelocity * p.mergeVelocity + CURATION_WEIGHTS.popularity * p.popularity;
|
|
3571
3593
|
return {
|
|
3572
3594
|
repoKey: p.repoKey,
|
|
3573
3595
|
description: p.description,
|
|
@@ -3580,6 +3602,8 @@ function curateProjects(issues, opts = {}) {
|
|
|
3580
3602
|
winnableCount,
|
|
3581
3603
|
winnableCountNorm,
|
|
3582
3604
|
vocabRelevance: p.vocabRelevance,
|
|
3605
|
+
distinctNonLanguageSkillTags: p.distinctNonLanguageSkillTags,
|
|
3606
|
+
skillDensity: p.skillDensity,
|
|
3583
3607
|
freshness: p.freshness,
|
|
3584
3608
|
mergeVelocity: p.mergeVelocity,
|
|
3585
3609
|
popularity: p.popularity
|
|
@@ -3591,18 +3615,32 @@ function curateProjects(issues, opts = {}) {
|
|
|
3591
3615
|
);
|
|
3592
3616
|
return cards;
|
|
3593
3617
|
}
|
|
3594
|
-
|
|
3618
|
+
function rosterActiveFromContribution(issues) {
|
|
3619
|
+
return curateProjects(issues).map((c) => ({ repoKey: c.repoKey, topTags: c.topTags }));
|
|
3620
|
+
}
|
|
3621
|
+
var CURATION_WEIGHTS, SKILL_DENSITY_SATURATION, SKILL_FLOOR_ENABLED, SKILL_FLOOR_MIN, CURATION_NORM, repoKeyOf;
|
|
3595
3622
|
var init_projectCuration = __esm({
|
|
3596
3623
|
"../../packages/core/src/feeds/projectCuration.ts"() {
|
|
3597
3624
|
"use strict";
|
|
3625
|
+
init_vocab();
|
|
3598
3626
|
init_winnability();
|
|
3599
3627
|
CURATION_WEIGHTS = {
|
|
3600
3628
|
winnableCount: 0.45,
|
|
3601
|
-
vocabRelevance: 0.
|
|
3629
|
+
vocabRelevance: 0.05,
|
|
3630
|
+
skillDensity: 0.15,
|
|
3602
3631
|
freshness: 0.15,
|
|
3603
3632
|
mergeVelocity: 0.15,
|
|
3604
3633
|
popularity: 0.05
|
|
3605
3634
|
};
|
|
3635
|
+
SKILL_DENSITY_SATURATION = 3;
|
|
3636
|
+
SKILL_FLOOR_ENABLED = false;
|
|
3637
|
+
SKILL_FLOOR_MIN = 1;
|
|
3638
|
+
{
|
|
3639
|
+
const _sum = Object.values(CURATION_WEIGHTS).reduce((a, b) => a + b, 0);
|
|
3640
|
+
if (Math.abs(_sum - 1) > 1e-9) {
|
|
3641
|
+
throw new Error(`CURATION_WEIGHTS must sum to 1.0, got ${_sum}`);
|
|
3642
|
+
}
|
|
3643
|
+
}
|
|
3606
3644
|
CURATION_NORM = {
|
|
3607
3645
|
/** ~60 commits in the last ~30d is treated as "maxed" commit-cadence freshness. */
|
|
3608
3646
|
commitCadence: 60,
|
|
@@ -3877,7 +3915,7 @@ var init_feeds = __esm({
|
|
|
3877
3915
|
DEFAULT_ASHBY_SLUGS = flattenTiers(ASHBY_SLUGS_BY_TIER);
|
|
3878
3916
|
DEFAULT_LEVER_SLUGS = flattenTiers(LEVER_SLUGS_BY_TIER);
|
|
3879
3917
|
DEFAULT_WORKABLE_SLUGS = ["zego", "workmotion"];
|
|
3880
|
-
MAX_JOBS_PER_COMPANY =
|
|
3918
|
+
MAX_JOBS_PER_COMPANY = 10;
|
|
3881
3919
|
BIGCO_SLUGS_BY_SOURCE = {
|
|
3882
3920
|
greenhouse: new Set(GREENHOUSE_SLUGS_BY_TIER.bigco.map((s) => s.toLowerCase())),
|
|
3883
3921
|
ashby: new Set(ASHBY_SLUGS_BY_TIER.bigco.map((s) => s.toLowerCase())),
|
|
@@ -3926,7 +3964,7 @@ function makeClient(fetchImpl, cfg) {
|
|
|
3926
3964
|
async function probe(path) {
|
|
3927
3965
|
return gov.probe(`${GITHUB_API2}${path}`, { headers: authHeaders2() });
|
|
3928
3966
|
}
|
|
3929
|
-
return { raw, json, probe, setSecondaryHint: gov.setSecondaryHint, getStats: gov.getStats };
|
|
3967
|
+
return { raw, json, probe, governor: gov, setSecondaryHint: gov.setSecondaryHint, getStats: gov.getStats };
|
|
3930
3968
|
}
|
|
3931
3969
|
async function contributorCount(client, fullName) {
|
|
3932
3970
|
const res = await client.raw(`/repos/${fullName}/contributors?per_page=1&anon=false`);
|
|
@@ -3942,14 +3980,27 @@ async function contributorCount(client, fullName) {
|
|
|
3942
3980
|
}
|
|
3943
3981
|
}
|
|
3944
3982
|
async function openPRIssueRefs(client, fullName) {
|
|
3983
|
+
const token = process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"];
|
|
3984
|
+
const [owner, name] = fullName.split("/");
|
|
3985
|
+
if (token && owner && name) {
|
|
3986
|
+
const res = await openPRClosingRefs(owner, name, token, void 0, client.governor);
|
|
3987
|
+
if (res === null) return null;
|
|
3988
|
+
if (res.capHit) {
|
|
3989
|
+
console.warn(
|
|
3990
|
+
`[contribute] open-PR closing-ref scan capped at 100/${res.totalCount} open PRs for ${fullName} (closing refs beyond the first 100 open PRs not scanned)`
|
|
3991
|
+
);
|
|
3992
|
+
}
|
|
3993
|
+
return res.refs;
|
|
3994
|
+
}
|
|
3945
3995
|
const prs = await client.json(
|
|
3946
3996
|
`/repos/${fullName}/pulls?state=open&per_page=100`
|
|
3947
3997
|
);
|
|
3948
3998
|
if (!Array.isArray(prs)) return null;
|
|
3949
3999
|
const refs = /* @__PURE__ */ new Set();
|
|
3950
4000
|
for (const pr of prs) {
|
|
3951
|
-
|
|
3952
|
-
${pr.body ?? ""}
|
|
4001
|
+
const text = `${pr.title ?? ""}
|
|
4002
|
+
${pr.body ?? ""}`;
|
|
4003
|
+
for (const m of text.matchAll(/\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)/gi)) {
|
|
3953
4004
|
refs.add(Number(m[1]));
|
|
3954
4005
|
}
|
|
3955
4006
|
}
|
|
@@ -3999,7 +4050,11 @@ function buildContributionJob(a) {
|
|
|
3999
4050
|
// verified-empty/non-matching set; a failed check leaves it undefined (never a
|
|
4000
4051
|
// fabricated 0), so the claim path falls through to a live re-count.
|
|
4001
4052
|
openPRsAtDiscovery: a.openPRsAtDiscovery,
|
|
4002
|
-
repoDescription: a.repo.description || null
|
|
4053
|
+
repoDescription: a.repo.description || null,
|
|
4054
|
+
// TERM-27: persist the repo's primary language so project curation can
|
|
4055
|
+
// exclude the repo's OWN language id (folded into every issue's tags) from
|
|
4056
|
+
// the distinct-skill signal. Same `repo` used by the tokenize() tag build.
|
|
4057
|
+
language: a.repo.language ?? null
|
|
4003
4058
|
},
|
|
4004
4059
|
// Provenance: repo-first discovered items only (label-first omits the field).
|
|
4005
4060
|
...a.discovered ? { discovered: true } : {},
|
|
@@ -4323,6 +4378,7 @@ var init_contributions = __esm({
|
|
|
4323
4378
|
init_contribution_gate();
|
|
4324
4379
|
init_contribution_classify();
|
|
4325
4380
|
init_github_bounties();
|
|
4381
|
+
init_github();
|
|
4326
4382
|
init_http();
|
|
4327
4383
|
init_gh_governor();
|
|
4328
4384
|
GITHUB_API2 = "https://api.github.com";
|
|
@@ -8171,11 +8227,35 @@ import { createHash as createHash2 } from "crypto";
|
|
|
8171
8227
|
function opportunityShortToken(id) {
|
|
8172
8228
|
return createHash2("sha256").update(id, "utf8").digest("base64url").slice(0, 8);
|
|
8173
8229
|
}
|
|
8174
|
-
|
|
8230
|
+
function jobShortToken(id) {
|
|
8231
|
+
return createHash2("sha256").update(`job:${id}`, "utf8").digest("base64url").slice(0, 8);
|
|
8232
|
+
}
|
|
8233
|
+
function jobTokenMap(index) {
|
|
8234
|
+
const cached = jobTokenMaps.get(index);
|
|
8235
|
+
if (cached) return cached;
|
|
8236
|
+
const map = /* @__PURE__ */ new Map();
|
|
8237
|
+
for (const job of index.jobs) {
|
|
8238
|
+
const token = jobShortToken(job.id);
|
|
8239
|
+
map.set(token, map.has(token) ? AMBIGUOUS_JOB_TOKEN : job);
|
|
8240
|
+
}
|
|
8241
|
+
jobTokenMaps.set(index, map);
|
|
8242
|
+
return map;
|
|
8243
|
+
}
|
|
8244
|
+
function resolveJobToken(index, token) {
|
|
8245
|
+
const hit = jobTokenMap(index).get(token);
|
|
8246
|
+
return hit && hit !== AMBIGUOUS_JOB_TOKEN ? hit : null;
|
|
8247
|
+
}
|
|
8248
|
+
function _jobTokenMapForTests(index) {
|
|
8249
|
+
return jobTokenMap(index);
|
|
8250
|
+
}
|
|
8251
|
+
var contributeShortToken, AMBIGUOUS_JOB_TOKEN, jobTokenMaps, _AMBIGUOUS_JOB_TOKEN_FOR_TESTS;
|
|
8175
8252
|
var init_short_token = __esm({
|
|
8176
8253
|
"../../packages/core/src/short-token.ts"() {
|
|
8177
8254
|
"use strict";
|
|
8178
8255
|
contributeShortToken = opportunityShortToken;
|
|
8256
|
+
AMBIGUOUS_JOB_TOKEN = /* @__PURE__ */ Symbol("ambiguous-job-token");
|
|
8257
|
+
jobTokenMaps = /* @__PURE__ */ new WeakMap();
|
|
8258
|
+
_AMBIGUOUS_JOB_TOKEN_FOR_TESTS = AMBIGUOUS_JOB_TOKEN;
|
|
8179
8259
|
}
|
|
8180
8260
|
});
|
|
8181
8261
|
|
|
@@ -8214,12 +8294,17 @@ __export(src_exports, {
|
|
|
8214
8294
|
MIN_STARS: () => MIN_STARS,
|
|
8215
8295
|
PROBE_TIMEOUT_MS: () => PROBE_TIMEOUT_MS,
|
|
8216
8296
|
RIGOR: () => RIGOR,
|
|
8297
|
+
SKILL_DENSITY_SATURATION: () => SKILL_DENSITY_SATURATION,
|
|
8298
|
+
SKILL_FLOOR_ENABLED: () => SKILL_FLOOR_ENABLED,
|
|
8299
|
+
SKILL_FLOOR_MIN: () => SKILL_FLOOR_MIN,
|
|
8217
8300
|
STRONG_MATCH_THRESHOLD: () => STRONG_MATCH_THRESHOLD,
|
|
8218
8301
|
SYNONYMS: () => SYNONYMS,
|
|
8219
8302
|
TRIVIAL_PR_TITLE: () => TRIVIAL_PR_TITLE,
|
|
8220
8303
|
VOCABULARY: () => VOCABULARY,
|
|
8221
8304
|
VOCAB_NODES: () => VOCAB_NODES,
|
|
8222
8305
|
WINNABILITY_NORM: () => WINNABILITY_NORM,
|
|
8306
|
+
_AMBIGUOUS_JOB_TOKEN_FOR_TESTS: () => _AMBIGUOUS_JOB_TOKEN_FOR_TESTS,
|
|
8307
|
+
_jobTokenMapForTests: () => _jobTokenMapForTests,
|
|
8223
8308
|
acceptanceCountForDomains: () => acceptanceCountForDomains,
|
|
8224
8309
|
aggregate: () => aggregate,
|
|
8225
8310
|
aggregateBounties: () => aggregateBounties,
|
|
@@ -8286,6 +8371,7 @@ __export(src_exports, {
|
|
|
8286
8371
|
isOverIntroLimit: () => isOverIntroLimit,
|
|
8287
8372
|
isTrivialPRTitle: () => isTrivialPRTitle,
|
|
8288
8373
|
isWinnableIssue: () => isWinnableIssue,
|
|
8374
|
+
jobShortToken: () => jobShortToken,
|
|
8289
8375
|
joinLabels: () => joinLabels,
|
|
8290
8376
|
labelFor: () => labelFor,
|
|
8291
8377
|
lever: () => lever,
|
|
@@ -8299,6 +8385,7 @@ __export(src_exports, {
|
|
|
8299
8385
|
mergeProbability: () => mergeProbability,
|
|
8300
8386
|
mmrRerank: () => mmrRerank,
|
|
8301
8387
|
normalize: () => normalize,
|
|
8388
|
+
openPRClosingRefs: () => openPRClosingRefs,
|
|
8302
8389
|
opire: () => opire,
|
|
8303
8390
|
opportunityShortToken: () => opportunityShortToken,
|
|
8304
8391
|
pageMatches: () => pageMatches,
|
|
@@ -8313,7 +8400,9 @@ __export(src_exports, {
|
|
|
8313
8400
|
recordClick: () => recordClick,
|
|
8314
8401
|
rejectExtraIntroFields: () => rejectExtraIntroFields,
|
|
8315
8402
|
relevanceScore: () => relevanceScore,
|
|
8403
|
+
resolveJobToken: () => resolveJobToken,
|
|
8316
8404
|
revealIntroContacts: () => revealIntroContacts,
|
|
8405
|
+
rosterActiveFromContribution: () => rosterActiveFromContribution,
|
|
8317
8406
|
safetyNumber: () => safetyNumber,
|
|
8318
8407
|
sameLogin: () => sameLogin,
|
|
8319
8408
|
setStatus: () => setStatus,
|
|
@@ -8536,61 +8625,19 @@ var init_claims = __esm({
|
|
|
8536
8625
|
}
|
|
8537
8626
|
});
|
|
8538
8627
|
|
|
8539
|
-
// ../../node_modules/keytar/build/Release/keytar.node
|
|
8540
|
-
var keytar_default;
|
|
8541
|
-
var init_keytar = __esm({
|
|
8542
|
-
"../../node_modules/keytar/build/Release/keytar.node"() {
|
|
8543
|
-
keytar_default = "../keytar-KOAAH267.node";
|
|
8544
|
-
}
|
|
8545
|
-
});
|
|
8546
|
-
|
|
8547
|
-
// node-file:/private/tmp/claude-501/-Users-ericgang-job-placement-inline/9716ff9c-0531-4844-adf4-286763cf8ab8/scratchpad/wt-cli-update/node_modules/keytar/build/Release/keytar.node
|
|
8548
|
-
var require_keytar = __commonJS({
|
|
8549
|
-
"node-file:/private/tmp/claude-501/-Users-ericgang-job-placement-inline/9716ff9c-0531-4844-adf4-286763cf8ab8/scratchpad/wt-cli-update/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
8550
|
-
"use strict";
|
|
8551
|
-
init_keytar();
|
|
8552
|
-
try {
|
|
8553
|
-
module.exports = __require(keytar_default);
|
|
8554
|
-
} catch {
|
|
8555
|
-
}
|
|
8556
|
-
}
|
|
8557
|
-
});
|
|
8558
|
-
|
|
8559
8628
|
// ../../node_modules/keytar/lib/keytar.js
|
|
8560
|
-
var
|
|
8629
|
+
var require_keytar = __commonJS({
|
|
8561
8630
|
"../../node_modules/keytar/lib/keytar.js"(exports, module) {
|
|
8562
8631
|
"use strict";
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
if (!val || val.length <= 0) {
|
|
8566
|
-
throw new Error(name + " is required.");
|
|
8567
|
-
}
|
|
8632
|
+
function disabled() {
|
|
8633
|
+
throw new Error("keytar disabled in this dev checkout (keychain popup guard) \u2014 key-file fallback expected");
|
|
8568
8634
|
}
|
|
8569
8635
|
module.exports = {
|
|
8570
|
-
getPassword:
|
|
8571
|
-
|
|
8572
|
-
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
setPassword: function(service, account, password) {
|
|
8576
|
-
checkRequired(service, "Service");
|
|
8577
|
-
checkRequired(account, "Account");
|
|
8578
|
-
checkRequired(password, "Password");
|
|
8579
|
-
return keytar.setPassword(service, account, password);
|
|
8580
|
-
},
|
|
8581
|
-
deletePassword: function(service, account) {
|
|
8582
|
-
checkRequired(service, "Service");
|
|
8583
|
-
checkRequired(account, "Account");
|
|
8584
|
-
return keytar.deletePassword(service, account);
|
|
8585
|
-
},
|
|
8586
|
-
findPassword: function(service) {
|
|
8587
|
-
checkRequired(service, "Service");
|
|
8588
|
-
return keytar.findPassword(service);
|
|
8589
|
-
},
|
|
8590
|
-
findCredentials: function(service) {
|
|
8591
|
-
checkRequired(service, "Service");
|
|
8592
|
-
return keytar.findCredentials(service);
|
|
8593
|
-
}
|
|
8636
|
+
getPassword: disabled,
|
|
8637
|
+
setPassword: disabled,
|
|
8638
|
+
deletePassword: disabled,
|
|
8639
|
+
findPassword: disabled,
|
|
8640
|
+
findCredentials: disabled
|
|
8594
8641
|
};
|
|
8595
8642
|
}
|
|
8596
8643
|
});
|
|
@@ -8798,7 +8845,7 @@ function skipKeychain2() {
|
|
|
8798
8845
|
async function tryLoadFromKeytar(policy) {
|
|
8799
8846
|
if (forceKeytarUnavailableForTests || skipKeychain2()) return null;
|
|
8800
8847
|
try {
|
|
8801
|
-
const kt = policy === "keychain-required" ? createRequire(import.meta.url)("keytar") : await Promise.resolve().then(() => __toESM(
|
|
8848
|
+
const kt = policy === "keychain-required" ? createRequire(import.meta.url)("keytar") : await Promise.resolve().then(() => __toESM(require_keytar(), 1));
|
|
8802
8849
|
const stored = await kt.getPassword(KEYTAR_SERVICE, KEYTAR_ACCOUNT);
|
|
8803
8850
|
if (stored) {
|
|
8804
8851
|
return Buffer.from(stored, "hex");
|
|
@@ -8839,7 +8886,7 @@ async function deleteKey() {
|
|
|
8839
8886
|
}
|
|
8840
8887
|
if (!forceKeytarUnavailableForTests && !skipKeychain2()) {
|
|
8841
8888
|
try {
|
|
8842
|
-
const kt = await Promise.resolve().then(() => __toESM(
|
|
8889
|
+
const kt = await Promise.resolve().then(() => __toESM(require_keytar(), 1));
|
|
8843
8890
|
await kt.deletePassword(KEYTAR_SERVICE, KEYTAR_ACCOUNT);
|
|
8844
8891
|
} catch {
|
|
8845
8892
|
}
|
|
@@ -9691,7 +9738,7 @@ function skipKeychain() {
|
|
|
9691
9738
|
async function loadKey() {
|
|
9692
9739
|
if (!skipKeychain()) {
|
|
9693
9740
|
try {
|
|
9694
|
-
const kt = await Promise.resolve().then(() => __toESM(
|
|
9741
|
+
const kt = await Promise.resolve().then(() => __toESM(require_keytar(), 1));
|
|
9695
9742
|
const stored = await kt.getPassword("terminalhire", "profile-key");
|
|
9696
9743
|
if (stored) return Buffer.from(stored, "hex");
|
|
9697
9744
|
const key2 = randomBytes4(KEY_BYTES);
|
package/dist/bin/jpi-config.js
CHANGED
|
@@ -24,7 +24,8 @@ var DEFAULT_CONFIG = {
|
|
|
24
24
|
betaOptIn: false,
|
|
25
25
|
lastFullFeedbackAt: null,
|
|
26
26
|
lastPulseAskAt: null,
|
|
27
|
-
pulseDisclosed: false
|
|
27
|
+
pulseDisclosed: false,
|
|
28
|
+
mix: "balanced"
|
|
28
29
|
};
|
|
29
30
|
function readConfig() {
|
|
30
31
|
try {
|
|
@@ -42,6 +43,10 @@ function writeConfig(config) {
|
|
|
42
43
|
const merged = { ...current, ...config };
|
|
43
44
|
writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
44
45
|
}
|
|
46
|
+
function parseSurfaceMix(raw) {
|
|
47
|
+
if (raw === "jobs" || raw === "balanced" || raw === "credential") return raw;
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
45
50
|
|
|
46
51
|
// bin/jpi-config.js
|
|
47
52
|
var TERMINALHIRE_DIR2 = process.env.TERMINALHIRE_DIR || join2(homedir2(), ".terminalhire");
|
|
@@ -52,9 +57,44 @@ function parseNudgeMode(raw) {
|
|
|
52
57
|
if (m && parseInt(m[1], 10) >= 1) return raw;
|
|
53
58
|
return null;
|
|
54
59
|
}
|
|
60
|
+
function printMixValues() {
|
|
61
|
+
console.log(" Valid mix values (roles vs. contribution items on the ambient surface):");
|
|
62
|
+
console.log(" jobs \u2014 more roles, fewer contributions (contribute 5, roles ~15)");
|
|
63
|
+
console.log(" balanced \u2014 rebalanced default (contribute 8, roles ~12)");
|
|
64
|
+
console.log(" credential \u2014 contribution-forward (contribute 12, roles ~8)");
|
|
65
|
+
}
|
|
55
66
|
async function run() {
|
|
56
67
|
const args = process.argv.slice(2);
|
|
57
68
|
const filtered = args[0] === "config" ? args.slice(1) : args;
|
|
69
|
+
if (filtered[0] === "get" && filtered[1] === "mix") {
|
|
70
|
+
const cfg = readConfig();
|
|
71
|
+
const envOverride = process.env["TH_MIX"];
|
|
72
|
+
console.log("");
|
|
73
|
+
console.log(` mix: ${cfg.mix}`);
|
|
74
|
+
if (envOverride) {
|
|
75
|
+
console.log(` (overridden by TH_MIX=${envOverride} at runtime)`);
|
|
76
|
+
}
|
|
77
|
+
console.log("");
|
|
78
|
+
printMixValues();
|
|
79
|
+
console.log("");
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (filtered[0] === "set" && filtered[1] === "mix") {
|
|
83
|
+
const value = filtered[2];
|
|
84
|
+
if (!value) {
|
|
85
|
+
console.error("Error: config set mix requires a value: jobs | balanced | credential");
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
const parsed = parseSurfaceMix(value);
|
|
89
|
+
if (!parsed) {
|
|
90
|
+
console.error(`Error: invalid mix value "${value}". Valid: jobs | balanced | credential`);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
writeConfig({ mix: parsed });
|
|
94
|
+
console.log(` mix set to: ${parsed}`);
|
|
95
|
+
console.log(` (saved to ${CONFIG_FILE2})`);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
58
98
|
if (filtered.includes("--show") || filtered.length === 0) {
|
|
59
99
|
const cfg = readConfig();
|
|
60
100
|
const envOverride = process.env["TERMINALHIRE_NUDGE"];
|
|
@@ -66,6 +106,11 @@ async function run() {
|
|
|
66
106
|
console.log(` (overridden by TERMINALHIRE_NUDGE=${envOverride} at runtime)`);
|
|
67
107
|
}
|
|
68
108
|
console.log(` peer-connect: ${cfg.peerConnect ? "on" : "off"} (ambient peer & founder surfacing; default off)`);
|
|
109
|
+
const mixEnv = process.env["TH_MIX"];
|
|
110
|
+
console.log(` mix: ${cfg.mix} (roles vs. contributions on the ambient surface; default balanced)`);
|
|
111
|
+
if (mixEnv) {
|
|
112
|
+
console.log(` (mix overridden by TH_MIX=${mixEnv} at runtime)`);
|
|
113
|
+
}
|
|
69
114
|
console.log(` config file: ${CONFIG_FILE2}`);
|
|
70
115
|
console.log("");
|
|
71
116
|
console.log(" Valid nudge values:");
|
|
@@ -73,6 +118,9 @@ async function run() {
|
|
|
73
118
|
console.log(" always \u2014 print every statusLine render when matches exist");
|
|
74
119
|
console.log(" every:N \u2014 print every Nth render (e.g. every:3)");
|
|
75
120
|
console.log("");
|
|
121
|
+
printMixValues();
|
|
122
|
+
console.log(" (set with: config set mix <value> \xB7 read with: config get mix)");
|
|
123
|
+
console.log("");
|
|
76
124
|
console.log(" Peer-connect (--connect on|off):");
|
|
77
125
|
console.log(" on \u2014 surface peers & founders in the spinner + send an anonymous matched signal");
|
|
78
126
|
console.log(" off \u2014 no peer matching, no directory fetch, no signal (default)");
|
|
@@ -110,6 +158,8 @@ async function run() {
|
|
|
110
158
|
}
|
|
111
159
|
console.error("Usage: terminalhire config --nudge <session|always|every:N>");
|
|
112
160
|
console.error(" terminalhire config --connect <on|off>");
|
|
161
|
+
console.error(" terminalhire config set mix <jobs|balanced|credential>");
|
|
162
|
+
console.error(" terminalhire config get mix");
|
|
113
163
|
console.error(" terminalhire config --show");
|
|
114
164
|
process.exit(1);
|
|
115
165
|
}
|