@profullstack/qryptchat 0.11.0 → 0.12.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.
package/README.md CHANGED
@@ -55,6 +55,7 @@ qc mentions ops @al # who @al completes to: @alice, @alina
55
55
  echo "deploy done" | qc send ops -
56
56
  qc listen --json # new messages as NDJSON, until you stop it
57
57
  qc whoami
58
+ qc keys # are this terminal's keys your account's? (qc keys publish puts them back)
58
59
  ```
59
60
 
60
61
  `<chat>` is a chat id or any unique part of its name. Add `--json` for machine output.
@@ -736,6 +736,13 @@ class QcClient {
736
736
  return "unknown";
737
737
  }
738
738
  }
739
+ async publishKey() {
740
+ const mine = this.session.keys?.keys1024?.publicKey;
741
+ if (!mine)
742
+ throw new QcError("This terminal holds no keys. Run qc login.");
743
+ await this.request("/api/crypto/public-keys", { method: "PUT", body: { public_key: mine, key_type: "ML-KEM-1024" } });
744
+ return this.keyCheck();
745
+ }
739
746
  async profile() {
740
747
  const { user } = await this.request(`/api/users/by-username/${encodeURIComponent(this.me?.username ?? "")}`);
741
748
  return user;
@@ -1262,6 +1269,8 @@ Usage:
1262
1269
  qc logout forget this terminal's session and keys
1263
1270
  qc update [--check] update qc to the latest release (--check only says whether there is one)
1264
1271
  qc whoami who this terminal is signed in as
1272
+ qc keys [publish] whether this terminal's keys are your account's; publish makes them the
1273
+ account's again (when another device published keys qc does not hold)
1265
1274
  qc profile [--emoji \uD83D\uDD2D] [--pronouns she/her] [--website URL] [--bio TEXT]
1266
1275
  show or set your public profile (an empty value clears it);
1267
1276
  --openprofile prints it as OpenProfile.md
@@ -1379,7 +1388,7 @@ async function main2(argv, { version = "0.0.0" } = {}) {
1379
1388
  }
1380
1389
  case "agent": {
1381
1390
  if (rest[0] === "call") {
1382
- const { runVoiceAgent } = await import("./chunk-wkjs9anq.js");
1391
+ const { runVoiceAgent } = await import("./chunk-ycvwj8wy.js");
1383
1392
  return runVoiceAgent(await client(flags), {
1384
1393
  brain: typeof flags.brain === "string" ? flags.brain : undefined,
1385
1394
  voice: typeof flags.voice === "string" ? flags.voice : undefined,
@@ -1442,6 +1451,35 @@ ${ok("Installed OpenEmoji. Restart the terminal, then run: qc fonts status")}`);
1442
1451
  }
1443
1452
  return;
1444
1453
  }
1454
+ case "keys": {
1455
+ const c = await client(flags);
1456
+ const status = await c.keyCheck();
1457
+ if (rest[0] !== "publish") {
1458
+ if (flags.json)
1459
+ return json({ keys: status });
1460
+ if (status === "ok")
1461
+ return out(ok("This terminal's keys are your account's keys."));
1462
+ if (status === "mismatch")
1463
+ return out(warn("Your account publishes a different key, so messages sent to you since then won't decrypt here. If older messages read fine in qc read, run qc keys publish."));
1464
+ return out(info("Could not compare keys (no key on file, or the check failed)."));
1465
+ }
1466
+ if (status === "ok")
1467
+ return out(ok("Already published: nothing to do."));
1468
+ if (!flags.yes) {
1469
+ if (!process.stdin.isTTY)
1470
+ throw new Error("qc keys publish replaces the key everyone encrypts to. Add --yes to confirm.");
1471
+ const { createInterface } = await import("node:readline/promises");
1472
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
1473
+ const answer = await rl.question("Publish this terminal's key? Devices holding the other key will stop decrypting new messages until they restore your keys. [y/N] ");
1474
+ rl.close();
1475
+ if (!/^y(es)?$/i.test(answer.trim()))
1476
+ return out(info("Left the published key alone."));
1477
+ }
1478
+ const after = await c.publishKey();
1479
+ if (flags.json)
1480
+ return json({ published: true, keys: after });
1481
+ return out(ok("Published. New messages are encrypted to this terminal's key again; other devices on the other key should restore from Settings > Keys."));
1482
+ }
1445
1483
  case "logout":
1446
1484
  clearSession();
1447
1485
  return out(ok("Signed out. This terminal no longer holds your keys."));
@@ -1514,7 +1552,7 @@ ${info("Set: qc profile --emoji :telescope: --pronouns she/her --website https:/
1514
1552
  throw new Error('Usage: qc call <number> (e.g. qc call "(415) 555-1234" or qc call +442079460958)');
1515
1553
  const c = await client(flags);
1516
1554
  const url = `${c.base}/phone?to=${encodeURIComponent(rest.join(" "))}`;
1517
- const { openBrowser } = await import("./chunk-nsn86c8y.js");
1555
+ const { openBrowser } = await import("./chunk-zh85gmtq.js");
1518
1556
  const opened = openBrowser(url);
1519
1557
  return out(`${mark("send")}${opened === false ? "Open" : "Opened"} ${url}
1520
1558
  Calls to phones need your browser for the audio; tap Call there.`);
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  CALL_TYPE,
3
3
  parseCall
4
- } from "./chunk-ywyhy3sp.js";
4
+ } from "./chunk-hmyhm26d.js";
5
5
 
6
6
  // src/cli/voice-agent.js
7
7
  import { spawn } from "node:child_process";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  openBrowser2,
3
3
  login2
4
- } from "./chunk-ywyhy3sp.js";
4
+ } from "./chunk-hmyhm26d.js";
5
5
  export {
6
6
  login2 as login,
7
7
  openBrowser2 as openBrowser
package/dist/commands.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  mentionMatches2,
8
8
  withMentions2,
9
9
  main2
10
- } from "./chunk-ywyhy3sp.js";
10
+ } from "./chunk-hmyhm26d.js";
11
11
  import"./chunk-4ea1xy2c.js";
12
12
  export {
13
13
  HELP2 as HELP,
package/dist/mcp.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  findChat2,
4
4
  mentionMatches2,
5
5
  withMentions2
6
- } from "./chunk-ywyhy3sp.js";
6
+ } from "./chunk-hmyhm26d.js";
7
7
 
8
8
  // src/cli/mcp.js
9
9
  import { createInterface } from "node:readline";
package/dist/tui.js CHANGED
@@ -262,7 +262,7 @@ function saveRecent(list) {
262
262
  writeFileSync(recentFile(), JSON.stringify(list), { mode: 384 });
263
263
  } catch {}
264
264
  }
265
- var KEY_MISMATCH = "Keys don't match your account, so messages can't decrypt. Run qc login and approve from a browser that can read your chats.";
265
+ var KEY_MISMATCH = "Keys don't match your account, so new messages can't decrypt. If your history reads here, run qc keys publish; else qc login from a browser that reads your chats.";
266
266
  async function runTui(client, { initialChat } = {}) {
267
267
  const state = initialState(client.me);
268
268
  state.recent = loadRecent();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@profullstack/qryptchat",
3
- "version": "0.11.0",
3
+ "version": "0.12.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": {