terminalhire 0.10.6 → 0.10.8

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.
@@ -4786,7 +4786,7 @@ async function runChatPane(opts = {}) {
4786
4786
  signals.removeListener("exit", onExit);
4787
4787
  } catch {
4788
4788
  }
4789
- output.write(SHOW_CURSOR + "\n");
4789
+ output.write(SHOW_CURSOR + EXIT_ALT);
4790
4790
  }
4791
4791
  function finish(reason) {
4792
4792
  if (cleaned) return;
@@ -4972,7 +4972,7 @@ async function runChatPane(opts = {}) {
4972
4972
  try {
4973
4973
  if (typeof input.setRawMode === "function") input.setRawMode(true);
4974
4974
  if (typeof input.resume === "function") input.resume();
4975
- output.write(HIDE_CURSOR);
4975
+ output.write(ENTER_ALT + HIDE_CURSOR);
4976
4976
  input.on("data", onData);
4977
4977
  signals.on("SIGINT", onSignal);
4978
4978
  signals.on("SIGTERM", onTerm);
@@ -5094,14 +5094,14 @@ async function run() {
5094
5094
  process.exit(0);
5095
5095
  } catch (err) {
5096
5096
  try {
5097
- process.stdout.write(SHOW_CURSOR);
5097
+ process.stdout.write(SHOW_CURSOR + EXIT_ALT);
5098
5098
  } catch {
5099
5099
  }
5100
5100
  console.error("terminalhire chat error:", err instanceof Error ? err.message : err);
5101
5101
  process.exit(1);
5102
5102
  }
5103
5103
  }
5104
- var CHAT_BASE3, GH_SESSION_COOKIE3, HIDE_CURSOR, SHOW_CURSOR, CLEAR, KEY_CTRL_C, KEY_CTRL_S, KEY_ENTER_A, KEY_ENTER_B, KEY_BACKSPACE_A, KEY_BACKSPACE_B, MAX_INPUT_LEN, ANSI_CSI, ANSI_OSC, ANSI_OTHER, C0_C1_DEL, CHAT_DISCLOSURE, CHAT_AT_REST, CHAT_CODE_OF_CONDUCT, CHAT_MIN_AGE, DEPOSIT_CTA;
5104
+ var CHAT_BASE3, GH_SESSION_COOKIE3, HIDE_CURSOR, SHOW_CURSOR, ENTER_ALT, EXIT_ALT, CLEAR, KEY_CTRL_C, KEY_CTRL_S, KEY_ENTER_A, KEY_ENTER_B, KEY_BACKSPACE_A, KEY_BACKSPACE_B, MAX_INPUT_LEN, ANSI_CSI, ANSI_OSC, ANSI_OTHER, C0_C1_DEL, CHAT_DISCLOSURE, CHAT_AT_REST, CHAT_CODE_OF_CONDUCT, CHAT_MIN_AGE, DEPOSIT_CTA;
5105
5105
  var init_jpi_chat = __esm({
5106
5106
  "bin/jpi-chat.js"() {
5107
5107
  init_chat_client();
@@ -5111,6 +5111,8 @@ var init_jpi_chat = __esm({
5111
5111
  GH_SESSION_COOKIE3 = "__jpi_gh_session";
5112
5112
  HIDE_CURSOR = "\x1B[?25l";
5113
5113
  SHOW_CURSOR = "\x1B[?25h";
5114
+ ENTER_ALT = "\x1B[?1049h";
5115
+ EXIT_ALT = "\x1B[?1049l";
5114
5116
  CLEAR = "\x1B[2J\x1B[H";
5115
5117
  KEY_CTRL_C = "";
5116
5118
  KEY_CTRL_S = "";
@@ -10923,7 +10923,7 @@ async function runChatPane(opts = {}) {
10923
10923
  signals.removeListener("exit", onExit);
10924
10924
  } catch {
10925
10925
  }
10926
- output.write(SHOW_CURSOR + "\n");
10926
+ output.write(SHOW_CURSOR + EXIT_ALT);
10927
10927
  }
10928
10928
  function finish(reason) {
10929
10929
  if (cleaned) return;
@@ -11109,7 +11109,7 @@ async function runChatPane(opts = {}) {
11109
11109
  try {
11110
11110
  if (typeof input.setRawMode === "function") input.setRawMode(true);
11111
11111
  if (typeof input.resume === "function") input.resume();
11112
- output.write(HIDE_CURSOR);
11112
+ output.write(ENTER_ALT + HIDE_CURSOR);
11113
11113
  input.on("data", onData);
11114
11114
  signals.on("SIGINT", onSignal);
11115
11115
  signals.on("SIGTERM", onTerm);
@@ -11231,14 +11231,14 @@ async function run9() {
11231
11231
  process.exit(0);
11232
11232
  } catch (err) {
11233
11233
  try {
11234
- process.stdout.write(SHOW_CURSOR);
11234
+ process.stdout.write(SHOW_CURSOR + EXIT_ALT);
11235
11235
  } catch {
11236
11236
  }
11237
11237
  console.error("terminalhire chat error:", err instanceof Error ? err.message : err);
11238
11238
  process.exit(1);
11239
11239
  }
11240
11240
  }
11241
- var CHAT_BASE3, GH_SESSION_COOKIE5, HIDE_CURSOR, SHOW_CURSOR, CLEAR, KEY_CTRL_C, KEY_CTRL_S, KEY_ENTER_A, KEY_ENTER_B, KEY_BACKSPACE_A, KEY_BACKSPACE_B, MAX_INPUT_LEN, ANSI_CSI, ANSI_OSC, ANSI_OTHER, C0_C1_DEL, CHAT_DISCLOSURE, CHAT_AT_REST, CHAT_CODE_OF_CONDUCT, CHAT_MIN_AGE, DEPOSIT_CTA;
11241
+ var CHAT_BASE3, GH_SESSION_COOKIE5, HIDE_CURSOR, SHOW_CURSOR, ENTER_ALT, EXIT_ALT, CLEAR, KEY_CTRL_C, KEY_CTRL_S, KEY_ENTER_A, KEY_ENTER_B, KEY_BACKSPACE_A, KEY_BACKSPACE_B, MAX_INPUT_LEN, ANSI_CSI, ANSI_OSC, ANSI_OTHER, C0_C1_DEL, CHAT_DISCLOSURE, CHAT_AT_REST, CHAT_CODE_OF_CONDUCT, CHAT_MIN_AGE, DEPOSIT_CTA;
11242
11242
  var init_jpi_chat = __esm({
11243
11243
  "bin/jpi-chat.js"() {
11244
11244
  "use strict";
@@ -11249,6 +11249,8 @@ var init_jpi_chat = __esm({
11249
11249
  GH_SESSION_COOKIE5 = "__jpi_gh_session";
11250
11250
  HIDE_CURSOR = "\x1B[?25l";
11251
11251
  SHOW_CURSOR = "\x1B[?25h";
11252
+ ENTER_ALT = "\x1B[?1049h";
11253
+ EXIT_ALT = "\x1B[?1049l";
11252
11254
  CLEAR = "\x1B[2J\x1B[H";
11253
11255
  KEY_CTRL_C = "";
11254
11256
  KEY_CTRL_S = "";
@@ -13088,6 +13090,8 @@ async function run18() {
13088
13090
  } catch {
13089
13091
  }
13090
13092
  let incomingPending = { count: 0 };
13093
+ let sessionStale = false;
13094
+ const sessionExpired = (res) => res.status === 401;
13091
13095
  const sessionCookie = readWebSessionFile();
13092
13096
  if (sessionCookie && !isInboundNudgeMuted()) try {
13093
13097
  const res = await fetch(`${API_URL6}/api/intro/list`, {
@@ -13100,6 +13104,8 @@ async function run18() {
13100
13104
  const intros = Array.isArray(body?.intros) ? body.intros : [];
13101
13105
  const incoming = intros.filter((it) => it && it.role === "incoming" && it.status === "pending");
13102
13106
  incomingPending = { count: incoming.length };
13107
+ } else if (sessionExpired(res)) {
13108
+ sessionStale = true;
13103
13109
  }
13104
13110
  } catch {
13105
13111
  }
@@ -13118,6 +13124,8 @@ async function run18() {
13118
13124
  0
13119
13125
  );
13120
13126
  unreadChat = { count: total };
13127
+ } else if (sessionExpired(res)) {
13128
+ sessionStale = true;
13121
13129
  }
13122
13130
  } catch {
13123
13131
  }
@@ -13129,7 +13137,8 @@ async function run18() {
13129
13137
  topMatches,
13130
13138
  topPeers,
13131
13139
  incomingPending,
13132
- unreadChat
13140
+ unreadChat,
13141
+ sessionStale
13133
13142
  };
13134
13143
  writeFileSync17(INDEX_CACHE_FILE5, JSON.stringify(cacheEntry), "utf8");
13135
13144
  try {
@@ -13193,7 +13202,7 @@ var init_jpi_refresh = __esm({
13193
13202
  __dirname4 = fileURLToPath5(new URL(".", import.meta.url));
13194
13203
  TERMINALHIRE_DIR14 = join23(homedir21(), ".terminalhire");
13195
13204
  INDEX_CACHE_FILE5 = join23(TERMINALHIRE_DIR14, "index-cache.json");
13196
- API_URL6 = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://terminalhire.com";
13205
+ API_URL6 = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://www.terminalhire.com";
13197
13206
  }
13198
13207
  });
13199
13208
 
@@ -6980,7 +6980,7 @@ var GH_SESSION_COOKIE = "__jpi_gh_session";
6980
6980
  var __dirname2 = fileURLToPath3(new URL(".", import.meta.url));
6981
6981
  var TERMINALHIRE_DIR4 = join9(homedir7(), ".terminalhire");
6982
6982
  var INDEX_CACHE_FILE2 = join9(TERMINALHIRE_DIR4, "index-cache.json");
6983
- var API_URL2 = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://terminalhire.com";
6983
+ var API_URL2 = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://www.terminalhire.com";
6984
6984
  async function run() {
6985
6985
  try {
6986
6986
  let index;
@@ -7079,6 +7079,8 @@ async function run() {
7079
7079
  } catch {
7080
7080
  }
7081
7081
  let incomingPending = { count: 0 };
7082
+ let sessionStale = false;
7083
+ const sessionExpired = (res) => res.status === 401;
7082
7084
  const sessionCookie = readWebSessionFile();
7083
7085
  if (sessionCookie && !isInboundNudgeMuted()) try {
7084
7086
  const res = await fetch(`${API_URL2}/api/intro/list`, {
@@ -7091,6 +7093,8 @@ async function run() {
7091
7093
  const intros = Array.isArray(body?.intros) ? body.intros : [];
7092
7094
  const incoming = intros.filter((it) => it && it.role === "incoming" && it.status === "pending");
7093
7095
  incomingPending = { count: incoming.length };
7096
+ } else if (sessionExpired(res)) {
7097
+ sessionStale = true;
7094
7098
  }
7095
7099
  } catch {
7096
7100
  }
@@ -7109,6 +7113,8 @@ async function run() {
7109
7113
  0
7110
7114
  );
7111
7115
  unreadChat = { count: total };
7116
+ } else if (sessionExpired(res)) {
7117
+ sessionStale = true;
7112
7118
  }
7113
7119
  } catch {
7114
7120
  }
@@ -7120,7 +7126,8 @@ async function run() {
7120
7126
  topMatches,
7121
7127
  topPeers,
7122
7128
  incomingPending,
7123
- unreadChat
7129
+ unreadChat,
7130
+ sessionStale
7124
7131
  };
7125
7132
  writeFileSync6(INDEX_CACHE_FILE2, JSON.stringify(cacheEntry), "utf8");
7126
7133
  try {
package/dist/bin/jpi.js CHANGED
@@ -105,6 +105,16 @@ function getCachedUnreadChatCount() {
105
105
  return 0;
106
106
  }
107
107
  }
108
+ function getCachedSessionStale() {
109
+ try {
110
+ const raw = readFileSync(INDEX_CACHE_FILE, "utf8");
111
+ const entry = JSON.parse(raw);
112
+ if (Date.now() - entry.ts > INDEX_CACHE_TTL_MS) return false;
113
+ return entry.sessionStale === true;
114
+ } catch {
115
+ return false;
116
+ }
117
+ }
108
118
  function getNudgeMode() {
109
119
  const envVal = process.env["TERMINALHIRE_NUDGE"];
110
120
  if (envVal) {
@@ -178,9 +188,10 @@ try {
178
188
  const matchCount = getCachedMatchCount();
179
189
  const incomingCount = getCachedIncomingCount();
180
190
  const unreadChatCount = getCachedUnreadChatCount();
191
+ const sessionStale = getCachedSessionStale() && incomingCount === 0 && unreadChatCount === 0;
181
192
  const haveRoles = matchCount !== null && matchCount > 0;
182
- if (!haveRoles && incomingCount === 0 && unreadChatCount === 0) process.exit(0);
183
- const hasConnectionSignal = incomingCount > 0 || unreadChatCount > 0;
193
+ if (!haveRoles && incomingCount === 0 && unreadChatCount === 0 && !sessionStale) process.exit(0);
194
+ const hasConnectionSignal = incomingCount > 0 || unreadChatCount > 0 || sessionStale;
184
195
  const nudgeMode = getNudgeMode();
185
196
  if (!hasConnectionSignal && !shouldNudge(nudgeMode, sessionId)) process.exit(0);
186
197
  let line;
@@ -189,11 +200,14 @@ try {
189
200
  line = `\u2726 ${matchCount} ${plural} match your current work \u2014 run: terminalhire jobs`;
190
201
  if (incomingCount > 0) line += ` \xB7 \u2709 ${incomingCount} waiting to connect`;
191
202
  if (unreadChatCount > 0) line += ` \xB7 \u{1F4AC} ${unreadChatCount} unread`;
203
+ if (sessionStale) line += ` \xB7 \u26A0 session expired \u2014 run: terminalhire link`;
192
204
  } else if (incomingCount > 0) {
193
205
  line = `\u2709 ${incomingCount} waiting to connect \u2014 run: terminalhire intro --list`;
194
206
  if (unreadChatCount > 0) line += ` \xB7 \u{1F4AC} ${unreadChatCount} unread`;
195
- } else {
207
+ } else if (unreadChatCount > 0) {
196
208
  line = `\u{1F4AC} ${unreadChatCount} unread \u2014 run: terminalhire chat`;
209
+ } else {
210
+ line = `\u26A0 terminalhire session expired \u2014 run: terminalhire link to restore your connection signals`;
197
211
  }
198
212
  process.stdout.write(line + "\n");
199
213
  if (haveRoles && nudgeMode === "session") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "terminalhire",
3
- "version": "0.10.6",
3
+ "version": "0.10.8",
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",