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