terminalhire 0.9.0 → 0.9.2
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 +74 -39
- package/dist/bin/jpi-chat.js +75 -44
- package/dist/bin/jpi-dispatch.js +452 -210
- package/dist/bin/jpi-intro.js +72 -45
- package/dist/bin/jpi-link.js +285 -0
- package/dist/bin/jpi-trajectory.js +83 -44
- package/dist/src/chat-client.js +48 -15
- package/dist/src/intro.js +68 -45
- package/dist/src/link.js +253 -0
- package/dist/src/trajectory.js +77 -44
- package/dist/src/web-session.js +55 -0
- package/package.json +1 -1
|
@@ -285,7 +285,7 @@ function finalize(build) {
|
|
|
285
285
|
};
|
|
286
286
|
}
|
|
287
287
|
function reconstruct(files, opts = {}) {
|
|
288
|
-
const
|
|
288
|
+
const join5 = opts.joinSidechains !== false;
|
|
289
289
|
const mains = [];
|
|
290
290
|
const sidechains = [];
|
|
291
291
|
for (const file of files) {
|
|
@@ -310,7 +310,7 @@ function reconstruct(files, opts = {}) {
|
|
|
310
310
|
}
|
|
311
311
|
const orphanedSidechainPaths = [];
|
|
312
312
|
const joinedPaths = /* @__PURE__ */ new Set();
|
|
313
|
-
if (
|
|
313
|
+
if (join5) {
|
|
314
314
|
const sidechainsBySession = /* @__PURE__ */ new Map();
|
|
315
315
|
for (const sc of sidechains) {
|
|
316
316
|
const acc = sidechainsBySession.get(sc.sessionId) ?? [];
|
|
@@ -855,6 +855,45 @@ var init_episodes = __esm({
|
|
|
855
855
|
}
|
|
856
856
|
});
|
|
857
857
|
|
|
858
|
+
// src/web-session.ts
|
|
859
|
+
import {
|
|
860
|
+
chmodSync,
|
|
861
|
+
existsSync,
|
|
862
|
+
mkdirSync,
|
|
863
|
+
readFileSync,
|
|
864
|
+
rmSync,
|
|
865
|
+
writeFileSync
|
|
866
|
+
} from "fs";
|
|
867
|
+
import { homedir } from "os";
|
|
868
|
+
import { join } from "path";
|
|
869
|
+
function terminalhireDir() {
|
|
870
|
+
return join(homedir(), ".terminalhire");
|
|
871
|
+
}
|
|
872
|
+
function webSessionFilePath() {
|
|
873
|
+
return join(terminalhireDir(), "web-session");
|
|
874
|
+
}
|
|
875
|
+
function readWebSessionFile() {
|
|
876
|
+
try {
|
|
877
|
+
const path = webSessionFilePath();
|
|
878
|
+
if (!existsSync(path)) return null;
|
|
879
|
+
const v = readFileSync(path, "utf8").trim();
|
|
880
|
+
return v.length > 0 ? v : null;
|
|
881
|
+
} catch {
|
|
882
|
+
return null;
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
function readWebSessionCookie() {
|
|
886
|
+
const fromFile = readWebSessionFile();
|
|
887
|
+
if (fromFile) return fromFile;
|
|
888
|
+
const env = process.env["TERMINALHIRE_WEB_SESSION"];
|
|
889
|
+
return typeof env === "string" && env.length > 0 ? env : null;
|
|
890
|
+
}
|
|
891
|
+
var init_web_session = __esm({
|
|
892
|
+
"src/web-session.ts"() {
|
|
893
|
+
"use strict";
|
|
894
|
+
}
|
|
895
|
+
});
|
|
896
|
+
|
|
858
897
|
// ../../packages/core/src/types.ts
|
|
859
898
|
var init_types = __esm({
|
|
860
899
|
"../../packages/core/src/types.ts"() {
|
|
@@ -1530,8 +1569,8 @@ var init_feeds = __esm({
|
|
|
1530
1569
|
});
|
|
1531
1570
|
|
|
1532
1571
|
// ../../packages/core/src/partners.ts
|
|
1533
|
-
import { readFileSync } from "fs";
|
|
1534
|
-
import { join } from "path";
|
|
1572
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
1573
|
+
import { join as join2 } from "path";
|
|
1535
1574
|
import { fileURLToPath } from "url";
|
|
1536
1575
|
var EXAMPLE_BUYER, BUYER_REGISTRY;
|
|
1537
1576
|
var init_partners = __esm({
|
|
@@ -1629,13 +1668,13 @@ import {
|
|
|
1629
1668
|
randomBytes as randomBytes2
|
|
1630
1669
|
} from "crypto";
|
|
1631
1670
|
import {
|
|
1632
|
-
readFileSync as
|
|
1633
|
-
writeFileSync,
|
|
1634
|
-
mkdirSync,
|
|
1635
|
-
existsSync
|
|
1671
|
+
readFileSync as readFileSync3,
|
|
1672
|
+
writeFileSync as writeFileSync2,
|
|
1673
|
+
mkdirSync as mkdirSync2,
|
|
1674
|
+
existsSync as existsSync2
|
|
1636
1675
|
} from "fs";
|
|
1637
|
-
import { join as
|
|
1638
|
-
import { homedir } from "os";
|
|
1676
|
+
import { join as join3 } from "path";
|
|
1677
|
+
import { homedir as homedir2 } from "os";
|
|
1639
1678
|
async function loadKey() {
|
|
1640
1679
|
try {
|
|
1641
1680
|
const kt = await import("keytar");
|
|
@@ -1648,12 +1687,12 @@ async function loadKey() {
|
|
|
1648
1687
|
return key2;
|
|
1649
1688
|
} catch {
|
|
1650
1689
|
}
|
|
1651
|
-
|
|
1652
|
-
if (
|
|
1653
|
-
return Buffer.from(
|
|
1690
|
+
mkdirSync2(TERMINALHIRE_DIR, { recursive: true });
|
|
1691
|
+
if (existsSync2(KEY_FILE)) {
|
|
1692
|
+
return Buffer.from(readFileSync3(KEY_FILE, "utf8").trim(), "hex");
|
|
1654
1693
|
}
|
|
1655
1694
|
const key = randomBytes2(KEY_BYTES);
|
|
1656
|
-
|
|
1695
|
+
writeFileSync2(KEY_FILE, key.toString("hex"), { mode: 384, encoding: "utf8" });
|
|
1657
1696
|
return key;
|
|
1658
1697
|
}
|
|
1659
1698
|
function encrypt(plaintext, key) {
|
|
@@ -1711,10 +1750,10 @@ function migrateTagWeights(profile) {
|
|
|
1711
1750
|
}
|
|
1712
1751
|
}
|
|
1713
1752
|
async function readProfile() {
|
|
1714
|
-
if (!
|
|
1753
|
+
if (!existsSync2(PROFILE_FILE)) return blankProfile();
|
|
1715
1754
|
try {
|
|
1716
1755
|
const key = await loadKey();
|
|
1717
|
-
const raw =
|
|
1756
|
+
const raw = readFileSync3(PROFILE_FILE, "utf8");
|
|
1718
1757
|
const blob = JSON.parse(raw);
|
|
1719
1758
|
const plaintext = decrypt(blob, key);
|
|
1720
1759
|
const parsed = JSON.parse(plaintext);
|
|
@@ -1725,12 +1764,12 @@ async function readProfile() {
|
|
|
1725
1764
|
}
|
|
1726
1765
|
}
|
|
1727
1766
|
async function writeProfile(profile) {
|
|
1728
|
-
|
|
1767
|
+
mkdirSync2(TERMINALHIRE_DIR, { recursive: true });
|
|
1729
1768
|
const key = await loadKey();
|
|
1730
1769
|
profile.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1731
1770
|
profile.skillTags = deriveSkillTags(profile.tagWeights);
|
|
1732
1771
|
const blob = encrypt(JSON.stringify(profile), key);
|
|
1733
|
-
|
|
1772
|
+
writeFileSync2(PROFILE_FILE, JSON.stringify(blob, null, 2), { encoding: "utf8" });
|
|
1734
1773
|
}
|
|
1735
1774
|
function accumulateSession(profile, tags, isEmployerContext, inferredSeniority, seniorityIsAuthoritative = false) {
|
|
1736
1775
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1791,13 +1830,13 @@ async function removeSavedJob(id) {
|
|
|
1791
1830
|
return true;
|
|
1792
1831
|
}
|
|
1793
1832
|
async function deleteProfile() {
|
|
1794
|
-
const { rmSync } = await import("fs");
|
|
1833
|
+
const { rmSync: rmSync2 } = await import("fs");
|
|
1795
1834
|
try {
|
|
1796
|
-
|
|
1835
|
+
rmSync2(PROFILE_FILE);
|
|
1797
1836
|
} catch {
|
|
1798
1837
|
}
|
|
1799
1838
|
try {
|
|
1800
|
-
|
|
1839
|
+
rmSync2(KEY_FILE);
|
|
1801
1840
|
} catch {
|
|
1802
1841
|
}
|
|
1803
1842
|
}
|
|
@@ -1819,9 +1858,9 @@ var init_profile = __esm({
|
|
|
1819
1858
|
"src/profile.ts"() {
|
|
1820
1859
|
"use strict";
|
|
1821
1860
|
init_src();
|
|
1822
|
-
TERMINALHIRE_DIR =
|
|
1823
|
-
PROFILE_FILE =
|
|
1824
|
-
KEY_FILE =
|
|
1861
|
+
TERMINALHIRE_DIR = join3(homedir2(), ".terminalhire");
|
|
1862
|
+
PROFILE_FILE = join3(TERMINALHIRE_DIR, "profile.enc");
|
|
1863
|
+
KEY_FILE = join3(TERMINALHIRE_DIR, "key");
|
|
1825
1864
|
ALGO = "aes-256-gcm";
|
|
1826
1865
|
KEY_BYTES = 32;
|
|
1827
1866
|
IV_BYTES = 12;
|
|
@@ -1891,14 +1930,14 @@ __export(trajectory_exports, {
|
|
|
1891
1930
|
runTrajectoryPush: () => runTrajectoryPush
|
|
1892
1931
|
});
|
|
1893
1932
|
import {
|
|
1894
|
-
existsSync as
|
|
1895
|
-
mkdirSync as
|
|
1896
|
-
readFileSync as
|
|
1933
|
+
existsSync as existsSync3,
|
|
1934
|
+
mkdirSync as mkdirSync3,
|
|
1935
|
+
readFileSync as readFileSync4,
|
|
1897
1936
|
readdirSync,
|
|
1898
|
-
writeFileSync as
|
|
1937
|
+
writeFileSync as writeFileSync3
|
|
1899
1938
|
} from "fs";
|
|
1900
|
-
import { homedir as
|
|
1901
|
-
import { join as
|
|
1939
|
+
import { homedir as homedir3 } from "os";
|
|
1940
|
+
import { join as join4 } from "path";
|
|
1902
1941
|
function isRecord4(value) {
|
|
1903
1942
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1904
1943
|
}
|
|
@@ -1930,7 +1969,7 @@ function findJsonlFiles(dir) {
|
|
|
1930
1969
|
return out;
|
|
1931
1970
|
}
|
|
1932
1971
|
for (const entry of entries) {
|
|
1933
|
-
const full =
|
|
1972
|
+
const full = join4(dir, entry.name);
|
|
1934
1973
|
if (entry.isDirectory()) {
|
|
1935
1974
|
out.push(...findJsonlFiles(full));
|
|
1936
1975
|
} else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
@@ -1944,7 +1983,7 @@ function loadCorpus(paths) {
|
|
|
1944
1983
|
for (const path of paths) {
|
|
1945
1984
|
let text;
|
|
1946
1985
|
try {
|
|
1947
|
-
text =
|
|
1986
|
+
text = readFileSync4(path, "utf8");
|
|
1948
1987
|
} catch {
|
|
1949
1988
|
continue;
|
|
1950
1989
|
}
|
|
@@ -2043,12 +2082,12 @@ function renderMarkdown(view) {
|
|
|
2043
2082
|
return lines.join("\n");
|
|
2044
2083
|
}
|
|
2045
2084
|
function writeExportArtifacts(score, markdown) {
|
|
2046
|
-
const dir =
|
|
2047
|
-
|
|
2048
|
-
const jsonPath =
|
|
2049
|
-
const mdPath =
|
|
2050
|
-
|
|
2051
|
-
|
|
2085
|
+
const dir = join4(homedir3(), ".terminalhire");
|
|
2086
|
+
mkdirSync3(dir, { recursive: true });
|
|
2087
|
+
const jsonPath = join4(dir, "trajectory-export.json");
|
|
2088
|
+
const mdPath = join4(dir, "trajectory-export.md");
|
|
2089
|
+
writeFileSync3(jsonPath, JSON.stringify(score, null, 2) + "\n", "utf8");
|
|
2090
|
+
writeFileSync3(mdPath, markdown, "utf8");
|
|
2052
2091
|
return { jsonPath, mdPath };
|
|
2053
2092
|
}
|
|
2054
2093
|
function renderInward(allNodes, view, files) {
|
|
@@ -2067,8 +2106,8 @@ function renderInward(allNodes, view, files) {
|
|
|
2067
2106
|
console.log("");
|
|
2068
2107
|
}
|
|
2069
2108
|
function buildTrajectory() {
|
|
2070
|
-
const projectsDir =
|
|
2071
|
-
if (!
|
|
2109
|
+
const projectsDir = join4(homedir3(), ".claude", "projects");
|
|
2110
|
+
if (!existsSync3(projectsDir)) return null;
|
|
2072
2111
|
const paths = findJsonlFiles(projectsDir);
|
|
2073
2112
|
if (paths.length === 0) return null;
|
|
2074
2113
|
const files = loadCorpus(paths);
|
|
@@ -2155,10 +2194,9 @@ function defaultPushDeps() {
|
|
|
2155
2194
|
void Promise.resolve().then(() => (init_open_url(), open_url_exports)).then((m) => m.openInBrowser(url)).catch(() => {
|
|
2156
2195
|
});
|
|
2157
2196
|
},
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
},
|
|
2197
|
+
// Session source priority: persisted file (`terminalhire link`) FIRST, then the
|
|
2198
|
+
// legacy TERMINALHIRE_WEB_SESSION env, then none.
|
|
2199
|
+
sessionCookie: () => readWebSessionCookie(),
|
|
2162
2200
|
log: (msg) => console.log(msg),
|
|
2163
2201
|
errorLog: (msg) => console.error(msg),
|
|
2164
2202
|
exit: (code) => process.exit(code)
|
|
@@ -2317,6 +2355,7 @@ var init_trajectory = __esm({
|
|
|
2317
2355
|
"src/trajectory.ts"() {
|
|
2318
2356
|
"use strict";
|
|
2319
2357
|
init_episodes();
|
|
2358
|
+
init_web_session();
|
|
2320
2359
|
CAP_LABELS = {
|
|
2321
2360
|
"cap:ui-automation": "UI automation",
|
|
2322
2361
|
"cap:deploys": "Deployment",
|
package/dist/src/chat-client.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/chat-client.ts
|
|
2
|
-
import { existsSync as
|
|
3
|
-
import { homedir as
|
|
4
|
-
import { join as
|
|
2
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
3
|
+
import { homedir as homedir4 } from "os";
|
|
4
|
+
import { join as join5 } from "path";
|
|
5
5
|
|
|
6
6
|
// ../../packages/core/src/vocab/graph.data.ts
|
|
7
7
|
var VOCAB_NODES = [
|
|
@@ -3455,16 +3455,50 @@ async function loadOrCreateIdentity() {
|
|
|
3455
3455
|
return keypair;
|
|
3456
3456
|
}
|
|
3457
3457
|
|
|
3458
|
+
// src/web-session.ts
|
|
3459
|
+
import {
|
|
3460
|
+
chmodSync,
|
|
3461
|
+
existsSync as existsSync3,
|
|
3462
|
+
mkdirSync as mkdirSync3,
|
|
3463
|
+
readFileSync as readFileSync4,
|
|
3464
|
+
rmSync as rmSync3,
|
|
3465
|
+
writeFileSync as writeFileSync3
|
|
3466
|
+
} from "fs";
|
|
3467
|
+
import { homedir as homedir3 } from "os";
|
|
3468
|
+
import { join as join4 } from "path";
|
|
3469
|
+
function terminalhireDir() {
|
|
3470
|
+
return join4(homedir3(), ".terminalhire");
|
|
3471
|
+
}
|
|
3472
|
+
function webSessionFilePath() {
|
|
3473
|
+
return join4(terminalhireDir(), "web-session");
|
|
3474
|
+
}
|
|
3475
|
+
function readWebSessionFile() {
|
|
3476
|
+
try {
|
|
3477
|
+
const path = webSessionFilePath();
|
|
3478
|
+
if (!existsSync3(path)) return null;
|
|
3479
|
+
const v = readFileSync4(path, "utf8").trim();
|
|
3480
|
+
return v.length > 0 ? v : null;
|
|
3481
|
+
} catch {
|
|
3482
|
+
return null;
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
3485
|
+
function readWebSessionCookie() {
|
|
3486
|
+
const fromFile = readWebSessionFile();
|
|
3487
|
+
if (fromFile) return fromFile;
|
|
3488
|
+
const env = process.env["TERMINALHIRE_WEB_SESSION"];
|
|
3489
|
+
return typeof env === "string" && env.length > 0 ? env : null;
|
|
3490
|
+
}
|
|
3491
|
+
|
|
3458
3492
|
// src/chat-client.ts
|
|
3459
3493
|
var CHAT_BASE = process.env["TERMINALHIRE_API_URL"] || "https://www.terminalhire.com";
|
|
3460
3494
|
var GH_SESSION_COOKIE = "__jpi_gh_session";
|
|
3461
|
-
var TERMINALHIRE_DIR3 =
|
|
3462
|
-
var PEERS_FILE =
|
|
3495
|
+
var TERMINALHIRE_DIR3 = join5(homedir4(), ".terminalhire");
|
|
3496
|
+
var PEERS_FILE = join5(TERMINALHIRE_DIR3, "chat-peers.json");
|
|
3463
3497
|
var REQUEST_TIMEOUT_MS = 1e4;
|
|
3464
3498
|
var ChatNotLinkedError = class extends Error {
|
|
3465
3499
|
constructor() {
|
|
3466
3500
|
super(
|
|
3467
|
-
|
|
3501
|
+
"No linked web session found on this machine. Run `terminalhire link` to connect this terminal to your account, then re-run."
|
|
3468
3502
|
);
|
|
3469
3503
|
this.name = "ChatNotLinkedError";
|
|
3470
3504
|
}
|
|
@@ -3472,7 +3506,7 @@ var ChatNotLinkedError = class extends Error {
|
|
|
3472
3506
|
var ChatSessionExpiredError = class extends Error {
|
|
3473
3507
|
constructor() {
|
|
3474
3508
|
super(
|
|
3475
|
-
|
|
3509
|
+
"Your linked web session expired. Run `terminalhire link` to reconnect this terminal, then re-run."
|
|
3476
3510
|
);
|
|
3477
3511
|
this.name = "ChatSessionExpiredError";
|
|
3478
3512
|
}
|
|
@@ -3499,8 +3533,8 @@ var ChatRequestError = class extends Error {
|
|
|
3499
3533
|
};
|
|
3500
3534
|
function defaultReadPeerPins() {
|
|
3501
3535
|
try {
|
|
3502
|
-
if (!
|
|
3503
|
-
const parsed = JSON.parse(
|
|
3536
|
+
if (!existsSync4(PEERS_FILE)) return {};
|
|
3537
|
+
const parsed = JSON.parse(readFileSync5(PEERS_FILE, "utf8"));
|
|
3504
3538
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
|
|
3505
3539
|
const out = {};
|
|
3506
3540
|
for (const [login, key] of Object.entries(parsed)) {
|
|
@@ -3512,16 +3546,15 @@ function defaultReadPeerPins() {
|
|
|
3512
3546
|
}
|
|
3513
3547
|
}
|
|
3514
3548
|
function defaultWritePeerPins(pins) {
|
|
3515
|
-
|
|
3516
|
-
|
|
3549
|
+
mkdirSync4(TERMINALHIRE_DIR3, { recursive: true });
|
|
3550
|
+
writeFileSync4(PEERS_FILE, JSON.stringify(pins, null, 2), { mode: 384, encoding: "utf8" });
|
|
3517
3551
|
}
|
|
3518
3552
|
function defaultChatClientDeps() {
|
|
3519
3553
|
return {
|
|
3520
3554
|
fetchImpl: (...args) => globalThis.fetch(...args),
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
},
|
|
3555
|
+
// Session source priority: persisted file (`terminalhire link`) FIRST, then the
|
|
3556
|
+
// legacy TERMINALHIRE_WEB_SESSION env, then none.
|
|
3557
|
+
sessionCookie: () => readWebSessionCookie(),
|
|
3525
3558
|
loadIdentity: () => loadOrCreateIdentity(),
|
|
3526
3559
|
readPeerPins: defaultReadPeerPins,
|
|
3527
3560
|
writePeerPins: defaultWritePeerPins
|
package/dist/src/intro.js
CHANGED
|
@@ -793,13 +793,13 @@ import {
|
|
|
793
793
|
randomBytes as randomBytes2
|
|
794
794
|
} from "crypto";
|
|
795
795
|
import {
|
|
796
|
-
readFileSync as
|
|
797
|
-
writeFileSync,
|
|
798
|
-
mkdirSync,
|
|
799
|
-
existsSync
|
|
796
|
+
readFileSync as readFileSync3,
|
|
797
|
+
writeFileSync as writeFileSync2,
|
|
798
|
+
mkdirSync as mkdirSync2,
|
|
799
|
+
existsSync as existsSync2
|
|
800
800
|
} from "fs";
|
|
801
|
-
import { join as
|
|
802
|
-
import { homedir } from "os";
|
|
801
|
+
import { join as join3 } from "path";
|
|
802
|
+
import { homedir as homedir2 } from "os";
|
|
803
803
|
async function loadKey() {
|
|
804
804
|
try {
|
|
805
805
|
const kt = await import("keytar");
|
|
@@ -812,12 +812,12 @@ async function loadKey() {
|
|
|
812
812
|
return key2;
|
|
813
813
|
} catch {
|
|
814
814
|
}
|
|
815
|
-
|
|
816
|
-
if (
|
|
817
|
-
return Buffer.from(
|
|
815
|
+
mkdirSync2(TERMINALHIRE_DIR, { recursive: true });
|
|
816
|
+
if (existsSync2(KEY_FILE)) {
|
|
817
|
+
return Buffer.from(readFileSync3(KEY_FILE, "utf8").trim(), "hex");
|
|
818
818
|
}
|
|
819
819
|
const key = randomBytes2(KEY_BYTES);
|
|
820
|
-
|
|
820
|
+
writeFileSync2(KEY_FILE, key.toString("hex"), { mode: 384, encoding: "utf8" });
|
|
821
821
|
return key;
|
|
822
822
|
}
|
|
823
823
|
function encrypt(plaintext, key) {
|
|
@@ -875,10 +875,10 @@ function migrateTagWeights(profile) {
|
|
|
875
875
|
}
|
|
876
876
|
}
|
|
877
877
|
async function readProfile() {
|
|
878
|
-
if (!
|
|
878
|
+
if (!existsSync2(PROFILE_FILE)) return blankProfile();
|
|
879
879
|
try {
|
|
880
880
|
const key = await loadKey();
|
|
881
|
-
const raw =
|
|
881
|
+
const raw = readFileSync3(PROFILE_FILE, "utf8");
|
|
882
882
|
const blob = JSON.parse(raw);
|
|
883
883
|
const plaintext = decrypt(blob, key);
|
|
884
884
|
const parsed = JSON.parse(plaintext);
|
|
@@ -889,12 +889,12 @@ async function readProfile() {
|
|
|
889
889
|
}
|
|
890
890
|
}
|
|
891
891
|
async function writeProfile(profile) {
|
|
892
|
-
|
|
892
|
+
mkdirSync2(TERMINALHIRE_DIR, { recursive: true });
|
|
893
893
|
const key = await loadKey();
|
|
894
894
|
profile.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
895
895
|
profile.skillTags = deriveSkillTags(profile.tagWeights);
|
|
896
896
|
const blob = encrypt(JSON.stringify(profile), key);
|
|
897
|
-
|
|
897
|
+
writeFileSync2(PROFILE_FILE, JSON.stringify(blob, null, 2), { encoding: "utf8" });
|
|
898
898
|
}
|
|
899
899
|
function accumulateSession(profile, tags, isEmployerContext, inferredSeniority, seniorityIsAuthoritative = false) {
|
|
900
900
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -955,13 +955,13 @@ async function removeSavedJob(id) {
|
|
|
955
955
|
return true;
|
|
956
956
|
}
|
|
957
957
|
async function deleteProfile() {
|
|
958
|
-
const { rmSync } = await import("fs");
|
|
958
|
+
const { rmSync: rmSync2 } = await import("fs");
|
|
959
959
|
try {
|
|
960
|
-
|
|
960
|
+
rmSync2(PROFILE_FILE);
|
|
961
961
|
} catch {
|
|
962
962
|
}
|
|
963
963
|
try {
|
|
964
|
-
|
|
964
|
+
rmSync2(KEY_FILE);
|
|
965
965
|
} catch {
|
|
966
966
|
}
|
|
967
967
|
}
|
|
@@ -983,9 +983,9 @@ var init_profile = __esm({
|
|
|
983
983
|
"src/profile.ts"() {
|
|
984
984
|
"use strict";
|
|
985
985
|
init_src();
|
|
986
|
-
TERMINALHIRE_DIR =
|
|
987
|
-
PROFILE_FILE =
|
|
988
|
-
KEY_FILE =
|
|
986
|
+
TERMINALHIRE_DIR = join3(homedir2(), ".terminalhire");
|
|
987
|
+
PROFILE_FILE = join3(TERMINALHIRE_DIR, "profile.enc");
|
|
988
|
+
KEY_FILE = join3(TERMINALHIRE_DIR, "key");
|
|
989
989
|
ALGO = "aes-256-gcm";
|
|
990
990
|
KEY_BYTES = 32;
|
|
991
991
|
IV_BYTES = 12;
|
|
@@ -1048,6 +1048,42 @@ var init_open_url = __esm({
|
|
|
1048
1048
|
|
|
1049
1049
|
// src/intro.ts
|
|
1050
1050
|
init_src();
|
|
1051
|
+
|
|
1052
|
+
// src/web-session.ts
|
|
1053
|
+
import {
|
|
1054
|
+
chmodSync,
|
|
1055
|
+
existsSync,
|
|
1056
|
+
mkdirSync,
|
|
1057
|
+
readFileSync as readFileSync2,
|
|
1058
|
+
rmSync,
|
|
1059
|
+
writeFileSync
|
|
1060
|
+
} from "fs";
|
|
1061
|
+
import { homedir } from "os";
|
|
1062
|
+
import { join as join2 } from "path";
|
|
1063
|
+
function terminalhireDir() {
|
|
1064
|
+
return join2(homedir(), ".terminalhire");
|
|
1065
|
+
}
|
|
1066
|
+
function webSessionFilePath() {
|
|
1067
|
+
return join2(terminalhireDir(), "web-session");
|
|
1068
|
+
}
|
|
1069
|
+
function readWebSessionFile() {
|
|
1070
|
+
try {
|
|
1071
|
+
const path = webSessionFilePath();
|
|
1072
|
+
if (!existsSync(path)) return null;
|
|
1073
|
+
const v = readFileSync2(path, "utf8").trim();
|
|
1074
|
+
return v.length > 0 ? v : null;
|
|
1075
|
+
} catch {
|
|
1076
|
+
return null;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
function readWebSessionCookie() {
|
|
1080
|
+
const fromFile = readWebSessionFile();
|
|
1081
|
+
if (fromFile) return fromFile;
|
|
1082
|
+
const env = process.env["TERMINALHIRE_WEB_SESSION"];
|
|
1083
|
+
return typeof env === "string" && env.length > 0 ? env : null;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// src/intro.ts
|
|
1051
1087
|
var LINK_BASE = process.env["TERMINALHIRE_API_URL"] || "https://www.terminalhire.com";
|
|
1052
1088
|
var GH_SESSION_COOKIE = "__jpi_gh_session";
|
|
1053
1089
|
function defaultIntroDeps() {
|
|
@@ -1085,10 +1121,9 @@ function defaultIntroDeps() {
|
|
|
1085
1121
|
void Promise.resolve().then(() => (init_open_url(), open_url_exports)).then((m) => m.openInBrowser(url)).catch(() => {
|
|
1086
1122
|
});
|
|
1087
1123
|
},
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
},
|
|
1124
|
+
// Session source priority: persisted file (`terminalhire link`) FIRST, then the
|
|
1125
|
+
// legacy TERMINALHIRE_WEB_SESSION env, then none.
|
|
1126
|
+
sessionCookie: () => readWebSessionCookie(),
|
|
1092
1127
|
log: (msg) => console.log(msg),
|
|
1093
1128
|
errorLog: (msg) => console.error(msg),
|
|
1094
1129
|
exit: (code) => process.exit(code)
|
|
@@ -1160,10 +1195,7 @@ async function runIntroRequest(args, overrides) {
|
|
|
1160
1195
|
const cookie = deps.sessionCookie();
|
|
1161
1196
|
if (!cookie) {
|
|
1162
1197
|
deps.log("\n No linked web session found on this machine.");
|
|
1163
|
-
deps.log("
|
|
1164
|
-
deps.log(` \u2192 ${LINK_BASE}/dashboard
|
|
1165
|
-
`);
|
|
1166
|
-
deps.openBrowser(`${LINK_BASE}/dashboard`);
|
|
1198
|
+
deps.log(" Run `terminalhire link` to connect this terminal to your account, then re-run.\n");
|
|
1167
1199
|
deps.exit(0);
|
|
1168
1200
|
return;
|
|
1169
1201
|
}
|
|
@@ -1183,9 +1215,8 @@ async function runIntroRequest(args, overrides) {
|
|
|
1183
1215
|
return;
|
|
1184
1216
|
}
|
|
1185
1217
|
if (res.status === 401) {
|
|
1186
|
-
deps.log("\n Your web session expired
|
|
1187
|
-
deps.log(
|
|
1188
|
-
`);
|
|
1218
|
+
deps.log("\n Your linked web session expired.");
|
|
1219
|
+
deps.log(" Run `terminalhire link` to reconnect this terminal, then re-run.\n");
|
|
1189
1220
|
deps.exit(1);
|
|
1190
1221
|
return;
|
|
1191
1222
|
}
|
|
@@ -1216,10 +1247,7 @@ async function runIntroDecision(args, overrides) {
|
|
|
1216
1247
|
const cookie = deps.sessionCookie();
|
|
1217
1248
|
if (!cookie) {
|
|
1218
1249
|
deps.log("\n No linked web session found on this machine.");
|
|
1219
|
-
deps.log("
|
|
1220
|
-
deps.log(` \u2192 ${LINK_BASE}/dashboard
|
|
1221
|
-
`);
|
|
1222
|
-
deps.openBrowser(`${LINK_BASE}/dashboard`);
|
|
1250
|
+
deps.log(" Run `terminalhire link` to connect this terminal to your account, then re-run.\n");
|
|
1223
1251
|
deps.exit(0);
|
|
1224
1252
|
return;
|
|
1225
1253
|
}
|
|
@@ -1262,9 +1290,8 @@ async function runIntroDecision(args, overrides) {
|
|
|
1262
1290
|
return;
|
|
1263
1291
|
}
|
|
1264
1292
|
if (res.status === 401) {
|
|
1265
|
-
deps.log("\n Your web session expired
|
|
1266
|
-
deps.log(
|
|
1267
|
-
`);
|
|
1293
|
+
deps.log("\n Your linked web session expired.");
|
|
1294
|
+
deps.log(" Run `terminalhire link` to reconnect this terminal, then re-run.\n");
|
|
1268
1295
|
deps.exit(1);
|
|
1269
1296
|
return;
|
|
1270
1297
|
}
|
|
@@ -1303,10 +1330,7 @@ async function runIntroList(overrides) {
|
|
|
1303
1330
|
const cookie = deps.sessionCookie();
|
|
1304
1331
|
if (!cookie) {
|
|
1305
1332
|
deps.log("\n No linked web session found on this machine.");
|
|
1306
|
-
deps.log("
|
|
1307
|
-
deps.log(` \u2192 ${LINK_BASE}/dashboard
|
|
1308
|
-
`);
|
|
1309
|
-
deps.openBrowser(`${LINK_BASE}/dashboard`);
|
|
1333
|
+
deps.log(" Run `terminalhire link` to connect this terminal to your account, then re-run.\n");
|
|
1310
1334
|
deps.exit(0);
|
|
1311
1335
|
return;
|
|
1312
1336
|
}
|
|
@@ -1325,9 +1349,8 @@ async function runIntroList(overrides) {
|
|
|
1325
1349
|
return;
|
|
1326
1350
|
}
|
|
1327
1351
|
if (res.status === 401) {
|
|
1328
|
-
deps.log("\n Your web session expired
|
|
1329
|
-
deps.log(
|
|
1330
|
-
`);
|
|
1352
|
+
deps.log("\n Your linked web session expired.");
|
|
1353
|
+
deps.log(" Run `terminalhire link` to reconnect this terminal, then re-run.\n");
|
|
1331
1354
|
deps.exit(1);
|
|
1332
1355
|
return;
|
|
1333
1356
|
}
|