terminalhire 0.19.2 → 0.20.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.
@@ -950,6 +950,65 @@ var init_src = __esm({
950
950
  }
951
951
  });
952
952
 
953
+ // ../../node_modules/keytar/build/Release/keytar.node
954
+ var keytar_default;
955
+ var init_keytar = __esm({
956
+ "../../node_modules/keytar/build/Release/keytar.node"() {
957
+ keytar_default = "../keytar-KOAAH267.node";
958
+ }
959
+ });
960
+
961
+ // node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node
962
+ var require_keytar = __commonJS({
963
+ "node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node"(exports, module) {
964
+ "use strict";
965
+ init_keytar();
966
+ try {
967
+ module.exports = __require(keytar_default);
968
+ } catch {
969
+ }
970
+ }
971
+ });
972
+
973
+ // ../../node_modules/keytar/lib/keytar.js
974
+ var require_keytar2 = __commonJS({
975
+ "../../node_modules/keytar/lib/keytar.js"(exports, module) {
976
+ "use strict";
977
+ var keytar = require_keytar();
978
+ function checkRequired(val, name) {
979
+ if (!val || val.length <= 0) {
980
+ throw new Error(name + " is required.");
981
+ }
982
+ }
983
+ module.exports = {
984
+ getPassword: function(service, account) {
985
+ checkRequired(service, "Service");
986
+ checkRequired(account, "Account");
987
+ return keytar.getPassword(service, account);
988
+ },
989
+ setPassword: function(service, account, password) {
990
+ checkRequired(service, "Service");
991
+ checkRequired(account, "Account");
992
+ checkRequired(password, "Password");
993
+ return keytar.setPassword(service, account, password);
994
+ },
995
+ deletePassword: function(service, account) {
996
+ checkRequired(service, "Service");
997
+ checkRequired(account, "Account");
998
+ return keytar.deletePassword(service, account);
999
+ },
1000
+ findPassword: function(service) {
1001
+ checkRequired(service, "Service");
1002
+ return keytar.findPassword(service);
1003
+ },
1004
+ findCredentials: function(service) {
1005
+ checkRequired(service, "Service");
1006
+ return keytar.findCredentials(service);
1007
+ }
1008
+ };
1009
+ }
1010
+ });
1011
+
953
1012
  // src/claims.ts
954
1013
  var claims_exports = {};
