terminalhire 0.42.15 → 0.42.17

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.
Files changed (45) hide show
  1. package/dist/bin/approved-claims-sync.js +3 -1
  2. package/dist/bin/claim-push-bg.js +20 -11
  3. package/dist/bin/directory.js +7 -5
  4. package/dist/bin/founder-bounty-notify.js +2 -2
  5. package/dist/bin/founder-note-sync.js +2 -0
  6. package/dist/bin/founder-verdict-sync.js +4 -2
  7. package/dist/bin/jpi-bounties.js +89 -52
  8. package/dist/bin/jpi-chat-read.js +45 -18
  9. package/dist/bin/jpi-chat.js +86 -37
  10. package/dist/bin/jpi-claim.js +567 -305
  11. package/dist/bin/jpi-config.js +6 -6
  12. package/dist/bin/jpi-contribute.js +78 -41
  13. package/dist/bin/jpi-devs.js +25 -23
  14. package/dist/bin/jpi-dispatch-dev.js +53 -0
  15. package/dist/bin/jpi-dispatch.js +859 -496
  16. package/dist/bin/jpi-hub.js +66 -39
  17. package/dist/bin/jpi-inbox.js +85 -36
  18. package/dist/bin/jpi-init.js +24 -22
  19. package/dist/bin/jpi-intro.js +37 -18
  20. package/dist/bin/jpi-jobs.js +102 -49
  21. package/dist/bin/jpi-link.js +75 -16
  22. package/dist/bin/jpi-login.js +38 -31
  23. package/dist/bin/jpi-mcp-chat.js +47 -20
  24. package/dist/bin/jpi-mcp.js +586 -320
  25. package/dist/bin/jpi-post.js +8 -6
  26. package/dist/bin/jpi-project.js +14 -12
  27. package/dist/bin/jpi-refresh.js +178 -94
  28. package/dist/bin/jpi-run.js +78 -68
  29. package/dist/bin/jpi-spinner.js +30 -4
  30. package/dist/bin/jpi-statusline.js +28 -3
  31. package/dist/bin/jpi-sync.js +29 -20
  32. package/dist/bin/jpi-trajectory.js +46 -27
  33. package/dist/bin/jpi.js +42 -4
  34. package/dist/bin/peer-connect-prompt.js +4 -2
  35. package/dist/bin/pulse-prompt.js +24 -5
  36. package/dist/bin/recall-check.js +7 -5
  37. package/dist/bin/spinner-render.js +32 -4
  38. package/dist/bin/spinner.js +32 -4
  39. package/dist/src/api-base.js +16 -0
  40. package/dist/src/chat-client.js +26 -7
  41. package/dist/src/intro.js +37 -18
  42. package/dist/src/link.js +61 -11
  43. package/dist/src/trajectory.js +46 -27
  44. package/dist/src/web-session.js +40 -5
  45. package/package.json +4 -2
@@ -1,4 +1,6 @@
1
1
  // src/api-base.ts
2
+ import { homedir } from "os";
3
+ import { join } from "path";
2
4
  var PROD_API_BASE = "https://terminalhire.com";
3
5
  var DEV_API_BASE = "https://dev.terminalhire.com";
