terminalhire 0.35.3 → 0.35.4
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 +20 -4
- package/dist/bin/jpi-chat-read.js +12 -7
- package/dist/bin/jpi-chat.js +14 -9
- package/dist/bin/jpi-claim.js +21 -5
- package/dist/bin/jpi-config.js +8 -3
- package/dist/bin/jpi-contribute.js +9 -35
- package/dist/bin/jpi-devs.js +21 -4
- package/dist/bin/jpi-dispatch.js +6145 -459
- package/dist/bin/jpi-hub.js +27 -11
- package/dist/bin/jpi-inbox.js +14 -9
- package/dist/bin/jpi-init.js +18 -2
- package/dist/bin/jpi-intro.js +3 -3
- package/dist/bin/jpi-jobs.js +29 -8
- package/dist/bin/jpi-learn.js +2 -2
- package/dist/bin/jpi-link.js +9 -4
- package/dist/bin/jpi-login.js +29 -8
- package/dist/bin/jpi-mcp.js +5838 -141
- package/dist/bin/jpi-profile.js +2 -2
- package/dist/bin/jpi-project.js +18 -2
- package/dist/bin/jpi-refresh.js +59 -46
- package/dist/bin/jpi-repo.js +2 -2
- package/dist/bin/jpi-save.js +2 -2
- package/dist/bin/jpi-spinner.js +0 -12
- package/dist/bin/jpi-sync.js +2 -2
- package/dist/bin/jpi-trajectory.js +4 -4
- package/dist/bin/peer-connect-prompt.js +8 -3
- package/dist/bin/pulse-prompt.js +9 -4
- package/dist/bin/spinner.js +0 -14
- package/dist/src/chat-client.js +4 -4
- package/dist/src/chat-keystore.js +2 -2
- 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 +3 -3
- package/dist/src/link.js +9 -4
- package/dist/src/profile.js +2 -2
- package/dist/src/repo-experience.js +2 -2
- package/dist/src/trajectory.js +4 -4
- 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
|
@@ -4054,7 +4054,12 @@ function buildContributionJob(a) {
|
|
|
4054
4054
|
// TERM-27: persist the repo's primary language so project curation can
|
|
4055
4055
|
// exclude the repo's OWN language id (folded into every issue's tags) from
|
|
4056
4056
|
// the distinct-skill signal. Same `repo` used by the tokenize() tag build.
|
|
4057
|
-
language: a.repo.language ?? null
|
|
4057
|
+
language: a.repo.language ?? null,
|
|
4058
|
+
// TERM-35: stamp the search item's comment count (already in the response —
|
|
4059
|
+
// zero extra egress). A NEUTRAL volume signal only: set solely when the
|
|
4060
|
+
// search item carries a finite count >= 0; a failed/absent value leaves it
|
|
4061
|
+
// undefined (never a fabricated 0), so a render's chip falls through cleanly.
|
|
4062
|
+
commentsAtDiscovery: typeof a.issue.comments === "number" && Number.isFinite(a.issue.comments) && a.issue.comments >= 0 ? a.issue.comments : void 0
|
|
4058
4063
|
},
|
|
4059
4064
|
// Provenance: repo-first discovered items only (label-first omits the field).
|
|
4060
4065
|
...a.discovered ? { discovered: true } : {},
|
|
@@ -4570,6 +4575,15 @@ async function enrichWinnability(jobs, contribute, w) {
|
|
|
4570
4575
|
);
|
|
4571
4576
|
}
|
|
4572
4577
|
}
|
|
4578
|
+
function hasClickableUrl(url) {
|
|
4579
|
+
if (!url) return false;
|
|
4580
|
+
try {
|
|
4581
|
+
const parsed = new URL(url);
|
|
4582
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
4583
|
+
} catch {
|
|
4584
|
+
return false;
|
|
4585
|
+
}
|
|
4586
|
+
}
|
|
4573
4587
|
async function buildIndex(opts) {
|
|
4574
4588
|
const includePartners = opts?.includePartners ?? true;
|
|
4575
4589
|
const publicJobs = await aggregate(opts);
|
|
@@ -4580,6 +4594,7 @@ async function buildIndex(opts) {
|
|
|
4580
4594
|
...opts?.partnerRoles ?? []
|
|
4581
4595
|
];
|
|
4582
4596
|
for (const job of partnerJobs) {
|
|
4597
|
+
if (!hasClickableUrl(job.url)) continue;
|
|
4583
4598
|
if (!seen.has(job.id)) {
|
|
4584
4599
|
seen.add(job.id);
|
|
4585
4600
|
allJobs.push(job);
|
|
@@ -4661,7 +4676,8 @@ async function fetchIssueStatus(fullName, issueNumber, opts = {}) {
|
|
|
4661
4676
|
for (const a of body.assignees ?? []) {
|
|
4662
4677
|
if (a && typeof a.login === "string") assignees.add(a.login);
|
|
4663
4678
|
}
|
|
4664
|
-
|
|
4679
|
+
const comments = typeof body.comments === "number" && Number.isFinite(body.comments) && body.comments >= 0 ? body.comments : null;
|
|
4680
|
+
return { state, assignees: [...assignees], comments };
|
|
4665
4681
|
}
|
|
4666
4682
|
var GITHUB_API3, DEFAULT_ISSUE_STATUS_TIMEOUT_MS;
|
|
4667
4683
|
var init_github_issue_status = __esm({
|
|
@@ -8598,7 +8614,7 @@ var TERMINALHIRE_DIR2, KEY_FILE, KEYTAR_SERVICE, KEYTAR_ACCOUNT, ALGO, KEY_BYTES
|
|
|
8598
8614
|
var init_crypto_store = __esm({
|
|
8599
8615
|
"src/crypto-store.ts"() {
|
|
8600
8616
|
"use strict";
|
|
8601
|
-
TERMINALHIRE_DIR2 = join3(homedir2(), ".terminalhire");
|
|
8617
|
+
TERMINALHIRE_DIR2 = process.env.TERMINALHIRE_DIR || join3(homedir2(), ".terminalhire");
|
|
8602
8618
|
KEY_FILE = join3(TERMINALHIRE_DIR2, "key");
|
|
8603
8619
|
KEYTAR_SERVICE = "terminalhire";
|
|
8604
8620
|
KEYTAR_ACCOUNT = "profile-key";
|
|
@@ -8748,7 +8764,7 @@ var init_profile = __esm({
|
|
|
8748
8764
|
"use strict";
|
|
8749
8765
|
init_src();
|
|
8750
8766
|
init_crypto_store();
|
|
8751
|
-
TERMINALHIRE_DIR3 = join4(homedir3(), ".terminalhire");
|
|
8767
|
+
TERMINALHIRE_DIR3 = process.env.TERMINALHIRE_DIR || join4(homedir3(), ".terminalhire");
|
|
8752
8768
|
PROFILE_FILE = join4(TERMINALHIRE_DIR3, "profile.enc");
|
|
8753
8769
|
profileStore = createEncryptedStore(PROFILE_FILE, {
|
|
8754
8770
|
blank: blankProfile,
|
|
@@ -4183,7 +4183,7 @@ var TERMINALHIRE_DIR, TOKEN_FILE, KEY_FILE, ALGO, KEY_BYTES, IV_BYTES;
|
|
|
4183
4183
|
var init_github_auth = __esm({
|
|
4184
4184
|
"src/github-auth.ts"() {
|
|
4185
4185
|
"use strict";
|
|
4186
|
-
TERMINALHIRE_DIR = join2(homedir(), ".terminalhire");
|
|
4186
|
+
TERMINALHIRE_DIR = process.env.TERMINALHIRE_DIR || join2(homedir(), ".terminalhire");
|
|
4187
4187
|
TOKEN_FILE = join2(TERMINALHIRE_DIR, "github-token.enc");
|
|
4188
4188
|
KEY_FILE = join2(TERMINALHIRE_DIR, "key");
|
|
4189
4189
|
ALGO = "aes-256-gcm";
|
|
@@ -4214,7 +4214,7 @@ var init_chat_keystore = __esm({
|
|
|
4214
4214
|
"use strict";
|
|
4215
4215
|
init_src();
|
|
4216
4216
|
init_github_auth();
|
|
4217
|
-
TERMINALHIRE_DIR2 = join3(homedir2(), ".terminalhire");
|
|
4217
|
+
TERMINALHIRE_DIR2 = process.env.TERMINALHIRE_DIR || join3(homedir2(), ".terminalhire");
|
|
4218
4218
|
IDENTITY_FILE = join3(TERMINALHIRE_DIR2, "chat-identity.enc");
|
|
4219
4219
|
}
|
|
4220
4220
|
});
|
|
@@ -4231,7 +4231,7 @@ import {
|
|
|
4231
4231
|
import { homedir as homedir3 } from "os";
|
|
4232
4232
|
import { join as join4 } from "path";
|
|
4233
4233
|
function terminalhireDir() {
|
|
4234
|
-
return join4(homedir3(), ".terminalhire");
|
|
4234
|
+
return process.env.TERMINALHIRE_DIR || join4(homedir3(), ".terminalhire");
|
|
4235
4235
|
}
|
|
4236
4236
|
function webSessionFilePath() {
|
|
4237
4237
|
return join4(terminalhireDir(), "web-session");
|
|
@@ -4456,7 +4456,7 @@ var init_chat_client = __esm({
|
|
|
4456
4456
|
init_web_session();
|
|
4457
4457
|
CHAT_BASE = process.env["TERMINALHIRE_API_URL"] || "https://terminalhire.com";
|
|
4458
4458
|
GH_SESSION_COOKIE = "__jpi_gh_session";
|
|
4459
|
-
TERMINALHIRE_DIR3 = join5(homedir4(), ".terminalhire");
|
|
4459
|
+
TERMINALHIRE_DIR3 = process.env.TERMINALHIRE_DIR || join5(homedir4(), ".terminalhire");
|
|
4460
4460
|
PEERS_FILE = join5(TERMINALHIRE_DIR3, "chat-peers.json");
|
|
4461
4461
|
REQUEST_TIMEOUT_MS = 1e4;
|
|
4462
4462
|
ChatNotLinkedError = class extends Error {
|
|
@@ -4516,13 +4516,19 @@ function writeConfig(config) {
|
|
|
4516
4516
|
mkdirSync5(TERMINALHIRE_DIR4, { recursive: true });
|
|
4517
4517
|
const current = readConfig();
|
|
4518
4518
|
const merged = { ...current, ...config };
|
|
4519
|
+
if ("contributePrompted" in merged) {
|
|
4520
|
+
if (merged.contributeEnabled === false && !("contributeEnabled" in config)) {
|
|
4521
|
+
delete merged.contributeEnabled;
|
|
4522
|
+
}
|
|
4523
|
+
delete merged.contributePrompted;
|
|
4524
|
+
}
|
|
4519
4525
|
writeFileSync5(CONFIG_FILE, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
4520
4526
|
}
|
|
4521
4527
|
var TERMINALHIRE_DIR4, CONFIG_FILE, DEFAULT_CONFIG;
|
|
4522
4528
|
var init_config = __esm({
|
|
4523
4529
|
"src/config.ts"() {
|
|
4524
4530
|
"use strict";
|
|
4525
|
-
TERMINALHIRE_DIR4 = join6(homedir5(), ".terminalhire");
|
|
4531
|
+
TERMINALHIRE_DIR4 = process.env.TERMINALHIRE_DIR || join6(homedir5(), ".terminalhire");
|
|
4526
4532
|
CONFIG_FILE = join6(TERMINALHIRE_DIR4, "config.json");
|
|
4527
4533
|
DEFAULT_CONFIG = {
|
|
4528
4534
|
nudge: "session",
|
|
@@ -4533,8 +4539,7 @@ var init_config = __esm({
|
|
|
4533
4539
|
chatShareActivity: false,
|
|
4534
4540
|
inboundNudgeMuted: false,
|
|
4535
4541
|
inboundNudgeDisclosed: false,
|
|
4536
|
-
contributeEnabled:
|
|
4537
|
-
contributePrompted: false,
|
|
4542
|
+
contributeEnabled: true,
|
|
4538
4543
|
betaOptIn: false,
|
|
4539
4544
|
lastFullFeedbackAt: null,
|
|
4540
4545
|
lastPulseAskAt: null,
|
package/dist/bin/jpi-chat.js
CHANGED
|
@@ -4211,7 +4211,7 @@ var TERMINALHIRE_DIR, TOKEN_FILE, KEY_FILE, ALGO, KEY_BYTES, IV_BYTES;
|
|
|
4211
4211
|
var init_github_auth = __esm({
|
|
4212
4212
|
"src/github-auth.ts"() {
|
|
4213
4213
|
"use strict";
|
|
4214
|
-
TERMINALHIRE_DIR = join2(homedir(), ".terminalhire");
|
|
4214
|
+
TERMINALHIRE_DIR = process.env.TERMINALHIRE_DIR || join2(homedir(), ".terminalhire");
|
|
4215
4215
|
TOKEN_FILE = join2(TERMINALHIRE_DIR, "github-token.enc");
|
|
4216
4216
|
KEY_FILE = join2(TERMINALHIRE_DIR, "key");
|
|
4217
4217
|
ALGO = "aes-256-gcm";
|
|
@@ -4242,7 +4242,7 @@ var init_chat_keystore = __esm({
|
|
|
4242
4242
|
"use strict";
|
|
4243
4243
|
init_src();
|
|
4244
4244
|
init_github_auth();
|
|
4245
|
-
TERMINALHIRE_DIR2 = join3(homedir2(), ".terminalhire");
|
|
4245
|
+
TERMINALHIRE_DIR2 = process.env.TERMINALHIRE_DIR || join3(homedir2(), ".terminalhire");
|
|
4246
4246
|
IDENTITY_FILE = join3(TERMINALHIRE_DIR2, "chat-identity.enc");
|
|
4247
4247
|
}
|
|
4248
4248
|
});
|
|
@@ -4259,7 +4259,7 @@ import {
|
|
|
4259
4259
|
import { homedir as homedir3 } from "os";
|
|
4260
4260
|
import { join as join4 } from "path";
|
|
4261
4261
|
function terminalhireDir() {
|
|
4262
|
-
return join4(homedir3(), ".terminalhire");
|
|
4262
|
+
return process.env.TERMINALHIRE_DIR || join4(homedir3(), ".terminalhire");
|
|
4263
4263
|
}
|
|
4264
4264
|
function webSessionFilePath() {
|
|
4265
4265
|
return join4(terminalhireDir(), "web-session");
|
|
@@ -4484,7 +4484,7 @@ var init_chat_client = __esm({
|
|
|
4484
4484
|
init_web_session();
|
|
4485
4485
|
CHAT_BASE = process.env["TERMINALHIRE_API_URL"] || "https://terminalhire.com";
|
|
4486
4486
|
GH_SESSION_COOKIE = "__jpi_gh_session";
|
|
4487
|
-
TERMINALHIRE_DIR3 = join5(homedir4(), ".terminalhire");
|
|
4487
|
+
TERMINALHIRE_DIR3 = process.env.TERMINALHIRE_DIR || join5(homedir4(), ".terminalhire");
|
|
4488
4488
|
PEERS_FILE = join5(TERMINALHIRE_DIR3, "chat-peers.json");
|
|
4489
4489
|
REQUEST_TIMEOUT_MS = 1e4;
|
|
4490
4490
|
ChatNotLinkedError = class extends Error {
|
|
@@ -4544,13 +4544,19 @@ function writeConfig(config) {
|
|
|
4544
4544
|
mkdirSync5(TERMINALHIRE_DIR4, { recursive: true });
|
|
4545
4545
|
const current = readConfig();
|
|
4546
4546
|
const merged = { ...current, ...config };
|
|
4547
|
+
if ("contributePrompted" in merged) {
|
|
4548
|
+
if (merged.contributeEnabled === false && !("contributeEnabled" in config)) {
|
|
4549
|
+
delete merged.contributeEnabled;
|
|
4550
|
+
}
|
|
4551
|
+
delete merged.contributePrompted;
|
|
4552
|
+
}
|
|
4547
4553
|
writeFileSync5(CONFIG_FILE, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
4548
4554
|
}
|
|
4549
4555
|
var TERMINALHIRE_DIR4, CONFIG_FILE, DEFAULT_CONFIG;
|
|
4550
4556
|
var init_config = __esm({
|
|
4551
4557
|
"src/config.ts"() {
|
|
4552
4558
|
"use strict";
|
|
4553
|
-
TERMINALHIRE_DIR4 = join6(homedir5(), ".terminalhire");
|
|
4559
|
+
TERMINALHIRE_DIR4 = process.env.TERMINALHIRE_DIR || join6(homedir5(), ".terminalhire");
|
|
4554
4560
|
CONFIG_FILE = join6(TERMINALHIRE_DIR4, "config.json");
|
|
4555
4561
|
DEFAULT_CONFIG = {
|
|
4556
4562
|
nudge: "session",
|
|
@@ -4561,8 +4567,7 @@ var init_config = __esm({
|
|
|
4561
4567
|
chatShareActivity: false,
|
|
4562
4568
|
inboundNudgeMuted: false,
|
|
4563
4569
|
inboundNudgeDisclosed: false,
|
|
4564
|
-
contributeEnabled:
|
|
4565
|
-
contributePrompted: false,
|
|
4570
|
+
contributeEnabled: true,
|
|
4566
4571
|
betaOptIn: false,
|
|
4567
4572
|
lastFullFeedbackAt: null,
|
|
4568
4573
|
lastPulseAskAt: null,
|
|
@@ -5165,7 +5170,7 @@ var TERMINALHIRE_DIR6, KEY_FILE2, KEYTAR_SERVICE, KEYTAR_ACCOUNT, ALGO2, KEY_BYT
|
|
|
5165
5170
|
var init_crypto_store = __esm({
|
|
5166
5171
|
"src/crypto-store.ts"() {
|
|
5167
5172
|
"use strict";
|
|
5168
|
-
TERMINALHIRE_DIR6 = join8(homedir7(), ".terminalhire");
|
|
5173
|
+
TERMINALHIRE_DIR6 = process.env.TERMINALHIRE_DIR || join8(homedir7(), ".terminalhire");
|
|
5169
5174
|
KEY_FILE2 = join8(TERMINALHIRE_DIR6, "key");
|
|
5170
5175
|
KEYTAR_SERVICE = "terminalhire";
|
|
5171
5176
|
KEYTAR_ACCOUNT = "profile-key";
|
|
@@ -5315,7 +5320,7 @@ var init_profile = __esm({
|
|
|
5315
5320
|
"use strict";
|
|
5316
5321
|
init_src();
|
|
5317
5322
|
init_crypto_store();
|
|
5318
|
-
TERMINALHIRE_DIR7 = join9(homedir8(), ".terminalhire");
|
|
5323
|
+
TERMINALHIRE_DIR7 = process.env.TERMINALHIRE_DIR || join9(homedir8(), ".terminalhire");
|
|
5319
5324
|
PROFILE_FILE = join9(TERMINALHIRE_DIR7, "profile.enc");
|
|
5320
5325
|
profileStore = createEncryptedStore(PROFILE_FILE, {
|
|
5321
5326
|
blank: blankProfile,
|
package/dist/bin/jpi-claim.js
CHANGED
|
@@ -4054,7 +4054,12 @@ function buildContributionJob(a) {
|
|
|
4054
4054
|
// TERM-27: persist the repo's primary language so project curation can
|
|
4055
4055
|
// exclude the repo's OWN language id (folded into every issue's tags) from
|
|
4056
4056
|
// the distinct-skill signal. Same `repo` used by the tokenize() tag build.
|
|
4057
|
-
language: a.repo.language ?? null
|
|
4057
|
+
language: a.repo.language ?? null,
|
|
4058
|
+
// TERM-35: stamp the search item's comment count (already in the response —
|
|
4059
|
+
// zero extra egress). A NEUTRAL volume signal only: set solely when the
|
|
4060
|
+
// search item carries a finite count >= 0; a failed/absent value leaves it
|
|
4061
|
+
// undefined (never a fabricated 0), so a render's chip falls through cleanly.
|
|
4062
|
+
commentsAtDiscovery: typeof a.issue.comments === "number" && Number.isFinite(a.issue.comments) && a.issue.comments >= 0 ? a.issue.comments : void 0
|
|
4058
4063
|
},
|
|
4059
4064
|
// Provenance: repo-first discovered items only (label-first omits the field).
|
|
4060
4065
|
...a.discovered ? { discovered: true } : {},
|
|
@@ -4570,6 +4575,15 @@ async function enrichWinnability(jobs, contribute, w) {
|
|
|
4570
4575
|
);
|
|
4571
4576
|
}
|
|
4572
4577
|
}
|
|
4578
|
+
function hasClickableUrl(url) {
|
|
4579
|
+
if (!url) return false;
|
|
4580
|
+
try {
|
|
4581
|
+
const parsed = new URL(url);
|
|
4582
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
4583
|
+
} catch {
|
|
4584
|
+
return false;
|
|
4585
|
+
}
|
|
4586
|
+
}
|
|
4573
4587
|
async function buildIndex(opts) {
|
|
4574
4588
|
const includePartners = opts?.includePartners ?? true;
|
|
4575
4589
|
const publicJobs = await aggregate(opts);
|
|
@@ -4580,6 +4594,7 @@ async function buildIndex(opts) {
|
|
|
4580
4594
|
...opts?.partnerRoles ?? []
|
|
4581
4595
|
];
|
|
4582
4596
|
for (const job of partnerJobs) {
|
|
4597
|
+
if (!hasClickableUrl(job.url)) continue;
|
|
4583
4598
|
if (!seen.has(job.id)) {
|
|
4584
4599
|
seen.add(job.id);
|
|
4585
4600
|
allJobs.push(job);
|
|
@@ -4661,7 +4676,8 @@ async function fetchIssueStatus(fullName, issueNumber, opts = {}) {
|
|
|
4661
4676
|
for (const a of body.assignees ?? []) {
|
|
4662
4677
|
if (a && typeof a.login === "string") assignees.add(a.login);
|
|
4663
4678
|
}
|
|
4664
|
-
|
|
4679
|
+
const comments = typeof body.comments === "number" && Number.isFinite(body.comments) && body.comments >= 0 ? body.comments : null;
|
|
4680
|
+
return { state, assignees: [...assignees], comments };
|
|
4665
4681
|
}
|
|
4666
4682
|
var GITHUB_API3, DEFAULT_ISSUE_STATUS_TIMEOUT_MS;
|
|
4667
4683
|
var init_github_issue_status = __esm({
|
|
@@ -8937,7 +8953,7 @@ var TERMINALHIRE_DIR4, KEY_FILE2, KEYTAR_SERVICE, KEYTAR_ACCOUNT, ALGO2, KEY_BYT
|
|
|
8937
8953
|
var init_crypto_store = __esm({
|
|
8938
8954
|
"src/crypto-store.ts"() {
|
|
8939
8955
|
"use strict";
|
|
8940
|
-
TERMINALHIRE_DIR4 = join5(homedir4(), ".terminalhire");
|
|
8956
|
+
TERMINALHIRE_DIR4 = process.env.TERMINALHIRE_DIR || join5(homedir4(), ".terminalhire");
|
|
8941
8957
|
KEY_FILE2 = join5(TERMINALHIRE_DIR4, "key");
|
|
8942
8958
|
KEYTAR_SERVICE = "terminalhire";
|
|
8943
8959
|
KEYTAR_ACCOUNT = "profile-key";
|
|
@@ -9087,7 +9103,7 @@ var init_profile = __esm({
|
|
|
9087
9103
|
"use strict";
|
|
9088
9104
|
init_src();
|
|
9089
9105
|
init_crypto_store();
|
|
9090
|
-
TERMINALHIRE_DIR5 = join6(homedir5(), ".terminalhire");
|
|
9106
|
+
TERMINALHIRE_DIR5 = process.env.TERMINALHIRE_DIR || join6(homedir5(), ".terminalhire");
|
|
9091
9107
|
PROFILE_FILE = join6(TERMINALHIRE_DIR5, "profile.enc");
|
|
9092
9108
|
profileStore = createEncryptedStore(PROFILE_FILE, {
|
|
9093
9109
|
blank: blankProfile,
|
|
@@ -9726,7 +9742,7 @@ import {
|
|
|
9726
9742
|
} from "fs";
|
|
9727
9743
|
import { join as join3 } from "path";
|
|
9728
9744
|
import { homedir as homedir2 } from "os";
|
|
9729
|
-
var TERMINALHIRE_DIR2 = join3(homedir2(), ".terminalhire");
|
|
9745
|
+
var TERMINALHIRE_DIR2 = process.env.TERMINALHIRE_DIR || join3(homedir2(), ".terminalhire");
|
|
9730
9746
|
var TOKEN_FILE = join3(TERMINALHIRE_DIR2, "github-token.enc");
|
|
9731
9747
|
var KEY_FILE = join3(TERMINALHIRE_DIR2, "key");
|
|
9732
9748
|
var ALGO = "aes-256-gcm";
|
package/dist/bin/jpi-config.js
CHANGED
|
@@ -8,7 +8,7 @@ import { homedir as homedir2 } from "os";
|
|
|
8
8
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
9
9
|
import { join } from "path";
|
|
10
10
|
import { homedir } from "os";
|
|
11
|
-
var TERMINALHIRE_DIR = join(homedir(), ".terminalhire");
|
|
11
|
+
var TERMINALHIRE_DIR = process.env.TERMINALHIRE_DIR || join(homedir(), ".terminalhire");
|
|
12
12
|
var CONFIG_FILE = join(TERMINALHIRE_DIR, "config.json");
|
|
13
13
|
var DEFAULT_CONFIG = {
|
|
14
14
|
nudge: "session",
|
|
@@ -19,8 +19,7 @@ var DEFAULT_CONFIG = {
|
|
|
19
19
|
chatShareActivity: false,
|
|
20
20
|
inboundNudgeMuted: false,
|
|
21
21
|
inboundNudgeDisclosed: false,
|
|
22
|
-
contributeEnabled:
|
|
23
|
-
contributePrompted: false,
|
|
22
|
+
contributeEnabled: true,
|
|
24
23
|
betaOptIn: false,
|
|
25
24
|
lastFullFeedbackAt: null,
|
|
26
25
|
lastPulseAskAt: null,
|
|
@@ -41,6 +40,12 @@ function writeConfig(config) {
|
|
|
41
40
|
mkdirSync(TERMINALHIRE_DIR, { recursive: true });
|
|
42
41
|
const current = readConfig();
|
|
43
42
|
const merged = { ...current, ...config };
|
|
43
|
+
if ("contributePrompted" in merged) {
|
|
44
|
+
if (merged.contributeEnabled === false && !("contributeEnabled" in config)) {
|
|
45
|
+
delete merged.contributeEnabled;
|
|
46
|
+
}
|
|
47
|
+
delete merged.contributePrompted;
|
|
48
|
+
}
|
|
44
49
|
writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
45
50
|
}
|
|
46
51
|
function parseSurfaceMix(raw) {
|
|
@@ -1633,7 +1633,7 @@ var TERMINALHIRE_DIR3, KEY_FILE, KEYTAR_SERVICE, KEYTAR_ACCOUNT, ALGO, KEY_BYTES
|
|
|
1633
1633
|
var init_crypto_store = __esm({
|
|
1634
1634
|
"src/crypto-store.ts"() {
|
|
1635
1635
|
"use strict";
|
|
1636
|
-
TERMINALHIRE_DIR3 = join4(homedir3(), ".terminalhire");
|
|
1636
|
+
TERMINALHIRE_DIR3 = process.env.TERMINALHIRE_DIR || join4(homedir3(), ".terminalhire");
|
|
1637
1637
|
KEY_FILE = join4(TERMINALHIRE_DIR3, "key");
|
|
1638
1638
|
KEYTAR_SERVICE = "terminalhire";
|
|
1639
1639
|
KEYTAR_ACCOUNT = "profile-key";
|
|
@@ -1783,7 +1783,7 @@ var init_profile = __esm({
|
|
|
1783
1783
|
"use strict";
|
|
1784
1784
|
init_src();
|
|
1785
1785
|
init_crypto_store();
|
|
1786
|
-
TERMINALHIRE_DIR4 = join5(homedir4(), ".terminalhire");
|
|
1786
|
+
TERMINALHIRE_DIR4 = process.env.TERMINALHIRE_DIR || join5(homedir4(), ".terminalhire");
|
|
1787
1787
|
PROFILE_FILE = join5(TERMINALHIRE_DIR4, "profile.enc");
|
|
1788
1788
|
profileStore = createEncryptedStore(PROFILE_FILE, {
|
|
1789
1789
|
blank: blankProfile,
|
|
@@ -2239,7 +2239,6 @@ init_src();
|
|
|
2239
2239
|
import { readFileSync as readFileSync6 } from "fs";
|
|
2240
2240
|
import { join as join8 } from "path";
|
|
2241
2241
|
import { homedir as homedir7 } from "os";
|
|
2242
|
-
import { createInterface } from "readline";
|
|
2243
2242
|
|
|
2244
2243
|
// bin/cache-store.js
|
|
2245
2244
|
import { readFileSync as readFileSync2, writeFileSync, mkdirSync, renameSync } from "fs";
|
|
@@ -2275,7 +2274,7 @@ function updateIndexCache(patch) {
|
|
|
2275
2274
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync } from "fs";
|
|
2276
2275
|
import { join as join3 } from "path";
|
|
2277
2276
|
import { homedir as homedir2 } from "os";
|
|
2278
|
-
var TERMINALHIRE_DIR2 = join3(homedir2(), ".terminalhire");
|
|
2277
|
+
var TERMINALHIRE_DIR2 = process.env.TERMINALHIRE_DIR || join3(homedir2(), ".terminalhire");
|
|
2279
2278
|
var CONFIG_FILE = join3(TERMINALHIRE_DIR2, "config.json");
|
|
2280
2279
|
var DEFAULT_CONFIG = {
|
|
2281
2280
|
nudge: "session",
|
|
@@ -2286,8 +2285,7 @@ var DEFAULT_CONFIG = {
|
|
|
2286
2285
|
chatShareActivity: false,
|
|
2287
2286
|
inboundNudgeMuted: false,
|
|
2288
2287
|
inboundNudgeDisclosed: false,
|
|
2289
|
-
contributeEnabled:
|
|
2290
|
-
contributePrompted: false,
|
|
2288
|
+
contributeEnabled: true,
|
|
2291
2289
|
betaOptIn: false,
|
|
2292
2290
|
lastFullFeedbackAt: null,
|
|
2293
2291
|
lastPulseAskAt: null,
|
|
@@ -2304,14 +2302,9 @@ function readConfig() {
|
|
|
2304
2302
|
return { ...DEFAULT_CONFIG };
|
|
2305
2303
|
}
|
|
2306
2304
|
}
|
|
2307
|
-
function writeConfig(config) {
|
|
2308
|
-
mkdirSync2(TERMINALHIRE_DIR2, { recursive: true });
|
|
2309
|
-
const current = readConfig();
|
|
2310
|
-
const merged = { ...current, ...config };
|
|
2311
|
-
writeFileSync2(CONFIG_FILE, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
2312
|
-
}
|
|
2313
2305
|
function isContributeEnabled() {
|
|
2314
|
-
|
|
2306
|
+
const cfg = readConfig();
|
|
2307
|
+
return !(cfg.contributeEnabled === false && !("contributePrompted" in cfg));
|
|
2315
2308
|
}
|
|
2316
2309
|
|
|
2317
2310
|
// bin/sanitize.js
|
|
@@ -2352,7 +2345,7 @@ var INDEX_TTL_MS = 15 * 60 * 1e3;
|
|
|
2352
2345
|
var API_URL = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://terminalhire.com";
|
|
2353
2346
|
var CONTINUITY_RANK_DISABLED = process.env["TERMINALHIRE_NO_CONTINUITY_RANK"] === "1";
|
|
2354
2347
|
var 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 to your stack.";
|
|
2355
|
-
var
|
|
2348
|
+
var CONTRIBUTE_OFF = "Contribute is off \u2014 you set contributeEnabled: false in ~/.terminalhire/config.json.\nRemove that line (or set it to true) to see open issues where a merged PR would count toward your r\xE9sum\xE9.";
|
|
2356
2349
|
var 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.";
|
|
2357
2350
|
function readIndexCache() {
|
|
2358
2351
|
try {
|
|
@@ -2377,15 +2370,6 @@ async function fetchIndex(fetchImpl, useCache = true) {
|
|
|
2377
2370
|
if (useCache) writeIndexCache(index);
|
|
2378
2371
|
return index;
|
|
2379
2372
|
}
|
|
2380
|
-
function defaultPrompt(question) {
|
|
2381
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
2382
|
-
return new Promise((resolve) => {
|
|
2383
|
-
rl.question(question, (answer) => {
|
|
2384
|
-
rl.close();
|
|
2385
|
-
resolve(answer.trim().toLowerCase());
|
|
2386
|
-
});
|
|
2387
|
-
});
|
|
2388
|
-
}
|
|
2389
2373
|
var STRONG_THRESHOLD = 0.5;
|
|
2390
2374
|
if (STRONG_THRESHOLD <= 0) {
|
|
2391
2375
|
throw new Error("STRONG_THRESHOLD must be > 0 or the contested-issue fail-safe breaks");
|
|
@@ -2496,22 +2480,12 @@ ${line3}`;
|
|
|
2496
2480
|
}
|
|
2497
2481
|
async function run(opts = {}) {
|
|
2498
2482
|
const log = opts.log ?? console.log;
|
|
2499
|
-
const isTTY = opts.isTTY ?? Boolean(process.stdin.isTTY);
|
|
2500
|
-
const promptImpl = opts.prompt ?? defaultPrompt;
|
|
2501
2483
|
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
2502
2484
|
const useCache = opts.fetchImpl == null;
|
|
2503
2485
|
try {
|
|
2504
2486
|
if (!isContributeEnabled()) {
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
const yes = answer === "y" || answer === "yes";
|
|
2508
|
-
writeConfig(yes ? { contributeEnabled: true, contributePrompted: true } : { contributePrompted: true });
|
|
2509
|
-
if (!yes) return;
|
|
2510
|
-
} else {
|
|
2511
|
-
log(OPT_IN_PROMPT);
|
|
2512
|
-
writeConfig({ contributePrompted: true });
|
|
2513
|
-
return;
|
|
2514
|
-
}
|
|
2487
|
+
log(CONTRIBUTE_OFF);
|
|
2488
|
+
return;
|
|
2515
2489
|
}
|
|
2516
2490
|
const index = await fetchIndex(fetchImpl, useCache);
|
|
2517
2491
|
const items = Array.isArray(index?.contribute) ? index.contribute : [];
|
package/dist/bin/jpi-devs.js
CHANGED
|
@@ -4054,7 +4054,12 @@ function buildContributionJob(a) {
|
|
|
4054
4054
|
// TERM-27: persist the repo's primary language so project curation can
|
|
4055
4055
|
// exclude the repo's OWN language id (folded into every issue's tags) from
|
|
4056
4056
|
// the distinct-skill signal. Same `repo` used by the tokenize() tag build.
|
|
4057
|
-
language: a.repo.language ?? null
|
|
4057
|
+
language: a.repo.language ?? null,
|
|
4058
|
+
// TERM-35: stamp the search item's comment count (already in the response —
|
|
4059
|
+
// zero extra egress). A NEUTRAL volume signal only: set solely when the
|
|
4060
|
+
// search item carries a finite count >= 0; a failed/absent value leaves it
|
|
4061
|
+
// undefined (never a fabricated 0), so a render's chip falls through cleanly.
|
|
4062
|
+
commentsAtDiscovery: typeof a.issue.comments === "number" && Number.isFinite(a.issue.comments) && a.issue.comments >= 0 ? a.issue.comments : void 0
|
|
4058
4063
|
},
|
|
4059
4064
|
// Provenance: repo-first discovered items only (label-first omits the field).
|
|
4060
4065
|
...a.discovered ? { discovered: true } : {},
|
|
@@ -4570,6 +4575,15 @@ async function enrichWinnability(jobs, contribute, w) {
|
|
|
4570
4575
|
);
|
|
4571
4576
|
}
|
|
4572
4577
|
}
|
|
4578
|
+
function hasClickableUrl(url) {
|
|
4579
|
+
if (!url) return false;
|
|
4580
|
+
try {
|
|
4581
|
+
const parsed = new URL(url);
|
|
4582
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
4583
|
+
} catch {
|
|
4584
|
+
return false;
|
|
4585
|
+
}
|
|
4586
|
+
}
|
|
4573
4587
|
async function buildIndex(opts) {
|
|
4574
4588
|
const includePartners = opts?.includePartners ?? true;
|
|
4575
4589
|
const publicJobs = await aggregate(opts);
|
|
@@ -4580,6 +4594,7 @@ async function buildIndex(opts) {
|
|
|
4580
4594
|
...opts?.partnerRoles ?? []
|
|
4581
4595
|
];
|
|
4582
4596
|
for (const job of partnerJobs) {
|
|
4597
|
+
if (!hasClickableUrl(job.url)) continue;
|
|
4583
4598
|
if (!seen.has(job.id)) {
|
|
4584
4599
|
seen.add(job.id);
|
|
4585
4600
|
allJobs.push(job);
|
|
@@ -4661,7 +4676,8 @@ async function fetchIssueStatus(fullName, issueNumber, opts = {}) {
|
|
|
4661
4676
|
for (const a of body.assignees ?? []) {
|
|
4662
4677
|
if (a && typeof a.login === "string") assignees.add(a.login);
|
|
4663
4678
|
}
|
|
4664
|
-
|
|
4679
|
+
const comments = typeof body.comments === "number" && Number.isFinite(body.comments) && body.comments >= 0 ? body.comments : null;
|
|
4680
|
+
return { state, assignees: [...assignees], comments };
|
|
4665
4681
|
}
|
|
4666
4682
|
var GITHUB_API3, DEFAULT_ISSUE_STATUS_TIMEOUT_MS;
|
|
4667
4683
|
var init_github_issue_status = __esm({
|
|
@@ -8598,7 +8614,7 @@ var TERMINALHIRE_DIR2, KEY_FILE, KEYTAR_SERVICE, KEYTAR_ACCOUNT, ALGO, KEY_BYTES
|
|
|
8598
8614
|
var init_crypto_store = __esm({
|
|
8599
8615
|
"src/crypto-store.ts"() {
|
|
8600
8616
|
"use strict";
|
|
8601
|
-
TERMINALHIRE_DIR2 = join3(homedir2(), ".terminalhire");
|
|
8617
|
+
TERMINALHIRE_DIR2 = process.env.TERMINALHIRE_DIR || join3(homedir2(), ".terminalhire");
|
|
8602
8618
|
KEY_FILE = join3(TERMINALHIRE_DIR2, "key");
|
|
8603
8619
|
KEYTAR_SERVICE = "terminalhire";
|
|
8604
8620
|
KEYTAR_ACCOUNT = "profile-key";
|
|
@@ -8748,7 +8764,7 @@ var init_profile = __esm({
|
|
|
8748
8764
|
"use strict";
|
|
8749
8765
|
init_src();
|
|
8750
8766
|
init_crypto_store();
|
|
8751
|
-
TERMINALHIRE_DIR3 = join4(homedir3(), ".terminalhire");
|
|
8767
|
+
TERMINALHIRE_DIR3 = process.env.TERMINALHIRE_DIR || join4(homedir3(), ".terminalhire");
|
|
8752
8768
|
PROFILE_FILE = join4(TERMINALHIRE_DIR3, "profile.enc");
|
|
8753
8769
|
profileStore = createEncryptedStore(PROFILE_FILE, {
|
|
8754
8770
|
blank: blankProfile,
|
|
@@ -8894,6 +8910,7 @@ function linkTitle(title, url) {
|
|
|
8894
8910
|
// bin/match-slots.js
|
|
8895
8911
|
var ROTATE_WINDOW_MS = 5 * 60 * 1e3;
|
|
8896
8912
|
var ROLE_HEAD_ROTATE_MS = 60 * 60 * 1e3;
|
|
8913
|
+
var LEAD_ROTATE_MS = 25 * 60 * 1e3;
|
|
8897
8914
|
function rotate(list, now, windowMs = ROTATE_WINDOW_MS) {
|
|
8898
8915
|
if (!Array.isArray(list) || list.length === 0) return [];
|
|
8899
8916
|
const idx = Math.floor(now / windowMs) % list.length;
|