@profullstack/qryptchat 0.4.6 → 0.5.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/dist/{chunk-kabknfjj.js → chunk-74kad4wd.js} +41 -1
- package/dist/commands.js +1 -1
- package/dist/mcp.js +1 -1
- package/dist/tui.js +3 -2
- package/package.json +2 -2
|
@@ -727,6 +727,20 @@ class QcClient {
|
|
|
727
727
|
return "unknown";
|
|
728
728
|
}
|
|
729
729
|
}
|
|
730
|
+
async profile() {
|
|
731
|
+
const { user } = await this.request(`/api/users/by-username/${encodeURIComponent(this.me?.username ?? "")}`);
|
|
732
|
+
return user;
|
|
733
|
+
}
|
|
734
|
+
async updateProfile(fields) {
|
|
735
|
+
const { user } = await this.request("/api/profile/update", { method: "POST", body: fields });
|
|
736
|
+
return user;
|
|
737
|
+
}
|
|
738
|
+
async openProfile() {
|
|
739
|
+
const res = await this.fetch(`${this.base}/u/${encodeURIComponent(this.me?.username ?? "")}/openprofile.md`);
|
|
740
|
+
if (!res.ok)
|
|
741
|
+
throw new QcError(`HTTP ${res.status}`, res.status);
|
|
742
|
+
return res.text();
|
|
743
|
+
}
|
|
730
744
|
async conversations() {
|
|
731
745
|
const { conversations = [] } = await this.request("/api/conversations/load", { method: "POST", body: {} });
|
|
732
746
|
return conversations.map((c) => ({ ...c, title: conversationTitle(c, this.me) }));
|
|
@@ -751,6 +765,8 @@ class QcClient {
|
|
|
751
765
|
conversationId: m.conversation_id,
|
|
752
766
|
senderId: m.sender_id,
|
|
753
767
|
sender: m.sender?.display_name || m.sender?.username || "unknown",
|
|
768
|
+
emoji: m.sender?.emoji || "",
|
|
769
|
+
pronouns: m.sender?.pronouns || "",
|
|
754
770
|
username: m.sender?.username || "",
|
|
755
771
|
mine: m.sender_id === this.me?.id,
|
|
756
772
|
text: m.content,
|
|
@@ -1082,6 +1098,9 @@ Usage:
|
|
|
1082
1098
|
qc login [--oob] sign in through your browser; --oob to paste a code (SSH)
|
|
1083
1099
|
qc logout forget this terminal's session and keys
|
|
1084
1100
|
qc whoami who this terminal is signed in as
|
|
1101
|
+
qc profile [--emoji \uD83D\uDD2D] [--pronouns she/her] [--website URL] [--bio TEXT]
|
|
1102
|
+
show or set your public profile (an empty value clears it);
|
|
1103
|
+
--openprofile prints it as OpenProfile.md
|
|
1085
1104
|
qc chats list your chats
|
|
1086
1105
|
qc read <chat> [-n 20] print the last messages of a chat
|
|
1087
1106
|
qc send <chat> <text> send a message (text "-" reads stdin; --reply <message-id> to reply)
|
|
@@ -1107,7 +1126,7 @@ function parseArgs2(argv) {
|
|
|
1107
1126
|
const [k, v] = a.slice(2).split("=", 2);
|
|
1108
1127
|
if (v !== undefined)
|
|
1109
1128
|
args.flags[k] = v;
|
|
1110
|
-
else if (["url", "n", "limit", "reply"].includes(k) && argv[i + 1] !== undefined)
|
|
1129
|
+
else if (["url", "n", "limit", "reply", "emoji", "pronouns", "website", "bio"].includes(k) && argv[i + 1] !== undefined && !argv[i + 1].startsWith("--"))
|
|
1111
1130
|
args.flags[k] = argv[++i];
|
|
1112
1131
|
else
|
|
1113
1132
|
args.flags[k] = true;
|
|
@@ -1193,6 +1212,27 @@ async function main2(argv, { version = "0.0.0" } = {}) {
|
|
|
1193
1212
|
throw new Error("Not signed in. Run qc login.");
|
|
1194
1213
|
return flags.json ? json({ user: session.user, base: session.base }) : out(`@${session.user?.username} (${session.user?.display_name ?? ""}) on ${session.base}`);
|
|
1195
1214
|
}
|
|
1215
|
+
case "profile": {
|
|
1216
|
+
const c = await client(flags);
|
|
1217
|
+
if (flags.openprofile)
|
|
1218
|
+
return out((await c.openProfile()).trimEnd());
|
|
1219
|
+
const fields = {};
|
|
1220
|
+
for (const k of ["emoji", "pronouns", "website", "bio"])
|
|
1221
|
+
if (flags[k] !== undefined)
|
|
1222
|
+
fields[k] = flags[k] === true ? "" : String(flags[k]);
|
|
1223
|
+
const p = Object.keys(fields).length ? await c.updateProfile(fields) : await c.profile();
|
|
1224
|
+
if (flags.json)
|
|
1225
|
+
return json({ username: p.username, emoji: p.emoji ?? null, pronouns: p.pronouns ?? null, website: p.website ?? null, bio: p.bio ?? null });
|
|
1226
|
+
out(`${p.emoji ? `${p.emoji} ` : ""}${p.displayName ?? p.display_name ?? p.username} @${p.username}${p.pronouns ? ` (${p.pronouns})` : ""}`);
|
|
1227
|
+
if (p.website)
|
|
1228
|
+
out(p.website);
|
|
1229
|
+
if (p.bio)
|
|
1230
|
+
out(p.bio);
|
|
1231
|
+
if (!Object.keys(fields).length)
|
|
1232
|
+
out(`
|
|
1233
|
+
Set: qc profile --emoji \uD83D\uDD2D --pronouns she/her --website https://you.example (an empty value clears)`);
|
|
1234
|
+
return;
|
|
1235
|
+
}
|
|
1196
1236
|
case "chats":
|
|
1197
1237
|
case "ls": {
|
|
1198
1238
|
const chats = await (await client(flags)).conversations();
|
package/dist/commands.js
CHANGED
package/dist/mcp.js
CHANGED
package/dist/tui.js
CHANGED
|
@@ -56,7 +56,8 @@ function transcriptLines(messages, width, theme) {
|
|
|
56
56
|
if (!sameRun) {
|
|
57
57
|
lines.push({
|
|
58
58
|
spans: [
|
|
59
|
-
{ text: m.mine ? "you" : m.sender
|
|
59
|
+
{ text: `${m.emoji ? `${m.emoji} ` : ""}${m.mine ? "you" : m.sender}`, fg: m.mine ? theme.primary : nameColor(theme, m.senderId || m.sender), bold: true },
|
|
60
|
+
...m.pronouns && !m.mine ? [{ text: ` ${m.pronouns}`, fg: theme.muted }] : [],
|
|
60
61
|
{ text: ` ${timeOf(m.at)}`, fg: theme.muted }
|
|
61
62
|
]
|
|
62
63
|
});
|
|
@@ -211,7 +212,7 @@ async function runTui(client, { initialChat } = {}) {
|
|
|
211
212
|
const state = initialState(client.me);
|
|
212
213
|
state.recent = loadRecent();
|
|
213
214
|
const abort = new AbortController;
|
|
214
|
-
const app = await createApp({ quitKeys: ["ctrl+c"], focusNavigation: false });
|
|
215
|
+
const app = await createApp({ quitKeys: ["ctrl+c"], focusNavigation: false, focusEvents: true });
|
|
215
216
|
const redraw = () => app.invalidate();
|
|
216
217
|
const env = process.env.QC_HD && !process.env.HQTUI_IMAGES ? { ...process.env, HQTUI_IMAGES: process.env.QC_HD } : process.env;
|
|
217
218
|
state.images = createImageStore({ write: (seq) => app.terminal.write(seq), onReady: redraw, env });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@profullstack/qryptchat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.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": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@noble/ciphers": "^2.0.0",
|
|
20
20
|
"@profullstack/encrypt": "^0.1.0",
|
|
21
|
-
"@profullstack/hqtui": "^0.10.
|
|
21
|
+
"@profullstack/hqtui": "^0.10.1",
|
|
22
22
|
"mlkem": "^2.5.0"
|
|
23
23
|
},
|
|
24
24
|
"keywords": [
|