terminalhire 0.10.1 → 0.10.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/jpi-chat-read.js +2 -1
- package/dist/bin/jpi-chat.js +2 -1
- package/dist/bin/jpi-config.js +2 -1
- package/dist/bin/jpi-devs.js +17 -1
- package/dist/bin/jpi-dispatch.js +300 -214
- package/dist/bin/jpi-intro.js +3 -8
- package/dist/bin/jpi-link.js +44 -0
- package/dist/bin/jpi-login.js +2 -1
- package/dist/bin/jpi-refresh.js +19 -2
- package/dist/bin/peer-connect-prompt.js +2 -1
- package/dist/src/config.js +2 -1
- package/dist/src/intro.js +3 -8
- package/dist/src/link.js +37 -0
- package/package.json +1 -1
|
@@ -4151,7 +4151,8 @@ var init_config = __esm({
|
|
|
4151
4151
|
peerConnectPrompted: false,
|
|
4152
4152
|
resumePublishPrompted: false,
|
|
4153
4153
|
chatDisclosureAck: false,
|
|
4154
|
-
inboundNudgeMuted: false
|
|
4154
|
+
inboundNudgeMuted: false,
|
|
4155
|
+
inboundNudgeDisclosed: false
|
|
4155
4156
|
};
|
|
4156
4157
|
}
|
|
4157
4158
|
});
|
package/dist/bin/jpi-chat.js
CHANGED
|
@@ -4156,7 +4156,8 @@ var init_config = __esm({
|
|
|
4156
4156
|
peerConnectPrompted: false,
|
|
4157
4157
|
resumePublishPrompted: false,
|
|
4158
4158
|
chatDisclosureAck: false,
|
|
4159
|
-
inboundNudgeMuted: false
|
|
4159
|
+
inboundNudgeMuted: false,
|
|
4160
|
+
inboundNudgeDisclosed: false
|
|
4160
4161
|
};
|
|
4161
4162
|
}
|
|
4162
4163
|
});
|
package/dist/bin/jpi-config.js
CHANGED
package/dist/bin/jpi-devs.js
CHANGED
|
@@ -6251,6 +6251,15 @@ function reportMatched(results, fetchImpl = fetch) {
|
|
|
6251
6251
|
} catch {
|
|
6252
6252
|
}
|
|
6253
6253
|
}
|
|
6254
|
+
function excludeOwnCard(results, ownLogin) {
|
|
6255
|
+
if (!Array.isArray(results)) return results;
|
|
6256
|
+
if (typeof ownLogin !== "string" || ownLogin.length === 0) return results;
|
|
6257
|
+
const own = ownLogin.toLowerCase();
|
|
6258
|
+
return results.filter((r) => {
|
|
6259
|
+
const handle = r?.job?.company;
|
|
6260
|
+
return typeof handle !== "string" || handle.toLowerCase() !== own;
|
|
6261
|
+
});
|
|
6262
|
+
}
|
|
6254
6263
|
|
|
6255
6264
|
// bin/jpi-devs.js
|
|
6256
6265
|
var API_URL2 = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://terminalhire.com";
|
|
@@ -6327,7 +6336,14 @@ async function run() {
|
|
|
6327
6336
|
console.log("\nNo builders or projects published yet. Check back soon \u2014 the directory fills as devs publish.");
|
|
6328
6337
|
return;
|
|
6329
6338
|
}
|
|
6330
|
-
|
|
6339
|
+
let results = match2(fp, cards, SHOW_ALL ? cards.length : LIMIT);
|
|
6340
|
+
let ownLogin;
|
|
6341
|
+
try {
|
|
6342
|
+
const { readProfile: readProfile2 } = await Promise.resolve().then(() => (init_profile(), profile_exports));
|
|
6343
|
+
ownLogin = (await readProfile2())?.github?.login;
|
|
6344
|
+
} catch {
|
|
6345
|
+
}
|
|
6346
|
+
results = excludeOwnCard(results, ownLogin);
|
|
6331
6347
|
if (results.length === 0) {
|
|
6332
6348
|
console.log(`No matching builders or projects for your current ${AS_PROJECT ? "project" : "profile"}.`);
|
|
6333
6349
|
console.log(" Your tags: " + fp.skillTags.join(", "));
|
package/dist/bin/jpi-dispatch.js
CHANGED
|
@@ -9,6 +9,139 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// src/web-session.ts
|
|
13
|
+
var web_session_exports = {};
|
|
14
|
+
__export(web_session_exports, {
|
|
15
|
+
clearWebSessionFile: () => clearWebSessionFile,
|
|
16
|
+
readWebSessionCookie: () => readWebSessionCookie,
|
|
17
|
+
readWebSessionFile: () => readWebSessionFile,
|
|
18
|
+
webSessionFilePath: () => webSessionFilePath,
|
|
19
|
+
writeWebSessionFile: () => writeWebSessionFile
|
|
20
|
+
});
|
|
21
|
+
import {
|
|
22
|
+
chmodSync,
|
|
23
|
+
existsSync,
|
|
24
|
+
mkdirSync,
|
|
25
|
+
readFileSync,
|
|
26
|
+
rmSync,
|
|
27
|
+
writeFileSync
|
|
28
|
+
} from "fs";
|
|
29
|
+
import { homedir } from "os";
|
|
30
|
+
import { join } from "path";
|
|
31
|
+
function terminalhireDir() {
|
|
32
|
+
return join(homedir(), ".terminalhire");
|
|
33
|
+
}
|
|
34
|
+
function webSessionFilePath() {
|
|
35
|
+
return join(terminalhireDir(), "web-session");
|
|
36
|
+
}
|
|
37
|
+
function readWebSessionFile() {
|
|
38
|
+
try {
|
|
39
|
+
const path = webSessionFilePath();
|
|
40
|
+
if (!existsSync(path)) return null;
|
|
41
|
+
const v = readFileSync(path, "utf8").trim();
|
|
42
|
+
return v.length > 0 ? v : null;
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function readWebSessionCookie() {
|
|
48
|
+
const fromFile = readWebSessionFile();
|
|
49
|
+
if (fromFile) return fromFile;
|
|
50
|
+
const env = process.env["TERMINALHIRE_WEB_SESSION"];
|
|
51
|
+
return typeof env === "string" && env.length > 0 ? env : null;
|
|
52
|
+
}
|
|
53
|
+
function writeWebSessionFile(token) {
|
|
54
|
+
mkdirSync(terminalhireDir(), { recursive: true });
|
|
55
|
+
const path = webSessionFilePath();
|
|
56
|
+
writeFileSync(path, token, { mode: 384, encoding: "utf8" });
|
|
57
|
+
try {
|
|
58
|
+
chmodSync(path, 384);
|
|
59
|
+
} catch {
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function clearWebSessionFile() {
|
|
63
|
+
try {
|
|
64
|
+
rmSync(webSessionFilePath());
|
|
65
|
+
} catch {
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
var init_web_session = __esm({
|
|
69
|
+
"src/web-session.ts"() {
|
|
70
|
+
"use strict";
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// src/config.ts
|
|
75
|
+
var config_exports = {};
|
|
76
|
+
__export(config_exports, {
|
|
77
|
+
getNudgeMode: () => getNudgeMode,
|
|
78
|
+
isInboundNudgeMuted: () => isInboundNudgeMuted,
|
|
79
|
+
isPeerConnectEnabled: () => isPeerConnectEnabled,
|
|
80
|
+
parseNudgeMode: () => parseNudgeMode,
|
|
81
|
+
readConfig: () => readConfig,
|
|
82
|
+
writeConfig: () => writeConfig
|
|
83
|
+
});
|
|
84
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
|
|
85
|
+
import { join as join2 } from "path";
|
|
86
|
+
import { homedir as homedir2 } from "os";
|
|
87
|
+
function readConfig() {
|
|
88
|
+
try {
|
|
89
|
+
if (!existsSync2(CONFIG_FILE)) return { ...DEFAULT_CONFIG };
|
|
90
|
+
const raw = readFileSync2(CONFIG_FILE, "utf8");
|
|
91
|
+
const parsed = JSON.parse(raw);
|
|
92
|
+
return { ...DEFAULT_CONFIG, ...parsed };
|
|
93
|
+
} catch {
|
|
94
|
+
return { ...DEFAULT_CONFIG };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function writeConfig(config) {
|
|
98
|
+
mkdirSync2(TERMINALHIRE_DIR, { recursive: true });
|
|
99
|
+
const current = readConfig();
|
|
100
|
+
const merged = { ...current, ...config };
|
|
101
|
+
writeFileSync2(CONFIG_FILE, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
102
|
+
}
|
|
103
|
+
function parseNudgeMode(raw) {
|
|
104
|
+
if (raw === "session" || raw === "always") return raw;
|
|
105
|
+
const m = /^every:(\d+)$/.exec(raw);
|
|
106
|
+
if (m) {
|
|
107
|
+
const n = parseInt(m[1], 10);
|
|
108
|
+
if (n >= 1) return `every:${n}`;
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
function getNudgeMode() {
|
|
113
|
+
const envVal = process.env["TERMINALHIRE_NUDGE"];
|
|
114
|
+
if (envVal) {
|
|
115
|
+
const parsed = parseNudgeMode(envVal);
|
|
116
|
+
if (parsed) return parsed;
|
|
117
|
+
}
|
|
118
|
+
const config = readConfig();
|
|
119
|
+
return config.nudge ?? "session";
|
|
120
|
+
}
|
|
121
|
+
function isPeerConnectEnabled() {
|
|
122
|
+
return readConfig().peerConnect === true;
|
|
123
|
+
}
|
|
124
|
+
function isInboundNudgeMuted() {
|
|
125
|
+
return readConfig().inboundNudgeMuted === true;
|
|
126
|
+
}
|
|
127
|
+
var TERMINALHIRE_DIR, CONFIG_FILE, DEFAULT_CONFIG;
|
|
128
|
+
var init_config = __esm({
|
|
129
|
+
"src/config.ts"() {
|
|
130
|
+
"use strict";
|
|
131
|
+
TERMINALHIRE_DIR = join2(homedir2(), ".terminalhire");
|
|
132
|
+
CONFIG_FILE = join2(TERMINALHIRE_DIR, "config.json");
|
|
133
|
+
DEFAULT_CONFIG = {
|
|
134
|
+
nudge: "session",
|
|
135
|
+
peerConnect: false,
|
|
136
|
+
peerConnectPrompted: false,
|
|
137
|
+
resumePublishPrompted: false,
|
|
138
|
+
chatDisclosureAck: false,
|
|
139
|
+
inboundNudgeMuted: false,
|
|
140
|
+
inboundNudgeDisclosed: false
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
12
145
|
// bin/version-nudge.js
|
|
13
146
|
var version_nudge_exports = {};
|
|
14
147
|
__export(version_nudge_exports, {
|
|
@@ -19,9 +152,9 @@ __export(version_nudge_exports, {
|
|
|
19
152
|
readLatestVersionFromCache: () => readLatestVersionFromCache,
|
|
20
153
|
readLocalVersion: () => readLocalVersion
|
|
21
154
|
});
|
|
22
|
-
import { readFileSync, existsSync } from "fs";
|
|
23
|
-
import { join } from "path";
|
|
24
|
-
import { homedir } from "os";
|
|
155
|
+
import { readFileSync as readFileSync3, existsSync as existsSync3 } from "fs";
|
|
156
|
+
import { join as join3 } from "path";
|
|
157
|
+
import { homedir as homedir3 } from "os";
|
|
25
158
|
import { fileURLToPath } from "url";
|
|
26
159
|
function parseVersion(v) {
|
|
27
160
|
if (typeof v !== "string") return null;
|
|
@@ -46,12 +179,12 @@ function buildStaleNudge(local, latest) {
|
|
|
46
179
|
function readLocalVersion() {
|
|
47
180
|
try {
|
|
48
181
|
const candidates = [
|
|
49
|
-
|
|
50
|
-
|
|
182
|
+
join3(__dirname, "..", "..", "package.json"),
|
|
183
|
+
join3(__dirname, "..", "package.json")
|
|
51
184
|
];
|
|
52
185
|
for (const p of candidates) {
|
|
53
|
-
if (
|
|
54
|
-
const pkg = JSON.parse(
|
|
186
|
+
if (existsSync3(p)) {
|
|
187
|
+
const pkg = JSON.parse(readFileSync3(p, "utf8"));
|
|
55
188
|
if (pkg.version) return pkg.version;
|
|
56
189
|
}
|
|
57
190
|
}
|
|
@@ -61,7 +194,7 @@ function readLocalVersion() {
|
|
|
61
194
|
}
|
|
62
195
|
function readLatestVersionFromCache() {
|
|
63
196
|
try {
|
|
64
|
-
const cache = JSON.parse(
|
|
197
|
+
const cache = JSON.parse(readFileSync3(INDEX_CACHE_FILE, "utf8"));
|
|
65
198
|
const v = cache?.index?.cliVersion;
|
|
66
199
|
return typeof v === "string" ? v : null;
|
|
67
200
|
} catch {
|
|
@@ -78,7 +211,7 @@ var init_version_nudge = __esm({
|
|
|
78
211
|
"bin/version-nudge.js"() {
|
|
79
212
|
"use strict";
|
|
80
213
|
__dirname = fileURLToPath(new URL(".", import.meta.url));
|
|
81
|
-
INDEX_CACHE_FILE =
|
|
214
|
+
INDEX_CACHE_FILE = join3(homedir3(), ".terminalhire", "index-cache.json");
|
|
82
215
|
}
|
|
83
216
|
});
|
|
84
217
|
|
|
@@ -135,14 +268,14 @@ import {
|
|
|
135
268
|
randomBytes
|
|
136
269
|
} from "crypto";
|
|
137
270
|
import {
|
|
138
|
-
readFileSync as
|
|
139
|
-
writeFileSync,
|
|
140
|
-
mkdirSync,
|
|
141
|
-
existsSync as
|
|
142
|
-
rmSync
|
|
271
|
+
readFileSync as readFileSync4,
|
|
272
|
+
writeFileSync as writeFileSync3,
|
|
273
|
+
mkdirSync as mkdirSync3,
|
|
274
|
+
existsSync as existsSync4,
|
|
275
|
+
rmSync as rmSync2
|
|
143
276
|
} from "fs";
|
|
144
|
-
import { join as
|
|
145
|
-
import { homedir as
|
|
277
|
+
import { join as join4 } from "path";
|
|
278
|
+
import { homedir as homedir4 } from "os";
|
|
146
279
|
async function loadKey() {
|
|
147
280
|
try {
|
|
148
281
|
const kt = await import("keytar");
|
|
@@ -153,12 +286,12 @@ async function loadKey() {
|
|
|
153
286
|
return key2;
|
|
154
287
|
} catch {
|
|
155
288
|
}
|
|
156
|
-
|
|
157
|
-
if (
|
|
158
|
-
return Buffer.from(
|
|
289
|
+
mkdirSync3(TERMINALHIRE_DIR2, { recursive: true });
|
|
290
|
+
if (existsSync4(KEY_FILE)) {
|
|
291
|
+
return Buffer.from(readFileSync4(KEY_FILE, "utf8").trim(), "hex");
|
|
159
292
|
}
|
|
160
293
|
const key = randomBytes(KEY_BYTES);
|
|
161
|
-
|
|
294
|
+
writeFileSync3(KEY_FILE, key.toString("hex"), { mode: 384, encoding: "utf8" });
|
|
162
295
|
return key;
|
|
163
296
|
}
|
|
164
297
|
function encrypt(plaintext, key) {
|
|
@@ -178,10 +311,10 @@ function decrypt(blob, key) {
|
|
|
178
311
|
return plain.toString("utf8");
|
|
179
312
|
}
|
|
180
313
|
async function readGitHubToken() {
|
|
181
|
-
if (!
|
|
314
|
+
if (!existsSync4(TOKEN_FILE)) return void 0;
|
|
182
315
|
try {
|
|
183
316
|
const key = await loadKey();
|
|
184
|
-
const raw =
|
|
317
|
+
const raw = readFileSync4(TOKEN_FILE, "utf8");
|
|
185
318
|
const blob = JSON.parse(raw);
|
|
186
319
|
return decrypt(blob, key);
|
|
187
320
|
} catch {
|
|
@@ -189,19 +322,19 @@ async function readGitHubToken() {
|
|
|
189
322
|
}
|
|
190
323
|
}
|
|
191
324
|
async function writeGitHubToken(token) {
|
|
192
|
-
|
|
325
|
+
mkdirSync3(TERMINALHIRE_DIR2, { recursive: true });
|
|
193
326
|
const key = await loadKey();
|
|
194
327
|
const blob = encrypt(token, key);
|
|
195
|
-
|
|
328
|
+
writeFileSync3(TOKEN_FILE, JSON.stringify(blob, null, 2), { encoding: "utf8" });
|
|
196
329
|
}
|
|
197
330
|
async function deleteGitHubToken() {
|
|
198
331
|
try {
|
|
199
|
-
|
|
332
|
+
rmSync2(TOKEN_FILE);
|
|
200
333
|
} catch {
|
|
201
334
|
}
|
|
202
335
|
}
|
|
203
336
|
async function hasGitHubToken() {
|
|
204
|
-
return
|
|
337
|
+
return existsSync4(TOKEN_FILE);
|
|
205
338
|
}
|
|
206
339
|
async function runDeviceFlow() {
|
|
207
340
|
if (process.env["TERMINALHIRE_GITHUB_MOCK"] === "1" || process.env["TERMINALHIRE_GITHUB_MOCK"] === "1" || process.env["JPI_GITHUB_MOCK"] === "1") {
|
|
@@ -313,13 +446,13 @@ async function resolveStoredLogin() {
|
|
|
313
446
|
function sleep(ms) {
|
|
314
447
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
315
448
|
}
|
|
316
|
-
var
|
|
449
|
+
var TERMINALHIRE_DIR2, TOKEN_FILE, KEY_FILE, ALGO, KEY_BYTES, IV_BYTES, GITHUB_SCOPE, DEVICE_CODE_URL, ACCESS_TOKEN_URL, BAKED_IN_CLIENT_ID, MOCK_TOKEN, MOCK_LOGIN;
|
|
317
450
|
var init_github_auth = __esm({
|
|
318
451
|
"src/github-auth.ts"() {
|
|
319
452
|
"use strict";
|
|
320
|
-
|
|
321
|
-
TOKEN_FILE =
|
|
322
|
-
KEY_FILE =
|
|
453
|
+
TERMINALHIRE_DIR2 = join4(homedir4(), ".terminalhire");
|
|
454
|
+
TOKEN_FILE = join4(TERMINALHIRE_DIR2, "github-token.enc");
|
|
455
|
+
KEY_FILE = join4(TERMINALHIRE_DIR2, "key");
|
|
323
456
|
ALGO = "aes-256-gcm";
|
|
324
457
|
KEY_BYTES = 32;
|
|
325
458
|
IV_BYTES = 12;
|
|
@@ -2866,21 +2999,21 @@ var init_feeds = __esm({
|
|
|
2866
2999
|
});
|
|
2867
3000
|
|
|
2868
3001
|
// ../../packages/core/src/partners.ts
|
|
2869
|
-
import { readFileSync as
|
|
2870
|
-
import { join as
|
|
3002
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
3003
|
+
import { join as join5 } from "path";
|
|
2871
3004
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2872
3005
|
function resolveDataPath() {
|
|
2873
3006
|
try {
|
|
2874
3007
|
const dir = fileURLToPath2(new URL("../../../data", import.meta.url));
|
|
2875
|
-
return
|
|
3008
|
+
return join5(dir, "partner-roles.json");
|
|
2876
3009
|
} catch {
|
|
2877
|
-
return
|
|
3010
|
+
return join5(process.cwd(), "data", "partner-roles.json");
|
|
2878
3011
|
}
|
|
2879
3012
|
}
|
|
2880
3013
|
function loadPartnerRoles() {
|
|
2881
3014
|
const filePath = resolveDataPath();
|
|
2882
3015
|
try {
|
|
2883
|
-
const raw =
|
|
3016
|
+
const raw = readFileSync5(filePath, "utf-8");
|
|
2884
3017
|
const parsed = JSON.parse(raw);
|
|
2885
3018
|
if (!Array.isArray(parsed)) {
|
|
2886
3019
|
console.warn("[partners] partner-roles.json is not an array \u2014 skipping");
|
|
@@ -6281,13 +6414,13 @@ import {
|
|
|
6281
6414
|
randomBytes as randomBytes4
|
|
6282
6415
|
} from "crypto";
|
|
6283
6416
|
import {
|
|
6284
|
-
readFileSync as
|
|
6285
|
-
writeFileSync as
|
|
6286
|
-
mkdirSync as
|
|
6287
|
-
existsSync as
|
|
6417
|
+
readFileSync as readFileSync6,
|
|
6418
|
+
writeFileSync as writeFileSync4,
|
|
6419
|
+
mkdirSync as mkdirSync4,
|
|
6420
|
+
existsSync as existsSync5
|
|
6288
6421
|
} from "fs";
|
|
6289
|
-
import { join as
|
|
6290
|
-
import { homedir as
|
|
6422
|
+
import { join as join6 } from "path";
|
|
6423
|
+
import { homedir as homedir5 } from "os";
|
|
6291
6424
|
async function loadKey2() {
|
|
6292
6425
|
try {
|
|
6293
6426
|
const kt = await import("keytar");
|
|
@@ -6300,12 +6433,12 @@ async function loadKey2() {
|
|
|
6300
6433
|
return key2;
|
|
6301
6434
|
} catch {
|
|
6302
6435
|
}
|
|
6303
|
-
|
|
6304
|
-
if (
|
|
6305
|
-
return Buffer.from(
|
|
6436
|
+
mkdirSync4(TERMINALHIRE_DIR3, { recursive: true });
|
|
6437
|
+
if (existsSync5(KEY_FILE2)) {
|
|
6438
|
+
return Buffer.from(readFileSync6(KEY_FILE2, "utf8").trim(), "hex");
|
|
6306
6439
|
}
|
|
6307
6440
|
const key = randomBytes4(KEY_BYTES2);
|
|
6308
|
-
|
|
6441
|
+
writeFileSync4(KEY_FILE2, key.toString("hex"), { mode: 384, encoding: "utf8" });
|
|
6309
6442
|
return key;
|
|
6310
6443
|
}
|
|
6311
6444
|
function encrypt2(plaintext, key) {
|
|
@@ -6363,10 +6496,10 @@ function migrateTagWeights(profile) {
|
|
|
6363
6496
|
}
|
|
6364
6497
|
}
|
|
6365
6498
|
async function readProfile() {
|
|
6366
|
-
if (!
|
|
6499
|
+
if (!existsSync5(PROFILE_FILE)) return blankProfile();
|
|
6367
6500
|
try {
|
|
6368
6501
|
const key = await loadKey2();
|
|
6369
|
-
const raw =
|
|
6502
|
+
const raw = readFileSync6(PROFILE_FILE, "utf8");
|
|
6370
6503
|
const blob = JSON.parse(raw);
|
|
6371
6504
|
const plaintext = decrypt2(blob, key);
|
|
6372
6505
|
const parsed = JSON.parse(plaintext);
|
|
@@ -6377,12 +6510,12 @@ async function readProfile() {
|
|
|
6377
6510
|
}
|
|
6378
6511
|
}
|
|
6379
6512
|
async function writeProfile(profile) {
|
|
6380
|
-
|
|
6513
|
+
mkdirSync4(TERMINALHIRE_DIR3, { recursive: true });
|
|
6381
6514
|
const key = await loadKey2();
|
|
6382
6515
|
profile.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6383
6516
|
profile.skillTags = deriveSkillTags(profile.tagWeights);
|
|
6384
6517
|
const blob = encrypt2(JSON.stringify(profile), key);
|
|
6385
|
-
|
|
6518
|
+
writeFileSync4(PROFILE_FILE, JSON.stringify(blob, null, 2), { encoding: "utf8" });
|
|
6386
6519
|
}
|
|
6387
6520
|
function accumulateSession(profile, tags, isEmployerContext2, inferredSeniority, seniorityIsAuthoritative = false) {
|
|
6388
6521
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -6466,14 +6599,14 @@ function profileToFingerprint(profile) {
|
|
|
6466
6599
|
}
|
|
6467
6600
|
};
|
|
6468
6601
|
}
|
|
6469
|
-
var
|
|
6602
|
+
var TERMINALHIRE_DIR3, PROFILE_FILE, KEY_FILE2, ALGO2, KEY_BYTES2, IV_BYTES2, DECAY_HALF_LIFE_MS, LANGUAGE_TAGS, MIN_FINGERPRINT_SCORE;
|
|
6470
6603
|
var init_profile = __esm({
|
|
6471
6604
|
"src/profile.ts"() {
|
|
6472
6605
|
"use strict";
|
|
6473
6606
|
init_src();
|
|
6474
|
-
|
|
6475
|
-
PROFILE_FILE =
|
|
6476
|
-
KEY_FILE2 =
|
|
6607
|
+
TERMINALHIRE_DIR3 = join6(homedir5(), ".terminalhire");
|
|
6608
|
+
PROFILE_FILE = join6(TERMINALHIRE_DIR3, "profile.enc");
|
|
6609
|
+
KEY_FILE2 = join6(TERMINALHIRE_DIR3, "key");
|
|
6477
6610
|
ALGO2 = "aes-256-gcm";
|
|
6478
6611
|
KEY_BYTES2 = 32;
|
|
6479
6612
|
IV_BYTES2 = 12;
|
|
@@ -6501,49 +6634,6 @@ var init_profile = __esm({
|
|
|
6501
6634
|
}
|
|
6502
6635
|
});
|
|
6503
6636
|
|
|
6504
|
-
// src/config.ts
|
|
6505
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync as existsSync4 } from "fs";
|
|
6506
|
-
import { join as join5 } from "path";
|
|
6507
|
-
import { homedir as homedir4 } from "os";
|
|
6508
|
-
function readConfig() {
|
|
6509
|
-
try {
|
|
6510
|
-
if (!existsSync4(CONFIG_FILE)) return { ...DEFAULT_CONFIG };
|
|
6511
|
-
const raw = readFileSync5(CONFIG_FILE, "utf8");
|
|
6512
|
-
const parsed = JSON.parse(raw);
|
|
6513
|
-
return { ...DEFAULT_CONFIG, ...parsed };
|
|
6514
|
-
} catch {
|
|
6515
|
-
return { ...DEFAULT_CONFIG };
|
|
6516
|
-
}
|
|
6517
|
-
}
|
|
6518
|
-
function writeConfig(config) {
|
|
6519
|
-
mkdirSync3(TERMINALHIRE_DIR3, { recursive: true });
|
|
6520
|
-
const current = readConfig();
|
|
6521
|
-
const merged = { ...current, ...config };
|
|
6522
|
-
writeFileSync3(CONFIG_FILE, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
6523
|
-
}
|
|
6524
|
-
function isPeerConnectEnabled() {
|
|
6525
|
-
return readConfig().peerConnect === true;
|
|
6526
|
-
}
|
|
6527
|
-
function isInboundNudgeMuted() {
|
|
6528
|
-
return readConfig().inboundNudgeMuted === true;
|
|
6529
|
-
}
|
|
6530
|
-
var TERMINALHIRE_DIR3, CONFIG_FILE, DEFAULT_CONFIG;
|
|
6531
|
-
var init_config = __esm({
|
|
6532
|
-
"src/config.ts"() {
|
|
6533
|
-
"use strict";
|
|
6534
|
-
TERMINALHIRE_DIR3 = join5(homedir4(), ".terminalhire");
|
|
6535
|
-
CONFIG_FILE = join5(TERMINALHIRE_DIR3, "config.json");
|
|
6536
|
-
DEFAULT_CONFIG = {
|
|
6537
|
-
nudge: "session",
|
|
6538
|
-
peerConnect: false,
|
|
6539
|
-
peerConnectPrompted: false,
|
|
6540
|
-
resumePublishPrompted: false,
|
|
6541
|
-
chatDisclosureAck: false,
|
|
6542
|
-
inboundNudgeMuted: false
|
|
6543
|
-
};
|
|
6544
|
-
}
|
|
6545
|
-
});
|
|
6546
|
-
|
|
6547
6637
|
// bin/peer-connect-prompt.js
|
|
6548
6638
|
var peer_connect_prompt_exports = {};
|
|
6549
6639
|
__export(peer_connect_prompt_exports, {
|
|
@@ -6816,14 +6906,14 @@ var jpi_jobs_exports = {};
|
|
|
6816
6906
|
__export(jpi_jobs_exports, {
|
|
6817
6907
|
run: () => run2
|
|
6818
6908
|
});
|
|
6819
|
-
import { readFileSync as
|
|
6820
|
-
import { join as
|
|
6821
|
-
import { homedir as
|
|
6909
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync6 } from "fs";
|
|
6910
|
+
import { join as join7 } from "path";
|
|
6911
|
+
import { homedir as homedir6 } from "os";
|
|
6822
6912
|
import { createInterface as createInterface2 } from "readline";
|
|
6823
6913
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
6824
6914
|
function readIndexCache() {
|
|
6825
6915
|
try {
|
|
6826
|
-
const raw =
|
|
6916
|
+
const raw = readFileSync7(INDEX_CACHE_FILE2, "utf8");
|
|
6827
6917
|
const entry = JSON.parse(raw);
|
|
6828
6918
|
if (Date.now() - entry.ts < INDEX_TTL_MS) return entry.index;
|
|
6829
6919
|
return null;
|
|
@@ -6832,8 +6922,8 @@ function readIndexCache() {
|
|
|
6832
6922
|
}
|
|
6833
6923
|
}
|
|
6834
6924
|
function writeIndexCache(index) {
|
|
6835
|
-
|
|
6836
|
-
|
|
6925
|
+
mkdirSync5(TERMINALHIRE_DIR4, { recursive: true });
|
|
6926
|
+
writeFileSync5(INDEX_CACHE_FILE2, JSON.stringify({ ts: Date.now(), index }), "utf8");
|
|
6837
6927
|
}
|
|
6838
6928
|
async function fetchIndex() {
|
|
6839
6929
|
const cached = readIndexCache();
|
|
@@ -6998,10 +7088,10 @@ async function run2() {
|
|
|
6998
7088
|
acceptance: profile.acceptance
|
|
6999
7089
|
});
|
|
7000
7090
|
try {
|
|
7001
|
-
const cacheRaw =
|
|
7091
|
+
const cacheRaw = readFileSync7(INDEX_CACHE_FILE2, "utf8");
|
|
7002
7092
|
const cacheEntry = JSON.parse(cacheRaw);
|
|
7003
7093
|
cacheEntry.matchCount = results.length;
|
|
7004
|
-
|
|
7094
|
+
writeFileSync5(INDEX_CACHE_FILE2, JSON.stringify(cacheEntry), "utf8");
|
|
7005
7095
|
} catch {
|
|
7006
7096
|
}
|
|
7007
7097
|
if (results.length === 0) {
|
|
@@ -7051,8 +7141,8 @@ var init_jpi_jobs = __esm({
|
|
|
7051
7141
|
"bin/jpi-jobs.js"() {
|
|
7052
7142
|
"use strict";
|
|
7053
7143
|
__dirname2 = fileURLToPath3(new URL(".", import.meta.url));
|
|
7054
|
-
TERMINALHIRE_DIR4 =
|
|
7055
|
-
INDEX_CACHE_FILE2 =
|
|
7144
|
+
TERMINALHIRE_DIR4 = join7(homedir6(), ".terminalhire");
|
|
7145
|
+
INDEX_CACHE_FILE2 = join7(TERMINALHIRE_DIR4, "index-cache.json");
|
|
7056
7146
|
INDEX_TTL_MS = 15 * 60 * 1e3;
|
|
7057
7147
|
API_URL = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://terminalhire.com";
|
|
7058
7148
|
DEFAULT_LIMIT = 10;
|
|
@@ -7065,12 +7155,12 @@ var init_jpi_jobs = __esm({
|
|
|
7065
7155
|
});
|
|
7066
7156
|
|
|
7067
7157
|
// bin/directory.js
|
|
7068
|
-
import { readFileSync as
|
|
7069
|
-
import { join as
|
|
7070
|
-
import { homedir as
|
|
7158
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6 } from "fs";
|
|
7159
|
+
import { join as join8 } from "path";
|
|
7160
|
+
import { homedir as homedir7 } from "os";
|
|
7071
7161
|
function readDirectoryCache() {
|
|
7072
7162
|
try {
|
|
7073
|
-
const entry = JSON.parse(
|
|
7163
|
+
const entry = JSON.parse(readFileSync8(DIRECTORY_CACHE_FILE, "utf8"));
|
|
7074
7164
|
if (typeof entry.ts === "number" && Number.isFinite(entry.ts) && Date.now() - entry.ts < INDEX_TTL_MS2) {
|
|
7075
7165
|
return { index: entry.index, ts: entry.ts };
|
|
7076
7166
|
}
|
|
@@ -7080,12 +7170,12 @@ function readDirectoryCache() {
|
|
|
7080
7170
|
}
|
|
7081
7171
|
}
|
|
7082
7172
|
function writeDirectoryCache(index) {
|
|
7083
|
-
|
|
7084
|
-
|
|
7173
|
+
mkdirSync6(TERMINALHIRE_DIR5, { recursive: true });
|
|
7174
|
+
writeFileSync6(DIRECTORY_CACHE_FILE, JSON.stringify({ ts: Date.now(), index }), "utf8");
|
|
7085
7175
|
}
|
|
7086
7176
|
function readProject() {
|
|
7087
7177
|
try {
|
|
7088
|
-
return JSON.parse(
|
|
7178
|
+
return JSON.parse(readFileSync8(PROJECT_FILE, "utf8"));
|
|
7089
7179
|
} catch {
|
|
7090
7180
|
return null;
|
|
7091
7181
|
}
|
|
@@ -7129,13 +7219,22 @@ function reportMatched(results, fetchImpl = fetch) {
|
|
|
7129
7219
|
} catch {
|
|
7130
7220
|
}
|
|
7131
7221
|
}
|
|
7222
|
+
function excludeOwnCard(results, ownLogin) {
|
|
7223
|
+
if (!Array.isArray(results)) return results;
|
|
7224
|
+
if (typeof ownLogin !== "string" || ownLogin.length === 0) return results;
|
|
7225
|
+
const own = ownLogin.toLowerCase();
|
|
7226
|
+
return results.filter((r) => {
|
|
7227
|
+
const handle = r?.job?.company;
|
|
7228
|
+
return typeof handle !== "string" || handle.toLowerCase() !== own;
|
|
7229
|
+
});
|
|
7230
|
+
}
|
|
7132
7231
|
var TERMINALHIRE_DIR5, DIRECTORY_CACHE_FILE, PROJECT_FILE, INDEX_TTL_MS2, API_URL2;
|
|
7133
7232
|
var init_directory2 = __esm({
|
|
7134
7233
|
"bin/directory.js"() {
|
|
7135
7234
|
"use strict";
|
|
7136
|
-
TERMINALHIRE_DIR5 =
|
|
7137
|
-
DIRECTORY_CACHE_FILE =
|
|
7138
|
-
PROJECT_FILE =
|
|
7235
|
+
TERMINALHIRE_DIR5 = join8(homedir7(), ".terminalhire");
|
|
7236
|
+
DIRECTORY_CACHE_FILE = join8(TERMINALHIRE_DIR5, "directory-cache.json");
|
|
7237
|
+
PROJECT_FILE = join8(TERMINALHIRE_DIR5, "project.json");
|
|
7139
7238
|
INDEX_TTL_MS2 = 15 * 60 * 1e3;
|
|
7140
7239
|
API_URL2 = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://terminalhire.com";
|
|
7141
7240
|
}
|
|
@@ -7215,7 +7314,14 @@ async function run3() {
|
|
|
7215
7314
|
console.log("\nNo builders or projects published yet. Check back soon \u2014 the directory fills as devs publish.");
|
|
7216
7315
|
return;
|
|
7217
7316
|
}
|
|
7218
|
-
|
|
7317
|
+
let results = match2(fp, cards, SHOW_ALL2 ? cards.length : LIMIT2);
|
|
7318
|
+
let ownLogin;
|
|
7319
|
+
try {
|
|
7320
|
+
const { readProfile: readProfile2 } = await Promise.resolve().then(() => (init_profile(), profile_exports));
|
|
7321
|
+
ownLogin = (await readProfile2())?.github?.login;
|
|
7322
|
+
} catch {
|
|
7323
|
+
}
|
|
7324
|
+
results = excludeOwnCard(results, ownLogin);
|
|
7219
7325
|
if (results.length === 0) {
|
|
7220
7326
|
console.log(`No matching builders or projects for your current ${AS_PROJECT ? "project" : "profile"}.`);
|
|
7221
7327
|
console.log(" Your tags: " + fp.skillTags.join(", "));
|
|
@@ -7264,13 +7370,13 @@ var jpi_project_exports = {};
|
|
|
7264
7370
|
__export(jpi_project_exports, {
|
|
7265
7371
|
run: () => run4
|
|
7266
7372
|
});
|
|
7267
|
-
import { readFileSync as
|
|
7268
|
-
import { join as
|
|
7269
|
-
import { homedir as
|
|
7373
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "fs";
|
|
7374
|
+
import { join as join9 } from "path";
|
|
7375
|
+
import { homedir as homedir8 } from "os";
|
|
7270
7376
|
import { createInterface as createInterface4 } from "readline";
|
|
7271
7377
|
function readProject2() {
|
|
7272
7378
|
try {
|
|
7273
|
-
return JSON.parse(
|
|
7379
|
+
return JSON.parse(readFileSync9(PROJECT_FILE2, "utf8"));
|
|
7274
7380
|
} catch {
|
|
7275
7381
|
return null;
|
|
7276
7382
|
}
|
|
@@ -7346,8 +7452,8 @@ async function run4() {
|
|
|
7346
7452
|
prefs: {},
|
|
7347
7453
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7348
7454
|
};
|
|
7349
|
-
|
|
7350
|
-
|
|
7455
|
+
mkdirSync7(TERMINALHIRE_DIR6, { recursive: true });
|
|
7456
|
+
writeFileSync7(PROJECT_FILE2, JSON.stringify(project, null, 2), "utf8");
|
|
7351
7457
|
console.log(`
|
|
7352
7458
|
\u2726 Project saved locally (never sent): ${title}`);
|
|
7353
7459
|
console.log(` Skills: ${skillTags.join(", ")}`);
|
|
@@ -7362,8 +7468,8 @@ var TERMINALHIRE_DIR6, PROJECT_FILE2, args3, SHOW, declarationArg;
|
|
|
7362
7468
|
var init_jpi_project = __esm({
|
|
7363
7469
|
"bin/jpi-project.js"() {
|
|
7364
7470
|
"use strict";
|
|
7365
|
-
TERMINALHIRE_DIR6 =
|
|
7366
|
-
PROJECT_FILE2 =
|
|
7471
|
+
TERMINALHIRE_DIR6 = join9(homedir8(), ".terminalhire");
|
|
7472
|
+
PROJECT_FILE2 = join9(TERMINALHIRE_DIR6, "project.json");
|
|
7367
7473
|
args3 = process.argv.slice(2);
|
|
7368
7474
|
SHOW = args3.includes("--show");
|
|
7369
7475
|
declarationArg = args3.filter((a) => !a.startsWith("--")).join(" ").trim();
|
|
@@ -7375,13 +7481,13 @@ var jpi_bounties_exports = {};
|
|
|
7375
7481
|
__export(jpi_bounties_exports, {
|
|
7376
7482
|
run: () => run5
|
|
7377
7483
|
});
|
|
7378
|
-
import { readFileSync as
|
|
7379
|
-
import { join as
|
|
7380
|
-
import { homedir as
|
|
7484
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8 } from "fs";
|
|
7485
|
+
import { join as join10 } from "path";
|
|
7486
|
+
import { homedir as homedir9 } from "os";
|
|
7381
7487
|
import { createInterface as createInterface5 } from "readline";
|
|
7382
7488
|
function readIndexCache2() {
|
|
7383
7489
|
try {
|
|
7384
|
-
const entry = JSON.parse(
|
|
7490
|
+
const entry = JSON.parse(readFileSync10(INDEX_CACHE_FILE3, "utf8"));
|
|
7385
7491
|
if (Date.now() - entry.ts < INDEX_TTL_MS3) return entry.index;
|
|
7386
7492
|
return null;
|
|
7387
7493
|
} catch {
|
|
@@ -7389,8 +7495,8 @@ function readIndexCache2() {
|
|
|
7389
7495
|
}
|
|
7390
7496
|
}
|
|
7391
7497
|
function writeIndexCache2(index) {
|
|
7392
|
-
|
|
7393
|
-
|
|
7498
|
+
mkdirSync8(TERMINALHIRE_DIR7, { recursive: true });
|
|
7499
|
+
writeFileSync8(INDEX_CACHE_FILE3, JSON.stringify({ ts: Date.now(), index }), "utf8");
|
|
7394
7500
|
}
|
|
7395
7501
|
async function fetchIndex2() {
|
|
7396
7502
|
const cached = readIndexCache2();
|
|
@@ -7498,8 +7604,8 @@ var TERMINALHIRE_DIR7, INDEX_CACHE_FILE3, INDEX_TTL_MS3, API_URL4, DEFAULT_LIMIT
|
|
|
7498
7604
|
var init_jpi_bounties = __esm({
|
|
7499
7605
|
"bin/jpi-bounties.js"() {
|
|
7500
7606
|
"use strict";
|
|
7501
|
-
TERMINALHIRE_DIR7 =
|
|
7502
|
-
INDEX_CACHE_FILE3 =
|
|
7607
|
+
TERMINALHIRE_DIR7 = join10(homedir9(), ".terminalhire");
|
|
7608
|
+
INDEX_CACHE_FILE3 = join10(TERMINALHIRE_DIR7, "index-cache.json");
|
|
7503
7609
|
INDEX_TTL_MS3 = 15 * 60 * 1e3;
|
|
7504
7610
|
API_URL4 = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://terminalhire.com";
|
|
7505
7611
|
DEFAULT_LIMIT3 = 15;
|
|
@@ -7524,26 +7630,26 @@ __export(claims_exports, {
|
|
|
7524
7630
|
removeClaim: () => removeClaim,
|
|
7525
7631
|
updateClaim: () => updateClaim
|
|
7526
7632
|
});
|
|
7527
|
-
import { readFileSync as
|
|
7528
|
-
import { join as
|
|
7529
|
-
import { homedir as
|
|
7633
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9, renameSync, existsSync as existsSync7 } from "fs";
|
|
7634
|
+
import { join as join11 } from "path";
|
|
7635
|
+
import { homedir as homedir10 } from "os";
|
|
7530
7636
|
function nowISO() {
|
|
7531
7637
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
7532
7638
|
}
|
|
7533
7639
|
function readClaims() {
|
|
7534
7640
|
try {
|
|
7535
|
-
if (!
|
|
7536
|
-
const data = JSON.parse(
|
|
7641
|
+
if (!existsSync7(CLAIMS_FILE)) return [];
|
|
7642
|
+
const data = JSON.parse(readFileSync11(CLAIMS_FILE, "utf8"));
|
|
7537
7643
|
return Array.isArray(data?.claims) ? data.claims : [];
|
|
7538
7644
|
} catch {
|
|
7539
7645
|
return [];
|
|
7540
7646
|
}
|
|
7541
7647
|
}
|
|
7542
7648
|
function writeClaims(claims) {
|
|
7543
|
-
|
|
7649
|
+
mkdirSync9(TERMINALHIRE_DIR8, { recursive: true });
|
|
7544
7650
|
const tmp = `${CLAIMS_FILE}.tmp`;
|
|
7545
7651
|
const payload = { claims };
|
|
7546
|
-
|
|
7652
|
+
writeFileSync9(tmp, JSON.stringify(payload, null, 2), "utf8");
|
|
7547
7653
|
renameSync(tmp, CLAIMS_FILE);
|
|
7548
7654
|
}
|
|
7549
7655
|
function findClaim(id) {
|
|
@@ -7600,8 +7706,8 @@ var TERMINALHIRE_DIR8, CLAIMS_FILE, TERMINAL_STATES;
|
|
|
7600
7706
|
var init_claims = __esm({
|
|
7601
7707
|
"src/claims.ts"() {
|
|
7602
7708
|
"use strict";
|
|
7603
|
-
TERMINALHIRE_DIR8 =
|
|
7604
|
-
CLAIMS_FILE =
|
|
7709
|
+
TERMINALHIRE_DIR8 = join11(homedir10(), ".terminalhire");
|
|
7710
|
+
CLAIMS_FILE = join11(TERMINALHIRE_DIR8, "claims.json");
|
|
7605
7711
|
TERMINAL_STATES = /* @__PURE__ */ new Set(["merged", "abandoned"]);
|
|
7606
7712
|
}
|
|
7607
7713
|
});
|
|
@@ -7611,9 +7717,9 @@ var jpi_claim_exports = {};
|
|
|
7611
7717
|
__export(jpi_claim_exports, {
|
|
7612
7718
|
run: () => run6
|
|
7613
7719
|
});
|
|
7614
|
-
import { readFileSync as
|
|
7615
|
-
import { join as
|
|
7616
|
-
import { homedir as
|
|
7720
|
+
import { readFileSync as readFileSync12, existsSync as existsSync8 } from "fs";
|
|
7721
|
+
import { join as join12 } from "path";
|
|
7722
|
+
import { homedir as homedir11 } from "os";
|
|
7617
7723
|
import { execFile } from "child_process";
|
|
7618
7724
|
import { promisify } from "util";
|
|
7619
7725
|
import { createInterface as createInterface6 } from "readline";
|
|
@@ -7660,8 +7766,8 @@ function parseRepoFromRemote(url) {
|
|
|
7660
7766
|
}
|
|
7661
7767
|
function findBountyInCache(bountyId) {
|
|
7662
7768
|
try {
|
|
7663
|
-
if (!
|
|
7664
|
-
const entry = JSON.parse(
|
|
7769
|
+
if (!existsSync8(INDEX_CACHE_FILE4)) return null;
|
|
7770
|
+
const entry = JSON.parse(readFileSync12(INDEX_CACHE_FILE4, "utf8"));
|
|
7665
7771
|
const jobs = entry?.index?.jobs ?? [];
|
|
7666
7772
|
const job = jobs.find((j) => j.id === bountyId && j.source === "bounty");
|
|
7667
7773
|
return job ?? null;
|
|
@@ -8169,8 +8275,8 @@ var TERMINALHIRE_DIR9, INDEX_CACHE_FILE4, GH_API, GH_HEADERS, pExecFile, VALUE_F
|
|
|
8169
8275
|
var init_jpi_claim = __esm({
|
|
8170
8276
|
"bin/jpi-claim.js"() {
|
|
8171
8277
|
"use strict";
|
|
8172
|
-
TERMINALHIRE_DIR9 =
|
|
8173
|
-
INDEX_CACHE_FILE4 =
|
|
8278
|
+
TERMINALHIRE_DIR9 = join12(homedir11(), ".terminalhire");
|
|
8279
|
+
INDEX_CACHE_FILE4 = join12(TERMINALHIRE_DIR9, "index-cache.json");
|
|
8174
8280
|
GH_API = "https://api.github.com";
|
|
8175
8281
|
GH_HEADERS = { "User-Agent": "terminalhire-claim", Accept: "application/vnd.github+json" };
|
|
8176
8282
|
pExecFile = promisify(execFile);
|
|
@@ -9024,60 +9130,6 @@ var init_episodes = __esm({
|
|
|
9024
9130
|
}
|
|
9025
9131
|
});
|
|
9026
9132
|
|
|
9027
|
-
// src/web-session.ts
|
|
9028
|
-
import {
|
|
9029
|
-
chmodSync as chmodSync2,
|
|
9030
|
-
existsSync as existsSync8,
|
|
9031
|
-
mkdirSync as mkdirSync9,
|
|
9032
|
-
readFileSync as readFileSync12,
|
|
9033
|
-
rmSync as rmSync2,
|
|
9034
|
-
writeFileSync as writeFileSync9
|
|
9035
|
-
} from "fs";
|
|
9036
|
-
import { homedir as homedir11 } from "os";
|
|
9037
|
-
import { join as join12 } from "path";
|
|
9038
|
-
function terminalhireDir() {
|
|
9039
|
-
return join12(homedir11(), ".terminalhire");
|
|
9040
|
-
}
|
|
9041
|
-
function webSessionFilePath() {
|
|
9042
|
-
return join12(terminalhireDir(), "web-session");
|
|
9043
|
-
}
|
|
9044
|
-
function readWebSessionFile() {
|
|
9045
|
-
try {
|
|
9046
|
-
const path = webSessionFilePath();
|
|
9047
|
-
if (!existsSync8(path)) return null;
|
|
9048
|
-
const v = readFileSync12(path, "utf8").trim();
|
|
9049
|
-
return v.length > 0 ? v : null;
|
|
9050
|
-
} catch {
|
|
9051
|
-
return null;
|
|
9052
|
-
}
|
|
9053
|
-
}
|
|
9054
|
-
function readWebSessionCookie() {
|
|
9055
|
-
const fromFile = readWebSessionFile();
|
|
9056
|
-
if (fromFile) return fromFile;
|
|
9057
|
-
const env = process.env["TERMINALHIRE_WEB_SESSION"];
|
|
9058
|
-
return typeof env === "string" && env.length > 0 ? env : null;
|
|
9059
|
-
}
|
|
9060
|
-
function writeWebSessionFile(token) {
|
|
9061
|
-
mkdirSync9(terminalhireDir(), { recursive: true });
|
|
9062
|
-
const path = webSessionFilePath();
|
|
9063
|
-
writeFileSync9(path, token, { mode: 384, encoding: "utf8" });
|
|
9064
|
-
try {
|
|
9065
|
-
chmodSync2(path, 384);
|
|
9066
|
-
} catch {
|
|
9067
|
-
}
|
|
9068
|
-
}
|
|
9069
|
-
function clearWebSessionFile() {
|
|
9070
|
-
try {
|
|
9071
|
-
rmSync2(webSessionFilePath());
|
|
9072
|
-
} catch {
|
|
9073
|
-
}
|
|
9074
|
-
}
|
|
9075
|
-
var init_web_session = __esm({
|
|
9076
|
-
"src/web-session.ts"() {
|
|
9077
|
-
"use strict";
|
|
9078
|
-
}
|
|
9079
|
-
});
|
|
9080
|
-
|
|
9081
9133
|
// src/trajectory.ts
|
|
9082
9134
|
var trajectory_exports = {};
|
|
9083
9135
|
__export(trajectory_exports, {
|
|
@@ -9633,7 +9685,7 @@ function renderConsentCard2(payload, deps) {
|
|
|
9633
9685
|
}
|
|
9634
9686
|
async function runIntroRequest(args5, overrides) {
|
|
9635
9687
|
const deps = { ...defaultIntroDeps(), ...overrides };
|
|
9636
|
-
const targetLogin = args5.targetLogin?.trim();
|
|
9688
|
+
const targetLogin = args5.targetLogin?.trim().replace(/^@/, "");
|
|
9637
9689
|
if (!targetLogin) {
|
|
9638
9690
|
deps.errorLog('\n Usage: terminalhire intro <github-login> [--note "..."] [--contact <email>] [--name "..."]\n');
|
|
9639
9691
|
deps.exit(1);
|
|
@@ -9652,13 +9704,8 @@ async function runIntroRequest(args5, overrides) {
|
|
|
9652
9704
|
}
|
|
9653
9705
|
const profile = await deps.readProfileContact();
|
|
9654
9706
|
const displayName = (args5.name ?? profile.displayName ?? requesterLogin).trim();
|
|
9655
|
-
const
|
|
9656
|
-
|
|
9657
|
-
deps.errorLog("\n No contact on file. Set one with `terminalhire profile --edit`,");
|
|
9658
|
-
deps.errorLog(" or pass `--contact <email-or-handle>`. Nothing was sent.\n");
|
|
9659
|
-
deps.exit(1);
|
|
9660
|
-
return;
|
|
9661
|
-
}
|
|
9707
|
+
const explicitContact = (args5.contact ?? profile.contactEmail ?? "").trim();
|
|
9708
|
+
const contact = explicitContact || `@${requesterLogin}`;
|
|
9662
9709
|
const payload = buildIntroPayload({
|
|
9663
9710
|
requesterLogin,
|
|
9664
9711
|
requesterDisplayName: displayName,
|
|
@@ -11223,6 +11270,7 @@ async function run10() {
|
|
|
11223
11270
|
console.log("\n terminalhire connect \u2014 find and reach other developers, locally matched:");
|
|
11224
11271
|
console.log(" terminalhire devs Rank opted-in builders & projects for you");
|
|
11225
11272
|
console.log(' terminalhire project "<title>: <skills>" Declare a project to staff');
|
|
11273
|
+
console.log(" terminalhire connect <github-login> Request a consented intro (alias for `intro`)");
|
|
11226
11274
|
console.log(" terminalhire intro <github-login> Request a consented intro (double opt-in)");
|
|
11227
11275
|
console.log(" terminalhire intro --list See intros you have sent + received");
|
|
11228
11276
|
console.log(" terminalhire chat Message your accepted connections");
|
|
@@ -11312,6 +11360,7 @@ function defaultLinkDeps() {
|
|
|
11312
11360
|
},
|
|
11313
11361
|
generateNonce: () => randomBytes5(16).toString("hex"),
|
|
11314
11362
|
persistToken: (token) => writeWebSessionFile(token),
|
|
11363
|
+
markNudgeDisclosed: () => writeConfig({ inboundNudgeDisclosed: true }),
|
|
11315
11364
|
log: (msg) => console.log(msg),
|
|
11316
11365
|
errorLog: (msg) => console.error(msg),
|
|
11317
11366
|
exit: (code) => process.exit(code)
|
|
@@ -11352,6 +11401,10 @@ async function runLink(overrides) {
|
|
|
11352
11401
|
deps.log(" Your spinner will quietly surface incoming connection requests.");
|
|
11353
11402
|
deps.log(" Turn that off any time with `terminalhire connect --mute`.");
|
|
11354
11403
|
deps.log(" Unlink any time with `terminalhire link --logout`.\n");
|
|
11404
|
+
try {
|
|
11405
|
+
deps.markNudgeDisclosed();
|
|
11406
|
+
} catch {
|
|
11407
|
+
}
|
|
11355
11408
|
deps.exit(0);
|
|
11356
11409
|
}
|
|
11357
11410
|
function defaultLinkLogoutDeps() {
|
|
@@ -11396,6 +11449,7 @@ var init_link = __esm({
|
|
|
11396
11449
|
"src/link.ts"() {
|
|
11397
11450
|
"use strict";
|
|
11398
11451
|
init_web_session();
|
|
11452
|
+
init_config();
|
|
11399
11453
|
LINK_BASE3 = "https://www.terminalhire.com";
|
|
11400
11454
|
GH_SESSION_COOKIE5 = "__jpi_gh_session";
|
|
11401
11455
|
LINK_TIMEOUT_MS = 12e4;
|
|
@@ -11828,7 +11882,7 @@ __export(jpi_config_exports, {
|
|
|
11828
11882
|
});
|
|
11829
11883
|
import { join as join18 } from "path";
|
|
11830
11884
|
import { homedir as homedir16 } from "os";
|
|
11831
|
-
function
|
|
11885
|
+
function parseNudgeMode2(raw) {
|
|
11832
11886
|
if (raw === "session" || raw === "always") return raw;
|
|
11833
11887
|
const m = /^every:(\d+)$/.exec(raw);
|
|
11834
11888
|
if (m && parseInt(m[1], 10) >= 1) return raw;
|
|
@@ -11868,7 +11922,7 @@ async function run14() {
|
|
|
11868
11922
|
console.error("Error: --nudge requires a value: session | always | every:N");
|
|
11869
11923
|
process.exit(1);
|
|
11870
11924
|
}
|
|
11871
|
-
const parsed =
|
|
11925
|
+
const parsed = parseNudgeMode2(value);
|
|
11872
11926
|
if (!parsed) {
|
|
11873
11927
|
console.error(`Error: invalid nudge value "${value}". Valid: session | always | every:N`);
|
|
11874
11928
|
process.exit(1);
|
|
@@ -12982,9 +13036,16 @@ async function run18() {
|
|
|
12982
13036
|
const directory = await fetchDirectory({ quiet: true });
|
|
12983
13037
|
const cards = directory?.cards ?? [];
|
|
12984
13038
|
if (cards.length > 0) {
|
|
12985
|
-
const
|
|
13039
|
+
const strongPeers = match2(fp, cards, cards.length).filter(
|
|
12986
13040
|
(r) => r.score >= STRONG_MATCH_THRESHOLD2
|
|
12987
13041
|
);
|
|
13042
|
+
let ownLogin;
|
|
13043
|
+
try {
|
|
13044
|
+
const { readProfile: readProfile2 } = await Promise.resolve().then(() => (init_profile(), profile_exports));
|
|
13045
|
+
ownLogin = (await readProfile2())?.github?.login;
|
|
13046
|
+
} catch {
|
|
13047
|
+
}
|
|
13048
|
+
const peerResults = excludeOwnCard(strongPeers, ownLogin);
|
|
12988
13049
|
topPeers = peerResults.map((r) => ({
|
|
12989
13050
|
login: r.job.company,
|
|
12990
13051
|
// public handle (person login / project owner)
|
|
@@ -13226,6 +13287,7 @@ function readPackageVersion() {
|
|
|
13226
13287
|
}
|
|
13227
13288
|
return "0.1.1";
|
|
13228
13289
|
}
|
|
13290
|
+
var SUBCOMMANDS = ["jobs", "devs", "project", "bounties", "claim", "trajectory", "mirror", "intro", "chat", "connect", "link", "profile", "login", "logout", "learn", "config", "spinner", "sync", "init", "refresh", "save", "saved", "unsave", "help", "--help", "-h", "--version", "-v"];
|
|
13229
13291
|
var firstArg = process.argv[2];
|
|
13230
13292
|
if (!firstArg && !process.stdin.isTTY) {
|
|
13231
13293
|
const { default: childProcess } = await import("child_process");
|
|
@@ -13235,6 +13297,21 @@ if (!firstArg && !process.stdin.isTTY) {
|
|
|
13235
13297
|
});
|
|
13236
13298
|
process.exit(child.status ?? 0);
|
|
13237
13299
|
}
|
|
13300
|
+
if (firstArg && SUBCOMMANDS.includes(firstArg) && process.stdin.isTTY) {
|
|
13301
|
+
try {
|
|
13302
|
+
const { readWebSessionFile: readWebSessionFile2 } = await Promise.resolve().then(() => (init_web_session(), web_session_exports));
|
|
13303
|
+
if (readWebSessionFile2()) {
|
|
13304
|
+
const { readConfig: readConfig3, writeConfig: writeConfig3, isInboundNudgeMuted: isInboundNudgeMuted2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
13305
|
+
if (!readConfig3().inboundNudgeDisclosed && !isInboundNudgeMuted2()) {
|
|
13306
|
+
process.stderr.write(
|
|
13307
|
+
"\n Heads up: terminalhire now surfaces incoming connection requests in your spinner.\n Turn it off any time with `terminalhire connect --mute`.\n\n"
|
|
13308
|
+
);
|
|
13309
|
+
writeConfig3({ inboundNudgeDisclosed: true });
|
|
13310
|
+
}
|
|
13311
|
+
}
|
|
13312
|
+
} catch {
|
|
13313
|
+
}
|
|
13314
|
+
}
|
|
13238
13315
|
if (!firstArg || firstArg === "help" || firstArg === "--help" || firstArg === "-h") {
|
|
13239
13316
|
console.log("");
|
|
13240
13317
|
console.log(`terminalhire v${readPackageVersion()} \u2014 local-first job matching for developers`);
|
|
@@ -13267,6 +13344,7 @@ if (!firstArg || firstArg === "help" || firstArg === "--help" || firstArg === "-
|
|
|
13267
13344
|
console.log(" terminalhire chat <github-login> --read Read a thread inline (last 8; -n N / --all for depth)");
|
|
13268
13345
|
console.log(' terminalhire chat <github-login> --send "\u2026" Send one line to a connection (E2E encrypted)');
|
|
13269
13346
|
console.log(" terminalhire chat <github-login> Open the live E2E chat pane with an accepted connection");
|
|
13347
|
+
console.log(" terminalhire connect <github-login> Request a consented intro (alias for `intro`)");
|
|
13270
13348
|
console.log(" terminalhire connect Connect family overview + inbound-nudge state");
|
|
13271
13349
|
console.log(" terminalhire connect --mute Stop surfacing incoming connection requests in the spinner");
|
|
13272
13350
|
console.log(" terminalhire connect --unmute Resume surfacing incoming connection requests");
|
|
@@ -13370,6 +13448,14 @@ if (firstArg === "chat") {
|
|
|
13370
13448
|
process.exit(0);
|
|
13371
13449
|
}
|
|
13372
13450
|
if (firstArg === "connect") {
|
|
13451
|
+
const sub = process.argv[3];
|
|
13452
|
+
const isConnectOwn = !sub || sub === "--mute" || sub === "--unmute";
|
|
13453
|
+
if (!isConnectOwn) {
|
|
13454
|
+
process.argv.splice(2, 1);
|
|
13455
|
+
const mod3 = await Promise.resolve().then(() => (init_jpi_intro(), jpi_intro_exports));
|
|
13456
|
+
await mod3.run();
|
|
13457
|
+
process.exit(0);
|
|
13458
|
+
}
|
|
13373
13459
|
const mod2 = await Promise.resolve().then(() => (init_jpi_connect(), jpi_connect_exports));
|
|
13374
13460
|
await mod2.run();
|
|
13375
13461
|
process.exit(0);
|
package/dist/bin/jpi-intro.js
CHANGED
|
@@ -1159,7 +1159,7 @@ function renderConsentCard(payload, deps) {
|
|
|
1159
1159
|
}
|
|
1160
1160
|
async function runIntroRequest(args, overrides) {
|
|
1161
1161
|
const deps = { ...defaultIntroDeps(), ...overrides };
|
|
1162
|
-
const targetLogin = args.targetLogin?.trim();
|
|
1162
|
+
const targetLogin = args.targetLogin?.trim().replace(/^@/, "");
|
|
1163
1163
|
if (!targetLogin) {
|
|
1164
1164
|
deps.errorLog('\n Usage: terminalhire intro <github-login> [--note "..."] [--contact <email>] [--name "..."]\n');
|
|
1165
1165
|
deps.exit(1);
|
|
@@ -1178,13 +1178,8 @@ async function runIntroRequest(args, overrides) {
|
|
|
1178
1178
|
}
|
|
1179
1179
|
const profile = await deps.readProfileContact();
|
|
1180
1180
|
const displayName = (args.name ?? profile.displayName ?? requesterLogin).trim();
|
|
1181
|
-
const
|
|
1182
|
-
|
|
1183
|
-
deps.errorLog("\n No contact on file. Set one with `terminalhire profile --edit`,");
|
|
1184
|
-
deps.errorLog(" or pass `--contact <email-or-handle>`. Nothing was sent.\n");
|
|
1185
|
-
deps.exit(1);
|
|
1186
|
-
return;
|
|
1187
|
-
}
|
|
1181
|
+
const explicitContact = (args.contact ?? profile.contactEmail ?? "").trim();
|
|
1182
|
+
const contact = explicitContact || `@${requesterLogin}`;
|
|
1188
1183
|
const payload = buildIntroPayload({
|
|
1189
1184
|
requesterLogin,
|
|
1190
1185
|
requesterDisplayName: displayName,
|
package/dist/bin/jpi-link.js
CHANGED
|
@@ -57,6 +57,44 @@ var init_web_session = __esm({
|
|
|
57
57
|
}
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
+
// src/config.ts
|
|
61
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
|
|
62
|
+
import { join as join2 } from "path";
|
|
63
|
+
import { homedir as homedir2 } from "os";
|
|
64
|
+
function readConfig() {
|
|
65
|
+
try {
|
|
66
|
+
if (!existsSync2(CONFIG_FILE)) return { ...DEFAULT_CONFIG };
|
|
67
|
+
const raw = readFileSync2(CONFIG_FILE, "utf8");
|
|
68
|
+
const parsed = JSON.parse(raw);
|
|
69
|
+
return { ...DEFAULT_CONFIG, ...parsed };
|
|
70
|
+
} catch {
|
|
71
|
+
return { ...DEFAULT_CONFIG };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function writeConfig(config) {
|
|
75
|
+
mkdirSync2(TERMINALHIRE_DIR, { recursive: true });
|
|
76
|
+
const current = readConfig();
|
|
77
|
+
const merged = { ...current, ...config };
|
|
78
|
+
writeFileSync2(CONFIG_FILE, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
79
|
+
}
|
|
80
|
+
var TERMINALHIRE_DIR, CONFIG_FILE, DEFAULT_CONFIG;
|
|
81
|
+
var init_config = __esm({
|
|
82
|
+
"src/config.ts"() {
|
|
83
|
+
"use strict";
|
|
84
|
+
TERMINALHIRE_DIR = join2(homedir2(), ".terminalhire");
|
|
85
|
+
CONFIG_FILE = join2(TERMINALHIRE_DIR, "config.json");
|
|
86
|
+
DEFAULT_CONFIG = {
|
|
87
|
+
nudge: "session",
|
|
88
|
+
peerConnect: false,
|
|
89
|
+
peerConnectPrompted: false,
|
|
90
|
+
resumePublishPrompted: false,
|
|
91
|
+
chatDisclosureAck: false,
|
|
92
|
+
inboundNudgeMuted: false,
|
|
93
|
+
inboundNudgeDisclosed: false
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
60
98
|
// src/open-url.js
|
|
61
99
|
var open_url_exports = {};
|
|
62
100
|
__export(open_url_exports, {
|
|
@@ -165,6 +203,7 @@ function defaultLinkDeps() {
|
|
|
165
203
|
},
|
|
166
204
|
generateNonce: () => randomBytes(16).toString("hex"),
|
|
167
205
|
persistToken: (token) => writeWebSessionFile(token),
|
|
206
|
+
markNudgeDisclosed: () => writeConfig({ inboundNudgeDisclosed: true }),
|
|
168
207
|
log: (msg) => console.log(msg),
|
|
169
208
|
errorLog: (msg) => console.error(msg),
|
|
170
209
|
exit: (code) => process.exit(code)
|
|
@@ -205,6 +244,10 @@ async function runLink(overrides) {
|
|
|
205
244
|
deps.log(" Your spinner will quietly surface incoming connection requests.");
|
|
206
245
|
deps.log(" Turn that off any time with `terminalhire connect --mute`.");
|
|
207
246
|
deps.log(" Unlink any time with `terminalhire link --logout`.\n");
|
|
247
|
+
try {
|
|
248
|
+
deps.markNudgeDisclosed();
|
|
249
|
+
} catch {
|
|
250
|
+
}
|
|
208
251
|
deps.exit(0);
|
|
209
252
|
}
|
|
210
253
|
function defaultLinkLogoutDeps() {
|
|
@@ -249,6 +292,7 @@ var init_link = __esm({
|
|
|
249
292
|
"src/link.ts"() {
|
|
250
293
|
"use strict";
|
|
251
294
|
init_web_session();
|
|
295
|
+
init_config();
|
|
252
296
|
LINK_BASE = "https://www.terminalhire.com";
|
|
253
297
|
GH_SESSION_COOKIE = "__jpi_gh_session";
|
|
254
298
|
LINK_TIMEOUT_MS = 12e4;
|
package/dist/bin/jpi-login.js
CHANGED
|
@@ -6456,7 +6456,8 @@ var init_config = __esm({
|
|
|
6456
6456
|
peerConnectPrompted: false,
|
|
6457
6457
|
resumePublishPrompted: false,
|
|
6458
6458
|
chatDisclosureAck: false,
|
|
6459
|
-
inboundNudgeMuted: false
|
|
6459
|
+
inboundNudgeMuted: false,
|
|
6460
|
+
inboundNudgeDisclosed: false
|
|
6460
6461
|
};
|
|
6461
6462
|
}
|
|
6462
6463
|
});
|
package/dist/bin/jpi-refresh.js
CHANGED
|
@@ -6905,6 +6905,15 @@ function reportMatched(results, fetchImpl = fetch) {
|
|
|
6905
6905
|
} catch {
|
|
6906
6906
|
}
|
|
6907
6907
|
}
|
|
6908
|
+
function excludeOwnCard(results, ownLogin) {
|
|
6909
|
+
if (!Array.isArray(results)) return results;
|
|
6910
|
+
if (typeof ownLogin !== "string" || ownLogin.length === 0) return results;
|
|
6911
|
+
const own = ownLogin.toLowerCase();
|
|
6912
|
+
return results.filter((r) => {
|
|
6913
|
+
const handle = r?.job?.company;
|
|
6914
|
+
return typeof handle !== "string" || handle.toLowerCase() !== own;
|
|
6915
|
+
});
|
|
6916
|
+
}
|
|
6908
6917
|
|
|
6909
6918
|
// src/config.ts
|
|
6910
6919
|
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync } from "fs";
|
|
@@ -6918,7 +6927,8 @@ var DEFAULT_CONFIG = {
|
|
|
6918
6927
|
peerConnectPrompted: false,
|
|
6919
6928
|
resumePublishPrompted: false,
|
|
6920
6929
|
chatDisclosureAck: false,
|
|
6921
|
-
inboundNudgeMuted: false
|
|
6930
|
+
inboundNudgeMuted: false,
|
|
6931
|
+
inboundNudgeDisclosed: false
|
|
6922
6932
|
};
|
|
6923
6933
|
function readConfig() {
|
|
6924
6934
|
try {
|
|
@@ -7040,9 +7050,16 @@ async function run() {
|
|
|
7040
7050
|
const directory = await fetchDirectory({ quiet: true });
|
|
7041
7051
|
const cards = directory?.cards ?? [];
|
|
7042
7052
|
if (cards.length > 0) {
|
|
7043
|
-
const
|
|
7053
|
+
const strongPeers = match2(fp, cards, cards.length).filter(
|
|
7044
7054
|
(r) => r.score >= STRONG_MATCH_THRESHOLD2
|
|
7045
7055
|
);
|
|
7056
|
+
let ownLogin;
|
|
7057
|
+
try {
|
|
7058
|
+
const { readProfile: readProfile2 } = await Promise.resolve().then(() => (init_profile(), profile_exports));
|
|
7059
|
+
ownLogin = (await readProfile2())?.github?.login;
|
|
7060
|
+
} catch {
|
|
7061
|
+
}
|
|
7062
|
+
const peerResults = excludeOwnCard(strongPeers, ownLogin);
|
|
7046
7063
|
topPeers = peerResults.map((r) => ({
|
|
7047
7064
|
login: r.job.company,
|
|
7048
7065
|
// public handle (person login / project owner)
|
package/dist/src/config.js
CHANGED
package/dist/src/intro.js
CHANGED
|
@@ -1152,7 +1152,7 @@ function renderConsentCard(payload, deps) {
|
|
|
1152
1152
|
}
|
|
1153
1153
|
async function runIntroRequest(args, overrides) {
|
|
1154
1154
|
const deps = { ...defaultIntroDeps(), ...overrides };
|
|
1155
|
-
const targetLogin = args.targetLogin?.trim();
|
|
1155
|
+
const targetLogin = args.targetLogin?.trim().replace(/^@/, "");
|
|
1156
1156
|
if (!targetLogin) {
|
|
1157
1157
|
deps.errorLog('\n Usage: terminalhire intro <github-login> [--note "..."] [--contact <email>] [--name "..."]\n');
|
|
1158
1158
|
deps.exit(1);
|
|
@@ -1171,13 +1171,8 @@ async function runIntroRequest(args, overrides) {
|
|
|
1171
1171
|
}
|
|
1172
1172
|
const profile = await deps.readProfileContact();
|
|
1173
1173
|
const displayName = (args.name ?? profile.displayName ?? requesterLogin).trim();
|
|
1174
|
-
const
|
|
1175
|
-
|
|
1176
|
-
deps.errorLog("\n No contact on file. Set one with `terminalhire profile --edit`,");
|
|
1177
|
-
deps.errorLog(" or pass `--contact <email-or-handle>`. Nothing was sent.\n");
|
|
1178
|
-
deps.exit(1);
|
|
1179
|
-
return;
|
|
1180
|
-
}
|
|
1174
|
+
const explicitContact = (args.contact ?? profile.contactEmail ?? "").trim();
|
|
1175
|
+
const contact = explicitContact || `@${requesterLogin}`;
|
|
1181
1176
|
const payload = buildIntroPayload({
|
|
1182
1177
|
requesterLogin,
|
|
1183
1178
|
requesterDisplayName: displayName,
|
package/dist/src/link.js
CHANGED
|
@@ -88,6 +88,38 @@ function clearWebSessionFile() {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
// src/config.ts
|
|
92
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
|
|
93
|
+
import { join as join2 } from "path";
|
|
94
|
+
import { homedir as homedir2 } from "os";
|
|
95
|
+
var TERMINALHIRE_DIR = join2(homedir2(), ".terminalhire");
|
|
96
|
+
var CONFIG_FILE = join2(TERMINALHIRE_DIR, "config.json");
|
|
97
|
+
var DEFAULT_CONFIG = {
|
|
98
|
+
nudge: "session",
|
|
99
|
+
peerConnect: false,
|
|
100
|
+
peerConnectPrompted: false,
|
|
101
|
+
resumePublishPrompted: false,
|
|
102
|
+
chatDisclosureAck: false,
|
|
103
|
+
inboundNudgeMuted: false,
|
|
104
|
+
inboundNudgeDisclosed: false
|
|
105
|
+
};
|
|
106
|
+
function readConfig() {
|
|
107
|
+
try {
|
|
108
|
+
if (!existsSync2(CONFIG_FILE)) return { ...DEFAULT_CONFIG };
|
|
109
|
+
const raw = readFileSync2(CONFIG_FILE, "utf8");
|
|
110
|
+
const parsed = JSON.parse(raw);
|
|
111
|
+
return { ...DEFAULT_CONFIG, ...parsed };
|
|
112
|
+
} catch {
|
|
113
|
+
return { ...DEFAULT_CONFIG };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function writeConfig(config) {
|
|
117
|
+
mkdirSync2(TERMINALHIRE_DIR, { recursive: true });
|
|
118
|
+
const current = readConfig();
|
|
119
|
+
const merged = { ...current, ...config };
|
|
120
|
+
writeFileSync2(CONFIG_FILE, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
121
|
+
}
|
|
122
|
+
|
|
91
123
|
// src/link.ts
|
|
92
124
|
var LINK_BASE = "https://www.terminalhire.com";
|
|
93
125
|
var GH_SESSION_COOKIE = "__jpi_gh_session";
|
|
@@ -169,6 +201,7 @@ function defaultLinkDeps() {
|
|
|
169
201
|
},
|
|
170
202
|
generateNonce: () => randomBytes(16).toString("hex"),
|
|
171
203
|
persistToken: (token) => writeWebSessionFile(token),
|
|
204
|
+
markNudgeDisclosed: () => writeConfig({ inboundNudgeDisclosed: true }),
|
|
172
205
|
log: (msg) => console.log(msg),
|
|
173
206
|
errorLog: (msg) => console.error(msg),
|
|
174
207
|
exit: (code) => process.exit(code)
|
|
@@ -209,6 +242,10 @@ async function runLink(overrides) {
|
|
|
209
242
|
deps.log(" Your spinner will quietly surface incoming connection requests.");
|
|
210
243
|
deps.log(" Turn that off any time with `terminalhire connect --mute`.");
|
|
211
244
|
deps.log(" Unlink any time with `terminalhire link --logout`.\n");
|
|
245
|
+
try {
|
|
246
|
+
deps.markNudgeDisclosed();
|
|
247
|
+
} catch {
|
|
248
|
+
}
|
|
212
249
|
deps.exit(0);
|
|
213
250
|
}
|
|
214
251
|
function defaultLinkLogoutDeps() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "terminalhire",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.3",
|
|
4
4
|
"description": "Local-first job matching for developers — ambient job matches in the Claude Code spinner. Matching runs on your machine; your profile never leaves it.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|