terminalhire 0.9.2 → 0.10.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/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-dispatch.js +436 -252
- package/dist/bin/jpi-intro.js +17 -2
- package/dist/bin/jpi-link.js +2 -0
- package/dist/bin/jpi-login.js +2 -1
- package/dist/bin/jpi-refresh.js +203 -63
- package/dist/bin/jpi-spinner.js +11 -2
- package/dist/bin/jpi.js +23 -4
- package/dist/bin/peer-connect-prompt.js +2 -1
- package/dist/bin/spinner.js +12 -2
- package/dist/bin/version-nudge.js +65 -0
- package/dist/src/config.js +6 -1
- package/dist/src/intro.js +17 -2
- package/dist/src/link.js +2 -0
- package/package.json +1 -1
package/dist/bin/jpi-dispatch.js
CHANGED
|
@@ -9,6 +9,79 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// bin/version-nudge.js
|
|
13
|
+
var version_nudge_exports = {};
|
|
14
|
+
__export(version_nudge_exports, {
|
|
15
|
+
buildStaleNudge: () => buildStaleNudge,
|
|
16
|
+
cachedStaleNudge: () => cachedStaleNudge,
|
|
17
|
+
compareVersions: () => compareVersions,
|
|
18
|
+
parseVersion: () => parseVersion,
|
|
19
|
+
readLatestVersionFromCache: () => readLatestVersionFromCache,
|
|
20
|
+
readLocalVersion: () => readLocalVersion
|
|
21
|
+
});
|
|
22
|
+
import { readFileSync, existsSync } from "fs";
|
|
23
|
+
import { join } from "path";
|
|
24
|
+
import { homedir } from "os";
|
|
25
|
+
import { fileURLToPath } from "url";
|
|
26
|
+
function parseVersion(v) {
|
|
27
|
+
if (typeof v !== "string") return null;
|
|
28
|
+
const m = v.trim().replace(/^v/, "").match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
29
|
+
if (!m) return null;
|
|
30
|
+
return [Number(m[1]), Number(m[2]), Number(m[3])];
|
|
31
|
+
}
|
|
32
|
+
function compareVersions(a, b) {
|
|
33
|
+
const pa = parseVersion(a);
|
|
34
|
+
const pb = parseVersion(b);
|
|
35
|
+
if (!pa || !pb) return null;
|
|
36
|
+
for (let i = 0; i < 3; i++) {
|
|
37
|
+
if (pa[i] < pb[i]) return -1;
|
|
38
|
+
if (pa[i] > pb[i]) return 1;
|
|
39
|
+
}
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
function buildStaleNudge(local, latest) {
|
|
43
|
+
if (compareVersions(local, latest) !== -1) return null;
|
|
44
|
+
return `your terminalhire CLI is behind (${local} \u2192 ${latest}) \u2014 npm i -g terminalhire@latest`;
|
|
45
|
+
}
|
|
46
|
+
function readLocalVersion() {
|
|
47
|
+
try {
|
|
48
|
+
const candidates = [
|
|
49
|
+
join(__dirname, "..", "..", "package.json"),
|
|
50
|
+
join(__dirname, "..", "package.json")
|
|
51
|
+
];
|
|
52
|
+
for (const p of candidates) {
|
|
53
|
+
if (existsSync(p)) {
|
|
54
|
+
const pkg = JSON.parse(readFileSync(p, "utf8"));
|
|
55
|
+
if (pkg.version) return pkg.version;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
} catch {
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
function readLatestVersionFromCache() {
|
|
63
|
+
try {
|
|
64
|
+
const cache = JSON.parse(readFileSync(INDEX_CACHE_FILE, "utf8"));
|
|
65
|
+
const v = cache?.index?.cliVersion;
|
|
66
|
+
return typeof v === "string" ? v : null;
|
|
67
|
+
} catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function cachedStaleNudge(localVersion) {
|
|
72
|
+
const local = localVersion ?? readLocalVersion();
|
|
73
|
+
if (!local) return null;
|
|
74
|
+
return buildStaleNudge(local, readLatestVersionFromCache());
|
|
75
|
+
}
|
|
76
|
+
var __dirname, INDEX_CACHE_FILE;
|
|
77
|
+
var init_version_nudge = __esm({
|
|
78
|
+
"bin/version-nudge.js"() {
|
|
79
|
+
"use strict";
|
|
80
|
+
__dirname = fileURLToPath(new URL(".", import.meta.url));
|
|
81
|
+
INDEX_CACHE_FILE = join(homedir(), ".terminalhire", "index-cache.json");
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
12
85
|
// src/open-url.js
|
|
13
86
|
var open_url_exports = {};
|
|
14
87
|
__export(open_url_exports, {
|
|
@@ -62,14 +135,14 @@ import {
|
|
|
62
135
|
randomBytes
|
|
63
136
|
} from "crypto";
|
|
64
137
|
import {
|
|
65
|
-
readFileSync,
|
|
138
|
+
readFileSync as readFileSync2,
|
|
66
139
|
writeFileSync,
|
|
67
140
|
mkdirSync,
|
|
68
|
-
existsSync,
|
|
141
|
+
existsSync as existsSync2,
|
|
69
142
|
rmSync
|
|
70
143
|
} from "fs";
|
|
71
|
-
import { join } from "path";
|
|
72
|
-
import { homedir } from "os";
|
|
144
|
+
import { join as join2 } from "path";
|
|
145
|
+
import { homedir as homedir2 } from "os";
|
|
73
146
|
async function loadKey() {
|
|
74
147
|
try {
|
|
75
148
|
const kt = await import("keytar");
|
|
@@ -81,8 +154,8 @@ async function loadKey() {
|
|
|
81
154
|
} catch {
|
|
82
155
|
}
|
|
83
156
|
mkdirSync(TERMINALHIRE_DIR, { recursive: true });
|
|
84
|
-
if (
|
|
85
|
-
return Buffer.from(
|
|
157
|
+
if (existsSync2(KEY_FILE)) {
|
|
158
|
+
return Buffer.from(readFileSync2(KEY_FILE, "utf8").trim(), "hex");
|
|
86
159
|
}
|
|
87
160
|
const key = randomBytes(KEY_BYTES);
|
|
88
161
|
writeFileSync(KEY_FILE, key.toString("hex"), { mode: 384, encoding: "utf8" });
|
|
@@ -105,10 +178,10 @@ function decrypt(blob, key) {
|
|
|
105
178
|
return plain.toString("utf8");
|
|
106
179
|
}
|
|
107
180
|
async function readGitHubToken() {
|
|
108
|
-
if (!
|
|
181
|
+
if (!existsSync2(TOKEN_FILE)) return void 0;
|
|
109
182
|
try {
|
|
110
183
|
const key = await loadKey();
|
|
111
|
-
const raw =
|
|
184
|
+
const raw = readFileSync2(TOKEN_FILE, "utf8");
|
|
112
185
|
const blob = JSON.parse(raw);
|
|
113
186
|
return decrypt(blob, key);
|
|
114
187
|
} catch {
|
|
@@ -128,7 +201,7 @@ async function deleteGitHubToken() {
|
|
|
128
201
|
}
|
|
129
202
|
}
|
|
130
203
|
async function hasGitHubToken() {
|
|
131
|
-
return
|
|
204
|
+
return existsSync2(TOKEN_FILE);
|
|
132
205
|
}
|
|
133
206
|
async function runDeviceFlow() {
|
|
134
207
|
if (process.env["TERMINALHIRE_GITHUB_MOCK"] === "1" || process.env["TERMINALHIRE_GITHUB_MOCK"] === "1" || process.env["JPI_GITHUB_MOCK"] === "1") {
|
|
@@ -244,9 +317,9 @@ var TERMINALHIRE_DIR, TOKEN_FILE, KEY_FILE, ALGO, KEY_BYTES, IV_BYTES, GITHUB_SC
|
|
|
244
317
|
var init_github_auth = __esm({
|
|
245
318
|
"src/github-auth.ts"() {
|
|
246
319
|
"use strict";
|
|
247
|
-
TERMINALHIRE_DIR =
|
|
248
|
-
TOKEN_FILE =
|
|
249
|
-
KEY_FILE =
|
|
320
|
+
TERMINALHIRE_DIR = join2(homedir2(), ".terminalhire");
|
|
321
|
+
TOKEN_FILE = join2(TERMINALHIRE_DIR, "github-token.enc");
|
|
322
|
+
KEY_FILE = join2(TERMINALHIRE_DIR, "key");
|
|
250
323
|
ALGO = "aes-256-gcm";
|
|
251
324
|
KEY_BYTES = 32;
|
|
252
325
|
IV_BYTES = 12;
|
|
@@ -1943,14 +2016,14 @@ async function mapWithConcurrency(items, limit, fn) {
|
|
|
1943
2016
|
if (items.length === 0) return results;
|
|
1944
2017
|
const workers = Math.max(1, Math.min(Math.floor(limit) || 1, items.length));
|
|
1945
2018
|
let next = 0;
|
|
1946
|
-
async function
|
|
2019
|
+
async function run20() {
|
|
1947
2020
|
for (; ; ) {
|
|
1948
2021
|
const i = next++;
|
|
1949
2022
|
if (i >= items.length) return;
|
|
1950
2023
|
results[i] = await fn(items[i], i);
|
|
1951
2024
|
}
|
|
1952
2025
|
}
|
|
1953
|
-
await Promise.all(Array.from({ length: workers },
|
|
2026
|
+
await Promise.all(Array.from({ length: workers }, run20));
|
|
1954
2027
|
return results;
|
|
1955
2028
|
}
|
|
1956
2029
|
var init_concurrency = __esm({
|
|
@@ -2793,21 +2866,21 @@ var init_feeds = __esm({
|
|
|
2793
2866
|
});
|
|
2794
2867
|
|
|
2795
2868
|
// ../../packages/core/src/partners.ts
|
|
2796
|
-
import { readFileSync as
|
|
2797
|
-
import { join as
|
|
2798
|
-
import { fileURLToPath } from "url";
|
|
2869
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
2870
|
+
import { join as join3 } from "path";
|
|
2871
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2799
2872
|
function resolveDataPath() {
|
|
2800
2873
|
try {
|
|
2801
|
-
const dir =
|
|
2802
|
-
return
|
|
2874
|
+
const dir = fileURLToPath2(new URL("../../../data", import.meta.url));
|
|
2875
|
+
return join3(dir, "partner-roles.json");
|
|
2803
2876
|
} catch {
|
|
2804
|
-
return
|
|
2877
|
+
return join3(process.cwd(), "data", "partner-roles.json");
|
|
2805
2878
|
}
|
|
2806
2879
|
}
|
|
2807
2880
|
function loadPartnerRoles() {
|
|
2808
2881
|
const filePath = resolveDataPath();
|
|
2809
2882
|
try {
|
|
2810
|
-
const raw =
|
|
2883
|
+
const raw = readFileSync3(filePath, "utf-8");
|
|
2811
2884
|
const parsed = JSON.parse(raw);
|
|
2812
2885
|
if (!Array.isArray(parsed)) {
|
|
2813
2886
|
console.warn("[partners] partner-roles.json is not an array \u2014 skipping");
|
|
@@ -6208,13 +6281,13 @@ import {
|
|
|
6208
6281
|
randomBytes as randomBytes4
|
|
6209
6282
|
} from "crypto";
|
|
6210
6283
|
import {
|
|
6211
|
-
readFileSync as
|
|
6284
|
+
readFileSync as readFileSync4,
|
|
6212
6285
|
writeFileSync as writeFileSync2,
|
|
6213
6286
|
mkdirSync as mkdirSync2,
|
|
6214
|
-
existsSync as
|
|
6287
|
+
existsSync as existsSync3
|
|
6215
6288
|
} from "fs";
|
|
6216
|
-
import { join as
|
|
6217
|
-
import { homedir as
|
|
6289
|
+
import { join as join4 } from "path";
|
|
6290
|
+
import { homedir as homedir3 } from "os";
|
|
6218
6291
|
async function loadKey2() {
|
|
6219
6292
|
try {
|
|
6220
6293
|
const kt = await import("keytar");
|
|
@@ -6228,8 +6301,8 @@ async function loadKey2() {
|
|
|
6228
6301
|
} catch {
|
|
6229
6302
|
}
|
|
6230
6303
|
mkdirSync2(TERMINALHIRE_DIR2, { recursive: true });
|
|
6231
|
-
if (
|
|
6232
|
-
return Buffer.from(
|
|
6304
|
+
if (existsSync3(KEY_FILE2)) {
|
|
6305
|
+
return Buffer.from(readFileSync4(KEY_FILE2, "utf8").trim(), "hex");
|
|
6233
6306
|
}
|
|
6234
6307
|
const key = randomBytes4(KEY_BYTES2);
|
|
6235
6308
|
writeFileSync2(KEY_FILE2, key.toString("hex"), { mode: 384, encoding: "utf8" });
|
|
@@ -6290,10 +6363,10 @@ function migrateTagWeights(profile) {
|
|
|
6290
6363
|
}
|
|
6291
6364
|
}
|
|
6292
6365
|
async function readProfile() {
|
|
6293
|
-
if (!
|
|
6366
|
+
if (!existsSync3(PROFILE_FILE)) return blankProfile();
|
|
6294
6367
|
try {
|
|
6295
6368
|
const key = await loadKey2();
|
|
6296
|
-
const raw =
|
|
6369
|
+
const raw = readFileSync4(PROFILE_FILE, "utf8");
|
|
6297
6370
|
const blob = JSON.parse(raw);
|
|
6298
6371
|
const plaintext = decrypt2(blob, key);
|
|
6299
6372
|
const parsed = JSON.parse(plaintext);
|
|
@@ -6398,9 +6471,9 @@ var init_profile = __esm({
|
|
|
6398
6471
|
"src/profile.ts"() {
|
|
6399
6472
|
"use strict";
|
|
6400
6473
|
init_src();
|
|
6401
|
-
TERMINALHIRE_DIR2 =
|
|
6402
|
-
PROFILE_FILE =
|
|
6403
|
-
KEY_FILE2 =
|
|
6474
|
+
TERMINALHIRE_DIR2 = join4(homedir3(), ".terminalhire");
|
|
6475
|
+
PROFILE_FILE = join4(TERMINALHIRE_DIR2, "profile.enc");
|
|
6476
|
+
KEY_FILE2 = join4(TERMINALHIRE_DIR2, "key");
|
|
6404
6477
|
ALGO2 = "aes-256-gcm";
|
|
6405
6478
|
KEY_BYTES2 = 32;
|
|
6406
6479
|
IV_BYTES2 = 12;
|
|
@@ -6429,13 +6502,13 @@ var init_profile = __esm({
|
|
|
6429
6502
|
});
|
|
6430
6503
|
|
|
6431
6504
|
// src/config.ts
|
|
6432
|
-
import { readFileSync as
|
|
6433
|
-
import { join as
|
|
6434
|
-
import { homedir as
|
|
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";
|
|
6435
6508
|
function readConfig() {
|
|
6436
6509
|
try {
|
|
6437
|
-
if (!
|
|
6438
|
-
const raw =
|
|
6510
|
+
if (!existsSync4(CONFIG_FILE)) return { ...DEFAULT_CONFIG };
|
|
6511
|
+
const raw = readFileSync5(CONFIG_FILE, "utf8");
|
|
6439
6512
|
const parsed = JSON.parse(raw);
|
|
6440
6513
|
return { ...DEFAULT_CONFIG, ...parsed };
|
|
6441
6514
|
} catch {
|
|
@@ -6451,18 +6524,22 @@ function writeConfig(config) {
|
|
|
6451
6524
|
function isPeerConnectEnabled() {
|
|
6452
6525
|
return readConfig().peerConnect === true;
|
|
6453
6526
|
}
|
|
6527
|
+
function isInboundNudgeMuted() {
|
|
6528
|
+
return readConfig().inboundNudgeMuted === true;
|
|
6529
|
+
}
|
|
6454
6530
|
var TERMINALHIRE_DIR3, CONFIG_FILE, DEFAULT_CONFIG;
|
|
6455
6531
|
var init_config = __esm({
|
|
6456
6532
|
"src/config.ts"() {
|
|
6457
6533
|
"use strict";
|
|
6458
|
-
TERMINALHIRE_DIR3 =
|
|
6459
|
-
CONFIG_FILE =
|
|
6534
|
+
TERMINALHIRE_DIR3 = join5(homedir4(), ".terminalhire");
|
|
6535
|
+
CONFIG_FILE = join5(TERMINALHIRE_DIR3, "config.json");
|
|
6460
6536
|
DEFAULT_CONFIG = {
|
|
6461
6537
|
nudge: "session",
|
|
6462
6538
|
peerConnect: false,
|
|
6463
6539
|
peerConnectPrompted: false,
|
|
6464
6540
|
resumePublishPrompted: false,
|
|
6465
|
-
chatDisclosureAck: false
|
|
6541
|
+
chatDisclosureAck: false,
|
|
6542
|
+
inboundNudgeMuted: false
|
|
6466
6543
|
};
|
|
6467
6544
|
}
|
|
6468
6545
|
});
|
|
@@ -6612,12 +6689,12 @@ async function runLogin() {
|
|
|
6612
6689
|
let ghProfile;
|
|
6613
6690
|
if (process.env["TERMINALHIRE_GITHUB_MOCK"] === "1" || process.env["JPI_GITHUB_MOCK"] === "1") {
|
|
6614
6691
|
const { createRequire: createRequire2 } = await import("module");
|
|
6615
|
-
const { fileURLToPath:
|
|
6616
|
-
const { join:
|
|
6617
|
-
const
|
|
6618
|
-
const fixturePath =
|
|
6619
|
-
const { readFileSync:
|
|
6620
|
-
ghProfile = JSON.parse(
|
|
6692
|
+
const { fileURLToPath: fileURLToPath8 } = await import("url");
|
|
6693
|
+
const { join: join26, dirname: dirname3 } = await import("path");
|
|
6694
|
+
const __dirname7 = fileURLToPath8(new URL(".", import.meta.url));
|
|
6695
|
+
const fixturePath = join26(__dirname7, "../../fixtures/github-sample.json");
|
|
6696
|
+
const { readFileSync: readFileSync24 } = await import("fs");
|
|
6697
|
+
ghProfile = JSON.parse(readFileSync24(fixturePath, "utf8"));
|
|
6621
6698
|
} else {
|
|
6622
6699
|
ghProfile = await fetchGitHubProfile2(login, token);
|
|
6623
6700
|
}
|
|
@@ -6739,14 +6816,14 @@ var jpi_jobs_exports = {};
|
|
|
6739
6816
|
__export(jpi_jobs_exports, {
|
|
6740
6817
|
run: () => run2
|
|
6741
6818
|
});
|
|
6742
|
-
import { readFileSync as
|
|
6743
|
-
import { join as
|
|
6744
|
-
import { homedir as
|
|
6819
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync5 } from "fs";
|
|
6820
|
+
import { join as join6 } from "path";
|
|
6821
|
+
import { homedir as homedir5 } from "os";
|
|
6745
6822
|
import { createInterface as createInterface2 } from "readline";
|
|
6746
|
-
import { fileURLToPath as
|
|
6823
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
6747
6824
|
function readIndexCache() {
|
|
6748
6825
|
try {
|
|
6749
|
-
const raw =
|
|
6826
|
+
const raw = readFileSync6(INDEX_CACHE_FILE2, "utf8");
|
|
6750
6827
|
const entry = JSON.parse(raw);
|
|
6751
6828
|
if (Date.now() - entry.ts < INDEX_TTL_MS) return entry.index;
|
|
6752
6829
|
return null;
|
|
@@ -6756,7 +6833,7 @@ function readIndexCache() {
|
|
|
6756
6833
|
}
|
|
6757
6834
|
function writeIndexCache(index) {
|
|
6758
6835
|
mkdirSync4(TERMINALHIRE_DIR4, { recursive: true });
|
|
6759
|
-
writeFileSync4(
|
|
6836
|
+
writeFileSync4(INDEX_CACHE_FILE2, JSON.stringify({ ts: Date.now(), index }), "utf8");
|
|
6760
6837
|
}
|
|
6761
6838
|
async function fetchIndex() {
|
|
6762
6839
|
const cached = readIndexCache();
|
|
@@ -6921,10 +6998,10 @@ async function run2() {
|
|
|
6921
6998
|
acceptance: profile.acceptance
|
|
6922
6999
|
});
|
|
6923
7000
|
try {
|
|
6924
|
-
const cacheRaw =
|
|
7001
|
+
const cacheRaw = readFileSync6(INDEX_CACHE_FILE2, "utf8");
|
|
6925
7002
|
const cacheEntry = JSON.parse(cacheRaw);
|
|
6926
7003
|
cacheEntry.matchCount = results.length;
|
|
6927
|
-
writeFileSync4(
|
|
7004
|
+
writeFileSync4(INDEX_CACHE_FILE2, JSON.stringify(cacheEntry), "utf8");
|
|
6928
7005
|
} catch {
|
|
6929
7006
|
}
|
|
6930
7007
|
if (results.length === 0) {
|
|
@@ -6969,13 +7046,13 @@ Open this URL to apply directly (no data shared):
|
|
|
6969
7046
|
process.exit(1);
|
|
6970
7047
|
}
|
|
6971
7048
|
}
|
|
6972
|
-
var
|
|
7049
|
+
var __dirname2, TERMINALHIRE_DIR4, INDEX_CACHE_FILE2, INDEX_TTL_MS, API_URL, DEFAULT_LIMIT, args, limitArg, LIMIT, REMOTE_ONLY, SHOW_ALL;
|
|
6973
7050
|
var init_jpi_jobs = __esm({
|
|
6974
7051
|
"bin/jpi-jobs.js"() {
|
|
6975
7052
|
"use strict";
|
|
6976
|
-
|
|
6977
|
-
TERMINALHIRE_DIR4 =
|
|
6978
|
-
|
|
7053
|
+
__dirname2 = fileURLToPath3(new URL(".", import.meta.url));
|
|
7054
|
+
TERMINALHIRE_DIR4 = join6(homedir5(), ".terminalhire");
|
|
7055
|
+
INDEX_CACHE_FILE2 = join6(TERMINALHIRE_DIR4, "index-cache.json");
|
|
6979
7056
|
INDEX_TTL_MS = 15 * 60 * 1e3;
|
|
6980
7057
|
API_URL = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://terminalhire.com";
|
|
6981
7058
|
DEFAULT_LIMIT = 10;
|
|
@@ -6988,12 +7065,12 @@ var init_jpi_jobs = __esm({
|
|
|
6988
7065
|
});
|
|
6989
7066
|
|
|
6990
7067
|
// bin/directory.js
|
|
6991
|
-
import { readFileSync as
|
|
6992
|
-
import { join as
|
|
6993
|
-
import { homedir as
|
|
7068
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5 } from "fs";
|
|
7069
|
+
import { join as join7 } from "path";
|
|
7070
|
+
import { homedir as homedir6 } from "os";
|
|
6994
7071
|
function readDirectoryCache() {
|
|
6995
7072
|
try {
|
|
6996
|
-
const entry = JSON.parse(
|
|
7073
|
+
const entry = JSON.parse(readFileSync7(DIRECTORY_CACHE_FILE, "utf8"));
|
|
6997
7074
|
if (typeof entry.ts === "number" && Number.isFinite(entry.ts) && Date.now() - entry.ts < INDEX_TTL_MS2) {
|
|
6998
7075
|
return { index: entry.index, ts: entry.ts };
|
|
6999
7076
|
}
|
|
@@ -7008,7 +7085,7 @@ function writeDirectoryCache(index) {
|
|
|
7008
7085
|
}
|
|
7009
7086
|
function readProject() {
|
|
7010
7087
|
try {
|
|
7011
|
-
return JSON.parse(
|
|
7088
|
+
return JSON.parse(readFileSync7(PROJECT_FILE, "utf8"));
|
|
7012
7089
|
} catch {
|
|
7013
7090
|
return null;
|
|
7014
7091
|
}
|
|
@@ -7056,9 +7133,9 @@ var TERMINALHIRE_DIR5, DIRECTORY_CACHE_FILE, PROJECT_FILE, INDEX_TTL_MS2, API_UR
|
|
|
7056
7133
|
var init_directory2 = __esm({
|
|
7057
7134
|
"bin/directory.js"() {
|
|
7058
7135
|
"use strict";
|
|
7059
|
-
TERMINALHIRE_DIR5 =
|
|
7060
|
-
DIRECTORY_CACHE_FILE =
|
|
7061
|
-
PROJECT_FILE =
|
|
7136
|
+
TERMINALHIRE_DIR5 = join7(homedir6(), ".terminalhire");
|
|
7137
|
+
DIRECTORY_CACHE_FILE = join7(TERMINALHIRE_DIR5, "directory-cache.json");
|
|
7138
|
+
PROJECT_FILE = join7(TERMINALHIRE_DIR5, "project.json");
|
|
7062
7139
|
INDEX_TTL_MS2 = 15 * 60 * 1e3;
|
|
7063
7140
|
API_URL2 = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://terminalhire.com";
|
|
7064
7141
|
}
|
|
@@ -7187,13 +7264,13 @@ var jpi_project_exports = {};
|
|
|
7187
7264
|
__export(jpi_project_exports, {
|
|
7188
7265
|
run: () => run4
|
|
7189
7266
|
});
|
|
7190
|
-
import { readFileSync as
|
|
7191
|
-
import { join as
|
|
7192
|
-
import { homedir as
|
|
7267
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6 } from "fs";
|
|
7268
|
+
import { join as join8 } from "path";
|
|
7269
|
+
import { homedir as homedir7 } from "os";
|
|
7193
7270
|
import { createInterface as createInterface4 } from "readline";
|
|
7194
7271
|
function readProject2() {
|
|
7195
7272
|
try {
|
|
7196
|
-
return JSON.parse(
|
|
7273
|
+
return JSON.parse(readFileSync8(PROJECT_FILE2, "utf8"));
|
|
7197
7274
|
} catch {
|
|
7198
7275
|
return null;
|
|
7199
7276
|
}
|
|
@@ -7285,8 +7362,8 @@ var TERMINALHIRE_DIR6, PROJECT_FILE2, args3, SHOW, declarationArg;
|
|
|
7285
7362
|
var init_jpi_project = __esm({
|
|
7286
7363
|
"bin/jpi-project.js"() {
|
|
7287
7364
|
"use strict";
|
|
7288
|
-
TERMINALHIRE_DIR6 =
|
|
7289
|
-
PROJECT_FILE2 =
|
|
7365
|
+
TERMINALHIRE_DIR6 = join8(homedir7(), ".terminalhire");
|
|
7366
|
+
PROJECT_FILE2 = join8(TERMINALHIRE_DIR6, "project.json");
|
|
7290
7367
|
args3 = process.argv.slice(2);
|
|
7291
7368
|
SHOW = args3.includes("--show");
|
|
7292
7369
|
declarationArg = args3.filter((a) => !a.startsWith("--")).join(" ").trim();
|
|
@@ -7298,13 +7375,13 @@ var jpi_bounties_exports = {};
|
|
|
7298
7375
|
__export(jpi_bounties_exports, {
|
|
7299
7376
|
run: () => run5
|
|
7300
7377
|
});
|
|
7301
|
-
import { readFileSync as
|
|
7302
|
-
import { join as
|
|
7303
|
-
import { homedir as
|
|
7378
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "fs";
|
|
7379
|
+
import { join as join9 } from "path";
|
|
7380
|
+
import { homedir as homedir8 } from "os";
|
|
7304
7381
|
import { createInterface as createInterface5 } from "readline";
|
|
7305
7382
|
function readIndexCache2() {
|
|
7306
7383
|
try {
|
|
7307
|
-
const entry = JSON.parse(
|
|
7384
|
+
const entry = JSON.parse(readFileSync9(INDEX_CACHE_FILE3, "utf8"));
|
|
7308
7385
|
if (Date.now() - entry.ts < INDEX_TTL_MS3) return entry.index;
|
|
7309
7386
|
return null;
|
|
7310
7387
|
} catch {
|
|
@@ -7313,7 +7390,7 @@ function readIndexCache2() {
|
|
|
7313
7390
|
}
|
|
7314
7391
|
function writeIndexCache2(index) {
|
|
7315
7392
|
mkdirSync7(TERMINALHIRE_DIR7, { recursive: true });
|
|
7316
|
-
writeFileSync7(
|
|
7393
|
+
writeFileSync7(INDEX_CACHE_FILE3, JSON.stringify({ ts: Date.now(), index }), "utf8");
|
|
7317
7394
|
}
|
|
7318
7395
|
async function fetchIndex2() {
|
|
7319
7396
|
const cached = readIndexCache2();
|
|
@@ -7417,12 +7494,12 @@ Open this to claim/work the bounty (you go straight to the source \u2014 we neve
|
|
|
7417
7494
|
process.exit(1);
|
|
7418
7495
|
}
|
|
7419
7496
|
}
|
|
7420
|
-
var TERMINALHIRE_DIR7,
|
|
7497
|
+
var TERMINALHIRE_DIR7, INDEX_CACHE_FILE3, INDEX_TTL_MS3, API_URL4, DEFAULT_LIMIT3, args4, limitArg3, LIMIT3, PRICED_ONLY, SHOW_ALL3, WINNABLE_ONLY, EFFORT_LABEL;
|
|
7421
7498
|
var init_jpi_bounties = __esm({
|
|
7422
7499
|
"bin/jpi-bounties.js"() {
|
|
7423
7500
|
"use strict";
|
|
7424
|
-
TERMINALHIRE_DIR7 =
|
|
7425
|
-
|
|
7501
|
+
TERMINALHIRE_DIR7 = join9(homedir8(), ".terminalhire");
|
|
7502
|
+
INDEX_CACHE_FILE3 = join9(TERMINALHIRE_DIR7, "index-cache.json");
|
|
7426
7503
|
INDEX_TTL_MS3 = 15 * 60 * 1e3;
|
|
7427
7504
|
API_URL4 = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://terminalhire.com";
|
|
7428
7505
|
DEFAULT_LIMIT3 = 15;
|
|
@@ -7447,16 +7524,16 @@ __export(claims_exports, {
|
|
|
7447
7524
|
removeClaim: () => removeClaim,
|
|
7448
7525
|
updateClaim: () => updateClaim
|
|
7449
7526
|
});
|
|
7450
|
-
import { readFileSync as
|
|
7451
|
-
import { join as
|
|
7452
|
-
import { homedir as
|
|
7527
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, renameSync, existsSync as existsSync6 } from "fs";
|
|
7528
|
+
import { join as join10 } from "path";
|
|
7529
|
+
import { homedir as homedir9 } from "os";
|
|
7453
7530
|
function nowISO() {
|
|
7454
7531
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
7455
7532
|
}
|
|
7456
7533
|
function readClaims() {
|
|
7457
7534
|
try {
|
|
7458
|
-
if (!
|
|
7459
|
-
const data = JSON.parse(
|
|
7535
|
+
if (!existsSync6(CLAIMS_FILE)) return [];
|
|
7536
|
+
const data = JSON.parse(readFileSync10(CLAIMS_FILE, "utf8"));
|
|
7460
7537
|
return Array.isArray(data?.claims) ? data.claims : [];
|
|
7461
7538
|
} catch {
|
|
7462
7539
|
return [];
|
|
@@ -7523,8 +7600,8 @@ var TERMINALHIRE_DIR8, CLAIMS_FILE, TERMINAL_STATES;
|
|
|
7523
7600
|
var init_claims = __esm({
|
|
7524
7601
|
"src/claims.ts"() {
|
|
7525
7602
|
"use strict";
|
|
7526
|
-
TERMINALHIRE_DIR8 =
|
|
7527
|
-
CLAIMS_FILE =
|
|
7603
|
+
TERMINALHIRE_DIR8 = join10(homedir9(), ".terminalhire");
|
|
7604
|
+
CLAIMS_FILE = join10(TERMINALHIRE_DIR8, "claims.json");
|
|
7528
7605
|
TERMINAL_STATES = /* @__PURE__ */ new Set(["merged", "abandoned"]);
|
|
7529
7606
|
}
|
|
7530
7607
|
});
|
|
@@ -7534,9 +7611,9 @@ var jpi_claim_exports = {};
|
|
|
7534
7611
|
__export(jpi_claim_exports, {
|
|
7535
7612
|
run: () => run6
|
|
7536
7613
|
});
|
|
7537
|
-
import { readFileSync as
|
|
7538
|
-
import { join as
|
|
7539
|
-
import { homedir as
|
|
7614
|
+
import { readFileSync as readFileSync11, existsSync as existsSync7 } from "fs";
|
|
7615
|
+
import { join as join11 } from "path";
|
|
7616
|
+
import { homedir as homedir10 } from "os";
|
|
7540
7617
|
import { execFile } from "child_process";
|
|
7541
7618
|
import { promisify } from "util";
|
|
7542
7619
|
import { createInterface as createInterface6 } from "readline";
|
|
@@ -7583,8 +7660,8 @@ function parseRepoFromRemote(url) {
|
|
|
7583
7660
|
}
|
|
7584
7661
|
function findBountyInCache(bountyId) {
|
|
7585
7662
|
try {
|
|
7586
|
-
if (!
|
|
7587
|
-
const entry = JSON.parse(
|
|
7663
|
+
if (!existsSync7(INDEX_CACHE_FILE4)) return null;
|
|
7664
|
+
const entry = JSON.parse(readFileSync11(INDEX_CACHE_FILE4, "utf8"));
|
|
7588
7665
|
const jobs = entry?.index?.jobs ?? [];
|
|
7589
7666
|
const job = jobs.find((j) => j.id === bountyId && j.source === "bounty");
|
|
7590
7667
|
return job ?? null;
|
|
@@ -8088,12 +8165,12 @@ async function run6() {
|
|
|
8088
8165
|
process.exit(1);
|
|
8089
8166
|
}
|
|
8090
8167
|
}
|
|
8091
|
-
var TERMINALHIRE_DIR9,
|
|
8168
|
+
var TERMINALHIRE_DIR9, INDEX_CACHE_FILE4, GH_API, GH_HEADERS, pExecFile, VALUE_FLAGS;
|
|
8092
8169
|
var init_jpi_claim = __esm({
|
|
8093
8170
|
"bin/jpi-claim.js"() {
|
|
8094
8171
|
"use strict";
|
|
8095
|
-
TERMINALHIRE_DIR9 =
|
|
8096
|
-
|
|
8172
|
+
TERMINALHIRE_DIR9 = join11(homedir10(), ".terminalhire");
|
|
8173
|
+
INDEX_CACHE_FILE4 = join11(TERMINALHIRE_DIR9, "index-cache.json");
|
|
8097
8174
|
GH_API = "https://api.github.com";
|
|
8098
8175
|
GH_HEADERS = { "User-Agent": "terminalhire-claim", Accept: "application/vnd.github+json" };
|
|
8099
8176
|
pExecFile = promisify(execFile);
|
|
@@ -8377,7 +8454,7 @@ function finalize(build) {
|
|
|
8377
8454
|
};
|
|
8378
8455
|
}
|
|
8379
8456
|
function reconstruct(files, opts = {}) {
|
|
8380
|
-
const
|
|
8457
|
+
const join26 = opts.joinSidechains !== false;
|
|
8381
8458
|
const mains = [];
|
|
8382
8459
|
const sidechains = [];
|
|
8383
8460
|
for (const file of files) {
|
|
@@ -8402,7 +8479,7 @@ function reconstruct(files, opts = {}) {
|
|
|
8402
8479
|
}
|
|
8403
8480
|
const orphanedSidechainPaths = [];
|
|
8404
8481
|
const joinedPaths = /* @__PURE__ */ new Set();
|
|
8405
|
-
if (
|
|
8482
|
+
if (join26) {
|
|
8406
8483
|
const sidechainsBySession = /* @__PURE__ */ new Map();
|
|
8407
8484
|
for (const sc of sidechains) {
|
|
8408
8485
|
const acc = sidechainsBySession.get(sc.sessionId) ?? [];
|
|
@@ -8889,12 +8966,12 @@ function deriveRecoveryDepth(episodes, nodesByUuid) {
|
|
|
8889
8966
|
continue;
|
|
8890
8967
|
}
|
|
8891
8968
|
spansConsidered++;
|
|
8892
|
-
let
|
|
8969
|
+
let run20 = 0;
|
|
8893
8970
|
const closeChain = () => {
|
|
8894
|
-
if (
|
|
8971
|
+
if (run20 > 0) {
|
|
8895
8972
|
recoveryChains++;
|
|
8896
|
-
totalDepth +=
|
|
8897
|
-
|
|
8973
|
+
totalDepth += run20;
|
|
8974
|
+
run20 = 0;
|
|
8898
8975
|
}
|
|
8899
8976
|
};
|
|
8900
8977
|
for (const uuid of episode.mainNodeUuids) {
|
|
@@ -8903,9 +8980,9 @@ function deriveRecoveryDepth(episodes, nodesByUuid) {
|
|
|
8903
8980
|
continue;
|
|
8904
8981
|
}
|
|
8905
8982
|
if (node.kind === "tool_result" /* ToolResult */ && node.isError) {
|
|
8906
|
-
|
|
8907
|
-
if (
|
|
8908
|
-
maxConsecutiveErrors =
|
|
8983
|
+
run20++;
|
|
8984
|
+
if (run20 > maxConsecutiveErrors) {
|
|
8985
|
+
maxConsecutiveErrors = run20;
|
|
8909
8986
|
}
|
|
8910
8987
|
} else if (node.kind === "tool_result" /* ToolResult */ && !node.isError) {
|
|
8911
8988
|
closeChain();
|
|
@@ -8950,25 +9027,25 @@ var init_episodes = __esm({
|
|
|
8950
9027
|
// src/web-session.ts
|
|
8951
9028
|
import {
|
|
8952
9029
|
chmodSync as chmodSync2,
|
|
8953
|
-
existsSync as
|
|
9030
|
+
existsSync as existsSync8,
|
|
8954
9031
|
mkdirSync as mkdirSync9,
|
|
8955
|
-
readFileSync as
|
|
9032
|
+
readFileSync as readFileSync12,
|
|
8956
9033
|
rmSync as rmSync2,
|
|
8957
9034
|
writeFileSync as writeFileSync9
|
|
8958
9035
|
} from "fs";
|
|
8959
|
-
import { homedir as
|
|
8960
|
-
import { join as
|
|
9036
|
+
import { homedir as homedir11 } from "os";
|
|
9037
|
+
import { join as join12 } from "path";
|
|
8961
9038
|
function terminalhireDir() {
|
|
8962
|
-
return
|
|
9039
|
+
return join12(homedir11(), ".terminalhire");
|
|
8963
9040
|
}
|
|
8964
9041
|
function webSessionFilePath() {
|
|
8965
|
-
return
|
|
9042
|
+
return join12(terminalhireDir(), "web-session");
|
|
8966
9043
|
}
|
|
8967
9044
|
function readWebSessionFile() {
|
|
8968
9045
|
try {
|
|
8969
9046
|
const path = webSessionFilePath();
|
|
8970
|
-
if (!
|
|
8971
|
-
const v =
|
|
9047
|
+
if (!existsSync8(path)) return null;
|
|
9048
|
+
const v = readFileSync12(path, "utf8").trim();
|
|
8972
9049
|
return v.length > 0 ? v : null;
|
|
8973
9050
|
} catch {
|
|
8974
9051
|
return null;
|
|
@@ -9010,14 +9087,14 @@ __export(trajectory_exports, {
|
|
|
9010
9087
|
runTrajectoryPush: () => runTrajectoryPush
|
|
9011
9088
|
});
|
|
9012
9089
|
import {
|
|
9013
|
-
existsSync as
|
|
9090
|
+
existsSync as existsSync9,
|
|
9014
9091
|
mkdirSync as mkdirSync10,
|
|
9015
|
-
readFileSync as
|
|
9092
|
+
readFileSync as readFileSync13,
|
|
9016
9093
|
readdirSync,
|
|
9017
9094
|
writeFileSync as writeFileSync10
|
|
9018
9095
|
} from "fs";
|
|
9019
|
-
import { homedir as
|
|
9020
|
-
import { join as
|
|
9096
|
+
import { homedir as homedir12 } from "os";
|
|
9097
|
+
import { join as join13 } from "path";
|
|
9021
9098
|
function isRecord4(value) {
|
|
9022
9099
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9023
9100
|
}
|
|
@@ -9049,7 +9126,7 @@ function findJsonlFiles(dir) {
|
|
|
9049
9126
|
return out;
|
|
9050
9127
|
}
|
|
9051
9128
|
for (const entry of entries) {
|
|
9052
|
-
const full =
|
|
9129
|
+
const full = join13(dir, entry.name);
|
|
9053
9130
|
if (entry.isDirectory()) {
|
|
9054
9131
|
out.push(...findJsonlFiles(full));
|
|
9055
9132
|
} else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
@@ -9063,7 +9140,7 @@ function loadCorpus(paths) {
|
|
|
9063
9140
|
for (const path of paths) {
|
|
9064
9141
|
let text;
|
|
9065
9142
|
try {
|
|
9066
|
-
text =
|
|
9143
|
+
text = readFileSync13(path, "utf8");
|
|
9067
9144
|
} catch {
|
|
9068
9145
|
continue;
|
|
9069
9146
|
}
|
|
@@ -9162,10 +9239,10 @@ function renderMarkdown(view) {
|
|
|
9162
9239
|
return lines.join("\n");
|
|
9163
9240
|
}
|
|
9164
9241
|
function writeExportArtifacts(score, markdown) {
|
|
9165
|
-
const dir =
|
|
9242
|
+
const dir = join13(homedir12(), ".terminalhire");
|
|
9166
9243
|
mkdirSync10(dir, { recursive: true });
|
|
9167
|
-
const jsonPath =
|
|
9168
|
-
const mdPath =
|
|
9244
|
+
const jsonPath = join13(dir, "trajectory-export.json");
|
|
9245
|
+
const mdPath = join13(dir, "trajectory-export.md");
|
|
9169
9246
|
writeFileSync10(jsonPath, JSON.stringify(score, null, 2) + "\n", "utf8");
|
|
9170
9247
|
writeFileSync10(mdPath, markdown, "utf8");
|
|
9171
9248
|
return { jsonPath, mdPath };
|
|
@@ -9186,8 +9263,8 @@ function renderInward(allNodes, view, files) {
|
|
|
9186
9263
|
console.log("");
|
|
9187
9264
|
}
|
|
9188
9265
|
function buildTrajectory() {
|
|
9189
|
-
const projectsDir =
|
|
9190
|
-
if (!
|
|
9266
|
+
const projectsDir = join13(homedir12(), ".claude", "projects");
|
|
9267
|
+
if (!existsSync9(projectsDir)) return null;
|
|
9191
9268
|
const paths = findJsonlFiles(projectsDir);
|
|
9192
9269
|
if (paths.length === 0) return null;
|
|
9193
9270
|
const files = loadCorpus(paths);
|
|
@@ -9636,9 +9713,24 @@ async function runIntroRequest(args5, overrides) {
|
|
|
9636
9713
|
deps.exit(1);
|
|
9637
9714
|
return;
|
|
9638
9715
|
}
|
|
9639
|
-
|
|
9716
|
+
let notified = false;
|
|
9717
|
+
try {
|
|
9718
|
+
const data = await res.json();
|
|
9719
|
+
notified = data.notified === true;
|
|
9720
|
+
} catch {
|
|
9721
|
+
}
|
|
9722
|
+
if (notified) {
|
|
9723
|
+
deps.log(`
|
|
9640
9724
|
Intro request sent to @${targetLogin}. They will see only your public login`);
|
|
9641
|
-
|
|
9725
|
+
deps.log(" until they accept; your contact is shared only if they do.\n");
|
|
9726
|
+
} else {
|
|
9727
|
+
deps.log(`
|
|
9728
|
+
Intro request recorded for @${targetLogin} \u2014 but we couldn't email them`);
|
|
9729
|
+
deps.log(" automatically (no public email on file). Send it to them yourself: they can run");
|
|
9730
|
+
deps.log(" `terminalhire intro --list` (or open their dashboard) to see and accept it.");
|
|
9731
|
+
deps.log(" They will see only your public login until they accept; your contact is");
|
|
9732
|
+
deps.log(" shared only if they do.\n");
|
|
9733
|
+
}
|
|
9642
9734
|
}
|
|
9643
9735
|
async function runIntroDecision(args5, overrides) {
|
|
9644
9736
|
const deps = { ...defaultIntroDeps(), ...overrides };
|
|
@@ -9849,13 +9941,13 @@ var init_jpi_intro = __esm({
|
|
|
9849
9941
|
});
|
|
9850
9942
|
|
|
9851
9943
|
// src/chat-keystore.ts
|
|
9852
|
-
import { existsSync as
|
|
9853
|
-
import { homedir as
|
|
9854
|
-
import { join as
|
|
9944
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync11, rmSync as rmSync3 } from "fs";
|
|
9945
|
+
import { homedir as homedir13 } from "os";
|
|
9946
|
+
import { join as join14 } from "path";
|
|
9855
9947
|
async function loadOrCreateIdentity() {
|
|
9856
9948
|
const key = await loadKey();
|
|
9857
|
-
if (
|
|
9858
|
-
const blob2 = JSON.parse(
|
|
9949
|
+
if (existsSync10(IDENTITY_FILE)) {
|
|
9950
|
+
const blob2 = JSON.parse(readFileSync14(IDENTITY_FILE, "utf8"));
|
|
9859
9951
|
return JSON.parse(decrypt(blob2, key));
|
|
9860
9952
|
}
|
|
9861
9953
|
const keypair = generateIdentityKeypair();
|
|
@@ -9870,19 +9962,19 @@ var init_chat_keystore = __esm({
|
|
|
9870
9962
|
"use strict";
|
|
9871
9963
|
init_src();
|
|
9872
9964
|
init_github_auth();
|
|
9873
|
-
TERMINALHIRE_DIR10 =
|
|
9874
|
-
IDENTITY_FILE =
|
|
9965
|
+
TERMINALHIRE_DIR10 = join14(homedir13(), ".terminalhire");
|
|
9966
|
+
IDENTITY_FILE = join14(TERMINALHIRE_DIR10, "chat-identity.enc");
|
|
9875
9967
|
}
|
|
9876
9968
|
});
|
|
9877
9969
|
|
|
9878
9970
|
// src/chat-client.ts
|
|
9879
|
-
import { existsSync as
|
|
9880
|
-
import { homedir as
|
|
9881
|
-
import { join as
|
|
9971
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync12, readFileSync as readFileSync15, writeFileSync as writeFileSync12 } from "fs";
|
|
9972
|
+
import { homedir as homedir14 } from "os";
|
|
9973
|
+
import { join as join15 } from "path";
|
|
9882
9974
|
function defaultReadPeerPins() {
|
|
9883
9975
|
try {
|
|
9884
|
-
if (!
|
|
9885
|
-
const parsed = JSON.parse(
|
|
9976
|
+
if (!existsSync11(PEERS_FILE)) return {};
|
|
9977
|
+
const parsed = JSON.parse(readFileSync15(PEERS_FILE, "utf8"));
|
|
9886
9978
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
|
|
9887
9979
|
const out = {};
|
|
9888
9980
|
for (const [login, key] of Object.entries(parsed)) {
|
|
@@ -10058,8 +10150,8 @@ var init_chat_client = __esm({
|
|
|
10058
10150
|
init_web_session();
|
|
10059
10151
|
CHAT_BASE = process.env["TERMINALHIRE_API_URL"] || "https://www.terminalhire.com";
|
|
10060
10152
|
GH_SESSION_COOKIE3 = "__jpi_gh_session";
|
|
10061
|
-
TERMINALHIRE_DIR11 =
|
|
10062
|
-
PEERS_FILE =
|
|
10153
|
+
TERMINALHIRE_DIR11 = join15(homedir14(), ".terminalhire");
|
|
10154
|
+
PEERS_FILE = join15(TERMINALHIRE_DIR11, "chat-peers.json");
|
|
10063
10155
|
REQUEST_TIMEOUT_MS = 1e4;
|
|
10064
10156
|
ChatNotLinkedError = class extends Error {
|
|
10065
10157
|
constructor() {
|
|
@@ -10113,13 +10205,13 @@ __export(jpi_chat_read_exports, {
|
|
|
10113
10205
|
runSend: () => runSend,
|
|
10114
10206
|
writeReadCursor: () => writeReadCursor
|
|
10115
10207
|
});
|
|
10116
|
-
import { existsSync as
|
|
10117
|
-
import { homedir as
|
|
10118
|
-
import { join as
|
|
10208
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync13, readFileSync as readFileSync16, writeFileSync as writeFileSync13 } from "fs";
|
|
10209
|
+
import { homedir as homedir15 } from "os";
|
|
10210
|
+
import { join as join16 } from "path";
|
|
10119
10211
|
function readReadCursors() {
|
|
10120
10212
|
try {
|
|
10121
|
-
if (!
|
|
10122
|
-
const parsed = JSON.parse(
|
|
10213
|
+
if (!existsSync12(READS_FILE)) return {};
|
|
10214
|
+
const parsed = JSON.parse(readFileSync16(READS_FILE, "utf8"));
|
|
10123
10215
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
|
|
10124
10216
|
const out = {};
|
|
10125
10217
|
for (const [login, iso] of Object.entries(parsed)) {
|
|
@@ -10415,8 +10507,8 @@ var init_jpi_chat_read = __esm({
|
|
|
10415
10507
|
init_chat_client();
|
|
10416
10508
|
init_jpi_chat();
|
|
10417
10509
|
CHAT_BASE2 = process.env["TERMINALHIRE_API_URL"] || "https://www.terminalhire.com";
|
|
10418
|
-
TERMINALHIRE_DIR12 =
|
|
10419
|
-
READS_FILE =
|
|
10510
|
+
TERMINALHIRE_DIR12 = join16(homedir15(), ".terminalhire");
|
|
10511
|
+
READS_FILE = join16(TERMINALHIRE_DIR12, "chat-reads.json");
|
|
10420
10512
|
}
|
|
10421
10513
|
});
|
|
10422
10514
|
|
|
@@ -11064,6 +11156,44 @@ var init_jpi_chat = __esm({
|
|
|
11064
11156
|
}
|
|
11065
11157
|
});
|
|
11066
11158
|
|
|
11159
|
+
// bin/jpi-connect.js
|
|
11160
|
+
var jpi_connect_exports = {};
|
|
11161
|
+
__export(jpi_connect_exports, {
|
|
11162
|
+
run: () => run10
|
|
11163
|
+
});
|
|
11164
|
+
async function run10() {
|
|
11165
|
+
const args5 = process.argv.slice(2).filter((a) => a !== "connect");
|
|
11166
|
+
if (args5.includes("--mute")) {
|
|
11167
|
+
writeConfig({ inboundNudgeMuted: true });
|
|
11168
|
+
console.log("\n Muted: your spinner will no longer surface incoming connection requests.");
|
|
11169
|
+
console.log(" Pending intros are still there \u2014 see them any time with `terminalhire intro --list`.");
|
|
11170
|
+
console.log(" Re-enable with `terminalhire connect --unmute`.\n");
|
|
11171
|
+
return;
|
|
11172
|
+
}
|
|
11173
|
+
if (args5.includes("--unmute")) {
|
|
11174
|
+
writeConfig({ inboundNudgeMuted: false });
|
|
11175
|
+
console.log("\n Unmuted: incoming connection requests will surface in your spinner again.");
|
|
11176
|
+
console.log(" (Requires a linked terminal \u2014 run `terminalhire link` if you have not.)\n");
|
|
11177
|
+
return;
|
|
11178
|
+
}
|
|
11179
|
+
const muted = isInboundNudgeMuted();
|
|
11180
|
+
console.log("\n terminalhire connect \u2014 find and reach other developers, locally matched:");
|
|
11181
|
+
console.log(" terminalhire devs Rank opted-in builders & projects for you");
|
|
11182
|
+
console.log(' terminalhire project "<title>: <skills>" Declare a project to staff');
|
|
11183
|
+
console.log(" terminalhire intro <github-login> Request a consented intro (double opt-in)");
|
|
11184
|
+
console.log(" terminalhire intro --list See intros you have sent + received");
|
|
11185
|
+
console.log(" terminalhire chat Message your accepted connections");
|
|
11186
|
+
console.log("");
|
|
11187
|
+
console.log(` Ambient inbound nudge: ${muted ? "muted" : "on"} (toggle: terminalhire connect --${muted ? "unmute" : "mute"})`);
|
|
11188
|
+
console.log("");
|
|
11189
|
+
}
|
|
11190
|
+
var init_jpi_connect = __esm({
|
|
11191
|
+
"bin/jpi-connect.js"() {
|
|
11192
|
+
"use strict";
|
|
11193
|
+
init_config();
|
|
11194
|
+
}
|
|
11195
|
+
});
|
|
11196
|
+
|
|
11067
11197
|
// src/link.ts
|
|
11068
11198
|
var link_exports = {};
|
|
11069
11199
|
__export(link_exports, {
|
|
@@ -11176,6 +11306,8 @@ async function runLink(overrides) {
|
|
|
11176
11306
|
deps.persistToken(outcome.token);
|
|
11177
11307
|
deps.log("\n This terminal is now linked to your terminalhire account.");
|
|
11178
11308
|
deps.log(" Try `terminalhire intro <login>`, `terminalhire chat`, or `terminalhire trajectory --push`.");
|
|
11309
|
+
deps.log(" Your spinner will quietly surface incoming connection requests.");
|
|
11310
|
+
deps.log(" Turn that off any time with `terminalhire connect --mute`.");
|
|
11179
11311
|
deps.log(" Unlink any time with `terminalhire link --logout`.\n");
|
|
11180
11312
|
deps.exit(0);
|
|
11181
11313
|
}
|
|
@@ -11241,9 +11373,9 @@ var init_link = __esm({
|
|
|
11241
11373
|
// bin/jpi-link.js
|
|
11242
11374
|
var jpi_link_exports = {};
|
|
11243
11375
|
__export(jpi_link_exports, {
|
|
11244
|
-
run: () =>
|
|
11376
|
+
run: () => run11
|
|
11245
11377
|
});
|
|
11246
|
-
async function
|
|
11378
|
+
async function run11() {
|
|
11247
11379
|
try {
|
|
11248
11380
|
const args5 = process.argv.slice(2);
|
|
11249
11381
|
if (args5.includes("--logout")) {
|
|
@@ -11267,7 +11399,7 @@ var init_jpi_link = __esm({
|
|
|
11267
11399
|
// bin/jpi-profile.js
|
|
11268
11400
|
var jpi_profile_exports = {};
|
|
11269
11401
|
__export(jpi_profile_exports, {
|
|
11270
|
-
run: () =>
|
|
11402
|
+
run: () => run12
|
|
11271
11403
|
});
|
|
11272
11404
|
import { createInterface as createInterface8 } from "readline";
|
|
11273
11405
|
function prompt4(question) {
|
|
@@ -11279,7 +11411,7 @@ function prompt4(question) {
|
|
|
11279
11411
|
});
|
|
11280
11412
|
});
|
|
11281
11413
|
}
|
|
11282
|
-
async function
|
|
11414
|
+
async function run12() {
|
|
11283
11415
|
const { readProfile: readProfile2, writeProfile: writeProfile2, deleteProfile: deleteProfile2 } = await Promise.resolve().then(() => (init_profile(), profile_exports));
|
|
11284
11416
|
const args5 = process.argv.slice(2);
|
|
11285
11417
|
if (args5.includes("--show")) {
|
|
@@ -11352,9 +11484,9 @@ var signal_exports = {};
|
|
|
11352
11484
|
__export(signal_exports, {
|
|
11353
11485
|
extractFingerprint: () => extractFingerprint
|
|
11354
11486
|
});
|
|
11355
|
-
import { readFileSync as
|
|
11487
|
+
import { readFileSync as readFileSync17, readdirSync as readdirSync2 } from "fs";
|
|
11356
11488
|
import { execFileSync } from "child_process";
|
|
11357
|
-
import { join as
|
|
11489
|
+
import { join as join17 } from "path";
|
|
11358
11490
|
function safeGit(args5, cwd) {
|
|
11359
11491
|
try {
|
|
11360
11492
|
return execFileSync("git", ["-C", cwd, ...args5], {
|
|
@@ -11382,20 +11514,20 @@ function isEmployerContext(cwd) {
|
|
|
11382
11514
|
}
|
|
11383
11515
|
function readJsonSafe(path) {
|
|
11384
11516
|
try {
|
|
11385
|
-
return JSON.parse(
|
|
11517
|
+
return JSON.parse(readFileSync17(path, "utf8"));
|
|
11386
11518
|
} catch {
|
|
11387
11519
|
return null;
|
|
11388
11520
|
}
|
|
11389
11521
|
}
|
|
11390
11522
|
function readFileSafe(path) {
|
|
11391
11523
|
try {
|
|
11392
|
-
return
|
|
11524
|
+
return readFileSync17(path, "utf8");
|
|
11393
11525
|
} catch {
|
|
11394
11526
|
return "";
|
|
11395
11527
|
}
|
|
11396
11528
|
}
|
|
11397
11529
|
function tokensFromPackageJson(cwd) {
|
|
11398
|
-
const pkg = readJsonSafe(
|
|
11530
|
+
const pkg = readJsonSafe(join17(cwd, "package.json"));
|
|
11399
11531
|
if (!pkg || typeof pkg !== "object") return [];
|
|
11400
11532
|
const p = pkg;
|
|
11401
11533
|
const deps = {
|
|
@@ -11409,9 +11541,9 @@ function workspaceMemberDirs(cwd) {
|
|
|
11409
11541
|
const dirs = [cwd];
|
|
11410
11542
|
for (const group of ["apps", "packages"]) {
|
|
11411
11543
|
try {
|
|
11412
|
-
const groupDir =
|
|
11544
|
+
const groupDir = join17(cwd, group);
|
|
11413
11545
|
for (const e of readdirSync2(groupDir, { withFileTypes: true })) {
|
|
11414
|
-
if (e.isDirectory() && !e.isSymbolicLink()) dirs.push(
|
|
11546
|
+
if (e.isDirectory() && !e.isSymbolicLink()) dirs.push(join17(groupDir, e.name));
|
|
11415
11547
|
}
|
|
11416
11548
|
} catch {
|
|
11417
11549
|
}
|
|
@@ -11419,18 +11551,18 @@ function workspaceMemberDirs(cwd) {
|
|
|
11419
11551
|
return dirs;
|
|
11420
11552
|
}
|
|
11421
11553
|
function tokensFromRequirementsTxt(cwd) {
|
|
11422
|
-
const content = readFileSafe(
|
|
11554
|
+
const content = readFileSafe(join17(cwd, "requirements.txt"));
|
|
11423
11555
|
if (!content) return [];
|
|
11424
11556
|
return content.split("\n").map((l) => l.trim().split(/[>=<!\[;]/)[0].trim().toLowerCase()).filter(Boolean);
|
|
11425
11557
|
}
|
|
11426
11558
|
function tokensFromGoMod(cwd) {
|
|
11427
|
-
const content = readFileSafe(
|
|
11559
|
+
const content = readFileSafe(join17(cwd, "go.mod"));
|
|
11428
11560
|
if (!content) return [];
|
|
11429
11561
|
const requires = Array.from(content.matchAll(/^\s+([^\s]+)\s+v/gm)).map((m) => m[1].split("/").pop() ?? "").filter(Boolean);
|
|
11430
11562
|
return ["go", ...requires];
|
|
11431
11563
|
}
|
|
11432
11564
|
function tokensFromCargoToml(cwd) {
|
|
11433
|
-
const content = readFileSafe(
|
|
11565
|
+
const content = readFileSafe(join17(cwd, "Cargo.toml"));
|
|
11434
11566
|
if (!content) return [];
|
|
11435
11567
|
const deps = [];
|
|
11436
11568
|
let inDeps = false;
|
|
@@ -11451,7 +11583,7 @@ function tokensFromFileExtensions(cwd) {
|
|
|
11451
11583
|
const tokens = [];
|
|
11452
11584
|
const scanDirs = [cwd];
|
|
11453
11585
|
try {
|
|
11454
|
-
const srcDir =
|
|
11586
|
+
const srcDir = join17(cwd, "src");
|
|
11455
11587
|
readdirSync2(srcDir);
|
|
11456
11588
|
scanDirs.push(srcDir);
|
|
11457
11589
|
} catch {
|
|
@@ -11612,9 +11744,9 @@ var init_signal = __esm({
|
|
|
11612
11744
|
// bin/jpi-learn.js
|
|
11613
11745
|
var jpi_learn_exports = {};
|
|
11614
11746
|
__export(jpi_learn_exports, {
|
|
11615
|
-
run: () =>
|
|
11747
|
+
run: () => run13
|
|
11616
11748
|
});
|
|
11617
|
-
async function
|
|
11749
|
+
async function run13() {
|
|
11618
11750
|
try {
|
|
11619
11751
|
const args5 = process.argv.slice(2);
|
|
11620
11752
|
const cwdIdx = args5.indexOf("--cwd");
|
|
@@ -11641,7 +11773,7 @@ var init_jpi_learn = __esm({
|
|
|
11641
11773
|
"use strict";
|
|
11642
11774
|
isMain = process.argv[1]?.endsWith("jpi-learn.js") || process.argv[1]?.endsWith("jpi-learn");
|
|
11643
11775
|
if (isMain) {
|
|
11644
|
-
|
|
11776
|
+
run13();
|
|
11645
11777
|
}
|
|
11646
11778
|
}
|
|
11647
11779
|
});
|
|
@@ -11649,17 +11781,17 @@ var init_jpi_learn = __esm({
|
|
|
11649
11781
|
// bin/jpi-config.js
|
|
11650
11782
|
var jpi_config_exports = {};
|
|
11651
11783
|
__export(jpi_config_exports, {
|
|
11652
|
-
run: () =>
|
|
11784
|
+
run: () => run14
|
|
11653
11785
|
});
|
|
11654
|
-
import { join as
|
|
11655
|
-
import { homedir as
|
|
11786
|
+
import { join as join18 } from "path";
|
|
11787
|
+
import { homedir as homedir16 } from "os";
|
|
11656
11788
|
function parseNudgeMode(raw) {
|
|
11657
11789
|
if (raw === "session" || raw === "always") return raw;
|
|
11658
11790
|
const m = /^every:(\d+)$/.exec(raw);
|
|
11659
11791
|
if (m && parseInt(m[1], 10) >= 1) return raw;
|
|
11660
11792
|
return null;
|
|
11661
11793
|
}
|
|
11662
|
-
async function
|
|
11794
|
+
async function run14() {
|
|
11663
11795
|
const args5 = process.argv.slice(2);
|
|
11664
11796
|
const filtered = args5[0] === "config" ? args5.slice(1) : args5;
|
|
11665
11797
|
if (filtered.includes("--show") || filtered.length === 0) {
|
|
@@ -11725,8 +11857,8 @@ var init_jpi_config = __esm({
|
|
|
11725
11857
|
"bin/jpi-config.js"() {
|
|
11726
11858
|
"use strict";
|
|
11727
11859
|
init_config();
|
|
11728
|
-
TERMINALHIRE_DIR13 =
|
|
11729
|
-
CONFIG_FILE2 =
|
|
11860
|
+
TERMINALHIRE_DIR13 = join18(homedir16(), ".terminalhire");
|
|
11861
|
+
CONFIG_FILE2 = join18(TERMINALHIRE_DIR13, "config.json");
|
|
11730
11862
|
}
|
|
11731
11863
|
});
|
|
11732
11864
|
|
|
@@ -11737,6 +11869,7 @@ __export(spinner_exports, {
|
|
|
11737
11869
|
applySpinnerTips: () => applySpinnerTips,
|
|
11738
11870
|
applySpinnerVerbs: () => applySpinnerVerbs,
|
|
11739
11871
|
buildContextVerbs: () => buildContextVerbs,
|
|
11872
|
+
buildIncomingIntroLine: () => buildIncomingIntroLine,
|
|
11740
11873
|
buildPeerLine: () => buildPeerLine,
|
|
11741
11874
|
buildSpinnerPool: () => buildSpinnerPool,
|
|
11742
11875
|
buildTips: () => buildTips,
|
|
@@ -11749,17 +11882,17 @@ __export(spinner_exports, {
|
|
|
11749
11882
|
readSpinnerConfig: () => readSpinnerConfig
|
|
11750
11883
|
});
|
|
11751
11884
|
import {
|
|
11752
|
-
readFileSync as
|
|
11885
|
+
readFileSync as readFileSync18,
|
|
11753
11886
|
writeFileSync as writeFileSync14,
|
|
11754
|
-
existsSync as
|
|
11887
|
+
existsSync as existsSync13,
|
|
11755
11888
|
mkdirSync as mkdirSync14,
|
|
11756
11889
|
renameSync as renameSync2
|
|
11757
11890
|
} from "fs";
|
|
11758
|
-
import { join as
|
|
11759
|
-
import { homedir as
|
|
11891
|
+
import { join as join19, dirname } from "path";
|
|
11892
|
+
import { homedir as homedir17 } from "os";
|
|
11760
11893
|
function readJson(path, fallback) {
|
|
11761
11894
|
try {
|
|
11762
|
-
return
|
|
11895
|
+
return existsSync13(path) ? JSON.parse(readFileSync18(path, "utf8")) : fallback;
|
|
11763
11896
|
} catch {
|
|
11764
11897
|
return fallback;
|
|
11765
11898
|
}
|
|
@@ -11859,16 +11992,25 @@ function buildPeerLine(topPeers) {
|
|
|
11859
11992
|
if (n < 1) return null;
|
|
11860
11993
|
return n === 1 ? `\u25C6 1 builder matches what you're building \xB7 terminalhire devs` : `\u25C6 ${n} builders match what you're building \xB7 terminalhire devs`;
|
|
11861
11994
|
}
|
|
11995
|
+
function buildIncomingIntroLine(incomingPending) {
|
|
11996
|
+
const n = incomingPending && typeof incomingPending.count === "number" ? incomingPending.count : 0;
|
|
11997
|
+
if (n < 1) return null;
|
|
11998
|
+
return n === 1 ? `\u2198 someone wants to connect \xB7 terminalhire intro --list` : `\u2198 ${n} people want to connect \xB7 terminalhire intro --list`;
|
|
11999
|
+
}
|
|
11862
12000
|
function buildSpinnerPool(topMatches, max = 6, opts = {}) {
|
|
11863
|
-
const { sessionTags, frequency = "always", topPeers } = opts;
|
|
12001
|
+
const { sessionTags, frequency = "always", topPeers, incomingPending } = opts;
|
|
12002
|
+
const introLine = buildIncomingIntroLine(incomingPending);
|
|
11864
12003
|
const ranked = rankBySessionTags(topMatches, sessionTags);
|
|
11865
12004
|
if (!Array.isArray(ranked) || ranked.length === 0) {
|
|
12005
|
+
if (introLine) return [introLine];
|
|
11866
12006
|
const peerLine = buildPeerLine(topPeers);
|
|
11867
12007
|
return peerLine ? [peerLine] : [];
|
|
11868
12008
|
}
|
|
11869
12009
|
const headers = buildContextVerbs(ranked, sessionTags);
|
|
11870
12010
|
const cap = Math.max(1, verbCountForFrequency(frequency, headers.length));
|
|
11871
|
-
|
|
12011
|
+
const pool = [...headers.slice(0, cap), ctaVerb()];
|
|
12012
|
+
if (introLine) pool.push(introLine);
|
|
12013
|
+
return pool;
|
|
11872
12014
|
}
|
|
11873
12015
|
function readState() {
|
|
11874
12016
|
return readJson(SPINNER_STATE_FILE, { verbs: [], mode: "replace" });
|
|
@@ -12027,10 +12169,10 @@ var TH_DIR, CLAUDE_SETTINGS, CONFIG_FILE3, SPINNER_STATE_FILE, SPINNER_DEFAULTS,
|
|
|
12027
12169
|
var init_spinner = __esm({
|
|
12028
12170
|
"bin/spinner.js"() {
|
|
12029
12171
|
"use strict";
|
|
12030
|
-
TH_DIR = process.env["TERMINALHIRE_DIR"] ||
|
|
12031
|
-
CLAUDE_SETTINGS = process.env["TERMINALHIRE_CLAUDE_SETTINGS"] ||
|
|
12032
|
-
CONFIG_FILE3 =
|
|
12033
|
-
SPINNER_STATE_FILE =
|
|
12172
|
+
TH_DIR = process.env["TERMINALHIRE_DIR"] || join19(homedir17(), ".terminalhire");
|
|
12173
|
+
CLAUDE_SETTINGS = process.env["TERMINALHIRE_CLAUDE_SETTINGS"] || join19(homedir17(), ".claude", "settings.json");
|
|
12174
|
+
CONFIG_FILE3 = join19(TH_DIR, "config.json");
|
|
12175
|
+
SPINNER_STATE_FILE = join19(TH_DIR, "spinner-state.json");
|
|
12034
12176
|
SPINNER_DEFAULTS = { enabled: false, mode: "append", max: 6, frequency: "sometimes" };
|
|
12035
12177
|
VERB_INTROS = ["Matched:", "You\u2019d fit:", "Worth a look:", "On your radar:", "Fits your stack:"];
|
|
12036
12178
|
}
|
|
@@ -12039,21 +12181,21 @@ var init_spinner = __esm({
|
|
|
12039
12181
|
// bin/jpi-spinner.js
|
|
12040
12182
|
var jpi_spinner_exports = {};
|
|
12041
12183
|
__export(jpi_spinner_exports, {
|
|
12042
|
-
run: () =>
|
|
12184
|
+
run: () => run15
|
|
12043
12185
|
});
|
|
12044
12186
|
import {
|
|
12045
|
-
readFileSync as
|
|
12187
|
+
readFileSync as readFileSync19,
|
|
12046
12188
|
writeFileSync as writeFileSync15,
|
|
12047
12189
|
copyFileSync,
|
|
12048
|
-
existsSync as
|
|
12190
|
+
existsSync as existsSync14,
|
|
12049
12191
|
mkdirSync as mkdirSync15
|
|
12050
12192
|
} from "fs";
|
|
12051
|
-
import { join as
|
|
12052
|
-
import { homedir as
|
|
12193
|
+
import { join as join20 } from "path";
|
|
12194
|
+
import { homedir as homedir18 } from "os";
|
|
12053
12195
|
import { createInterface as createInterface9 } from "readline";
|
|
12054
12196
|
function readConfig2() {
|
|
12055
12197
|
try {
|
|
12056
|
-
return
|
|
12198
|
+
return existsSync14(CONFIG_FILE4) ? JSON.parse(readFileSync19(CONFIG_FILE4, "utf8")) : {};
|
|
12057
12199
|
} catch {
|
|
12058
12200
|
return {};
|
|
12059
12201
|
}
|
|
@@ -12064,7 +12206,7 @@ function writeConfig2(patch) {
|
|
|
12064
12206
|
writeFileSync15(CONFIG_FILE4, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
12065
12207
|
}
|
|
12066
12208
|
function backupSettings() {
|
|
12067
|
-
if (!
|
|
12209
|
+
if (!existsSync14(SETTINGS_PATH)) return null;
|
|
12068
12210
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
12069
12211
|
const backupPath = `${SETTINGS_PATH}.terminalhire-backup-${ts}`;
|
|
12070
12212
|
copyFileSync(SETTINGS_PATH, backupPath);
|
|
@@ -12081,13 +12223,13 @@ function ask(question) {
|
|
|
12081
12223
|
}
|
|
12082
12224
|
function readTopMatches() {
|
|
12083
12225
|
try {
|
|
12084
|
-
const c = JSON.parse(
|
|
12226
|
+
const c = JSON.parse(readFileSync19(CACHE_FILE, "utf8"));
|
|
12085
12227
|
return Array.isArray(c.topMatches) ? c.topMatches : [];
|
|
12086
12228
|
} catch {
|
|
12087
12229
|
return [];
|
|
12088
12230
|
}
|
|
12089
12231
|
}
|
|
12090
|
-
async function
|
|
12232
|
+
async function run15() {
|
|
12091
12233
|
const args5 = process.argv.slice(2).filter((a) => a !== "spinner");
|
|
12092
12234
|
const has = (f) => args5.includes(f);
|
|
12093
12235
|
const val = (f) => {
|
|
@@ -12224,21 +12366,21 @@ var init_jpi_spinner = __esm({
|
|
|
12224
12366
|
"bin/jpi-spinner.js"() {
|
|
12225
12367
|
"use strict";
|
|
12226
12368
|
init_spinner();
|
|
12227
|
-
TH_DIR2 = process.env["TERMINALHIRE_DIR"] ||
|
|
12228
|
-
CONFIG_FILE4 =
|
|
12229
|
-
SETTINGS_PATH = process.env["TERMINALHIRE_CLAUDE_SETTINGS"] ||
|
|
12230
|
-
CACHE_FILE =
|
|
12369
|
+
TH_DIR2 = process.env["TERMINALHIRE_DIR"] || join20(homedir18(), ".terminalhire");
|
|
12370
|
+
CONFIG_FILE4 = join20(TH_DIR2, "config.json");
|
|
12371
|
+
SETTINGS_PATH = process.env["TERMINALHIRE_CLAUDE_SETTINGS"] || join20(homedir18(), ".claude", "settings.json");
|
|
12372
|
+
CACHE_FILE = join20(TH_DIR2, "index-cache.json");
|
|
12231
12373
|
}
|
|
12232
12374
|
});
|
|
12233
12375
|
|
|
12234
12376
|
// bin/jpi-sync.js
|
|
12235
12377
|
var jpi_sync_exports = {};
|
|
12236
12378
|
__export(jpi_sync_exports, {
|
|
12237
|
-
run: () =>
|
|
12379
|
+
run: () => run16
|
|
12238
12380
|
});
|
|
12239
|
-
import { readFileSync as
|
|
12240
|
-
import { join as
|
|
12241
|
-
import { homedir as
|
|
12381
|
+
import { readFileSync as readFileSync20, writeFileSync as writeFileSync16, mkdirSync as mkdirSync16, existsSync as existsSync15, rmSync as rmSync4 } from "fs";
|
|
12382
|
+
import { join as join21 } from "path";
|
|
12383
|
+
import { homedir as homedir19, hostname as osHostname } from "os";
|
|
12242
12384
|
import { createInterface as createInterface10 } from "readline";
|
|
12243
12385
|
function ask2(question) {
|
|
12244
12386
|
const rl = createInterface10({ input: process.stdin, output: process.stdout });
|
|
@@ -12251,7 +12393,7 @@ function ask2(question) {
|
|
|
12251
12393
|
}
|
|
12252
12394
|
function readMarker() {
|
|
12253
12395
|
try {
|
|
12254
|
-
return
|
|
12396
|
+
return existsSync15(TIER1_MARKER) ? JSON.parse(readFileSync20(TIER1_MARKER, "utf8")) : null;
|
|
12255
12397
|
} catch {
|
|
12256
12398
|
return null;
|
|
12257
12399
|
}
|
|
@@ -12546,7 +12688,7 @@ async function runDelete() {
|
|
|
12546
12688
|
clearMarker();
|
|
12547
12689
|
console.log("\n Synced profile deleted and local marker cleared.\n");
|
|
12548
12690
|
}
|
|
12549
|
-
async function
|
|
12691
|
+
async function run16() {
|
|
12550
12692
|
const args5 = process.argv.slice(2).filter((a) => a !== "sync");
|
|
12551
12693
|
const has = (f) => args5.includes(f);
|
|
12552
12694
|
if (has("--push") || has("--enable")) {
|
|
@@ -12577,8 +12719,8 @@ var init_jpi_sync = __esm({
|
|
|
12577
12719
|
"bin/jpi-sync.js"() {
|
|
12578
12720
|
"use strict";
|
|
12579
12721
|
init_open_url();
|
|
12580
|
-
TH_DIR3 = process.env["TERMINALHIRE_DIR"] ||
|
|
12581
|
-
TIER1_MARKER =
|
|
12722
|
+
TH_DIR3 = process.env["TERMINALHIRE_DIR"] || join21(homedir19(), ".terminalhire");
|
|
12723
|
+
TIER1_MARKER = join21(TH_DIR3, "tier1.json");
|
|
12582
12724
|
API_URL5 = process.env["TERMINALHIRE_API_URL"] || process.env["JPI_API_URL"] || "https://terminalhire.com";
|
|
12583
12725
|
SYNC_BASE = "https://www.terminalhire.com";
|
|
12584
12726
|
POLL_INTERVAL_MS = 2e3;
|
|
@@ -12590,14 +12732,14 @@ var init_jpi_sync = __esm({
|
|
|
12590
12732
|
// bin/jpi-init.js
|
|
12591
12733
|
var jpi_init_exports = {};
|
|
12592
12734
|
__export(jpi_init_exports, {
|
|
12593
|
-
run: () =>
|
|
12735
|
+
run: () => run17
|
|
12594
12736
|
});
|
|
12595
|
-
import { existsSync as
|
|
12596
|
-
import { join as
|
|
12597
|
-
import { fileURLToPath as
|
|
12737
|
+
import { existsSync as existsSync16 } from "fs";
|
|
12738
|
+
import { join as join22, resolve } from "path";
|
|
12739
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
12598
12740
|
import { createInterface as createInterface11 } from "readline";
|
|
12599
12741
|
import { spawnSync, spawn as spawn2 } from "child_process";
|
|
12600
|
-
import { homedir as
|
|
12742
|
+
import { homedir as homedir20 } from "os";
|
|
12601
12743
|
function ask3(question) {
|
|
12602
12744
|
const rl = createInterface11({ input: process.stdin, output: process.stdout });
|
|
12603
12745
|
return new Promise((resolve2) => {
|
|
@@ -12608,18 +12750,18 @@ function ask3(question) {
|
|
|
12608
12750
|
});
|
|
12609
12751
|
}
|
|
12610
12752
|
function resolveScript(name) {
|
|
12611
|
-
const distPath = resolve(
|
|
12612
|
-
const legacyPath = resolve(
|
|
12613
|
-
return
|
|
12753
|
+
const distPath = resolve(join22(__dirname3, "..", "..", "dist", "bin", `${name}.js`));
|
|
12754
|
+
const legacyPath = resolve(join22(__dirname3, `${name}.js`));
|
|
12755
|
+
return existsSync16(distPath) ? distPath : legacyPath;
|
|
12614
12756
|
}
|
|
12615
12757
|
function resolveInstallJs() {
|
|
12616
|
-
const fromDist = resolve(
|
|
12617
|
-
const fromBin = resolve(
|
|
12618
|
-
if (
|
|
12619
|
-
if (
|
|
12758
|
+
const fromDist = resolve(join22(__dirname3, "..", "..", "install.js"));
|
|
12759
|
+
const fromBin = resolve(join22(__dirname3, "..", "install.js"));
|
|
12760
|
+
if (existsSync16(fromDist)) return fromDist;
|
|
12761
|
+
if (existsSync16(fromBin)) return fromBin;
|
|
12620
12762
|
return fromBin;
|
|
12621
12763
|
}
|
|
12622
|
-
async function
|
|
12764
|
+
async function run17() {
|
|
12623
12765
|
console.log("");
|
|
12624
12766
|
console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
12625
12767
|
console.log("\u2502 terminalhire init \u2014 one-command onboarding \u2502");
|
|
@@ -12711,24 +12853,24 @@ async function run16() {
|
|
|
12711
12853
|
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
12712
12854
|
console.log("");
|
|
12713
12855
|
}
|
|
12714
|
-
var
|
|
12856
|
+
var __dirname3;
|
|
12715
12857
|
var init_jpi_init = __esm({
|
|
12716
12858
|
"bin/jpi-init.js"() {
|
|
12717
12859
|
"use strict";
|
|
12718
|
-
|
|
12860
|
+
__dirname3 = fileURLToPath4(new URL(".", import.meta.url));
|
|
12719
12861
|
}
|
|
12720
12862
|
});
|
|
12721
12863
|
|
|
12722
12864
|
// bin/jpi-refresh.js
|
|
12723
12865
|
var jpi_refresh_exports = {};
|
|
12724
12866
|
__export(jpi_refresh_exports, {
|
|
12725
|
-
run: () =>
|
|
12867
|
+
run: () => run18
|
|
12726
12868
|
});
|
|
12727
|
-
import { readFileSync as
|
|
12728
|
-
import { join as
|
|
12729
|
-
import { homedir as
|
|
12730
|
-
import { fileURLToPath as
|
|
12731
|
-
async function
|
|
12869
|
+
import { readFileSync as readFileSync21, writeFileSync as writeFileSync17, existsSync as existsSync17, mkdirSync as mkdirSync17 } from "fs";
|
|
12870
|
+
import { join as join23 } from "path";
|
|
12871
|
+
import { homedir as homedir21 } from "os";
|
|
12872
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
12873
|
+
async function run18() {
|
|
12732
12874
|
try {
|
|
12733
12875
|
let index;
|
|
12734
12876
|
try {
|
|
@@ -12818,15 +12960,32 @@ async function run17() {
|
|
|
12818
12960
|
}
|
|
12819
12961
|
} catch {
|
|
12820
12962
|
}
|
|
12963
|
+
let incomingPending = { count: 0 };
|
|
12964
|
+
const sessionCookie = readWebSessionFile();
|
|
12965
|
+
if (sessionCookie && !isInboundNudgeMuted()) try {
|
|
12966
|
+
const res = await fetch(`${API_URL6}/api/intro/list`, {
|
|
12967
|
+
method: "GET",
|
|
12968
|
+
headers: { Cookie: `${GH_SESSION_COOKIE6}=${sessionCookie}` },
|
|
12969
|
+
signal: AbortSignal.timeout(1e4)
|
|
12970
|
+
});
|
|
12971
|
+
if (res.ok) {
|
|
12972
|
+
const body = await res.json();
|
|
12973
|
+
const intros = Array.isArray(body?.intros) ? body.intros : [];
|
|
12974
|
+
const incoming = intros.filter((it) => it && it.role === "incoming" && it.status === "pending");
|
|
12975
|
+
incomingPending = { count: incoming.length };
|
|
12976
|
+
}
|
|
12977
|
+
} catch {
|
|
12978
|
+
}
|
|
12821
12979
|
mkdirSync17(TERMINALHIRE_DIR14, { recursive: true });
|
|
12822
12980
|
const cacheEntry = {
|
|
12823
12981
|
ts: Date.now(),
|
|
12824
12982
|
index,
|
|
12825
12983
|
matchCount,
|
|
12826
12984
|
topMatches,
|
|
12827
|
-
topPeers
|
|
12985
|
+
topPeers,
|
|
12986
|
+
incomingPending
|
|
12828
12987
|
};
|
|
12829
|
-
writeFileSync17(
|
|
12988
|
+
writeFileSync17(INDEX_CACHE_FILE5, JSON.stringify(cacheEntry), "utf8");
|
|
12830
12989
|
try {
|
|
12831
12990
|
const {
|
|
12832
12991
|
readSpinnerConfig: readSpinnerConfig2,
|
|
@@ -12850,7 +13009,7 @@ async function run17() {
|
|
|
12850
13009
|
} catch {
|
|
12851
13010
|
}
|
|
12852
13011
|
const ranked = rankBySessionTags2(topMatches, sessionTags);
|
|
12853
|
-
const verbs = buildSpinnerPool2(ranked, sc.max, { sessionTags, frequency: sc.frequency, topPeers });
|
|
13012
|
+
const verbs = buildSpinnerPool2(ranked, sc.max, { sessionTags, frequency: sc.frequency, topPeers, incomingPending });
|
|
12854
13013
|
if (verbs.length > 0) applySpinnerVerbs2(verbs, sc.mode);
|
|
12855
13014
|
else clearSpinnerVerbs2();
|
|
12856
13015
|
const tips = buildTips2(ranked, API_URL6, 8);
|
|
@@ -12862,6 +13021,13 @@ async function run17() {
|
|
|
12862
13021
|
}
|
|
12863
13022
|
} catch {
|
|
12864
13023
|
}
|
|
13024
|
+
try {
|
|
13025
|
+
const { readLocalVersion: readLocalVersion2, buildStaleNudge: buildStaleNudge2 } = await Promise.resolve().then(() => (init_version_nudge(), version_nudge_exports));
|
|
13026
|
+
const nudge = buildStaleNudge2(readLocalVersion2(), index?.cliVersion);
|
|
13027
|
+
if (nudge) process.stderr.write(`${nudge}
|
|
13028
|
+
`);
|
|
13029
|
+
} catch {
|
|
13030
|
+
}
|
|
12865
13031
|
process.exit(0);
|
|
12866
13032
|
} catch (err) {
|
|
12867
13033
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -12870,15 +13036,17 @@ async function run17() {
|
|
|
12870
13036
|
process.exit(1);
|
|
12871
13037
|
}
|
|
12872
13038
|
}
|
|
12873
|
-
var
|
|
13039
|
+
var GH_SESSION_COOKIE6, __dirname4, TERMINALHIRE_DIR14, INDEX_CACHE_FILE5, API_URL6;
|
|
12874
13040
|
var init_jpi_refresh = __esm({
|
|
12875
13041
|
"bin/jpi-refresh.js"() {
|
|
12876
13042
|
"use strict";
|
|
12877
13043
|
init_directory2();
|
|
12878
13044
|
init_config();
|
|
12879
|
-
|
|
12880
|
-
|
|
12881
|
-
|
|
13045
|
+
init_web_session();
|
|
13046
|
+
GH_SESSION_COOKIE6 = "__jpi_gh_session";
|
|
13047
|
+
__dirname4 = fileURLToPath5(new URL(".", import.meta.url));
|
|
13048
|
+
TERMINALHIRE_DIR14 = join23(homedir21(), ".terminalhire");
|
|
13049
|
+
INDEX_CACHE_FILE5 = join23(TERMINALHIRE_DIR14, "index-cache.json");
|
|
12882
13050
|
API_URL6 = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://terminalhire.com";
|
|
12883
13051
|
}
|
|
12884
13052
|
});
|
|
@@ -12886,16 +13054,16 @@ var init_jpi_refresh = __esm({
|
|
|
12886
13054
|
// bin/jpi-save.js
|
|
12887
13055
|
var jpi_save_exports = {};
|
|
12888
13056
|
__export(jpi_save_exports, {
|
|
12889
|
-
run: () =>
|
|
13057
|
+
run: () => run19
|
|
12890
13058
|
});
|
|
12891
|
-
import { readFileSync as
|
|
12892
|
-
import { join as
|
|
12893
|
-
import { homedir as
|
|
12894
|
-
import { fileURLToPath as
|
|
13059
|
+
import { readFileSync as readFileSync22, existsSync as existsSync18 } from "fs";
|
|
13060
|
+
import { join as join24 } from "path";
|
|
13061
|
+
import { homedir as homedir22 } from "os";
|
|
13062
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
12895
13063
|
function findJobInCache(jobId) {
|
|
12896
13064
|
try {
|
|
12897
|
-
if (!
|
|
12898
|
-
const raw =
|
|
13065
|
+
if (!existsSync18(INDEX_CACHE_FILE6)) return null;
|
|
13066
|
+
const raw = readFileSync22(INDEX_CACHE_FILE6, "utf8");
|
|
12899
13067
|
const entry = JSON.parse(raw);
|
|
12900
13068
|
const jobs = entry?.index?.jobs ?? [];
|
|
12901
13069
|
return jobs.find((j) => j.id === jobId) ?? null;
|
|
@@ -12964,7 +13132,7 @@ async function cmdUnsave(jobId) {
|
|
|
12964
13132
|
process.exit(1);
|
|
12965
13133
|
}
|
|
12966
13134
|
}
|
|
12967
|
-
async function
|
|
13135
|
+
async function run19() {
|
|
12968
13136
|
const verb = process.argv[2];
|
|
12969
13137
|
const jobId = process.argv[3];
|
|
12970
13138
|
try {
|
|
@@ -12983,31 +13151,31 @@ async function run18() {
|
|
|
12983
13151
|
process.exit(1);
|
|
12984
13152
|
}
|
|
12985
13153
|
}
|
|
12986
|
-
var
|
|
13154
|
+
var __dirname5, TERMINALHIRE_DIR15, INDEX_CACHE_FILE6;
|
|
12987
13155
|
var init_jpi_save = __esm({
|
|
12988
13156
|
"bin/jpi-save.js"() {
|
|
12989
13157
|
"use strict";
|
|
12990
|
-
|
|
12991
|
-
TERMINALHIRE_DIR15 =
|
|
12992
|
-
|
|
13158
|
+
__dirname5 = fileURLToPath6(new URL(".", import.meta.url));
|
|
13159
|
+
TERMINALHIRE_DIR15 = join24(homedir22(), ".terminalhire");
|
|
13160
|
+
INDEX_CACHE_FILE6 = join24(TERMINALHIRE_DIR15, "index-cache.json");
|
|
12993
13161
|
}
|
|
12994
13162
|
});
|
|
12995
13163
|
|
|
12996
13164
|
// bin/jpi-dispatch.js
|
|
12997
|
-
import { fileURLToPath as
|
|
12998
|
-
import { join as
|
|
12999
|
-
import { existsSync as
|
|
13165
|
+
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
13166
|
+
import { join as join25, dirname as dirname2 } from "path";
|
|
13167
|
+
import { existsSync as existsSync19, readFileSync as readFileSync23 } from "fs";
|
|
13000
13168
|
import { createRequire } from "module";
|
|
13001
|
-
var
|
|
13169
|
+
var __dirname6 = fileURLToPath7(new URL(".", import.meta.url));
|
|
13002
13170
|
function readPackageVersion() {
|
|
13003
13171
|
try {
|
|
13004
13172
|
const candidates = [
|
|
13005
|
-
|
|
13006
|
-
|
|
13173
|
+
join25(__dirname6, "..", "..", "package.json"),
|
|
13174
|
+
join25(__dirname6, "..", "package.json")
|
|
13007
13175
|
];
|
|
13008
13176
|
for (const p of candidates) {
|
|
13009
|
-
if (
|
|
13010
|
-
const pkg = JSON.parse(
|
|
13177
|
+
if (existsSync19(p)) {
|
|
13178
|
+
const pkg = JSON.parse(readFileSync23(p, "utf8"));
|
|
13011
13179
|
if (pkg.version) return pkg.version;
|
|
13012
13180
|
}
|
|
13013
13181
|
}
|
|
@@ -13018,7 +13186,7 @@ function readPackageVersion() {
|
|
|
13018
13186
|
var firstArg = process.argv[2];
|
|
13019
13187
|
if (!firstArg && !process.stdin.isTTY) {
|
|
13020
13188
|
const { default: childProcess } = await import("child_process");
|
|
13021
|
-
const nudgeScript =
|
|
13189
|
+
const nudgeScript = join25(__dirname6, "jpi.js");
|
|
13022
13190
|
const child = childProcess.spawnSync(process.execPath, [nudgeScript], {
|
|
13023
13191
|
stdio: ["inherit", "inherit", "inherit"]
|
|
13024
13192
|
});
|
|
@@ -13054,6 +13222,9 @@ if (!firstArg || firstArg === "help" || firstArg === "--help" || firstArg === "-
|
|
|
13054
13222
|
console.log(" terminalhire chat <github-login> --read Read a thread inline (last 8; -n N / --all for depth)");
|
|
13055
13223
|
console.log(' terminalhire chat <github-login> --send "\u2026" Send one line to a connection (E2E encrypted)');
|
|
13056
13224
|
console.log(" terminalhire chat <github-login> Open the live E2E chat pane with an accepted connection");
|
|
13225
|
+
console.log(" terminalhire connect Connect family overview + inbound-nudge state");
|
|
13226
|
+
console.log(" terminalhire connect --mute Stop surfacing incoming connection requests in the spinner");
|
|
13227
|
+
console.log(" terminalhire connect --unmute Resume surfacing incoming connection requests");
|
|
13057
13228
|
console.log(" terminalhire link Connect this terminal to your terminalhire account");
|
|
13058
13229
|
console.log(" terminalhire link --logout Revoke + remove this terminal's linked session");
|
|
13059
13230
|
console.log(" terminalhire profile --show Display your encrypted local profile");
|
|
@@ -13089,7 +13260,15 @@ if (!firstArg || firstArg === "help" || firstArg === "--help" || firstArg === "-
|
|
|
13089
13260
|
process.exit(0);
|
|
13090
13261
|
}
|
|
13091
13262
|
if (firstArg === "--version" || firstArg === "-v") {
|
|
13092
|
-
|
|
13263
|
+
const local = readPackageVersion();
|
|
13264
|
+
console.log(`terminalhire v${local}`);
|
|
13265
|
+
try {
|
|
13266
|
+
const { cachedStaleNudge: cachedStaleNudge2 } = await Promise.resolve().then(() => (init_version_nudge(), version_nudge_exports));
|
|
13267
|
+
const nudge = cachedStaleNudge2(local);
|
|
13268
|
+
if (nudge) process.stderr.write(`${nudge}
|
|
13269
|
+
`);
|
|
13270
|
+
} catch {
|
|
13271
|
+
}
|
|
13093
13272
|
process.exit(0);
|
|
13094
13273
|
}
|
|
13095
13274
|
if (firstArg === "login" || firstArg === "logout") {
|
|
@@ -13145,6 +13324,11 @@ if (firstArg === "chat") {
|
|
|
13145
13324
|
await mod2.run();
|
|
13146
13325
|
process.exit(0);
|
|
13147
13326
|
}
|
|
13327
|
+
if (firstArg === "connect") {
|
|
13328
|
+
const mod2 = await Promise.resolve().then(() => (init_jpi_connect(), jpi_connect_exports));
|
|
13329
|
+
await mod2.run();
|
|
13330
|
+
process.exit(0);
|
|
13331
|
+
}
|
|
13148
13332
|
if (firstArg === "link") {
|
|
13149
13333
|
process.argv.splice(2, 1);
|
|
13150
13334
|
const mod2 = await Promise.resolve().then(() => (init_jpi_link(), jpi_link_exports));
|