955
1014
  __export(claims_exports, {
@@ -962,9 +1021,9 @@ __export(claims_exports, {
962
1021
  toPushedClaim: () => toPushedClaim,
963
1022
  updateClaim: () => updateClaim
964
1023
  });
965
- import { readFileSync as readFileSync2, writeFileSync, mkdirSync, renameSync, existsSync } from "fs";
966
- import { join as join2 } from "path";
967
- import { homedir } from "os";
1024
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, renameSync, existsSync as existsSync3 } from "fs";
1025
+ import { join as join4 } from "path";
1026
+ import { homedir as homedir3 } from "os";
968
1027
  function toPushedClaim(claim) {
969
1028
  return {
970
1029
  kind: claim.kind,
@@ -984,8 +1043,8 @@ function normalizeClaim(c) {
984
1043
  }
985
1044
  function readClaims() {
986
1045
  try {
987
- if (!existsSync(CLAIMS_FILE)) return [];
988
- const data = JSON.parse(readFileSync2(CLAIMS_FILE, "utf8"));
1046
+ if (!existsSync3(CLAIMS_FILE)) return [];
1047
+ const data = JSON.parse(readFileSync4(CLAIMS_FILE, "utf8"));
989
1048
  const claims = Array.isArray(data?.claims) ? data.claims : [];
990
1049
  return claims.map(normalizeClaim);
991
1050
  } catch {
@@ -993,10 +1052,10 @@ function readClaims() {
993
1052
  }
994
1053
  }
995
1054
  function writeClaims(claims) {
996
- mkdirSync(TERMINALHIRE_DIR, { recursive: true });
1055
+ mkdirSync3(TERMINALHIRE_DIR3, { recursive: true });
997
1056
  const tmp = `${CLAIMS_FILE}.tmp`;
998
1057
  const payload = { claims };
999
- writeFileSync(tmp, JSON.stringify(payload, null, 2), "utf8");
1058
+ writeFileSync3(tmp, JSON.stringify(payload, null, 2), "utf8");
1000
1059
  renameSync(tmp, CLAIMS_FILE);
1001
1060
  }
1002
1061
  function findClaim(id) {
@@ -1053,12 +1112,12 @@ function acceptedPRRate(claims = readClaims()) {
1053
1112
  const merged = claims.filter((c) => c.state === "merged").length;
1054
1113
  return { merged, total, rate: total === 0 ? 0 : merged / total };
1055
1114
  }
1056
- var TERMINALHIRE_DIR, CLAIMS_FILE, TERMINAL_STATES;
1115
+ var TERMINALHIRE_DIR3, CLAIMS_FILE, TERMINAL_STATES;
1057
1116
  var init_claims = __esm({
1058
1117
  "src/claims.ts"() {
1059
1118
  "use strict";
1060
- TERMINALHIRE_DIR = join2(homedir(), ".terminalhire");
1061
- CLAIMS_FILE = join2(TERMINALHIRE_DIR, "claims.json");
1119
+ TERMINALHIRE_DIR3 = join4(homedir3(), ".terminalhire");
1120
+ CLAIMS_FILE = join4(TERMINALHIRE_DIR3, "claims.json");
1062
1121
  TERMINAL_STATES = /* @__PURE__ */ new Set(["merged", "abandoned"]);
1063
1122
  }
1064
1123
  });
@@ -1157,25 +1216,25 @@ __export(job_status_store_exports, {
1157
1216
  statusFilePath: () => statusFilePath
1158
1217
  });
1159
1218
  import {
1160
- readFileSync as readFileSync3,
1161
- writeFileSync as writeFileSync2,
1219
+ readFileSync as readFileSync5,
1220
+ writeFileSync as writeFileSync4,
1162
1221
  renameSync as renameSync2,
1163
- mkdirSync as mkdirSync2,
1164
- existsSync as existsSync2,
1222
+ mkdirSync as mkdirSync4,
1223
+ existsSync as existsSync4,
1165
1224
  copyFileSync,
1166
1225
  openSync,
1167
1226
  closeSync,
1168
1227
  unlinkSync
1169
1228
  } from "fs";
1170
- import { join as join3, dirname } from "path";
1171
- import { homedir as homedir2 } from "os";
1229
+ import { join as join5, dirname } from "path";
1230
+ import { homedir as homedir4 } from "os";
1172
1231
  function statusFilePath() {
1173
1232
  return STATUS_FILE;
1174
1233
  }
1175
1234
  function atomicWriteJson(path, obj) {
1176
- mkdirSync2(dirname(path), { recursive: true });
1235
+ mkdirSync4(dirname(path), { recursive: true });
1177
1236
  const tmp = `${path}.tmp-${process.pid}`;
1178
- writeFileSync2(tmp, JSON.stringify(obj, null, 2) + "\n", "utf8");
1237
+ writeFileSync4(tmp, JSON.stringify(obj, null, 2) + "\n", "utf8");
1179
1238
  renameSync2(tmp, path);
1180
1239
  }
1181
1240
  function sleepMs(ms) {
@@ -1192,7 +1251,7 @@ function withLock(fn) {
1192
1251
  for (; ; ) {
1193
1252
  let fd;
1194
1253
  try {
1195
- mkdirSync2(dirname(LOCK_FILE), { recursive: true });
1254
+ mkdirSync4(dirname(LOCK_FILE), { recursive: true });
1196
1255
  fd = openSync(LOCK_FILE, "wx");
1197
1256
  } catch (err) {
1198
1257
  if (err && err.code === "EEXIST") {
@@ -1223,10 +1282,10 @@ function withLock(fn) {
1223
1282
  }
1224
1283
  }
1225
1284
  function readStatusMap() {
1226
- if (!existsSync2(STATUS_FILE)) return {};
1285
+ if (!existsSync4(STATUS_FILE)) return {};
1227
1286
  let raw;
1228
1287
  try {
1229
- raw = readFileSync3(STATUS_FILE, "utf8");
1288
+ raw = readFileSync5(STATUS_FILE, "utf8");
1230
1289
  } catch {
1231
1290
  return {};
1232
1291
  }
@@ -1258,77 +1317,18 @@ function markClicked(id) {
1258
1317
  return next[id];
1259
1318
  });
1260
1319
  }
1261
- var TERMINALHIRE_DIR2, STATUS_FILE, LOCK_FILE, BAK_FILE;
1320
+ var TERMINALHIRE_DIR4, STATUS_FILE, LOCK_FILE, BAK_FILE;
1262
1321
  var init_job_status_store = __esm({
1263
1322
  "bin/job-status-store.js"() {
1264
1323
  "use strict";
1265
1324
  init_src();
1266
- TERMINALHIRE_DIR2 = process.env.TERMINALHIRE_DIR || join3(homedir2(), ".terminalhire");
1267
- STATUS_FILE = join3(TERMINALHIRE_DIR2, "job-status.json");
1325
+ TERMINALHIRE_DIR4 = process.env.TERMINALHIRE_DIR || join5(homedir4(), ".terminalhire");
1326
+ STATUS_FILE = join5(TERMINALHIRE_DIR4, "job-status.json");
1268
1327
  LOCK_FILE = `${STATUS_FILE}.lock`;
1269
1328
  BAK_FILE = `${STATUS_FILE}.bak`;
1270
1329
  }
1271
1330
  });
1272
1331
 
1273
- // ../../node_modules/keytar/build/Release/keytar.node
1274
- var keytar_default;
1275
- var init_keytar = __esm({
1276
- "../../node_modules/keytar/build/Release/keytar.node"() {
1277
- keytar_default = "../keytar-KOAAH267.node";
1278
- }
1279
- });
1280
-
1281
- // node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/release-0192/node_modules/keytar/build/Release/keytar.node
1282
- var require_keytar = __commonJS({
1283
- "node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/release-0192/node_modules/keytar/build/Release/keytar.node"(exports, module) {
1284
- "use strict";
1285
- init_keytar();
1286
- try {
1287
- module.exports = __require(keytar_default);
1288
- } catch {
1289
- }
1290
- }
1291
- });
1292
-
1293
- // ../../node_modules/keytar/lib/keytar.js
1294
- var require_keytar2 = __commonJS({
1295
- "../../node_modules/keytar/lib/keytar.js"(exports, module) {
1296
- "use strict";
1297
- var keytar = require_keytar();
1298
- function checkRequired(val, name) {
1299
- if (!val || val.length <= 0) {
1300
- throw new Error(name + " is required.");
1301
- }
1302
- }
1303
- module.exports = {
1304
- getPassword: function(service, account) {
1305
- checkRequired(service, "Service");
1306
- checkRequired(account, "Account");
1307
- return keytar.getPassword(service, account);
1308
- },
1309
- setPassword: function(service, account, password) {
1310
- checkRequired(service, "Service");
1311
- checkRequired(account, "Account");
1312
- checkRequired(password, "Password");
1313
- return keytar.setPassword(service, account, password);
1314
- },
1315
- deletePassword: function(service, account) {
1316
- checkRequired(service, "Service");
1317
- checkRequired(account, "Account");
1318
- return keytar.deletePassword(service, account);
1319
- },
1320
- findPassword: function(service) {
1321
- checkRequired(service, "Service");
1322
- return keytar.findPassword(service);
1323
- },
1324
- findCredentials: function(service) {
1325
- checkRequired(service, "Service");
1326
- return keytar.findCredentials(service);
1327
- }
1328
- };
1329
- }
1330
- });
1331
-
1332
1332
  // src/profile.ts
1333
1333
  var profile_exports = {};
1334
1334
  __export(profile_exports, {
@@ -1344,41 +1344,41 @@ __export(profile_exports, {
1344
1344
  writeProfile: () => writeProfile
1345
1345
  });
1346
1346
  import {
1347
- createCipheriv,
1348
- createDecipheriv,
1349
- randomBytes as randomBytes2
1347
+ createCipheriv as createCipheriv2,
1348
+ createDecipheriv as createDecipheriv2,
1349
+ randomBytes as randomBytes3
1350
1350
  } from "crypto";
1351
1351
  import {
1352
- readFileSync as readFileSync4,
1353
- writeFileSync as writeFileSync3,
1354
- mkdirSync as mkdirSync3,
1355
- existsSync as existsSync3
1352
+ readFileSync as readFileSync6,
1353
+ writeFileSync as writeFileSync5,
1354
+ mkdirSync as mkdirSync5,
1355
+ existsSync as existsSync5
1356
1356
  } from "fs";
1357
- import { join as join4 } from "path";
1358
- import { homedir as homedir3 } from "os";
1359
- async function loadKey() {
1357
+ import { join as join6 } from "path";
1358
+ import { homedir as homedir5 } from "os";
1359
+ async function loadKey2() {
1360
1360
  try {
1361
1361
  const kt = await Promise.resolve().then(() => __toESM(require_keytar2(), 1));
1362
1362
  const stored = await kt.getPassword("terminalhire", "profile-key");
1363
1363
  if (stored) {
1364
1364
  return Buffer.from(stored, "hex");
1365
1365
  }
1366
- const key2 = randomBytes2(KEY_BYTES);
1366
+ const key2 = randomBytes3(KEY_BYTES2);
1367
1367
  await kt.setPassword("terminalhire", "profile-key", key2.toString("hex"));
1368
1368
  return key2;
1369
1369
  } catch {
1370
1370
  }
1371
- mkdirSync3(TERMINALHIRE_DIR3, { recursive: true });
1372
- if (existsSync3(KEY_FILE)) {
1373
- return Buffer.from(readFileSync4(KEY_FILE, "utf8").trim(), "hex");
1371
+ mkdirSync5(TERMINALHIRE_DIR5, { recursive: true });
1372
+ if (existsSync5(KEY_FILE2)) {
1373
+ return Buffer.from(readFileSync6(KEY_FILE2, "utf8").trim(), "hex");
1374
1374
  }
1375
- const key = randomBytes2(KEY_BYTES);
1376
- writeFileSync3(KEY_FILE, key.toString("hex"), { mode: 384, encoding: "utf8" });
1375
+ const key = randomBytes3(KEY_BYTES2);
1376
+ writeFileSync5(KEY_FILE2, key.toString("hex"), { mode: 384, encoding: "utf8" });
1377
1377
  return key;
1378
1378
  }
1379
- function encrypt(plaintext, key) {
1380
- const iv = randomBytes2(IV_BYTES);
1381
- const cipher = createCipheriv(ALGO, key, iv);
1379
+ function encrypt2(plaintext, key) {
1380
+ const iv = randomBytes3(IV_BYTES2);
1381
+ const cipher = createCipheriv2(ALGO2, key, iv);
1382
1382
  const ct = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
1383
1383
  const tag = cipher.getAuthTag();
1384
1384
  return {
@@ -1387,9 +1387,9 @@ function encrypt(plaintext, key) {
1387
1387
  ciphertext: ct.toString("hex")
1388
1388
  };
1389
1389
  }
1390
- function decrypt(blob, key) {
1391
- const decipher = createDecipheriv(
1392
- ALGO,
1390
+ function decrypt2(blob, key) {
1391
+ const decipher = createDecipheriv2(
1392
+ ALGO2,
1393
1393
  key,
1394
1394
  Buffer.from(blob.iv, "hex")
1395
1395
  );
@@ -1431,12 +1431,12 @@ function migrateTagWeights(profile) {
1431
1431
  }
1432
1432
  }
1433
1433
  async function readProfile() {
1434
- if (!existsSync3(PROFILE_FILE)) return blankProfile();
1434
+ if (!existsSync5(PROFILE_FILE)) return blankProfile();
1435
1435
  try {
1436
- const key = await loadKey();
1437
- const raw = readFileSync4(PROFILE_FILE, "utf8");
1436
+ const key = await loadKey2();
1437
+ const raw = readFileSync6(PROFILE_FILE, "utf8");
1438
1438
  const blob = JSON.parse(raw);
1439
- const plaintext = decrypt(blob, key);
1439
+ const plaintext = decrypt2(blob, key);
1440
1440
  const parsed = JSON.parse(plaintext);
1441
1441
  migrateTagWeights(parsed);
1442
1442
  return parsed;
@@ -1445,12 +1445,12 @@ async function readProfile() {
1445
1445
  }
1446
1446
  }
1447
1447
  async function writeProfile(profile) {
1448
- mkdirSync3(TERMINALHIRE_DIR3, { recursive: true });
1449
- const key = await loadKey();
1448
+ mkdirSync5(TERMINALHIRE_DIR5, { recursive: true });
1449
+ const key = await loadKey2();
1450
1450
  profile.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1451
1451
  profile.skillTags = deriveSkillTags(profile.tagWeights);
1452
- const blob = encrypt(JSON.stringify(profile), key);
1453
- writeFileSync3(PROFILE_FILE, JSON.stringify(blob, null, 2), { encoding: "utf8" });
1452
+ const blob = encrypt2(JSON.stringify(profile), key);
1453
+ writeFileSync5(PROFILE_FILE, JSON.stringify(blob, null, 2), { encoding: "utf8" });
1454
1454
  }
1455
1455
  function accumulateSession(profile, tags, isEmployerContext, inferredSeniority, seniorityIsAuthoritative = false) {
1456
1456
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -1511,13 +1511,13 @@ async function removeSavedJob(id) {
1511
1511
  return true;
1512
1512
  }
1513
1513
  async function deleteProfile() {
1514
- const { rmSync: rmSync2 } = await import("fs");
1514
+ const { rmSync: rmSync4 } = await import("fs");
1515
1515
  try {
1516
- rmSync2(PROFILE_FILE);
1516
+ rmSync4(PROFILE_FILE);
1517
1517
  } catch {
1518
1518
  }
1519
1519
  try {
1520
- rmSync2(KEY_FILE);
1520
+ rmSync4(KEY_FILE2);
1521
1521
  } catch {
1522
1522
  }
1523
1523
  }
@@ -1534,17 +1534,17 @@ function profileToFingerprint(profile) {
1534
1534
  }
1535
1535
  };
1536
1536
  }
1537
- var TERMINALHIRE_DIR3, PROFILE_FILE, KEY_FILE, ALGO, KEY_BYTES, IV_BYTES, DECAY_HALF_LIFE_MS, LANGUAGE_TAGS, MIN_FINGERPRINT_SCORE;
1537
+ var TERMINALHIRE_DIR5, PROFILE_FILE, KEY_FILE2, ALGO2, KEY_BYTES2, IV_BYTES2, DECAY_HALF_LIFE_MS, LANGUAGE_TAGS, MIN_FINGERPRINT_SCORE;
1538
1538
  var init_profile = __esm({
1539
1539
  "src/profile.ts"() {
1540
1540
  "use strict";
1541
1541
  init_src();
1542
- TERMINALHIRE_DIR3 = join4(homedir3(), ".terminalhire");
1543
- PROFILE_FILE = join4(TERMINALHIRE_DIR3, "profile.enc");
1544
- KEY_FILE = join4(TERMINALHIRE_DIR3, "key");
1545
- ALGO = "aes-256-gcm";
1546
- KEY_BYTES = 32;
1547
- IV_BYTES = 12;
1542
+ TERMINALHIRE_DIR5 = join6(homedir5(), ".terminalhire");
1543
+ PROFILE_FILE = join6(TERMINALHIRE_DIR5, "profile.enc");
1544
+ KEY_FILE2 = join6(TERMINALHIRE_DIR5, "key");
1545
+ ALGO2 = "aes-256-gcm";
1546
+ KEY_BYTES2 = 32;
1547
+ IV_BYTES2 = 12;
1548
1548
  DECAY_HALF_LIFE_MS = 30 * 24 * 60 * 60 * 1e3;
1549
1549
  LANGUAGE_TAGS = /* @__PURE__ */ new Set([
1550
1550
  "typescript",
@@ -1571,9 +1571,9 @@ var init_profile = __esm({
1571
1571
 
1572
1572
  // bin/jpi-claim.js
1573
1573
  init_src();
1574
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync4, rmSync } from "fs";
1575
- import { join as join5 } from "path";
1576
- import { homedir as homedir4, hostname as osHostname } from "os";
1574
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, existsSync as existsSync6, rmSync as rmSync3 } from "fs";
1575
+ import { join as join7 } from "path";
1576
+ import { homedir as homedir6, hostname as osHostname } from "os";
1577
1577
  import { execFile } from "child_process";
1578
1578
  import { promisify } from "util";
1579
1579
  import { createInterface } from "readline";
@@ -1602,10 +1602,95 @@ function openInBrowser(url) {
1602
1602
  }
1603
1603
  }
1604
1604
 
1605
+ // bin/claim-push-bg.js
1606
+ import { createHash as createHash3 } from "crypto";
1607
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2, rmSync as rmSync2 } from "fs";
1608
+ import { join as join3 } from "path";
1609
+ import { homedir as homedir2 } from "os";
1610
+
1611
+ // src/github-auth.ts
1612
+ import {
1613
+ createCipheriv,
1614
+ createDecipheriv,
1615
+ randomBytes as randomBytes2
1616
+ } from "crypto";
1617
+ import {
1618
+ readFileSync as readFileSync2,
1619
+ writeFileSync,
1620
+ mkdirSync,
1621
+ existsSync,
1622
+ rmSync
1623
+ } from "fs";
1624
+ import { join as join2 } from "path";
1625
+ import { homedir } from "os";
1626
+ var TERMINALHIRE_DIR = join2(homedir(), ".terminalhire");
1627
+ var TOKEN_FILE = join2(TERMINALHIRE_DIR, "github-token.enc");
1628
+ var KEY_FILE = join2(TERMINALHIRE_DIR, "key");
1629
+ var ALGO = "aes-256-gcm";
1630
+ var KEY_BYTES = 32;
1631
+ var IV_BYTES = 12;
1632
+ async function loadKey() {
1633
+ try {
1634
+ const kt = await Promise.resolve().then(() => __toESM(require_keytar2(), 1));
1635
+ const stored = await kt.getPassword("terminalhire", "profile-key");
1636
+ if (stored) return Buffer.from(stored, "hex");
1637
+ const key2 = randomBytes2(KEY_BYTES);
1638
+ await kt.setPassword("terminalhire", "profile-key", key2.toString("hex"));
1639
+ return key2;
1640
+ } catch {
1641
+ }
1642
+ mkdirSync(TERMINALHIRE_DIR, { recursive: true });
1643
+ if (existsSync(KEY_FILE)) {
1644
+ return Buffer.from(readFileSync2(KEY_FILE, "utf8").trim(), "hex");
1645
+ }
1646
+ const key = randomBytes2(KEY_BYTES);
1647
+ writeFileSync(KEY_FILE, key.toString("hex"), { mode: 384, encoding: "utf8" });
1648
+ return key;
1649
+ }
1650
+ function encrypt(plaintext, key) {
1651
+ const iv = randomBytes2(IV_BYTES);
1652
+ const cipher = createCipheriv(ALGO, key, iv);
1653
+ const ct = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
1654
+ const tag = cipher.getAuthTag();
1655
+ return { iv: iv.toString("hex"), tag: tag.toString("hex"), ciphertext: ct.toString("hex") };
1656
+ }
1657
+
1658
+ // bin/claim-push-bg.js
1659
+ var TERMINALHIRE_DIR2 = process.env.TERMINALHIRE_DIR || join3(homedir2(), ".terminalhire");
1660
+ var CLAIM_PUSH_AUTO_MARKER = join3(TERMINALHIRE_DIR2, "claim-push-auto.json");
1661
+ var CLAIM_PUSH_TOKEN_FILE = join3(TERMINALHIRE_DIR2, "claim-push-token.enc");
1662
+ var AUTO_CONSENT_VERSION = 2;
1663
+ var AUTO_PUSH_THROTTLE_MS = 24 * 60 * 60 * 1e3;
1664
+ async function writePushTokenEnc(rawToken) {
1665
+ mkdirSync2(TERMINALHIRE_DIR2, { recursive: true });
1666
+ const key = await loadKey();
1667
+ const blob = encrypt(rawToken, key);
1668
+ writeFileSync2(CLAIM_PUSH_TOKEN_FILE, JSON.stringify(blob, null, 2), { encoding: "utf8" });
1669
+ }
1670
+ function clearPushTokenEnc() {
1671
+ try {
1672
+ rmSync2(CLAIM_PUSH_TOKEN_FILE);
1673
+ } catch {
1674
+ }
1675
+ }
1676
+ function writeAutoMarker(marker) {
1677
+ mkdirSync2(TERMINALHIRE_DIR2, { recursive: true });
1678
+ writeFileSync2(CLAIM_PUSH_AUTO_MARKER, JSON.stringify(marker, null, 2) + "\n", "utf8");
1679
+ }
1680
+ function clearAutoMarker() {
1681
+ try {
1682
+ rmSync2(CLAIM_PUSH_AUTO_MARKER);
1683
+ } catch {
1684
+ }
1685
+ }
1686
+ function computeSnapshotHash(pushed) {
1687
+ return createHash3("sha256").update(JSON.stringify(pushed)).digest("hex");
1688
+ }
1689
+
1605
1690
  // bin/jpi-claim.js
1606
- var TERMINALHIRE_DIR4 = process.env.TERMINALHIRE_DIR || join5(homedir4(), ".terminalhire");
1607
- var INDEX_CACHE_FILE = join5(TERMINALHIRE_DIR4, "index-cache.json");
1608
- var CLAIM_PUSH_MARKER = join5(TERMINALHIRE_DIR4, "claim-push.json");
1691
+ var TERMINALHIRE_DIR6 = process.env.TERMINALHIRE_DIR || join7(homedir6(), ".terminalhire");
1692
+ var INDEX_CACHE_FILE = join7(TERMINALHIRE_DIR6, "index-cache.json");
1693
+ var CLAIM_PUSH_MARKER = join7(TERMINALHIRE_DIR6, "claim-push.json");
1609
1694
  var API_URL = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://terminalhire.com";
1610
1695
  var CLAIM_SYNC_BASE = "https://terminalhire.com";
1611
1696
  var CLAIM_CONSENT_VERSION = 1;
@@ -1677,8 +1762,8 @@ function parseRepoFromRemote(url) {
1677
1762
  return m ? `${m[1]}/${m[2]}` : null;
1678
1763
  }
1679
1764
  function readClaimablePool() {
1680
- if (!existsSync4(INDEX_CACHE_FILE)) return [];
1681
- const entry = JSON.parse(readFileSync5(INDEX_CACHE_FILE, "utf8"));
1765
+ if (!existsSync6(INDEX_CACHE_FILE)) return [];
1766
+ const entry = JSON.parse(readFileSync7(INDEX_CACHE_FILE, "utf8"));
1682
1767
  const bounties = (entry?.index?.jobs ?? []).filter((j) => j.source === "bounty");
1683
1768
  const contributions = (entry?.index?.contribute ?? []).filter((j) => j.source === "contribute");
1684
1769
  return [...bounties, ...contributions];
@@ -2340,18 +2425,18 @@ function claimSleep(ms) {
2340
2425
  }
2341
2426
  function readClaimPushMarker() {
2342
2427
  try {
2343
- return existsSync4(CLAIM_PUSH_MARKER) ? JSON.parse(readFileSync5(CLAIM_PUSH_MARKER, "utf8")) : null;
2428
+ return existsSync6(CLAIM_PUSH_MARKER) ? JSON.parse(readFileSync7(CLAIM_PUSH_MARKER, "utf8")) : null;
2344
2429
  } catch {
2345
2430
  return null;
2346
2431
  }
2347
2432
  }
2348
2433
  function writeClaimPushMarker(marker) {
2349
- mkdirSync4(TERMINALHIRE_DIR4, { recursive: true });
2350
- writeFileSync4(CLAIM_PUSH_MARKER, JSON.stringify(marker, null, 2) + "\n", "utf8");
2434
+ mkdirSync6(TERMINALHIRE_DIR6, { recursive: true });
2435
+ writeFileSync6(CLAIM_PUSH_MARKER, JSON.stringify(marker, null, 2) + "\n", "utf8");
2351
2436
  }
2352
2437
  function clearClaimPushMarker() {
2353
2438
  try {
2354
- rmSync(CLAIM_PUSH_MARKER);
2439
+ rmSync3(CLAIM_PUSH_MARKER);
2355
2440
  } catch {
2356
2441
  }
2357
2442
  }
@@ -2371,7 +2456,20 @@ function renderClaimConsent(pushed, login) {
2371
2456
  console.log(" This is NOT required to use terminalhire.");
2372
2457
  console.log("");
2373
2458
  }
2374
- async function cmdPush() {
2459
+ function renderAutoConsent() {
2460
+ console.log("");
2461
+ console.log(" keep your dashboard updated in the background (opt-in)");
2462
+ console.log("");
2463
+ console.log(" Terminal Hire will keep your dashboard updated in the background \u2014");
2464
+ console.log(" pushing the SAME score-free fields, at most once/day \u2014 until you run");
2465
+ console.log(" `terminalhire claim --push --revoke`.");
2466
+ console.log("");
2467
+ console.log(" This stores a push-only credential on this machine (encrypted). It can");
2468
+ console.log(" ONLY add/update your OWN dashboard rows \u2014 it can never read or delete.");
2469
+ console.log(" Nothing new is sent: the payload is identical to the manual push above.");
2470
+ console.log("");
2471
+ }
2472
+ async function cmdPush({ keepUpdated = false } = {}) {
2375
2473
  const claimsMod = await Promise.resolve().then(() => (init_claims(), claims_exports));
2376
2474
  const { readProfile: readProfile2 } = await Promise.resolve().then(() => (init_profile(), profile_exports));
2377
2475
  const profile = await readProfile2();
@@ -2395,6 +2493,16 @@ async function cmdPush() {
2395
2493
  process.exit(0);
2396
2494
  }
2397
2495
  const consentedAt = (/* @__PURE__ */ new Date()).toISOString();
2496
+ let autoConsent = null;
2497
+ if (keepUpdated) {
2498
+ renderAutoConsent();
2499
+ const autoAnswer = await askYes(' Keep it updated in the background? Type "yes" to confirm: ');
2500
+ if (autoAnswer === "yes") {
2501
+ autoConsent = { version: AUTO_CONSENT_VERSION, consentedAt };
2502
+ } else {
2503
+ console.log("\n Background updates NOT enabled \u2014 doing a one-time push instead.");
2504
+ }
2505
+ }
2398
2506
  console.log("\n Starting browser verification...");
2399
2507
  let begin;
2400
2508
  try {
@@ -2467,7 +2575,9 @@ async function cmdPush() {
2467
2575
  res = await fetch(`${CLAIM_SYNC_BASE}/api/claim-sync`, {
2468
2576
  method: "POST",
2469
2577
  headers: { "Content-Type": "application/json" },
2470
- body: JSON.stringify({ consentToken, claims: pushed, proofToken }),
2578
+ // autoConsent is included ONLY when the dev opted into background updates —
2579
+ // the server mints the pushToken in the same push when it is present + valid.
2580
+ body: JSON.stringify({ consentToken, claims: pushed, proofToken, ...autoConsent ? { autoConsent } : {} }),
2471
2581
  signal: AbortSignal.timeout(1e4)
2472
2582
  });
2473
2583
  } catch (err) {
@@ -2486,11 +2596,31 @@ async function cmdPush() {
2486
2596
  process.exit(1);
2487
2597
  }
2488
2598
  let deleteToken = null;
2599
+ let pushToken = null;
2489
2600
  try {
2490
- deleteToken = (await res.json())?.deleteToken || null;
2601
+ const body = await res.json();
2602
+ deleteToken = body?.deleteToken || null;
2603
+ pushToken = body?.pushToken || null;
2491
2604
  } catch {
2492
2605
  }
2493
2606
  writeClaimPushMarker({ consentedAt, login, deleteToken });
2607
+ if (autoConsent && pushToken) {
2608
+ try {
2609
+ await writePushTokenEnc(pushToken);
2610
+ writeAutoMarker({
2611
+ autoConsentedAt: consentedAt,
2612
+ version: AUTO_CONSENT_VERSION,
2613
+ login,
2614
+ lastPushedAt: consentedAt,
2615
+ lastSnapshotHash: computeSnapshotHash(pushed)
2616
+ });
2617
+ console.log("\n \u2713 Background updates enabled \u2014 your dashboard will stay current");
2618
+ console.log(" (at most once/day). Stop any time: terminalhire claim --push --revoke");
2619
+ } catch {
2620
+ console.log("\n \u2713 Pushed, but could not enable background updates on this machine.");
2621
+ console.log(" Re-run `terminalhire claim --push --keep-updated` to retry.");
2622
+ }
2623
+ }
2494
2624
  console.log("\n \u2713 Your claims now show on your dashboard: https://terminalhire.com/dashboard");
2495
2625
  console.log(" Delete them any time: terminalhire claim --push --revoke\n");
2496
2626
  }
@@ -2532,7 +2662,10 @@ async function cmdRevoke() {
2532
2662
  process.exit(1);
2533
2663
  }
2534
2664
  clearClaimPushMarker();
2665
+ clearPushTokenEnc();
2666
+ clearAutoMarker();
2535
2667
  console.log("\n \u2713 Pushed claims deleted and local marker cleared.\n");
2668
+ console.log(" Background updates (if any) have been stopped.\n");
2536
2669
  }
2537
2670
  async function run() {
2538
2671
  const verb = process.argv[2];
@@ -2541,7 +2674,7 @@ async function run() {
2541
2674
  const json = Boolean(flags.json);
2542
2675
  if (verb === "--push") {
2543
2676
  if (flags.revoke) await cmdRevoke();
2544
- else await cmdPush();
2677
+ else await cmdPush({ keepUpdated: Boolean(flags["keep-updated"]) });
2545
2678
  return;
2546
2679
  }
2547
2680
  try {
@@ -2581,6 +2714,7 @@ async function run() {
2581
2714
  }
2582
2715
  export {
2583
2716
  AI_DISCLOSURE_NOTE,
2717
+ CLAIM_CONSENT_VERSION,
2584
2718
  buildSubmitBody,
2585
2719
  cmdRecord,
2586
2720
  findClaimableByShortRef,
@@ -1301,9 +1301,9 @@ var init_keytar = __esm({
1301
1301
  }
1302
1302
  });
1303
1303
 
1304
- // node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/release-0192/node_modules/keytar/build/Release/keytar.node
1304
+ // node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node
1305
1305
  var require_keytar = __commonJS({
1306
- "node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/release-0192/node_modules/keytar/build/Release/keytar.node"(exports, module) {
1306
+ "node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node"(exports, module) {
1307
1307
  "use strict";
1308
1308
  init_keytar();
1309
1309
  try {
@@ -6759,9 +6759,9 @@ var init_keytar = __esm({
6759
6759
  }
6760
6760
  });
6761
6761
 
6762
- // node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/release-0192/node_modules/keytar/build/Release/keytar.node
6762
+ // node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node
6763
6763
  var require_keytar = __commonJS({
6764
- "node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/release-0192/node_modules/keytar/build/Release/keytar.node"(exports, module) {
6764
+ "node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node"(exports, module) {
6765
6765
  "use strict";
6766
6766
  init_keytar();
6767
6767
  try {