@profullstack/qryptchat 0.6.1 → 0.6.2

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.
@@ -187,4 +187,31 @@ function clearSession(env = process.env) {
187
187
  rmSync(file);
188
188
  }
189
189
 
190
- export { DEFAULT_URL, configDir, sessionPath, baseUrl, loadSession, unlockSession, storeSession, clearSession };
190
+ // src/cli/notify.js
191
+ var ESC = "\x1B";
192
+ var BEL = "\x07";
193
+ var ST = `${ESC}\\`;
194
+ var clean = (s) => String(s ?? "").replace(/[\x00-\x1f\x7f;]/g, " ").trim();
195
+ function notifySequence(title, body, env = process.env) {
196
+ const mode = String(env.QC_NOTIFY ?? "1").toLowerCase();
197
+ if (["0", "off", "false", "no"].includes(mode))
198
+ return "";
199
+ if (mode === "bell")
200
+ return BEL;
201
+ const t = clean(title);
202
+ const b = clean(body);
203
+ const kitty = env.KITTY_WINDOW_ID || env.TERM === "xterm-kitty";
204
+ let osc = kitty ? `${ESC}]99;i=qc:d=0:o=unfocused;${t}${ST}${ESC}]99;i=qc:d=1:p=body;${b}${ST}` : `${ESC}]9;${t}: ${b}${BEL}`;
205
+ if (env.TMUX)
206
+ osc = `${ESC}Ptmux;${osc.replaceAll(ESC, ESC + ESC)}${ST}`;
207
+ return osc + BEL;
208
+ }
209
+ function notify(title, body, { env = process.env, streams = [process.stdout, process.stderr] } = {}) {
210
+ const seq = notifySequence(title, body, env);
211
+ const tty = streams.find((s) => s?.isTTY);
212
+ if (seq && tty)
213
+ tty.write(seq);
214
+ return Boolean(seq && tty);
215
+ }
216
+
217
+ export { DEFAULT_URL, configDir, sessionPath, baseUrl, loadSession, unlockSession, storeSession, clearSession, notify };
@@ -5,8 +5,9 @@ import {
5
5
  loadSession,
6
6
  unlockSession,
7
7
  storeSession,
8
- clearSession
9
- } from "./chunk-menzxtw0.js";
8
+ clearSession,
9
+ notify
10
+ } from "./chunk-g9xn5036.js";
10
11
 
11
12
  // src/cli/crypto.js
12
13
  import { MlKem1024 as MlKem10242 } from "mlkem";
@@ -1174,7 +1175,7 @@ Usage:
1174
1175
  qc read <chat> [-n 20] print the last messages of a chat
1175
1176
  qc send <chat> <text> send a message (text "-" reads stdin; --reply <message-id> to reply)
1176
1177
  qc react <chat> <message-id> <emoji> [--remove] react to a message
1177
- qc listen print new messages as they arrive (NDJSON with --json)
1178
+ qc listen print new messages as they arrive (NDJSON with --json; --notify alerts with it)
1178
1179
  qc mcp run as an MCP server on stdio (list_chats, read_chat, send_message)
1179
1180
 
1180
1181
  <chat> is a chat id or part of its name. Options: --json, --url <server> (or QC_URL).
@@ -1183,7 +1184,9 @@ OS keychain, or comes from a passphrase (QC_PASSPHRASE for scripts and qc mcp).
1183
1184
  HD: emoji and icons are drawn as our OpenEmoji/OpenIcon images in Kitty, Ghostty, WezTerm and iTerm2.
1184
1185
  Over SSH or in tmux (set -g allow-passthrough on) say which: QC_HD=1 (Kitty/Ghostty) or
1185
1186
  QC_HD=wezterm (WezTerm/iTerm2). QC_HD=0 turns it off. Mosh carries only text, so behind mosh
1186
- emoji stay characters: for images use ssh or WezTerm's multiplexer (wezterm connect).`;
1187
+ emoji stay characters: for images use ssh or WezTerm's multiplexer (wezterm connect).
1188
+ New messages raise a terminal notification (OSC 9, Kitty OSC 99) and a bell, naming the chat
1189
+ but never the text; in tmux set -g allow-passthrough on. QC_NOTIFY=bell rings only, QC_NOTIFY=0 is quiet.`;
1187
1190
  function parseArgs2(argv) {
1188
1191
  const args = { _: [], flags: {} };
1189
1192
  for (let i = 0;i < argv.length; i++) {
@@ -1419,6 +1422,8 @@ ${info("Set: qc profile --emoji :telescope: --pronouns she/her --website https:/
1419
1422
  if (seen.has(m.id) || m.id !== data.message.id)
1420
1423
  continue;
1421
1424
  seen.add(m.id);
1425
+ if (!m.mine && (flags.notify || !flags.json))
1426
+ notify("qrypt.chat", `${m.sender} in ${titles.get(id) ?? "a chat"}`);
1422
1427
  if (flags.json)
1423
1428
  out(JSON.stringify({ chat: id, title: titles.get(id), ...m }));
1424
1429
  else
package/dist/commands.js CHANGED
@@ -4,8 +4,8 @@ import {
4
4
  parseArgs2,
5
5
  findChat2,
6
6
  main2
7
- } from "./chunk-0f0frsar.js";
8
- import"./chunk-menzxtw0.js";
7
+ } from "./chunk-s0qccr26.js";
8
+ import"./chunk-g9xn5036.js";
9
9
  export {
10
10
  HELP2 as HELP,
11
11
  errorLine2 as errorLine,
package/dist/mcp.js CHANGED
@@ -1,7 +1,7 @@
1
- import"./chunk-menzxtw0.js";
1
+ import"./chunk-g9xn5036.js";
2
2
  import {
3
3
  findChat2
4
- } from "./chunk-0f0frsar.js";
4
+ } from "./chunk-s0qccr26.js";
5
5
 
6
6
  // src/cli/mcp.js
7
7
  import { createInterface } from "node:readline";
package/dist/tui.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
- configDir
3
- } from "./chunk-menzxtw0.js";
2
+ configDir,
3
+ notify
4
+ } from "./chunk-g9xn5036.js";
4
5
 
5
6
  // src/cli/tui.js
6
7
  import { createApp, createImageStore, drawIcon, drawRichText, editText, emojify, insertText, stringWidth, truncate, widgets, wrap } from "@profullstack/hqtui";
@@ -396,6 +397,10 @@ async function runTui(client, { initialChat } = {}) {
396
397
  const id = data?.message?.conversation_id;
397
398
  if (!id)
398
399
  return;
400
+ if (data.message.sender_id !== client.me?.id) {
401
+ const chat = state.conversations.find((c) => c.id === id);
402
+ notify("qrypt.chat", `new message${chat ? ` in ${chat.title}` : ""}`);
403
+ }
399
404
  if (id === state.activeId)
400
405
  loadMessages(id);
401
406
  else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@profullstack/qryptchat",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
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": {