4
6
  var ApiBaseError = class extends Error {
@@ -103,7 +105,7 @@ function approvalsNudgeGate({ autoMarkerExists, tokenFileExists, awaitingApprova
103
105
  function buildApprovalsNudge(awaitingApproval) {
104
106
  if (!Number.isInteger(awaitingApproval) || awaitingApproval <= 0) return null;
105
107
  const n = awaitingApproval;
106
- return ` \u26A0 ${n} claim${n === 1 ? "" : "s"} awaiting founder approval \u2014 terminalhire cannot check in the background until you enrol:
108
+ return ` \u26A0 ${n} claim${n === 1 ? "" : "s"} awaiting poster approval \u2014 terminalhire cannot check in the background until you enrol:
107
109
  terminalhire claim --push --keep-updated (or check one now: terminalhire claim slice <id>)`;
108
110
  }
109
111
  async function syncApprovedClaims({
@@ -115,8 +115,8 @@ import {
115
115
  statSync
116
116
  } from "fs";
117
117
  import { randomBytes as randomBytes3 } from "crypto";
118
- import { join as join4 } from "path";
119
- import { homedir as homedir3 } from "os";
118
+ import { join as join5 } from "path";
119
+ import { homedir as homedir4 } from "os";
120
120
  function sleepSync(ms) {
121
121
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
122
122
  }
@@ -310,8 +310,8 @@ var init_claims = __esm({
310
310
  "src/claims.ts"() {
311
311
  "use strict";
312
312
  init_state_dir();
313
- TERMINALHIRE_DIR3 = process.env.TERMINALHIRE_DIR || join4(homedir3(), ".terminalhire");
314
- CLAIMS_FILE = join4(TERMINALHIRE_DIR3, "claims.json");
313
+ TERMINALHIRE_DIR3 = process.env.TERMINALHIRE_DIR || join5(homedir4(), ".terminalhire");
314
+ CLAIMS_FILE = join5(TERMINALHIRE_DIR3, "claims.json");
315
315
  LOCK_DIR = `${CLAIMS_FILE}.lock`;
316
316
  LOCK_STALE_MS = Number(process.env.TERMINALHIRE_LOCK_STALE_MS) || 1e4;
317
317
  LOCK_RETRY_MS = Number(process.env.TERMINALHIRE_LOCK_RETRY_MS) || 25;
@@ -369,8 +369,8 @@ var init_claims = __esm({
369
369
  // bin/claim-push-bg.js
370
370
  import { createHash } from "crypto";
371
371
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, existsSync as existsSync5, rmSync as rmSync3 } from "fs";
372
- import { join as join5 } from "path";
373
- import { homedir as homedir4 } from "os";
372
+ import { join as join6 } from "path";
373
+ import { homedir as homedir5 } from "os";
374
374
 
375
375
  // src/github-auth.ts
376
376
  init_state_dir();
@@ -511,8 +511,11 @@ function decrypt(blob, key) {
511
511
  init_state_dir();
512
512
 
513
513
  // src/api-base.ts
514
+ import { homedir as homedir3 } from "os";
515
+ import { join as join4 } from "path";
514
516
  var PROD_API_BASE = "https://terminalhire.com";
515
517
  var DEV_API_BASE = "https://dev.terminalhire.com";
518
+ var DEV_STATE_DIR_NAME = ".terminalhire-dev";
516
519
  var ApiBaseError = class extends Error {
517
520
  constructor(message) {
518
521
  super(message);
@@ -613,6 +616,7 @@ function isNonProdApiBase(base = resolveApiBaseOrProd()) {
613
616
  }
614
617
  function warnSharedCredentialsIfNonProd(base, stream = process.stderr) {
615
618
  if (!isNonProdApiBase(base)) return;
619
+ if (usingSeparateStateDir()) return;
616
620
  try {
617
621
  stream.write(
618
622
  "terminalhire: non-prod API base \u2014 using the same local session/push credentials as prod; do not mix environments casually.\n"
@@ -620,12 +624,17 @@ function warnSharedCredentialsIfNonProd(base, stream = process.stderr) {
620
624
  } catch {
621
625
  }
622
626
  }
627
+ function usingSeparateStateDir(env = process.env) {
628
+ const dir = env["TERMINALHIRE_DIR"];
629
+ if (dir === void 0 || dir === "") return false;
630
+ return dir.endsWith(DEV_STATE_DIR_NAME);
631
+ }
623
632
 
624
633
  // bin/claim-push-bg.js
625
- var TERMINALHIRE_DIR4 = process.env.TERMINALHIRE_DIR || join5(homedir4(), ".terminalhire");
626
- var CLAIM_PUSH_AUTO_MARKER = join5(TERMINALHIRE_DIR4, "claim-push-auto.json");
627
- var CLAIM_PUSH_TOKEN_FILE = join5(TERMINALHIRE_DIR4, "claim-push-token.enc");
628
- var CLAIM_PUSH_MANUAL_MARKER = join5(TERMINALHIRE_DIR4, "claim-push.json");
634
+ var TERMINALHIRE_DIR4 = process.env.TERMINALHIRE_DIR || join6(homedir5(), ".terminalhire");
635
+ var CLAIM_PUSH_AUTO_MARKER = join6(TERMINALHIRE_DIR4, "claim-push-auto.json");
636
+ var CLAIM_PUSH_TOKEN_FILE = join6(TERMINALHIRE_DIR4, "claim-push-token.enc");
637
+ var CLAIM_PUSH_MANUAL_MARKER = join6(TERMINALHIRE_DIR4, "claim-push.json");
629
638
  var CLAIM_SYNC_BASE = resolveApiBase();
630
639
  warnSharedCredentialsIfNonProd(CLAIM_SYNC_BASE);
631
640
  var AUTO_CONSENT_VERSION = 3;
@@ -731,7 +740,7 @@ async function shouldNudgeUnpushed() {
731
740
  return false;
732
741
  }
733
742
  }
734
- var CLAIM_HEARTBEAT_FILE = join5(TERMINALHIRE_DIR4, "claim-heartbeat.json");
743
+ var CLAIM_HEARTBEAT_FILE = join6(TERMINALHIRE_DIR4, "claim-heartbeat.json");
735
744
  var HEARTBEAT_MIN_INTERVAL_MS = 3e4;
736
745
  var HEARTBEAT_MIN_CONSENT_VERSION = 3;
737
746
  function readHeartbeatState() {
@@ -2,8 +2,8 @@
2
2
 
3
3
  // bin/directory.js
4
4
  import { readFileSync, writeFileSync, renameSync } from "fs";
5
- import { join } from "path";
6
- import { homedir } from "os";
5
+ import { join as join2 } from "path";
6
+ import { homedir as homedir2 } from "os";
7
7
 
8
8
  // src/state-dir.ts
9
9
  import { closeSync, constants, fchmodSync, fstatSync, mkdirSync, openSync } from "fs";
@@ -54,6 +54,8 @@ function ensureStateDir(dir) {
54
54
  }
55
55
 
56
56
  // src/api-base.ts
57
+ import { homedir } from "os";
58
+ import { join } from "path";
57
59
  var PROD_API_BASE = "https://terminalhire.com";
58
60
  var DEV_API_BASE = "https://dev.terminalhire.com";
59
61
  var ApiBaseError = class extends Error {
@@ -146,9 +148,9 @@ function normalizeOverride(raw) {
146
148
  }
147
149
 
148
150
  // bin/directory.js
149
- var TERMINALHIRE_DIR = process.env.TERMINALHIRE_DIR || join(homedir(), ".terminalhire");
150
- var DIRECTORY_CACHE_FILE = join(TERMINALHIRE_DIR, "directory-cache.json");
151
- var PROJECT_FILE = join(TERMINALHIRE_DIR, "project.json");
151
+ var TERMINALHIRE_DIR = process.env.TERMINALHIRE_DIR || join2(homedir2(), ".terminalhire");
152
+ var DIRECTORY_CACHE_FILE = join2(TERMINALHIRE_DIR, "directory-cache.json");
153
+ var PROJECT_FILE = join2(TERMINALHIRE_DIR, "project.json");
152
154
  var INDEX_TTL_MS = 15 * 60 * 1e3;
153
155
  var API_URL = resolveApiBase();
154
156
  function readDirectoryCache() {
@@ -39,9 +39,9 @@ function formatFounderBountyNotifyBody(index, fireIds) {
39
39
  const j = byId.get(fireIds[0]);
40
40
  const amount = j && j.bounty && typeof j.bounty.amountUSD === "number" ? j.bounty.amountUSD : null;
41
41
  const price = typeof amount === "number" && Number.isFinite(amount) && amount > 0 ? `$${Math.round(amount)} ` : "";
42
- return `${price}founder bounty available \u2014 run: terminalhire bounties`;
42
+ return `${price}posted bounty available \u2014 run: terminalhire bounties`;
43
43
  }
44
- return `${fireIds.length} founder bounties available \u2014 run: terminalhire bounties`;
44
+ return `${fireIds.length} posted bounties available \u2014 run: terminalhire bounties`;
45
45
  }
46
46
  function escapeAppleScriptString(s) {
47
47
  return String(s).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
@@ -1,4 +1,6 @@
1
1
  // src/api-base.ts
2
+ import { homedir } from "os";
3
+ import { join } from "path";
2
4
  var PROD_API_BASE = "https://terminalhire.com";
3
5
  var DEV_API_BASE = "https://dev.terminalhire.com";
4
6
  var ApiBaseError = class extends Error {
@@ -1,4 +1,6 @@
1
1
  // src/api-base.ts
2
+ import { homedir } from "os";
3
+ import { join } from "path";
2
4
  var PROD_API_BASE = "https://terminalhire.com";
3
5
  var DEV_API_BASE = "https://dev.terminalhire.com";
4
6
  var ApiBaseError = class extends Error {
@@ -149,10 +151,10 @@ function buildVerdictNotice(t) {
149
151
  if (!t || typeof t.to !== "string") return null;
150
152
  const amount = typeof t.amountUSD === "number" && t.amountUSD > 0 ? `$${t.amountUSD}` : null;
151
153
  if (t.verdict === "rejected") {
152
- return ` \u2717 founder rejected${amount ? ` \u2014 ${amount}` : ""} \xB7 claim moved to ${t.to}`;
154
+ return ` \u2717 poster rejected${amount ? ` \u2014 ${amount}` : ""} \xB7 claim moved to ${t.to}`;
153
155
  }
154
156
  const paid = t.settled ? " \xB7 paid" : "";
155
- return ` \u2713 founder accepted${amount ? ` \u2014 ${amount}` : ""}${paid} \xB7 claim moved to ${t.to}`;
157
+ return ` \u2713 poster accepted${amount ? ` \u2014 ${amount}` : ""}${paid} \xB7 claim moved to ${t.to}`;
156
158
  }
157
159
  async function syncFounderVerdicts({
158
160
  claimsModule,
@@ -10562,17 +10562,17 @@ var init_founder_pin = __esm({
10562
10562
 
10563
10563
  // src/test-race-barrier.ts
10564
10564
  import { closeSync as closeSync2, constants as constants2, existsSync, lstatSync, openSync as openSync2 } from "fs";
10565
- import { join as join3 } from "path";
10565
+ import { join as join4 } from "path";
10566
10566
  function syncSleepMs(ms) {
10567
10567
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
10568
10568
  }
10569
10569
  function waitForTestRaceBarrier(phase) {
10570
10570
  const root = process.env[ENV_VAR];
10571
10571
  if (!root) return;
10572
- const phaseDir = join3(root, phase);
10572
+ const phaseDir = join4(root, phase);
10573
10573
  if (!existsSync(phaseDir)) return;
10574
- const readyFile = join3(phaseDir, `ready-${process.pid}`);
10575
- const goFile = join3(phaseDir, "go");
10574
+ const readyFile = join4(phaseDir, `ready-${process.pid}`);
10575
+ const goFile = join4(phaseDir, "go");
10576
10576
  const noFollow = constants2.O_NOFOLLOW ?? 0;
10577
10577
  if (lstatSync(readyFile, { throwIfNoEntry: false })) {
10578
10578
  throw new Error(
@@ -10612,8 +10612,8 @@ var init_test_race_barrier = __esm({
10612
10612
  // src/shared-key.ts
10613
10613
  import { randomBytes as randomBytes3 } from "crypto";
10614
10614
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync2, linkSync, unlinkSync } from "fs";
10615
- import { join as join4 } from "path";
10616
- import { homedir as homedir2 } from "os";
10615
+ import { join as join5 } from "path";
10616
+ import { homedir as homedir3 } from "os";
10617
10617
  function isValidKeyHex(value) {
10618
10618
  return KEY_HEX_RE.test(value);
10619
10619
  }
@@ -10667,8 +10667,8 @@ var init_shared_key = __esm({
10667
10667
  "use strict";
10668
10668
  init_state_dir();
10669
10669
  init_test_race_barrier();
10670
- TERMINALHIRE_DIR2 = process.env.TERMINALHIRE_DIR || join4(homedir2(), ".terminalhire");
10671
- KEY_FILE = join4(TERMINALHIRE_DIR2, "key");
10670
+ TERMINALHIRE_DIR2 = process.env.TERMINALHIRE_DIR || join5(homedir3(), ".terminalhire");
10671
+ KEY_FILE = join5(TERMINALHIRE_DIR2, "key");
10672
10672
  KEY_BYTES = 32;
10673
10673
  KEY_HEX_RE = new RegExp(`^[0-9a-f]{${KEY_BYTES * 2}}$`);
10674
10674
  }
@@ -10677,7 +10677,7 @@ var init_shared_key = __esm({
10677
10677
  // src/crypto-store.ts
10678
10678
  import { createCipheriv, createDecipheriv, randomBytes as randomBytes4 } from "crypto";
10679
10679
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync3, renameSync as renameSync2, rmSync, readdirSync } from "fs";
10680
- import { join as join5, dirname, basename } from "path";
10680
+ import { join as join6, dirname, basename } from "path";
10681
10681
  import { createRequire } from "module";
10682
10682
  function encrypt(plaintext, key) {
10683
10683
  const iv = randomBytes4(IV_BYTES);
@@ -10732,7 +10732,7 @@ function makeWarnOnce() {
10732
10732
  function atomicWriteFileSync(filePath, content) {
10733
10733
  const dir = dirname(filePath);
10734
10734
  ensureStateDirForSecret(dir);
10735
- const tmp = join5(
10735
+ const tmp = join6(
10736
10736
  dir,
10737
10737
  `.${basename(filePath)}.tmp-${process.pid}-${randomBytes4(6).toString("hex")}`
10738
10738
  );
@@ -10750,7 +10750,7 @@ async function deleteKey() {
10750
10750
  }
10751
10751
  for (const name of encFiles) {
10752
10752
  try {
10753
- rmSync(join5(stateDir, name));
10753
+ rmSync(join6(stateDir, name));
10754
10754
  } catch (e) {
10755
10755
  const code = e.code;
10756
10756
  if (code !== "ENOENT") {
@@ -10841,8 +10841,8 @@ __export(profile_exports, {
10841
10841
  removeSavedJob: () => removeSavedJob,
10842
10842
  writeProfile: () => writeProfile
10843
10843
  });
10844
- import { join as join6 } from "path";
10845
- import { homedir as homedir3 } from "os";
10844
+ import { join as join7 } from "path";
10845
+ import { homedir as homedir4 } from "os";
10846
10846
  function blankProfile() {
10847
10847
  return {
10848
10848
  version: 3,
@@ -10975,8 +10975,8 @@ var init_profile = __esm({
10975
10975
  "use strict";
10976
10976
  init_src();
10977
10977
  init_crypto_store();
10978
- TERMINALHIRE_DIR3 = process.env.TERMINALHIRE_DIR || join6(homedir3(), ".terminalhire");
10979
- PROFILE_FILE = join6(TERMINALHIRE_DIR3, "profile.enc");
10978
+ TERMINALHIRE_DIR3 = process.env.TERMINALHIRE_DIR || join7(homedir4(), ".terminalhire");
10979
+ PROFILE_FILE = join7(TERMINALHIRE_DIR3, "profile.enc");
10980
10980
  profileStore = createEncryptedStore(PROFILE_FILE, {
10981
10981
  blank: blankProfile,
10982
10982
  keyPolicy: "keytar-first-file-fallback"
@@ -11028,8 +11028,8 @@ __export(repo_experience_exports, {
11028
11028
  recordPolicySnapshot: () => recordPolicySnapshot,
11029
11029
  writeTombstone: () => writeTombstone
11030
11030
  });
11031
- import { join as join7 } from "path";
11032
- import { homedir as homedir4 } from "os";
11031
+ import { join as join8 } from "path";
11032
+ import { homedir as homedir5 } from "os";
11033
11033
  function blankFile() {
11034
11034
  return { version: 1, repos: {} };
11035
11035
  }
@@ -11236,8 +11236,8 @@ var init_repo_experience = __esm({
11236
11236
  "use strict";
11237
11237
  init_crypto_store();
11238
11238
  init_profile();
11239
- TERMINALHIRE_DIR4 = process.env.TERMINALHIRE_DIR || join7(homedir4(), ".terminalhire");
11240
- REPO_EXPERIENCE_FILE = join7(TERMINALHIRE_DIR4, "repo-experience.enc");
11239
+ TERMINALHIRE_DIR4 = process.env.TERMINALHIRE_DIR || join8(homedir5(), ".terminalhire");
11240
+ REPO_EXPERIENCE_FILE = join8(TERMINALHIRE_DIR4, "repo-experience.enc");
11241
11241
  MAX_REPOS = 100;
11242
11242
  MAX_CULTURE_SAMPLES = 12;
11243
11243
  MAX_NOTES = 10;
@@ -11278,8 +11278,8 @@ import {
11278
11278
  statSync
11279
11279
  } from "fs";
11280
11280
  import { randomBytes as randomBytes5 } from "crypto";
11281
- import { join as join8 } from "path";
11282
- import { homedir as homedir5 } from "os";
11281
+ import { join as join9 } from "path";
11282
+ import { homedir as homedir6 } from "os";
11283
11283
  function sleepSync(ms) {
11284
11284
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
11285
11285
  }
@@ -11473,8 +11473,8 @@ var init_claims = __esm({
11473
11473
  "src/claims.ts"() {
11474
11474
  "use strict";
11475
11475
  init_state_dir();
11476
- TERMINALHIRE_DIR5 = process.env.TERMINALHIRE_DIR || join8(homedir5(), ".terminalhire");
11477
- CLAIMS_FILE = join8(TERMINALHIRE_DIR5, "claims.json");
11476
+ TERMINALHIRE_DIR5 = process.env.TERMINALHIRE_DIR || join9(homedir6(), ".terminalhire");
11477
+ CLAIMS_FILE = join9(TERMINALHIRE_DIR5, "claims.json");
11478
11478
  LOCK_DIR = `${CLAIMS_FILE}.lock`;
11479
11479
  LOCK_STALE_MS = Number(process.env.TERMINALHIRE_LOCK_STALE_MS) || 1e4;
11480
11480
  LOCK_RETRY_MS = Number(process.env.TERMINALHIRE_LOCK_RETRY_MS) || 25;
@@ -11547,8 +11547,8 @@ __export(config_exports, {
11547
11547
  writeConfig: () => writeConfig
11548
11548
  });
11549
11549
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync5 } from "fs";
11550
- import { join as join9 } from "path";
11551
- import { homedir as homedir6 } from "os";
11550
+ import { join as join10 } from "path";
11551
+ import { homedir as homedir7 } from "os";
11552
11552
  function readConfig() {
11553
11553
  try {
11554
11554
  if (!existsSync5(CONFIG_FILE)) return { ...DEFAULT_CONFIG };
@@ -11630,8 +11630,8 @@ var init_config = __esm({
11630
11630
  "src/config.ts"() {
11631
11631
  "use strict";
11632
11632
  init_state_dir();
11633
- TERMINALHIRE_DIR6 = process.env.TERMINALHIRE_DIR || join9(homedir6(), ".terminalhire");
11634
- CONFIG_FILE = join9(TERMINALHIRE_DIR6, "config.json");
11633
+ TERMINALHIRE_DIR6 = process.env.TERMINALHIRE_DIR || join10(homedir7(), ".terminalhire");
11634
+ CONFIG_FILE = join10(TERMINALHIRE_DIR6, "config.json");
11635
11635
  DEFAULT_CONFIG = {
11636
11636
  nudge: "session",
11637
11637
  peerConnect: false,
@@ -11749,38 +11749,73 @@ __export(web_session_exports, {
11749
11749
  clearWebSessionFile: () => clearWebSessionFile,
11750
11750
  readWebSessionCookie: () => readWebSessionCookie,
11751
11751
  readWebSessionFile: () => readWebSessionFile,
11752
+ readWebSessionRecord: () => readWebSessionRecord,
11753
+ webSessionCookieForHost: () => webSessionCookieForHost,
11752
11754
  webSessionFilePath: () => webSessionFilePath,
11755
+ webSessionForHost: () => webSessionForHost,
11753
11756
  writeWebSessionFile: () => writeWebSessionFile
11754
11757
  });
11755
11758
  import { chmodSync, existsSync as existsSync6, readFileSync as readFileSync7, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "fs";
11756
- import { homedir as homedir7 } from "os";
11757
- import { join as join10 } from "path";
11759
+ import { homedir as homedir8 } from "os";
11760
+ import { join as join11 } from "path";
11758
11761
  function terminalhireDir() {
11759
- return process.env.TERMINALHIRE_DIR || join10(homedir7(), ".terminalhire");
11762
+ return process.env.TERMINALHIRE_DIR || join11(homedir8(), ".terminalhire");
11760
11763
  }
11761
11764
  function webSessionFilePath() {
11762
- return join10(terminalhireDir(), "web-session");
11765
+ return join11(terminalhireDir(), "web-session");
11763
11766
  }
11764
- function readWebSessionFile() {
11767
+ function parseWebSessionFile(raw) {
11768
+ const trimmed = raw.trim();
11769
+ if (trimmed.length === 0) return null;
11770
+ if (!trimmed.startsWith("{")) return { token: trimmed, host: null };
11771
+ try {
11772
+ const parsed = JSON.parse(trimmed);
11773
+ if (typeof parsed !== "object" || parsed === null) return null;
11774
+ const rec = parsed;
11775
+ if (typeof rec.token !== "string" || rec.token.length === 0) return null;
11776
+ const host = typeof rec.host === "string" ? rec.host.trim() : "";
11777
+ return { token: rec.token, host: host === "" ? null : host };
11778
+ } catch {
11779
+ return null;
11780
+ }
11781
+ }
11782
+ function readWebSessionRecord() {
11765
11783
  try {
11766
11784
  const path = webSessionFilePath();
11767
11785
  if (!existsSync6(path)) return null;
11768
- const v = readFileSync7(path, "utf8").trim();
11769
- return v.length > 0 ? v : null;
11786
+ return parseWebSessionFile(readFileSync7(path, "utf8"));
11770
11787
  } catch {
11771
11788
  return null;
11772
11789
  }
11773
11790
  }
11791
+ function readWebSessionFile() {
11792
+ return readWebSessionRecord()?.token ?? null;
11793
+ }
11794
+ function webSessionForHost(apiBase) {
11795
+ const record = readWebSessionRecord();
11796
+ if (!record) return { cookie: null, mismatch: null };
11797
+ if (record.host !== null && record.host !== apiBase) {
11798
+ return { cookie: null, mismatch: { linkedHost: record.host, currentHost: apiBase } };
11799
+ }
11800
+ return { cookie: record.token, mismatch: null };
11801
+ }
11802
+ function webSessionCookieForHost(apiBase) {
11803
+ const fromFile = webSessionForHost(apiBase);
11804
+ if (fromFile.cookie || fromFile.mismatch) return fromFile;
11805
+ const env = process.env["TERMINALHIRE_WEB_SESSION"];
11806
+ return { cookie: typeof env === "string" && env.length > 0 ? env : null, mismatch: null };
11807
+ }
11774
11808
  function readWebSessionCookie() {
11775
11809
  const fromFile = readWebSessionFile();
11776
11810
  if (fromFile) return fromFile;
11777
11811
  const env = process.env["TERMINALHIRE_WEB_SESSION"];
11778
11812
  return typeof env === "string" && env.length > 0 ? env : null;
11779
11813
  }
11780
- function writeWebSessionFile(token) {
11814
+ function writeWebSessionFile(token, host) {
11781
11815
  ensureStateDirForSecret(terminalhireDir());
11782
11816
  const path = webSessionFilePath();
11783
- writeFileSync6(path, token, { mode: 384, encoding: "utf8" });
11817
+ const body = typeof host === "string" && host.length > 0 ? JSON.stringify({ v: 1, host, token }) : token;
11818
+ writeFileSync6(path, body, { mode: 384, encoding: "utf8" });
11784
11819
  try {
11785
11820
  chmodSync(path, 384);
11786
11821
  } catch {
@@ -11815,13 +11850,13 @@ __export(jpi_decline_exports, {
11815
11850
  });
11816
11851
  import { createInterface } from "readline";
11817
11852
  import { existsSync as existsSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync7, rmSync as rmSync4 } from "fs";
11818
- import { homedir as homedir8 } from "os";
11819
- import { join as join11 } from "path";
11853
+ import { homedir as homedir9 } from "os";
11854
+ import { join as join12 } from "path";
11820
11855
  function terminalhireDir2() {
11821
- return process.env.TERMINALHIRE_DIR || join11(homedir8(), ".terminalhire");
11856
+ return process.env.TERMINALHIRE_DIR || join12(homedir9(), ".terminalhire");
11822
11857
  }
11823
11858
  function consentFilePath() {
11824
- return join11(terminalhireDir2(), "decline-consent");
11859
+ return join12(terminalhireDir2(), "decline-consent");
11825
11860
  }
11826
11861
  function postingIdFromJobId(jobId) {
11827
11862
  const id = String(jobId ?? "");
@@ -11839,12 +11874,12 @@ function declineBody(bountyId, reason) {
11839
11874
  function consentNotice(bountyId, reason) {
11840
11875
  return [
11841
11876
  "",
11842
- "This is the first thing you have sent a founder from this machine, so:",
11877
+ "This is the first thing you have sent a poster from this machine, so:",
11843
11878
  "",
11844
11879
  " Sending this posts EXACTLY this, and nothing else:",
11845
11880
  ` ${JSON.stringify(declineBody(bountyId, reason))}`,
11846
11881
  "",
11847
- " The founder sees a COUNT, never your name \u2014 answers are pooled across",
11882
+ " The poster sees a COUNT, never your name \u2014 answers are pooled across",
11848
11883
  " developers, and the breakdown stays hidden until enough people have",
11849
11884
  " answered that no single answer points at one person.",
11850
11885
  "",
@@ -11906,7 +11941,7 @@ async function sendDecline(bountyId, reason) {
11906
11941
  const { readWebSessionCookie: readWebSessionCookie2 } = await Promise.resolve().then(() => (init_web_session(), web_session_exports));
11907
11942
  const cookie = readWebSessionCookie2();
11908
11943
  if (!cookie) {
11909
- console.log("\nRun `terminalhire link` first \u2014 a founder needs to know the answer is real.");
11944
+ console.log("\nRun `terminalhire link` first \u2014 a poster needs to know the answer is real.");
11910
11945
  return false;
11911
11946
  }
11912
11947
  if (!await ensureDeclineConsent(bountyId, reason)) return false;
@@ -11925,7 +11960,7 @@ async function sendDecline(bountyId, reason) {
11925
11960
  Could not send that (${res.status}). Nothing else was sent.`);
11926
11961
  return false;
11927
11962
  }
11928
- console.log("\nSent \u2014 thanks. The founder sees a count, never your name.");
11963
+ console.log("\nSent \u2014 thanks. The poster sees a count, never your name.");
11929
11964
  return true;
11930
11965
  } catch {
11931
11966
  console.log("\nCould not reach terminalhire. Nothing else was sent.");
@@ -11933,7 +11968,7 @@ Could not send that (${res.status}). Nothing else was sent.`);
11933
11968
  }
11934
11969
  }
11935
11970
  async function runDeclinePrompt(bountyId, { ask = prompt } = {}) {
11936
- console.log("\nWhy are you passing? The founder sees a count, never your name.");
11971
+ console.log("\nWhy are you passing? The poster sees a count, never your name.");
11937
11972
  for (const c of DECLINE_CHOICES) console.log(` ${c.key}. ${c.label}`);
11938
11973
  const pick = await ask("\nEnter a number, or press Enter to skip: ");
11939
11974
  const reason = reasonForKey(pick);
@@ -11959,8 +11994,8 @@ var init_jpi_decline = __esm({
11959
11994
  // bin/jpi-bounties.js
11960
11995
  init_src();
11961
11996
  import { readFileSync as readFileSync9 } from "fs";
11962
- import { join as join12 } from "path";
11963
- import { homedir as homedir9 } from "os";
11997
+ import { join as join13 } from "path";
11998
+ import { homedir as homedir10 } from "os";
11964
11999
  import { createInterface as createInterface2 } from "readline";
11965
12000
 
11966
12001
  // ../../packages/core/src/payout-split.ts
@@ -12177,6 +12212,8 @@ function linkTitle(title, url) {
12177
12212
  }
12178
12213
 
12179
12214
  // src/api-base.ts
12215
+ import { homedir as homedir2 } from "os";
12216
+ import { join as join3 } from "path";
12180
12217
  var PROD_API_BASE = "https://terminalhire.com";
12181
12218
  var DEV_API_BASE = "https://dev.terminalhire.com";
12182
12219
  var ApiBaseError = class extends Error {
@@ -12270,8 +12307,8 @@ function normalizeOverride(raw) {
12270
12307
 
12271
12308
  // bin/jpi-bounties.js
12272
12309
  init_founder_pin();
12273
- var TERMINALHIRE_DIR7 = process.env.TERMINALHIRE_DIR || join12(homedir9(), ".terminalhire");
12274
- var INDEX_CACHE_FILE2 = join12(TERMINALHIRE_DIR7, "index-cache.json");
12310
+ var TERMINALHIRE_DIR7 = process.env.TERMINALHIRE_DIR || join13(homedir10(), ".terminalhire");
12311
+ var INDEX_CACHE_FILE2 = join13(TERMINALHIRE_DIR7, "index-cache.json");
12275
12312
  var INDEX_TTL_MS = 15 * 60 * 1e3;
12276
12313
  var API_URL2 = resolveApiBase();
12277
12314
  var RANK_MODE = process.env["TERMINALHIRE_BOUNTY_RANK"] ?? "winnability";
@@ -12335,7 +12372,7 @@ function founderClaimBlurb(amountUSD, paidWork) {
12335
12372
  if (typeof amountUSD === "number" && Number.isFinite(amountUSD) && amountUSD > 0) {
12336
12373
  share = ` You'd receive ${formatCents(developerShareCents(Math.round(amountUSD * 100)))} of the ${formatCents(Math.round(amountUSD * 100))} posted; terminalhire keeps 10%.`;
12337
12374
  }
12338
- return `Claim it from here \u2014 the founder pays through terminalhire rather than off-platform, and their acceptance is what triggers your payout.${share}`;
12375
+ return `Claim it from here \u2014 the poster pays through terminalhire rather than off-platform, and their acceptance is what triggers your payout.${share}`;
12339
12376
  }
