@profullstack/qryptchat 0.9.1 → 0.10.0

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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  CALL_TYPE,
3
3
  parseCall
4
- } from "./chunk-pg6thvma.js";
4
+ } from "./chunk-vj54b54e.js";
5
5
 
6
6
  // src/cli/voice-agent.js
7
7
  import { spawn } from "node:child_process";
@@ -106,6 +106,7 @@ var e2eeOptions = (key) => ({
106
106
  });
107
107
  var JOIN_RECENT_MS = 30 * 60 * 1000;
108
108
  var ALONE_LEAVE_MS = 30 * 1000;
109
+ var FIRST_WAIT_MS = 10 * 60 * 1000;
109
110
  var MAX_CALL_MS = 3 * 60 * 60 * 1000;
110
111
  var RATE = 16000;
111
112
  var SPEAK_RATE = 24000;
@@ -187,6 +188,7 @@ class CallSession {
187
188
  this.closed = false;
188
189
  this.started = Date.now();
189
190
  this.lastHuman = Date.now();
191
+ this.humanSeen = false;
190
192
  }
191
193
  get id() {
192
194
  return this.conversation.id;
@@ -215,10 +217,13 @@ class CallSession {
215
217
  return [...this.room?.remoteParticipants?.values() ?? []].some((p) => this.isHuman(userIdOf(p.identity)));
216
218
  }
217
219
  checkAlone() {
218
- if (this.humansPresent())
220
+ if (this.humansPresent()) {
219
221
  this.lastHuman = Date.now();
220
- if (Date.now() - this.lastHuman > ALONE_LEAVE_MS)
221
- return this.close("everyone left");
222
+ this.humanSeen = true;
223
+ }
224
+ const limit = this.humanSeen ? ALONE_LEAVE_MS : FIRST_WAIT_MS;
225
+ if (Date.now() - this.lastHuman > limit)
226
+ return this.close(this.humanSeen ? "everyone left" : "nobody came");
222
227
  if (Date.now() - this.started > MAX_CALL_MS)
223
228
  return this.close("call too long");
224
229
  }
@@ -0,0 +1,8 @@
1
+ import {
2
+ openBrowser2,
3
+ login2
4
+ } from "./chunk-vj54b54e.js";
5
+ export {
6
+ login2 as login,
7
+ openBrowser2 as openBrowser
8
+ };
@@ -969,7 +969,7 @@ function parsePasted(input, state) {
969
969
  }
970
970
  return /^[A-Za-z0-9_-]{20,}$/.test(text) ? text : null;
971
971
  }
972
- function openBrowser(url, { platform = process.platform, env = process.env } = {}) {
972
+ function openBrowser2(url, { platform = process.platform, env = process.env } = {}) {
973
973
  if (isRemote({ platform, env }))
974
974
  return false;
975
975
  const [cmd, args] = platform === "darwin" ? ["open", [url]] : platform === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
@@ -1010,7 +1010,7 @@ function waitForCallback(server, state) {
1010
1010
  });
1011
1011
  });
1012
1012
  }
