terminalhire 0.35.3 → 0.36.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 +1 -1
- package/dist/bin/jpi-bounties.js +120 -19
- package/dist/bin/jpi-chat-read.js +28 -8
- package/dist/bin/jpi-chat.js +30 -10
- package/dist/bin/jpi-claim.js +121 -20
- package/dist/bin/jpi-config.js +8 -3
- package/dist/bin/jpi-contribute.js +25 -36
- package/dist/bin/jpi-devs.js +121 -19
- package/dist/bin/jpi-dispatch.js +6496 -501
- package/dist/bin/jpi-hub.js +127 -26
- package/dist/bin/jpi-inbox.js +30 -10
- package/dist/bin/jpi-init.js +118 -17
- package/dist/bin/jpi-intro.js +19 -4
- package/dist/bin/jpi-jobs.js +129 -23
- package/dist/bin/jpi-learn.js +18 -3
- package/dist/bin/jpi-link.js +9 -4
- package/dist/bin/jpi-login.js +129 -23
- package/dist/bin/jpi-mcp-chat.js +27177 -0
- package/dist/bin/jpi-mcp.js +5838 -141
- package/dist/bin/jpi-profile.js +18 -3
- package/dist/bin/jpi-project.js +118 -17
- package/dist/bin/jpi-refresh.js +159 -61
- package/dist/bin/jpi-repo.js +18 -3
- package/dist/bin/jpi-save.js +18 -3
- package/dist/bin/jpi-spinner.js +16 -13
- package/dist/bin/jpi-sync.js +18 -3
- package/dist/bin/jpi-trajectory.js +20 -5
- package/dist/bin/peer-connect-prompt.js +8 -3
- package/dist/bin/pulse-prompt.js +9 -4
- package/dist/bin/spinner.js +16 -15
- package/dist/src/chat-client.js +20 -5
- package/dist/src/chat-keystore.js +18 -3
- package/dist/src/config.js +10 -8
- package/dist/src/crypto-store.js +1 -1
- package/dist/src/github-auth.js +1 -1
- package/dist/src/intro.js +19 -4
- package/dist/src/link.js +9 -4
- package/dist/src/profile.js +18 -3
- package/dist/src/repo-experience.js +18 -3
- package/dist/src/reputation/fetch.js +16 -1
- package/dist/src/signal.js +16 -1
- package/dist/src/trajectory.js +20 -5
- package/dist/src/web-session.js +1 -1
- package/package.json +2 -2
|
@@ -253,7 +253,7 @@ import {
|
|
|
253
253
|
} from "fs";
|
|
254
254
|
import { join } from "path";
|
|
255
255
|
import { homedir } from "os";
|
|
256
|
-
var TERMINALHIRE_DIR = join(homedir(), ".terminalhire");
|
|
256
|
+
var TERMINALHIRE_DIR = process.env.TERMINALHIRE_DIR || join(homedir(), ".terminalhire");
|
|
257
257
|
var TOKEN_FILE = join(TERMINALHIRE_DIR, "github-token.enc");
|
|
258
258
|
var KEY_FILE = join(TERMINALHIRE_DIR, "key");
|
|
259
259
|
var ALGO = "aes-256-gcm";
|
package/dist/bin/jpi-bounties.js
CHANGED
|
@@ -1748,6 +1748,32 @@ async function openPRClosingRefs(owner, name, token, signal, governor) {
|
|
|
1748
1748
|
return null;
|
|
1749
1749
|
}
|
|
1750
1750
|
}
|
|
1751
|
+
async function issueCrossRefPRAttempts(owner, name, issueNumber, token, signal, governor) {
|
|
1752
|
+
const url = `https://api.github.com/repos/${owner}/${name}/issues/${issueNumber}/timeline?per_page=100`;
|
|
1753
|
+
try {
|
|
1754
|
+
const res = governor ? await governor.get(url, { headers: ghHeaders(token), signal }) : await fetch(url, { headers: ghHeaders(token), signal });
|
|
1755
|
+
if (!res || !res.ok) return null;
|
|
1756
|
+
const link = res.headers?.get("link") ?? null;
|
|
1757
|
+
const hasNextPage = link != null && /\brel="next"/.test(link);
|
|
1758
|
+
const events = await res.json();
|
|
1759
|
+
if (!Array.isArray(events)) return null;
|
|
1760
|
+
if (hasNextPage || events.length >= 100) return null;
|
|
1761
|
+
let hasOpenPR = false;
|
|
1762
|
+
let hasClosedPR = false;
|
|
1763
|
+
const prNumbers = [];
|
|
1764
|
+
for (const ev of events) {
|
|
1765
|
+
if (ev?.event !== "cross-referenced") continue;
|
|
1766
|
+
const src = ev.source?.issue;
|
|
1767
|
+
if (!src || src.pull_request == null) continue;
|
|
1768
|
+
if (typeof src.number === "number") prNumbers.push(src.number);
|
|
1769
|
+
if (src.state === "open") hasOpenPR = true;
|
|
1770
|
+
else if (src.state === "closed") hasClosedPR = true;
|
|
1771
|
+
}
|
|
1772
|
+
return { hasOpenPR, hasClosedPR, prNumbers };
|
|
1773
|
+
} catch {
|
|
1774
|
+
return null;
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1751
1777
|
function makeScoringGovernor(governor) {
|
|
1752
1778
|
return governor ?? makeGitHubGovernor(
|
|
1753
1779
|
((url, init) => fetch(url, init)),
|
|
@@ -3925,6 +3951,30 @@ var init_feeds = __esm({
|
|
|
3925
3951
|
});
|
|
3926
3952
|
|
|
3927
3953
|
// ../../packages/core/src/feeds/contributions.ts
|
|
3954
|
+
function readSearchMaxPages() {
|
|
3955
|
+
const raw = process.env["CONTRIB_SEARCH_MAX_PAGES"];
|
|
3956
|
+
if (raw == null) return DEFAULT_SEARCH_MAX_PAGES;
|
|
3957
|
+
const n = Number.parseInt(raw, 10);
|
|
3958
|
+
if (Number.isNaN(n)) return DEFAULT_SEARCH_MAX_PAGES;
|
|
3959
|
+
return Math.min(Math.max(n, MIN_SEARCH_MAX_PAGES), MAX_SEARCH_MAX_PAGES);
|
|
3960
|
+
}
|
|
3961
|
+
function readMaxContribItems() {
|
|
3962
|
+
const raw = process.env["CONTRIB_MAX_ITEMS"];
|
|
3963
|
+
if (raw == null) return DEFAULT_MAX_CONTRIB_ITEMS;
|
|
3964
|
+
const n = Number.parseInt(raw, 10);
|
|
3965
|
+
if (Number.isNaN(n)) return DEFAULT_MAX_CONTRIB_ITEMS;
|
|
3966
|
+
return Math.min(Math.max(n, MIN_MAX_CONTRIB_ITEMS), MAX_MAX_CONTRIB_ITEMS);
|
|
3967
|
+
}
|
|
3968
|
+
function readMaxContribIssuesScanned() {
|
|
3969
|
+
const raw = process.env["CONTRIB_MAX_ISSUES_SCANNED"];
|
|
3970
|
+
if (raw == null) return DEFAULT_MAX_CONTRIB_ISSUES_SCANNED;
|
|
3971
|
+
const n = Number.parseInt(raw, 10);
|
|
3972
|
+
if (Number.isNaN(n)) return DEFAULT_MAX_CONTRIB_ISSUES_SCANNED;
|
|
3973
|
+
return Math.min(
|
|
3974
|
+
Math.max(n, MIN_MAX_CONTRIB_ISSUES_SCANNED),
|
|
3975
|
+
MAX_MAX_CONTRIB_ISSUES_SCANNED
|
|
3976
|
+
);
|
|
3977
|
+
}
|
|
3928
3978
|
function authHeaders2() {
|
|
3929
3979
|
const token = process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"];
|
|
3930
3980
|
const h = {
|
|
@@ -4012,13 +4062,21 @@ async function fetchRateLimit(client) {
|
|
|
4012
4062
|
}
|
|
4013
4063
|
async function searchContribIssues(client, queries) {
|
|
4014
4064
|
const byUrl = /* @__PURE__ */ new Map();
|
|
4065
|
+
const maxPages = readSearchMaxPages();
|
|
4015
4066
|
for (const q of queries) {
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
if (
|
|
4067
|
+
for (let page = 1; page <= maxPages; page++) {
|
|
4068
|
+
const res = await client.json(
|
|
4069
|
+
`/search/issues?q=${encodeURIComponent(q)}&sort=created&order=desc&per_page=${SEARCH_PER_PAGE2}&page=${page}`
|
|
4070
|
+
);
|
|
4071
|
+
const items = res?.items;
|
|
4072
|
+
if (items == null) break;
|
|
4073
|
+
for (const it of items) {
|
|
4074
|
+
if (it.pull_request) continue;
|
|
4075
|
+
if (!byUrl.has(it.html_url)) byUrl.set(it.html_url, it);
|
|
4076
|
+
}
|
|
4077
|
+
if (items.length < SEARCH_PER_PAGE2) break;
|
|
4078
|
+
const stats = client.getStats();
|
|
4079
|
+
if (stats.budgetAborted || stats.secondaryAborted) break;
|
|
4022
4080
|
}
|
|
4023
4081
|
}
|
|
4024
4082
|
return [...byUrl.values()].sort(
|
|
@@ -4054,7 +4112,12 @@ function buildContributionJob(a) {
|
|
|
4054
4112
|
// TERM-27: persist the repo's primary language so project curation can
|
|
4055
4113
|
// exclude the repo's OWN language id (folded into every issue's tags) from
|
|
4056
4114
|
// the distinct-skill signal. Same `repo` used by the tokenize() tag build.
|
|
4057
|
-
language: a.repo.language ?? null
|
|
4115
|
+
language: a.repo.language ?? null,
|
|
4116
|
+
// TERM-35: stamp the search item's comment count (already in the response —
|
|
4117
|
+
// zero extra egress). A NEUTRAL volume signal only: set solely when the
|
|
4118
|
+
// search item carries a finite count >= 0; a failed/absent value leaves it
|
|
4119
|
+
// undefined (never a fabricated 0), so a render's chip falls through cleanly.
|
|
4120
|
+
commentsAtDiscovery: typeof a.issue.comments === "number" && Number.isFinite(a.issue.comments) && a.issue.comments >= 0 ? a.issue.comments : void 0
|
|
4058
4121
|
},
|
|
4059
4122
|
// Provenance: repo-first discovered items only (label-first omits the field).
|
|
4060
4123
|
...a.discovered ? { discovered: true } : {},
|
|
@@ -4074,10 +4137,14 @@ async function aggregateContributions(opts = {}) {
|
|
|
4074
4137
|
probeTimeoutMs: opts.fetchImpl ? null : PROBE_TIMEOUT_MS
|
|
4075
4138
|
});
|
|
4076
4139
|
const queries = opts.queries ?? CONTRIB_SEARCH_QUERIES;
|
|
4140
|
+
const maxContribItems = readMaxContribItems();
|
|
4077
4141
|
const startRl = await fetchRateLimit(client);
|
|
4078
4142
|
const coreHealthyAtStart = (startRl?.core?.remaining ?? 0) >= 500;
|
|
4079
4143
|
client.setSecondaryHint(coreHealthyAtStart);
|
|
4080
|
-
const issues = (await searchContribIssues(client, queries)).slice(
|
|
4144
|
+
const issues = (await searchContribIssues(client, queries)).slice(
|
|
4145
|
+
0,
|
|
4146
|
+
readMaxContribIssuesScanned()
|
|
4147
|
+
);
|
|
4081
4148
|
const repoCache = /* @__PURE__ */ new Map();
|
|
4082
4149
|
const contribCache = /* @__PURE__ */ new Map();
|
|
4083
4150
|
const prRefsCache = /* @__PURE__ */ new Map();
|
|
@@ -4167,7 +4234,7 @@ async function aggregateContributions(opts = {}) {
|
|
|
4167
4234
|
let contribUndefined = 0;
|
|
4168
4235
|
let prRefsNull = 0;
|
|
4169
4236
|
for (const issue of issues) {
|
|
4170
|
-
if (jobs.length >=
|
|
4237
|
+
if (jobs.length >= maxContribItems) break;
|
|
4171
4238
|
const fullName = repoFullNameFromApiUrl2(issue.repository_url);
|
|
4172
4239
|
if (!fullName) continue;
|
|
4173
4240
|
const id = `contribute:${repoKey(fullName)}#${issue.number}`;
|
|
@@ -4225,7 +4292,7 @@ async function aggregateContributions(opts = {}) {
|
|
|
4225
4292
|
const doDiscovery = opts.discoverRepos ?? (opts.trendingSlugs != null || opts.vocabTerms != null);
|
|
4226
4293
|
let discoveredEmitted = 0;
|
|
4227
4294
|
let discoveryBudgetStopped = false;
|
|
4228
|
-
if (doDiscovery && jobs.length <
|
|
4295
|
+
if (doDiscovery && jobs.length < maxContribItems) {
|
|
4229
4296
|
const maxRepos = Math.min(
|
|
4230
4297
|
Math.max(0, opts.maxDiscoveredRepos ?? MAX_DISCOVERED_REPOS),
|
|
4231
4298
|
MAX_DISCOVERED_REPOS
|
|
@@ -4278,7 +4345,7 @@ async function aggregateContributions(opts = {}) {
|
|
|
4278
4345
|
}
|
|
4279
4346
|
const scanned = candidates.slice(0, maxRepos);
|
|
4280
4347
|
for (const fullName of scanned) {
|
|
4281
|
-
if (jobs.length >=
|
|
4348
|
+
if (jobs.length >= maxContribItems) break;
|
|
4282
4349
|
if (client.getStats().budgetAborted || client.getStats().secondaryAborted) {
|
|
4283
4350
|
discoveryBudgetStopped = true;
|
|
4284
4351
|
break;
|
|
@@ -4303,7 +4370,7 @@ async function aggregateContributions(opts = {}) {
|
|
|
4303
4370
|
const repoIssues = (searchRes?.items ?? []).filter((it) => !it.pull_request);
|
|
4304
4371
|
let perRepoDiscovered = 0;
|
|
4305
4372
|
for (const issue of repoIssues) {
|
|
4306
|
-
if (jobs.length >=
|
|
4373
|
+
if (jobs.length >= maxContribItems) break;
|
|
4307
4374
|
if (perRepoDiscovered >= MAX_ISSUES_PER_DISCOVERED_REPO) break;
|
|
4308
4375
|
if ((perRepo.get(repoKey(fullName)) ?? 0) >= MAX_BOUNTIES_PER_DISCOVERED_REPO) break;
|
|
4309
4376
|
const id = `contribute:${repoKey(fullName)}#${issue.number}`;
|
|
@@ -4368,7 +4435,7 @@ async function aggregateContributions(opts = {}) {
|
|
|
4368
4435
|
}
|
|
4369
4436
|
return jobs;
|
|
4370
4437
|
}
|
|
4371
|
-
var GITHUB_API2, CONTRIB_LABEL_QUERIES, CONTRIB_LANGUAGE_QUERIES, CONTRIB_SEARCH_QUERIES, SEARCH_PER_PAGE2,
|
|
4438
|
+
var GITHUB_API2, CONTRIB_LABEL_QUERIES, CONTRIB_LANGUAGE_QUERIES, CONTRIB_SEARCH_QUERIES, SEARCH_PER_PAGE2, DEFAULT_SEARCH_MAX_PAGES, MIN_SEARCH_MAX_PAGES, MAX_SEARCH_MAX_PAGES, DEFAULT_MAX_CONTRIB_ITEMS, MIN_MAX_CONTRIB_ITEMS, MAX_MAX_CONTRIB_ITEMS, DEFAULT_MAX_CONTRIB_ISSUES_SCANNED, MIN_MAX_CONTRIB_ISSUES_SCANNED, MAX_MAX_CONTRIB_ISSUES_SCANNED, MAX_DISCOVERED_REPOS, MAX_ISSUES_PER_DISCOVERED_REPO, DISCOVERY_REPOS_PER_TERM, DISCOVERY_VOCAB_TERMS, DISCOVERY_ISSUE_LABELS, repoKey;
|
|
4372
4439
|
var init_contributions = __esm({
|
|
4373
4440
|
"../../packages/core/src/feeds/contributions.ts"() {
|
|
4374
4441
|
"use strict";
|
|
@@ -4387,7 +4454,11 @@ var init_contributions = __esm({
|
|
|
4387
4454
|
'label:"good-first-issue" type:issue state:open',
|
|
4388
4455
|
'label:"help wanted" type:issue state:open',
|
|
4389
4456
|
'label:"help-wanted" type:issue state:open',
|
|
4390
|
-
'label:"up-for-grabs" type:issue state:open'
|
|
4457
|
+
'label:"up-for-grabs" type:issue state:open',
|
|
4458
|
+
// supply-expansion D: two more first-contribution label families widen the
|
|
4459
|
+
// global newest-first slice WITHOUT relaxing the credential gate.
|
|
4460
|
+
'label:"beginner-friendly" type:issue state:open',
|
|
4461
|
+
'label:"first-timers-only" type:issue state:open'
|
|
4391
4462
|
];
|
|
4392
4463
|
CONTRIB_LANGUAGE_QUERIES = [
|
|
4393
4464
|
...["rust", "go", "python", "c++", "ruby"].map(
|
|
@@ -4395,12 +4466,30 @@ var init_contributions = __esm({
|
|
|
4395
4466
|
),
|
|
4396
4467
|
...["rust", "go"].map(
|
|
4397
4468
|
(lang) => `label:"good first issue" language:${lang} type:issue state:open`
|
|
4469
|
+
),
|
|
4470
|
+
// supply-expansion D: cover the high-volume web/enterprise ecosystems the
|
|
4471
|
+
// original set omitted. TS/JS were previously left out of "good first issue"
|
|
4472
|
+
// (the global slice over-represented them) but a LANGUAGE-scoped page surfaces
|
|
4473
|
+
// DIFFERENT repos than the global newest-first slice, so re-including them widens
|
|
4474
|
+
// distinct-repo coverage rather than duplicating it.
|
|
4475
|
+
...["typescript", "javascript", "java", "python"].map(
|
|
4476
|
+
(lang) => `label:"good first issue" language:${lang} type:issue state:open`
|
|
4477
|
+
),
|
|
4478
|
+
...["typescript", "javascript", "c#", "php"].map(
|
|
4479
|
+
(lang) => `label:"help wanted" language:${lang} type:issue state:open`
|
|
4398
4480
|
)
|
|
4399
4481
|
];
|
|
4400
4482
|
CONTRIB_SEARCH_QUERIES = [...CONTRIB_LABEL_QUERIES, ...CONTRIB_LANGUAGE_QUERIES];
|
|
4401
4483
|
SEARCH_PER_PAGE2 = 100;
|
|
4402
|
-
|
|
4403
|
-
|
|
4484
|
+
DEFAULT_SEARCH_MAX_PAGES = 1;
|
|
4485
|
+
MIN_SEARCH_MAX_PAGES = 1;
|
|
4486
|
+
MAX_SEARCH_MAX_PAGES = 5;
|
|
4487
|
+
DEFAULT_MAX_CONTRIB_ITEMS = 400;
|
|
4488
|
+
MIN_MAX_CONTRIB_ITEMS = 50;
|
|
4489
|
+
MAX_MAX_CONTRIB_ITEMS = 1e3;
|
|
4490
|
+
DEFAULT_MAX_CONTRIB_ISSUES_SCANNED = 1500;
|
|
4491
|
+
MIN_MAX_CONTRIB_ISSUES_SCANNED = 100;
|
|
4492
|
+
MAX_MAX_CONTRIB_ISSUES_SCANNED = 5e3;
|
|
4404
4493
|
MAX_DISCOVERED_REPOS = 15;
|
|
4405
4494
|
MAX_ISSUES_PER_DISCOVERED_REPO = 3;
|
|
4406
4495
|
DISCOVERY_REPOS_PER_TERM = 20;
|
|
@@ -4570,6 +4659,15 @@ async function enrichWinnability(jobs, contribute, w) {
|
|
|
4570
4659
|
);
|
|
4571
4660
|
}
|
|
4572
4661
|
}
|
|
4662
|
+
function hasClickableUrl(url) {
|
|
4663
|
+
if (!url) return false;
|
|
4664
|
+
try {
|
|
4665
|
+
const parsed = new URL(url);
|
|
4666
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
4667
|
+
} catch {
|
|
4668
|
+
return false;
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4573
4671
|
async function buildIndex(opts) {
|
|
4574
4672
|
const includePartners = opts?.includePartners ?? true;
|
|
4575
4673
|
const publicJobs = await aggregate(opts);
|
|
@@ -4580,6 +4678,7 @@ async function buildIndex(opts) {
|
|
|
4580
4678
|
...opts?.partnerRoles ?? []
|
|
4581
4679
|
];
|
|
4582
4680
|
for (const job of partnerJobs) {
|
|
4681
|
+
if (!hasClickableUrl(job.url)) continue;
|
|
4583
4682
|
if (!seen.has(job.id)) {
|
|
4584
4683
|
seen.add(job.id);
|
|
4585
4684
|
allJobs.push(job);
|
|
@@ -4661,7 +4760,8 @@ async function fetchIssueStatus(fullName, issueNumber, opts = {}) {
|
|
|
4661
4760
|
for (const a of body.assignees ?? []) {
|
|
4662
4761
|
if (a && typeof a.login === "string") assignees.add(a.login);
|
|
4663
4762
|
}
|
|
4664
|
-
|
|
4763
|
+
const comments = typeof body.comments === "number" && Number.isFinite(body.comments) && body.comments >= 0 ? body.comments : null;
|
|
4764
|
+
return { state, assignees: [...assignees], comments };
|
|
4665
4765
|
}
|
|
4666
4766
|
var GITHUB_API3, DEFAULT_ISSUE_STATUS_TIMEOUT_MS;
|
|
4667
4767
|
var init_github_issue_status = __esm({
|
|
@@ -8371,6 +8471,7 @@ __export(src_exports, {
|
|
|
8371
8471
|
isOverIntroLimit: () => isOverIntroLimit,
|
|
8372
8472
|
isTrivialPRTitle: () => isTrivialPRTitle,
|
|
8373
8473
|
isWinnableIssue: () => isWinnableIssue,
|
|
8474
|
+
issueCrossRefPRAttempts: () => issueCrossRefPRAttempts,
|
|
8374
8475
|
jobShortToken: () => jobShortToken,
|
|
8375
8476
|
joinLabels: () => joinLabels,
|
|
8376
8477
|
labelFor: () => labelFor,
|
|
@@ -8598,7 +8699,7 @@ var TERMINALHIRE_DIR2, KEY_FILE, KEYTAR_SERVICE, KEYTAR_ACCOUNT, ALGO, KEY_BYTES
|
|
|
8598
8699
|
var init_crypto_store = __esm({
|
|
8599
8700
|
"src/crypto-store.ts"() {
|
|
8600
8701
|
"use strict";
|
|
8601
|
-
TERMINALHIRE_DIR2 = join3(homedir2(), ".terminalhire");
|
|
8702
|
+
TERMINALHIRE_DIR2 = process.env.TERMINALHIRE_DIR || join3(homedir2(), ".terminalhire");
|
|
8602
8703
|
KEY_FILE = join3(TERMINALHIRE_DIR2, "key");
|
|
8603
8704
|
KEYTAR_SERVICE = "terminalhire";
|
|
8604
8705
|
KEYTAR_ACCOUNT = "profile-key";
|
|
@@ -8748,7 +8849,7 @@ var init_profile = __esm({
|
|
|
8748
8849
|
"use strict";
|
|
8749
8850
|
init_src();
|
|
8750
8851
|
init_crypto_store();
|
|
8751
|
-
TERMINALHIRE_DIR3 = join4(homedir3(), ".terminalhire");
|
|
8852
|
+
TERMINALHIRE_DIR3 = process.env.TERMINALHIRE_DIR || join4(homedir3(), ".terminalhire");
|
|
8752
8853
|
PROFILE_FILE = join4(TERMINALHIRE_DIR3, "profile.enc");
|
|
8753
8854
|
profileStore = createEncryptedStore(PROFILE_FILE, {
|
|
8754
8855
|
blank: blankProfile,
|
|
@@ -892,7 +892,11 @@ var init_contributions = __esm({
|
|
|
892
892
|
'label:"good-first-issue" type:issue state:open',
|
|
893
893
|
'label:"help wanted" type:issue state:open',
|
|
894
894
|
'label:"help-wanted" type:issue state:open',
|
|
895
|
-
'label:"up-for-grabs" type:issue state:open'
|
|
895
|
+
'label:"up-for-grabs" type:issue state:open',
|
|
896
|
+
// supply-expansion D: two more first-contribution label families widen the
|
|
897
|
+
// global newest-first slice WITHOUT relaxing the credential gate.
|
|
898
|
+
'label:"beginner-friendly" type:issue state:open',
|
|
899
|
+
'label:"first-timers-only" type:issue state:open'
|
|
896
900
|
];
|
|
897
901
|
CONTRIB_LANGUAGE_QUERIES = [
|
|
898
902
|
...["rust", "go", "python", "c++", "ruby"].map(
|
|
@@ -900,6 +904,17 @@ var init_contributions = __esm({
|
|
|
900
904
|
),
|
|
901
905
|
...["rust", "go"].map(
|
|
902
906
|
(lang) => `label:"good first issue" language:${lang} type:issue state:open`
|
|
907
|
+
),
|
|
908
|
+
// supply-expansion D: cover the high-volume web/enterprise ecosystems the
|
|
909
|
+
// original set omitted. TS/JS were previously left out of "good first issue"
|
|
910
|
+
// (the global slice over-represented them) but a LANGUAGE-scoped page surfaces
|
|
911
|
+
// DIFFERENT repos than the global newest-first slice, so re-including them widens
|
|
912
|
+
// distinct-repo coverage rather than duplicating it.
|
|
913
|
+
...["typescript", "javascript", "java", "python"].map(
|
|
914
|
+
(lang) => `label:"good first issue" language:${lang} type:issue state:open`
|
|
915
|
+
),
|
|
916
|
+
...["typescript", "javascript", "c#", "php"].map(
|
|
917
|
+
(lang) => `label:"help wanted" language:${lang} type:issue state:open`
|
|
903
918
|
)
|
|
904
919
|
];
|
|
905
920
|
CONTRIB_SEARCH_QUERIES = [...CONTRIB_LABEL_QUERIES, ...CONTRIB_LANGUAGE_QUERIES];
|
|
@@ -4183,7 +4198,7 @@ var TERMINALHIRE_DIR, TOKEN_FILE, KEY_FILE, ALGO, KEY_BYTES, IV_BYTES;
|
|
|
4183
4198
|
var init_github_auth = __esm({
|
|
4184
4199
|
"src/github-auth.ts"() {
|
|
4185
4200
|
"use strict";
|
|
4186
|
-
TERMINALHIRE_DIR = join2(homedir(), ".terminalhire");
|
|
4201
|
+
TERMINALHIRE_DIR = process.env.TERMINALHIRE_DIR || join2(homedir(), ".terminalhire");
|
|
4187
4202
|
TOKEN_FILE = join2(TERMINALHIRE_DIR, "github-token.enc");
|
|
4188
4203
|
KEY_FILE = join2(TERMINALHIRE_DIR, "key");
|
|
4189
4204
|
ALGO = "aes-256-gcm";
|
|
@@ -4214,7 +4229,7 @@ var init_chat_keystore = __esm({
|
|
|
4214
4229
|
"use strict";
|
|
4215
4230
|
init_src();
|
|
4216
4231
|
init_github_auth();
|
|
4217
|
-
TERMINALHIRE_DIR2 = join3(homedir2(), ".terminalhire");
|
|
4232
|
+
TERMINALHIRE_DIR2 = process.env.TERMINALHIRE_DIR || join3(homedir2(), ".terminalhire");
|
|
4218
4233
|
IDENTITY_FILE = join3(TERMINALHIRE_DIR2, "chat-identity.enc");
|
|
4219
4234
|
}
|
|
4220
4235
|
});
|
|
@@ -4231,7 +4246,7 @@ import {
|
|
|
4231
4246
|
import { homedir as homedir3 } from "os";
|
|
4232
4247
|
import { join as join4 } from "path";
|
|
4233
4248
|
function terminalhireDir() {
|
|
4234
|
-
return join4(homedir3(), ".terminalhire");
|
|
4249
|
+
return process.env.TERMINALHIRE_DIR || join4(homedir3(), ".terminalhire");
|
|
4235
4250
|
}
|
|
4236
4251
|
function webSessionFilePath() {
|
|
4237
4252
|
return join4(terminalhireDir(), "web-session");
|
|
@@ -4456,7 +4471,7 @@ var init_chat_client = __esm({
|
|
|
4456
4471
|
init_web_session();
|
|
4457
4472
|
CHAT_BASE = process.env["TERMINALHIRE_API_URL"] || "https://terminalhire.com";
|
|
4458
4473
|
GH_SESSION_COOKIE = "__jpi_gh_session";
|
|
4459
|
-
TERMINALHIRE_DIR3 = join5(homedir4(), ".terminalhire");
|
|
4474
|
+
TERMINALHIRE_DIR3 = process.env.TERMINALHIRE_DIR || join5(homedir4(), ".terminalhire");
|
|
4460
4475
|
PEERS_FILE = join5(TERMINALHIRE_DIR3, "chat-peers.json");
|
|
4461
4476
|
REQUEST_TIMEOUT_MS = 1e4;
|
|
4462
4477
|
ChatNotLinkedError = class extends Error {
|
|
@@ -4516,13 +4531,19 @@ function writeConfig(config) {
|
|
|
4516
4531
|
mkdirSync5(TERMINALHIRE_DIR4, { recursive: true });
|
|
4517
4532
|
const current = readConfig();
|
|
4518
4533
|
const merged = { ...current, ...config };
|
|
4534
|
+
if ("contributePrompted" in merged) {
|
|
4535
|
+
if (merged.contributeEnabled === false && !("contributeEnabled" in config)) {
|
|
4536
|
+
delete merged.contributeEnabled;
|
|
4537
|
+
}
|
|
4538
|
+
delete merged.contributePrompted;
|
|
4539
|
+
}
|
|
4519
4540
|
writeFileSync5(CONFIG_FILE, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
4520
4541
|
}
|
|
4521
4542
|
var TERMINALHIRE_DIR4, CONFIG_FILE, DEFAULT_CONFIG;
|
|
4522
4543
|
var init_config = __esm({
|
|
4523
4544
|
"src/config.ts"() {
|
|
4524
4545
|
"use strict";
|
|
4525
|
-
TERMINALHIRE_DIR4 = join6(homedir5(), ".terminalhire");
|
|
4546
|
+
TERMINALHIRE_DIR4 = process.env.TERMINALHIRE_DIR || join6(homedir5(), ".terminalhire");
|
|
4526
4547
|
CONFIG_FILE = join6(TERMINALHIRE_DIR4, "config.json");
|
|
4527
4548
|
DEFAULT_CONFIG = {
|
|
4528
4549
|
nudge: "session",
|
|
@@ -4533,8 +4554,7 @@ var init_config = __esm({
|
|
|
4533
4554
|
chatShareActivity: false,
|
|
4534
4555
|
inboundNudgeMuted: false,
|
|
4535
4556
|
inboundNudgeDisclosed: false,
|
|
4536
|
-
contributeEnabled:
|
|
4537
|
-
contributePrompted: false,
|
|
4557
|
+
contributeEnabled: true,
|
|
4538
4558
|
betaOptIn: false,
|
|
4539
4559
|
lastFullFeedbackAt: null,
|
|
4540
4560
|
lastPulseAskAt: null,
|
package/dist/bin/jpi-chat.js
CHANGED
|
@@ -909,7 +909,11 @@ var init_contributions = __esm({
|
|
|
909
909
|
'label:"good-first-issue" type:issue state:open',
|
|
910
910
|
'label:"help wanted" type:issue state:open',
|
|
911
911
|
'label:"help-wanted" type:issue state:open',
|
|
912
|
-
'label:"up-for-grabs" type:issue state:open'
|
|
912
|
+
'label:"up-for-grabs" type:issue state:open',
|
|
913
|
+
// supply-expansion D: two more first-contribution label families widen the
|
|
914
|
+
// global newest-first slice WITHOUT relaxing the credential gate.
|
|
915
|
+
'label:"beginner-friendly" type:issue state:open',
|
|
916
|
+
'label:"first-timers-only" type:issue state:open'
|
|
913
917
|
];
|
|
914
918
|
CONTRIB_LANGUAGE_QUERIES = [
|
|
915
919
|
...["rust", "go", "python", "c++", "ruby"].map(
|
|
@@ -917,6 +921,17 @@ var init_contributions = __esm({
|
|
|
917
921
|
),
|
|
918
922
|
...["rust", "go"].map(
|
|
919
923
|
(lang) => `label:"good first issue" language:${lang} type:issue state:open`
|
|
924
|
+
),
|
|
925
|
+
// supply-expansion D: cover the high-volume web/enterprise ecosystems the
|
|
926
|
+
// original set omitted. TS/JS were previously left out of "good first issue"
|
|
927
|
+
// (the global slice over-represented them) but a LANGUAGE-scoped page surfaces
|
|
928
|
+
// DIFFERENT repos than the global newest-first slice, so re-including them widens
|
|
929
|
+
// distinct-repo coverage rather than duplicating it.
|
|
930
|
+
...["typescript", "javascript", "java", "python"].map(
|
|
931
|
+
(lang) => `label:"good first issue" language:${lang} type:issue state:open`
|
|
932
|
+
),
|
|
933
|
+
...["typescript", "javascript", "c#", "php"].map(
|
|
934
|
+
(lang) => `label:"help wanted" language:${lang} type:issue state:open`
|
|
920
935
|
)
|
|
921
936
|
];
|
|
922
937
|
CONTRIB_SEARCH_QUERIES = [...CONTRIB_LABEL_QUERIES, ...CONTRIB_LANGUAGE_QUERIES];
|
|
@@ -4211,7 +4226,7 @@ var TERMINALHIRE_DIR, TOKEN_FILE, KEY_FILE, ALGO, KEY_BYTES, IV_BYTES;
|
|
|
4211
4226
|
var init_github_auth = __esm({
|
|
4212
4227
|
"src/github-auth.ts"() {
|
|
4213
4228
|
"use strict";
|
|
4214
|
-
TERMINALHIRE_DIR = join2(homedir(), ".terminalhire");
|
|
4229
|
+
TERMINALHIRE_DIR = process.env.TERMINALHIRE_DIR || join2(homedir(), ".terminalhire");
|
|
4215
4230
|
TOKEN_FILE = join2(TERMINALHIRE_DIR, "github-token.enc");
|
|
4216
4231
|
KEY_FILE = join2(TERMINALHIRE_DIR, "key");
|
|
4217
4232
|
ALGO = "aes-256-gcm";
|
|
@@ -4242,7 +4257,7 @@ var init_chat_keystore = __esm({
|
|
|
4242
4257
|
"use strict";
|
|
4243
4258
|
init_src();
|
|
4244
4259
|
init_github_auth();
|
|
4245
|
-
TERMINALHIRE_DIR2 = join3(homedir2(), ".terminalhire");
|
|
4260
|
+
TERMINALHIRE_DIR2 = process.env.TERMINALHIRE_DIR || join3(homedir2(), ".terminalhire");
|
|
4246
4261
|
IDENTITY_FILE = join3(TERMINALHIRE_DIR2, "chat-identity.enc");
|
|
4247
4262
|
}
|
|
4248
4263
|
});
|
|
@@ -4259,7 +4274,7 @@ import {
|
|
|
4259
4274
|
import { homedir as homedir3 } from "os";
|
|
4260
4275
|
import { join as join4 } from "path";
|
|
4261
4276
|
function terminalhireDir() {
|
|
4262
|
-
return join4(homedir3(), ".terminalhire");
|
|
4277
|
+
return process.env.TERMINALHIRE_DIR || join4(homedir3(), ".terminalhire");
|
|
4263
4278
|
}
|
|
4264
4279
|
function webSessionFilePath() {
|
|
4265
4280
|
return join4(terminalhireDir(), "web-session");
|
|
@@ -4484,7 +4499,7 @@ var init_chat_client = __esm({
|
|
|
4484
4499
|
init_web_session();
|
|
4485
4500
|
CHAT_BASE = process.env["TERMINALHIRE_API_URL"] || "https://terminalhire.com";
|
|
4486
4501
|
GH_SESSION_COOKIE = "__jpi_gh_session";
|
|
4487
|
-
TERMINALHIRE_DIR3 = join5(homedir4(), ".terminalhire");
|
|
4502
|
+
TERMINALHIRE_DIR3 = process.env.TERMINALHIRE_DIR || join5(homedir4(), ".terminalhire");
|
|
4488
4503
|
PEERS_FILE = join5(TERMINALHIRE_DIR3, "chat-peers.json");
|
|
4489
4504
|
REQUEST_TIMEOUT_MS = 1e4;
|
|
4490
4505
|
ChatNotLinkedError = class extends Error {
|
|
@@ -4544,13 +4559,19 @@ function writeConfig(config) {
|
|
|
4544
4559
|
mkdirSync5(TERMINALHIRE_DIR4, { recursive: true });
|
|
4545
4560
|
const current = readConfig();
|
|
4546
4561
|
const merged = { ...current, ...config };
|
|
4562
|
+
if ("contributePrompted" in merged) {
|
|
4563
|
+
if (merged.contributeEnabled === false && !("contributeEnabled" in config)) {
|
|
4564
|
+
delete merged.contributeEnabled;
|
|
4565
|
+
}
|
|
4566
|
+
delete merged.contributePrompted;
|
|
4567
|
+
}
|
|
4547
4568
|
writeFileSync5(CONFIG_FILE, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
4548
4569
|
}
|
|
4549
4570
|
var TERMINALHIRE_DIR4, CONFIG_FILE, DEFAULT_CONFIG;
|
|
4550
4571
|
var init_config = __esm({
|
|
4551
4572
|
"src/config.ts"() {
|
|
4552
4573
|
"use strict";
|
|
4553
|
-
TERMINALHIRE_DIR4 = join6(homedir5(), ".terminalhire");
|
|
4574
|
+
TERMINALHIRE_DIR4 = process.env.TERMINALHIRE_DIR || join6(homedir5(), ".terminalhire");
|
|
4554
4575
|
CONFIG_FILE = join6(TERMINALHIRE_DIR4, "config.json");
|
|
4555
4576
|
DEFAULT_CONFIG = {
|
|
4556
4577
|
nudge: "session",
|
|
@@ -4561,8 +4582,7 @@ var init_config = __esm({
|
|
|
4561
4582
|
chatShareActivity: false,
|
|
4562
4583
|
inboundNudgeMuted: false,
|
|
4563
4584
|
inboundNudgeDisclosed: false,
|
|
4564
|
-
contributeEnabled:
|
|
4565
|
-
contributePrompted: false,
|
|
4585
|
+
contributeEnabled: true,
|
|
4566
4586
|
betaOptIn: false,
|
|
4567
4587
|
lastFullFeedbackAt: null,
|
|
4568
4588
|
lastPulseAskAt: null,
|
|
@@ -5165,7 +5185,7 @@ var TERMINALHIRE_DIR6, KEY_FILE2, KEYTAR_SERVICE, KEYTAR_ACCOUNT, ALGO2, KEY_BYT
|
|
|
5165
5185
|
var init_crypto_store = __esm({
|
|
5166
5186
|
"src/crypto-store.ts"() {
|
|
5167
5187
|
"use strict";
|
|
5168
|
-
TERMINALHIRE_DIR6 = join8(homedir7(), ".terminalhire");
|
|
5188
|
+
TERMINALHIRE_DIR6 = process.env.TERMINALHIRE_DIR || join8(homedir7(), ".terminalhire");
|
|
5169
5189
|
KEY_FILE2 = join8(TERMINALHIRE_DIR6, "key");
|
|
5170
5190
|
KEYTAR_SERVICE = "terminalhire";
|
|
5171
5191
|
KEYTAR_ACCOUNT = "profile-key";
|
|
@@ -5315,7 +5335,7 @@ var init_profile = __esm({
|
|
|
5315
5335
|
"use strict";
|
|
5316
5336
|
init_src();
|
|
5317
5337
|
init_crypto_store();
|
|
5318
|
-
TERMINALHIRE_DIR7 = join9(homedir8(), ".terminalhire");
|
|
5338
|
+
TERMINALHIRE_DIR7 = process.env.TERMINALHIRE_DIR || join9(homedir8(), ".terminalhire");
|
|
5319
5339
|
PROFILE_FILE = join9(TERMINALHIRE_DIR7, "profile.enc");
|
|
5320
5340
|
profileStore = createEncryptedStore(PROFILE_FILE, {
|
|
5321
5341
|
blank: blankProfile,
|