terminalhire 0.10.9 → 0.10.11

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.
@@ -4039,7 +4039,21 @@ function createChatClient(overrides) {
4039
4039
  const data = await res.json();
4040
4040
  const presence = data.presence ?? null;
4041
4041
  if (!presence) return null;
4042
- return { login: presence.login, lastSeen: presence.lastSeen };
4042
+ return {
4043
+ login: presence.login,
4044
+ lastSeen: presence.lastSeen ?? null,
4045
+ optin: presence.optin === true,
4046
+ shareActivity: presence.shareActivity === true
4047
+ };
4048
+ }
4049
+ async function setActivitySharing(share) {
4050
+ const res = await authedFetch("/api/chat/activity", {
4051
+ method: "POST",
4052
+ headers: { "Content-Type": "application/json" },
4053
+ body: JSON.stringify({ share })
4054
+ });
4055
+ if (!res.ok) throw new ChatRequestError("/api/chat/activity", res.status);
4056
+ await res.json();
4043
4057
  }
4044
4058
  async function applyBlock(login, action) {
4045
4059
  const target = login.trim();
@@ -4063,6 +4077,7 @@ function createChatClient(overrides) {
4063
4077
  pollMessages,
4064
4078
  heartbeat,
4065
4079
  getPeerPresence,
4080
+ setActivitySharing,
4066
4081
  blockPeer: (login) => applyBlock(login, "block"),
4067
4082
  unblock: (login) => applyBlock(login, "unblock"),
4068
4083
  getSafetyNumber
@@ -4151,6 +4166,7 @@ var init_config = __esm({
4151
4166
  peerConnectPrompted: false,
4152
4167
  resumePublishPrompted: false,
4153
4168
  chatDisclosureAck: false,
4169
+ chatShareActivity: false,
4154
4170
  inboundNudgeMuted: false,
4155
4171
  inboundNudgeDisclosed: false
4156
4172
  };
@@ -4159,6 +4175,9 @@ var init_config = __esm({
4159
4175
 
4160
4176
  // bin/jpi-chat.js
4161
4177
  import { createInterface } from "readline";
4178
+ import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
4179
+ import { homedir as homedir6 } from "os";
4180
+ import { join as join7 } from "path";
4162
4181
  function sanitizeLine(text) {
4163
4182
  return String(text).replace(ANSI_CSI, "").replace(ANSI_OSC, "").replace(ANSI_OTHER, "").replace(C0_C1_DEL, "");
4164
4183
  }
@@ -4245,7 +4264,13 @@ async function defaultListConnections(deps = {}) {
4245
4264
  const connections = listed.intros.filter((it) => it && it.status === "accepted" && it.counterpartyLogin).map((it) => ({ introId: it.id, peerLogin: it.counterpartyLogin }));
4246
4265
  return { status: "ok", connections };
4247
4266
  }
4248
- var CHAT_BASE2, GH_SESSION_COOKIE2, ANSI_CSI, ANSI_OSC, ANSI_OTHER, C0_C1_DEL, CHAT_DISCLOSURE, CHAT_AT_REST, CHAT_CODE_OF_CONDUCT, CHAT_MIN_AGE;
4267
+ async function defaultListPendingInvites(deps = {}) {
4268
+ const listed = await fetchIntroList(deps);
4269
+ if (listed.status !== "ok") return listed;
4270
+ const invites = listed.intros.filter((it) => it && it.role === "incoming" && it.status === "pending" && it.counterpartyLogin).map((it) => ({ login: it.counterpartyLogin }));
4271
+ return { status: "ok", invites };
4272
+ }
4273
+ var CHAT_BASE2, GH_SESSION_COOKIE2, ANSI_CSI, ANSI_OSC, ANSI_OTHER, C0_C1_DEL, CHAT_DISCLOSURE, CHAT_AT_REST, CHAT_CODE_OF_CONDUCT, CHAT_MIN_AGE, ACTIVE_WINDOW_MS;
4249
4274
  var init_jpi_chat = __esm({
4250
4275
  "bin/jpi-chat.js"() {
4251
4276
  "use strict";
@@ -4262,20 +4287,21 @@ var init_jpi_chat = __esm({
4262
4287
  CHAT_AT_REST = "Your private key is encrypted against casual access, not full machine compromise.";
4263
4288
  CHAT_CODE_OF_CONDUCT = "Code of conduct: keep it professional \u2014 harassment, spam, or abuse gets you blocked and removed.";
4264
4289
  CHAT_MIN_AGE = "You must be at least 13 years old to use connections chat.";
4290
+ ACTIVE_WINDOW_MS = 2 * 60 * 1e3;
4265
4291
  }
4266
4292
  });
4267
4293
 
4268
4294
  // bin/jpi-chat-read.js
4269
- import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
4270
- import { homedir as homedir6 } from "os";
4271
- import { join as join7 } from "path";
4295
+ import { existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
4296
+ import { homedir as homedir7 } from "os";
4297
+ import { join as join8 } from "path";
4272
4298
  async function syncUnreadBadge(deps = {}) {
4273
4299
  const readCookie = deps.readCookie ?? readWebSessionCookie;
4274
4300
  const fetchImpl = deps.fetchImpl ?? globalThis.fetch;
4275
4301
  const cacheFile = deps.cacheFile ?? INDEX_CACHE_FILE;
4276
4302
  try {
4277
4303
  const cookie = readCookie();
4278
- if (!cookie || !existsSync6(cacheFile)) return;
4304
+ if (!cookie || !existsSync7(cacheFile)) return;
4279
4305
  const res = await fetchImpl(`${CHAT_BASE3}/api/chat/inbox`, {
4280
4306
  method: "GET",
4281
4307
  headers: { Cookie: `${GH_SESSION_COOKIE3}=${cookie}` },
@@ -4288,7 +4314,7 @@ async function syncUnreadBadge(deps = {}) {
4288
4314
  (sum, it) => sum + (it && typeof it.unreadCount === "number" && it.unreadCount > 0 ? it.unreadCount : 0),
4289
4315
  0
4290
4316
  );
4291
- const entry = JSON.parse(readFileSync7(cacheFile, "utf8"));
4317
+ const entry = JSON.parse(readFileSync8(cacheFile, "utf8"));
4292
4318
  entry.unreadChat = { count: total };
4293
4319
  writeFileSync6(cacheFile, JSON.stringify(entry), "utf8");
4294
4320
  } catch {
@@ -4296,8 +4322,8 @@ async function syncUnreadBadge(deps = {}) {
4296
4322
  }
4297
4323
  function readReadCursors() {
4298
4324
  try {
4299
- if (!existsSync6(READS_FILE)) return {};
4300
- const parsed = JSON.parse(readFileSync7(READS_FILE, "utf8"));
4325
+ if (!existsSync7(READS_FILE)) return {};
4326
+ const parsed = JSON.parse(readFileSync8(READS_FILE, "utf8"));
4301
4327
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
4302
4328
  const out = {};
4303
4329
  for (const [login, iso] of Object.entries(parsed)) {
@@ -4353,10 +4379,19 @@ function truncate(s, n) {
4353
4379
  const t = String(s);
4354
4380
  return t.length <= n ? t : `${t.slice(0, n - 1)}\u2026`;
4355
4381
  }
4356
- function renderInbox(items) {
4382
+ function renderInbox(items, invites = []) {
4357
4383
  const lines = [];
4358
4384
  lines.push(" connections \xB7 terminalhire chat");
4359
4385
  lines.push(" " + "\u2500".repeat(64));
4386
+ if (invites && invites.length > 0) {
4387
+ lines.push(` PENDING INVITATIONS (${invites.length})`);
4388
+ for (const iv of invites) {
4389
+ const login = sanitizeLine(iv.login);
4390
+ const handle = `@${login}`;
4391
+ lines.push(` \u2198 ${handle.padEnd(18)} wants to connect \xB7 terminalhire intro --accept ${handle}`);
4392
+ }
4393
+ lines.push(" " + "\u2500".repeat(64));
4394
+ }
4360
4395
  if (!items || items.length === 0) {
4361
4396
  lines.push(" (no accepted connections yet \u2014 request one: terminalhire intro <login>)");
4362
4397
  } else {
@@ -4463,6 +4498,7 @@ async function runInbox(opts = {}) {
4463
4498
  input = process.stdin,
4464
4499
  client = createChatClient(),
4465
4500
  listConnections = defaultListConnections,
4501
+ listInvites = defaultListPendingInvites,
4466
4502
  readCursors = readReadCursors,
4467
4503
  ensureDisclosure = ensureChatDisclosure
4468
4504
  } = opts;
@@ -4473,6 +4509,12 @@ async function runInbox(opts = {}) {
4473
4509
  if (listed.status !== "ok") {
4474
4510
  return { ok: false, reason: writeProblem(output, listed, "") };
4475
4511
  }
4512
+ let invites = [];
4513
+ try {
4514
+ const inv = await listInvites();
4515
+ if (inv && inv.status === "ok") invites = inv.invites;
4516
+ } catch {
4517
+ }
4476
4518
  const cursors = readCursors();
4477
4519
  const items = [];
4478
4520
  for (const conn of listed.connections) {
@@ -4497,8 +4539,8 @@ async function runInbox(opts = {}) {
4497
4539
  });
4498
4540
  }
4499
4541
  await clearPresence(client);
4500
- output.write(renderInbox(items));
4501
- return { ok: true, count: items.length };
4542
+ output.write(renderInbox(items, invites));
4543
+ return { ok: true, count: items.length, invites: invites.length };
4502
4544
  }
4503
4545
  async function runReadThread(opts = {}) {
4504
4546
  const {
@@ -4571,7 +4613,10 @@ async function runSend(opts = {}) {
4571
4613
  input = process.stdin,
4572
4614
  client = createChatClient(),
4573
4615
  resolveConnection = defaultResolveConnection,
4574
- ensureDisclosure = ensureChatDisclosure
4616
+ ensureDisclosure = ensureChatDisclosure,
4617
+ writeCursor = writeReadCursor,
4618
+ syncCursor = postReadCursor,
4619
+ syncBadge = syncUnreadBadge
4575
4620
  } = opts;
4576
4621
  const target = String(login ?? "").replace(/^@/, "").trim();
4577
4622
  const body = String(text ?? "").trim();
@@ -4597,6 +4642,19 @@ async function runSend(opts = {}) {
4597
4642
  `);
4598
4643
  return { ok: false, reason: "error" };
4599
4644
  }
4645
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
4646
+ try {
4647
+ writeCursor(peerLogin, nowIso);
4648
+ } catch {
4649
+ }
4650
+ await syncCursor(peerLogin, nowIso);
4651
+ await syncBadge();
4652
+ if (typeof client.heartbeat === "function") {
4653
+ try {
4654
+ await client.heartbeat(false);
4655
+ } catch {
4656
+ }
4657
+ }
4600
4658
  output.write(
4601
4659
  `
4602
4660
  Sent to @${sanitizeLine(peerLogin)}: ${sanitizeLine(body)}
@@ -4614,9 +4672,9 @@ var init_jpi_chat_read = __esm({
4614
4672
  init_jpi_chat();
4615
4673
  CHAT_BASE3 = process.env["TERMINALHIRE_API_URL"] || "https://www.terminalhire.com";
4616
4674
  GH_SESSION_COOKIE3 = "__jpi_gh_session";
4617
- TERMINALHIRE_DIR5 = join7(homedir6(), ".terminalhire");
4618
- READS_FILE = join7(TERMINALHIRE_DIR5, "chat-reads.json");
4619
- INDEX_CACHE_FILE = join7(TERMINALHIRE_DIR5, "index-cache.json");
4675
+ TERMINALHIRE_DIR5 = join8(homedir7(), ".terminalhire");
4676
+ READS_FILE = join8(TERMINALHIRE_DIR5, "chat-reads.json");
4677
+ INDEX_CACHE_FILE = join8(TERMINALHIRE_DIR5, "index-cache.json");
4620
4678
  }
4621
4679
  });
4622
4680
  init_jpi_chat_read();