1013
- async function login(options = {}) {
1013
+ async function login2(options = {}) {
1014
1014
  const env = options.env ?? process.env;
1015
1015
  const print = options.print ?? ((line) => process.stderr.write(`${line}
1016
1016
  `));
@@ -1044,7 +1044,7 @@ async function login(options = {}) {
1044
1044
  print(` Confirmation code: ${match}`);
1045
1045
  print(" Check that the browser shows the same code before you approve.");
1046
1046
  print("");
1047
- const opened = !oob && openBrowser(url.toString(), { env });
1047
+ const opened = !oob && openBrowser2(url.toString(), { env });
1048
1048
  print(opened ? " Opened your browser. If it did not, open:" : " Open this link in a browser where you are signed in to qrypt.chat:");
1049
1049
  print(` ${url.toString()}`);
1050
1050
  print("");
@@ -1267,6 +1267,9 @@ Usage:
1267
1267
  qc archive <chat> archive a chat for you (qc unarchive <chat> brings it back)
1268
1268
  qc voice [--send <chat>] a link to a fresh end-to-end encrypted PairUX voice room (no account
1269
1269
  needed to join); qc voice login|join|... runs the pairux CLI (qc voice help)
1270
+ qc phone your free phone minutes, credit and recent calls to phones
1271
+ qc call <number> call a phone (US/Canada free 10 min a day; +country code for others):
1272
+ opens qrypt.chat's dialer with the number filled in
1270
1273
  qc read <chat> [-n 20] print the last messages of a chat
1271
1274
  qc send <chat> <text> send a message (text "-" reads stdin; --reply <message-id> to reply)
1272
1275
  qc react <chat> <message-id> <emoji> [--remove] react to a message
@@ -1334,7 +1337,7 @@ async function client(flags, { interactive = false } = {}) {
1334
1337
  if (!opened) {
1335
1338
  if (!interactive)
1336
1339
  throw new Error("Not signed in. Run qc login.");
1337
- opened = await login({ oob: !!flags.oob });
1340
+ opened = await login2({ oob: !!flags.oob });
1338
1341
  }
1339
1342
  return new QcClient(opened.session, { save: opened.save });
1340
1343
  }
@@ -1369,7 +1372,7 @@ async function main2(argv, { version = "0.0.0" } = {}) {
1369
1372
  }
1370
1373
  case "agent": {
1371
1374
  if (rest[0] === "call") {
1372
- const { runVoiceAgent } = await import("./chunk-997mmke4.js");
1375
+ const { runVoiceAgent } = await import("./chunk-ckgythyp.js");
1373
1376
  return runVoiceAgent(await client(flags), {
1374
1377
  brain: typeof flags.brain === "string" ? flags.brain : undefined,
1375
1378
  voice: typeof flags.voice === "string" ? flags.voice : undefined,
@@ -1424,7 +1427,7 @@ ${ok("Installed OpenEmoji. Restart the terminal, then run: qc fonts status")}`);
1424
1427
  throw new Error("Usage: qc fonts install|status|remove");
1425
1428
  }
1426
1429
  case "login": {
1427
- const { session } = await login({ oob: !!flags.oob });
1430
+ const { session } = await login2({ oob: !!flags.oob });
1428
1431
  out(ok(`Signed in as ${who(session.user)} on ${session.base}.`));
1429
1432
  out(`${mark("lock")}Keys sealed (ChaCha20-Poly1305) in ${sessionPath()}.`);
1430
1433
  if (await new QcClient(session).keyCheck() === "mismatch") {
@@ -1484,6 +1487,31 @@ ${info("Set: qc profile --emoji :telescope: --pronouns she/her --website https:/
1484
1487
  return json({ id: chat.id, archived: cmd === "archive" });
1485
1488
  return out(ok(cmd === "archive" ? `Archived ${chat.title}. qc chats --archived lists it; qc unarchive brings it back.` : `${chat.title} is back in your chats.`));
1486
1489
  }
1490
+ case "phone": {
1491
+ const c = await client(flags);
1492
+ const p = await c.request("/api/phone");
1493
+ if (flags.json)
1494
+ return json(p);
1495
+ const money = (m) => `$${(Math.floor(Math.max(0, m || 0) / 1e4) / 100).toFixed(2)}`;
1496
+ out(p.operator ? `${mark("info")}Phone: unlimited (operator).` : `${mark("info")}Phone: ${Math.floor(p.freeSecondsLeft / 60)} free US/Canada minutes left today, credit ${money(p.balanceMicros)}.`);
1497
+ out(` Calls show caller ID ${p.callerId}. Buy credit or call at ${c.base}/phone`);
1498
+ for (const call of (p.calls || []).slice(0, 10)) {
1499
+ const secs = call.billed_seconds || 0;
1500
+ const len = secs ? `${Math.floor(secs / 60)}:${String(secs % 60).padStart(2, "0")}` : "not connected";
1501
+ out(` ${stamp(call.created_at)} ${call.to_number} ${len}${call.charged_micros ? ` ${money(call.charged_micros)}` : ""}`);
1502
+ }
1503
+ return;
1504
+ }
1505
+ case "call": {
1506
+ if (!rest[0])
1507
+ throw new Error('Usage: qc call <number> (e.g. qc call "(415) 555-1234" or qc call +442079460958)');
1508
+ const c = await client(flags);
1509
+ const url = `${c.base}/phone?to=${encodeURIComponent(rest.join(" "))}`;
1510
+ const { openBrowser } = await import("./chunk-kycg804s.js");
1511
+ const opened = openBrowser(url);
1512
+ return out(`${mark("send")}${opened === false ? "Open" : "Opened"} ${url}
1513
+ Calls to phones need your browser for the audio; tap Call there.`);
1514
+ }
1487
1515
  case "names": {
1488
1516
  if (!rest[0])
1489
1517
  throw new Error("Usage: qc names <chat>");
@@ -1638,4 +1666,4 @@ async function voiceCommand(argv, { out, json }) {
1638
1666
  }
1639
1667
  }
1640
1668
 
1641
- export { CALL_TYPE, parseCall, exitWhenFlushed2, errorLine2, HELP2, parseArgs2, findChat2, main2 };
1669
+ export { CALL_TYPE, parseCall, openBrowser2, login2, exitWhenFlushed2, errorLine2, HELP2, parseArgs2, findChat2, main2 };
package/dist/commands.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  parseArgs2,
6
6
  findChat2,
7
7
  main2
8
- } from "./chunk-pg6thvma.js";
8
+ } from "./chunk-vj54b54e.js";
9
9
  import"./chunk-8gpysrd6.js";
10
10
  export {
11
11
  HELP2 as HELP,
package/dist/mcp.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import"./chunk-8gpysrd6.js";
2
2
  import {
3
3
  findChat2
4
- } from "./chunk-pg6thvma.js";
4
+ } from "./chunk-vj54b54e.js";
5
5
 
6
6
  // src/cli/mcp.js
7
7
  import { createInterface } from "node:readline";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@profullstack/qryptchat",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "description": "qc: qrypt.chat in your terminal. A full-screen end-to-end encrypted chat client (ML-KEM-1024), plus a scriptable CLI and an MCP server.",
5
5
  "type": "module",
6
6
  "bin": {