12340
12377
  function founderClaimBlock(job) {
12341
12378
  const ref = opportunityShortToken(job.id);
@@ -12383,7 +12420,7 @@ ${i + 1}. ${linkTitle(job.title, job.url)} [${ref}]`);
12383
12420
  }
12384
12421
  if (b.bountySource === "founder" && b.specProvenance) {
12385
12422
  console.log(
12386
- ` Spec: ${b.specProvenance === "agent_drafted_human_confirmed" ? "agent drafted \xB7 founder confirmed" : "founder authored"}`
12423
+ ` Spec: ${b.specProvenance === "agent_drafted_human_confirmed" ? "agent drafted \xB7 poster confirmed" : "poster authored"}`
12387
12424
  );
12388
12425
  }
12389
12426
  if (matchedTags && matchedTags.length)
@@ -12597,7 +12634,7 @@ Enter a number to open a bounty's claim page, d<number> to say why you're passin
12597
12634
  const postingId = postingIdFromJobId2(shown[dIdx]?.id);
12598
12635
  if (!postingId) {
12599
12636
  console.log(
12600
- "\nThat one is scraped from a public tracker \u2014 there is no founder here to tell."
12637
+ "\nThat one is scraped from a public tracker \u2014 there is no poster here to tell."
12601
12638
  );
12602
12639
  return;
12603
12640
  }