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.
- package/dist/bin/jpi-chat-read.js +74 -16
- package/dist/bin/jpi-chat.js +466 -31
- package/dist/bin/jpi-config.js +1 -0
- package/dist/bin/jpi-dispatch.js +284 -96
- package/dist/bin/jpi-link.js +1 -0
- package/dist/bin/jpi-login.js +1 -0
- package/dist/bin/jpi-refresh.js +12 -5
- package/dist/bin/jpi-spinner.js +9 -4
- package/dist/bin/peer-connect-prompt.js +1 -0
- package/dist/bin/spinner.js +10 -4
- package/dist/src/chat-client.js +16 -1
- package/dist/src/config.js +1 -0
- package/dist/src/link.js +1 -0
- package/package.json +1 -1
|
@@ -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 {
|
|
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
|
-
|
|
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
|
|
4270
|
-
import { homedir as
|
|
4271
|
-
import { join as
|
|
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 || !
|
|
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(
|
|
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 (!
|
|
4300
|
-
const parsed = JSON.parse(
|
|
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 =
|
|
4618
|
-
READS_FILE =
|
|
4619
|
-
INDEX_CACHE_FILE =
|
|
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();
|