@wirecat/cli-core 0.476.0 → 0.478.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/CHANGELOG.md +41 -0
- package/dist/calendar/mcp/index.d.ts +12 -12
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/messenger/account-command.js +10 -8
- package/dist/cli/messenger/catch-up-answers.d.ts +16 -0
- package/dist/cli/messenger/catch-up-answers.js +2 -1
- package/dist/cli/messenger/chat-answers.d.ts +8 -2
- package/dist/cli/messenger/chat-answers.js +43 -0
- package/dist/cli/messenger/contacts-command.js +20 -25
- package/dist/cli/messenger/context.d.ts +2 -0
- package/dist/cli/messenger/conversation-answers.d.ts +21 -0
- package/dist/cli/messenger/message-answers.d.ts +21 -0
- package/dist/cli/messenger/message-items.d.ts +1 -1
- package/dist/cli/messenger/message-items.js +10 -2
- package/dist/cli/messenger/message-writes.d.ts +42 -0
- package/dist/cli/messenger/people-queries.d.ts +2 -0
- package/dist/cli/messenger/people-queries.js +7 -1
- package/dist/cli/messenger/reactions-command.js +38 -2
- package/dist/cli/messenger/search-answers.js +5 -1
- package/dist/cli/messenger/serve-relay.d.ts +1 -0
- package/dist/domain/models.d.ts +24 -3
- package/dist/domain/models.js +2 -0
- package/dist/entities/attachment.d.ts +8 -0
- package/dist/entities/attachment.js +9 -1
- package/dist/entities/contact-context.d.ts +42 -0
- package/dist/entities/contact-read.d.ts +15 -25
- package/dist/entities/contact-read.js +4 -15
- package/dist/entities/contact.d.ts +103 -134
- package/dist/entities/contact.js +13 -2
- package/dist/entities/conversation-results.d.ts +42 -0
- package/dist/entities/evidence.d.ts +168 -0
- package/dist/entities/hit.d.ts +2 -0
- package/dist/entities/hit.js +2 -0
- package/dist/entities/index.d.ts +519 -202
- package/dist/entities/index.js +6 -3
- package/dist/entities/listener.d.ts +84 -0
- package/dist/entities/message-context.d.ts +63 -0
- package/dist/entities/message-write.d.ts +84 -0
- package/dist/entities/message.d.ts +21 -0
- package/dist/entities/reaction.d.ts +12 -0
- package/dist/entities/reaction.js +9 -0
- package/dist/entities/store-records.d.ts +21 -0
- package/dist/errors/reasons.js +2 -0
- package/dist/meetings/mcp/index.d.ts +15 -15
- package/dist/ports/messenger.d.ts +13 -2
- package/dist/render/markdown.js +4 -0
- package/dist/render/messages.js +7 -2
- package/dist/services/account.d.ts +1 -1
- package/dist/services/account.js +1 -2
- package/dist/services/people.d.ts +8 -5
- package/dist/services/people.js +6 -3
- package/dist/services/person-profile.d.ts +4 -3
- package/dist/services/person-profile.js +14 -3
- package/dist/services/pictures.d.ts +2 -1
- package/dist/services/pictures.js +2 -0
- package/dist/services/search-all.d.ts +3 -1
- package/dist/services/search-all.js +2 -0
- package/dist/store/sqlite/manifest.js +1 -0
- package/dist/store/sqlite/messages.js +5 -1
- package/dist/store/sqlite/migrations.generated.js +6 -0
- package/dist/store/sqlite/reads.js +1 -0
- package/dist/store/sqlite/schema.d.ts +16 -0
- package/dist/store/sqlite/schema.js +1 -0
- package/package.json +1 -1
- package/parity.json +20 -10
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,47 @@ shape of this file.
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
+
## 0.478.0 — 29.10.2026
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **`sender_is_me` on `inbox`, `review`, `search messages` and `search all`**, as 0.473.0 promised. The catch-up
|
|
15
|
+
answers and the search hits are built field by field, not from `messageItem`, and left it out; only `messages list`
|
|
16
|
+
and the other `messageItem` answers had it. A `search all` hit carries it for a message or a mail, and the picture
|
|
17
|
+
lane's hits of `search messages` carry it too. Every answer applies the one rule: `outgoing`, or the sender id is
|
|
18
|
+
the reading account's own.
|
|
19
|
+
|
|
20
|
+
## 0.477.0 — 29.10.2026
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- **A shared contact card is an attachment with a `contact` field** (store version 36). `Attachment.contact`
|
|
25
|
+
(`SharedContact`: `name`, `firstName?`, `lastName?`, `phone?`, `userId?`) and, in every message answer,
|
|
26
|
+
`attachments[].contact` (`name`, `first_name?`, `last_name?`, `phone?`, `user_id?`), the phone whole. The store keeps it in
|
|
27
|
+
the new column `attachments.contact`, so a card read with `--offline` is the card the messenger sent; a later copy of the
|
|
28
|
+
message without it keeps the stored one. The terminal shows `👤 name · phone`. Additive: `minCompatible` stays 34.
|
|
29
|
+
What an adapter does: set `contact` on the attachment instead of putting a masked phone in `title`.
|
|
30
|
+
- **`--hide-phone`** on `account show`, `account update` and `contacts show`: the answer without the phone number.
|
|
31
|
+
- **`reactions list <chat> <message> [reaction:<emoji>] [--limit <n>] [--cursor <cursor>]`** (read) shows who reacted
|
|
32
|
+
to a message, newest first, as `{ person: { id, name, username }, reaction, reacted_at }` rows paged by cursor. A
|
|
33
|
+
messenger turns it on with `Messenger.reactionsList` and `MessageReactions.reactors`; where the chat hides the list
|
|
34
|
+
it refuses with `reactions.list-hidden` (or `reactions.broadcast` for a channel) instead of answering with none. The
|
|
35
|
+
permission key is `reactions.list`. New entity `reaction`, new type `Reactor`.
|
|
36
|
+
|
|
37
|
+
### Changed — may break callers
|
|
38
|
+
|
|
39
|
+
- **Phone numbers are shown whole.** `account show`, `account update` and `contacts show` print the number the messenger
|
|
40
|
+
gave, in the CLI and over MCP; they are the owner's own data. `--show-phone` is gone (a script that passes it is refused
|
|
41
|
+
as an unknown option; drop it), and so is `maskedAccount` from `/cli`: `withoutPhone(answer)` is what `--hide-phone` uses.
|
|
42
|
+
- **`contacts info` is folded into `contacts show`, with no alias.** `contacts show <person>` returns the card as before (alias,
|
|
43
|
+
shared chats, `--with-notes`) and, with it, the messenger's profile: `usernames`, `birthday`, `phone`, `flags`, `seen`,
|
|
44
|
+
`contact`, `mutual_contact`, `common_chats_count`, `registered`, `has_photo` and `aliases` (earlier names), and in each shared
|
|
45
|
+
chat `their_messages`, `first_at`, `last_at` and `complete`. The profile's `bio` is `description`. `--offline` answers from
|
|
46
|
+
the store alone, as every read does. The entity `contact_profile` and the MCP tool `contacts info` are gone, and `PeopleService.profile`
|
|
47
|
+
takes the card as an optional second argument. Permission keys are read only as written (0.421.0): a saved
|
|
48
|
+
`contacts.info` is refused as a key no command checks, with the `config unset` that removes it; `contacts.show` now covers
|
|
49
|
+
the profile too.
|
|
50
|
+
|
|
10
51
|
## 0.476.0 — 29.10.2026
|
|
11
52
|
|
|
12
53
|
### Fixed
|
|
@@ -10,13 +10,13 @@ export declare const calendarTools: ({
|
|
|
10
10
|
inputSchema: {
|
|
11
11
|
type: string;
|
|
12
12
|
properties: {
|
|
13
|
-
limit?: undefined;
|
|
14
13
|
account_id: {
|
|
15
14
|
type: string;
|
|
16
15
|
minimum: number;
|
|
17
16
|
};
|
|
18
17
|
words?: undefined;
|
|
19
18
|
timezone?: undefined;
|
|
19
|
+
limit?: undefined;
|
|
20
20
|
event?: undefined;
|
|
21
21
|
} | {
|
|
22
22
|
account_id: {
|
|
@@ -38,9 +38,9 @@ export declare const calendarTools: ({
|
|
|
38
38
|
};
|
|
39
39
|
event?: undefined;
|
|
40
40
|
} | {
|
|
41
|
-
limit?: undefined;
|
|
42
41
|
words?: undefined;
|
|
43
42
|
timezone?: undefined;
|
|
43
|
+
limit?: undefined;
|
|
44
44
|
event: {
|
|
45
45
|
type: string;
|
|
46
46
|
minLength: number;
|
|
@@ -50,9 +50,9 @@ export declare const calendarTools: ({
|
|
|
50
50
|
minimum: number;
|
|
51
51
|
};
|
|
52
52
|
} | {
|
|
53
|
-
limit?: undefined;
|
|
54
53
|
words?: undefined;
|
|
55
54
|
timezone?: undefined;
|
|
55
|
+
limit?: undefined;
|
|
56
56
|
event?: undefined;
|
|
57
57
|
account_id?: undefined;
|
|
58
58
|
};
|
|
@@ -71,13 +71,13 @@ export declare const calendarTools: ({
|
|
|
71
71
|
inputSchema: {
|
|
72
72
|
type: string;
|
|
73
73
|
properties: {
|
|
74
|
-
limit?: undefined;
|
|
75
74
|
account_id: {
|
|
76
75
|
type: string;
|
|
77
76
|
minimum: number;
|
|
78
77
|
};
|
|
79
78
|
words?: undefined;
|
|
80
79
|
timezone?: undefined;
|
|
80
|
+
limit?: undefined;
|
|
81
81
|
event?: undefined;
|
|
82
82
|
} | {
|
|
83
83
|
account_id: {
|
|
@@ -99,9 +99,9 @@ export declare const calendarTools: ({
|
|
|
99
99
|
};
|
|
100
100
|
event?: undefined;
|
|
101
101
|
} | {
|
|
102
|
-
limit?: undefined;
|
|
103
102
|
words?: undefined;
|
|
104
103
|
timezone?: undefined;
|
|
104
|
+
limit?: undefined;
|
|
105
105
|
event: {
|
|
106
106
|
type: string;
|
|
107
107
|
minLength: number;
|
|
@@ -111,9 +111,9 @@ export declare const calendarTools: ({
|
|
|
111
111
|
minimum: number;
|
|
112
112
|
};
|
|
113
113
|
} | {
|
|
114
|
-
limit?: undefined;
|
|
115
114
|
words?: undefined;
|
|
116
115
|
timezone?: undefined;
|
|
116
|
+
limit?: undefined;
|
|
117
117
|
event?: undefined;
|
|
118
118
|
account_id?: undefined;
|
|
119
119
|
};
|
|
@@ -132,13 +132,13 @@ export declare const calendarTools: ({
|
|
|
132
132
|
inputSchema: {
|
|
133
133
|
type: string;
|
|
134
134
|
properties: {
|
|
135
|
-
limit?: undefined;
|
|
136
135
|
account_id: {
|
|
137
136
|
type: string;
|
|
138
137
|
minimum: number;
|
|
139
138
|
};
|
|
140
139
|
words?: undefined;
|
|
141
140
|
timezone?: undefined;
|
|
141
|
+
limit?: undefined;
|
|
142
142
|
event?: undefined;
|
|
143
143
|
} | {
|
|
144
144
|
account_id: {
|
|
@@ -160,9 +160,9 @@ export declare const calendarTools: ({
|
|
|
160
160
|
};
|
|
161
161
|
event?: undefined;
|
|
162
162
|
} | {
|
|
163
|
-
limit?: undefined;
|
|
164
163
|
words?: undefined;
|
|
165
164
|
timezone?: undefined;
|
|
165
|
+
limit?: undefined;
|
|
166
166
|
event: {
|
|
167
167
|
type: string;
|
|
168
168
|
minLength: number;
|
|
@@ -172,9 +172,9 @@ export declare const calendarTools: ({
|
|
|
172
172
|
minimum: number;
|
|
173
173
|
};
|
|
174
174
|
} | {
|
|
175
|
-
limit?: undefined;
|
|
176
175
|
words?: undefined;
|
|
177
176
|
timezone?: undefined;
|
|
177
|
+
limit?: undefined;
|
|
178
178
|
event?: undefined;
|
|
179
179
|
account_id?: undefined;
|
|
180
180
|
};
|
|
@@ -193,13 +193,13 @@ export declare const calendarTools: ({
|
|
|
193
193
|
inputSchema: {
|
|
194
194
|
type: string;
|
|
195
195
|
properties: {
|
|
196
|
-
limit?: undefined;
|
|
197
196
|
account_id: {
|
|
198
197
|
type: string;
|
|
199
198
|
minimum: number;
|
|
200
199
|
};
|
|
201
200
|
words?: undefined;
|
|
202
201
|
timezone?: undefined;
|
|
202
|
+
limit?: undefined;
|
|
203
203
|
event?: undefined;
|
|
204
204
|
} | {
|
|
205
205
|
account_id: {
|
|
@@ -221,9 +221,9 @@ export declare const calendarTools: ({
|
|
|
221
221
|
};
|
|
222
222
|
event?: undefined;
|
|
223
223
|
} | {
|
|
224
|
-
limit?: undefined;
|
|
225
224
|
words?: undefined;
|
|
226
225
|
timezone?: undefined;
|
|
226
|
+
limit?: undefined;
|
|
227
227
|
event: {
|
|
228
228
|
type: string;
|
|
229
229
|
minLength: number;
|
|
@@ -233,9 +233,9 @@ export declare const calendarTools: ({
|
|
|
233
233
|
minimum: number;
|
|
234
234
|
};
|
|
235
235
|
} | {
|
|
236
|
-
limit?: undefined;
|
|
237
236
|
words?: undefined;
|
|
238
237
|
timezone?: undefined;
|
|
238
|
+
limit?: undefined;
|
|
239
239
|
event?: undefined;
|
|
240
240
|
account_id?: undefined;
|
|
241
241
|
};
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ export { guardedClose, guardedCreatePoll, guardedVote } from "../sends/polls.js"
|
|
|
33
33
|
export type { InboxReader } from "../services/inbox.js";
|
|
34
34
|
export { INBOX_CHATS, newIn, REVIEW_CHATS, reviewIn, unreadIn } from "../services/inbox.js";
|
|
35
35
|
export { type DateWindow, dateWindow, momentOf } from "../services/moment.js";
|
|
36
|
-
export {
|
|
36
|
+
export { withoutPhone } from "../services/people.js";
|
|
37
37
|
export { unanswered } from "../services/questions.js";
|
|
38
38
|
export { openRequestTask } from "../services/task-rules.js";
|
|
39
39
|
export { TASK_PAIR_QUERY, TASK_QUERY } from "../services/tasks.js";
|
package/dist/cli/index.js
CHANGED
|
@@ -28,7 +28,7 @@ export { guardedApp, guardedPress, guardedStart } from "../sends/buttons.js";
|
|
|
28
28
|
export { guardedClose, guardedCreatePoll, guardedVote } from "../sends/polls.js";
|
|
29
29
|
export { INBOX_CHATS, newIn, REVIEW_CHATS, reviewIn, unreadIn } from "../services/inbox.js";
|
|
30
30
|
export { dateWindow, momentOf } from "../services/moment.js";
|
|
31
|
-
export {
|
|
31
|
+
export { withoutPhone } from "../services/people.js";
|
|
32
32
|
export { unanswered } from "../services/questions.js";
|
|
33
33
|
export { openRequestTask } from "../services/task-rules.js";
|
|
34
34
|
export { TASK_PAIR_QUERY, TASK_QUERY } from "../services/tasks.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { annotate } from "@wirecat/cli-base/commands";
|
|
3
3
|
import { Command } from "commander";
|
|
4
|
-
import {
|
|
4
|
+
import { withoutPhone } from "../../services/people.js";
|
|
5
5
|
import { storePath } from "../../store/path.js";
|
|
6
6
|
import { openStore } from "../../store/store.js";
|
|
7
7
|
import { REMOTE_READ, REMOTE_WRITE } from "../effects.js";
|
|
@@ -61,13 +61,13 @@ export const accountCommand = (messenger) => {
|
|
|
61
61
|
output: { entity: "account" },
|
|
62
62
|
examples: [`${tool} account show`],
|
|
63
63
|
})
|
|
64
|
-
.description("who this profile is logged in as
|
|
65
|
-
.option("--
|
|
64
|
+
.description("who this profile is logged in as, with the phone number")
|
|
65
|
+
.option("--hide-phone", "leave the phone number out")
|
|
66
66
|
.action(async function () {
|
|
67
|
-
const
|
|
67
|
+
const hide = this.opts().hidePhone === true;
|
|
68
68
|
const context = messengerContext(this, messenger);
|
|
69
69
|
const account = await context.withMessenger((connection) => connection.me());
|
|
70
|
-
renderAnswer(this, context, itemOf(accountAnswer(messenger.provider,
|
|
70
|
+
renderAnswer(this, context, itemOf(accountAnswer(messenger.provider, hide ? withoutPhone(account) : account)));
|
|
71
71
|
}))
|
|
72
72
|
.addCommand(annotate(new Command("update"), {
|
|
73
73
|
effects: REMOTE_WRITE,
|
|
@@ -79,16 +79,18 @@ export const accountCommand = (messenger) => {
|
|
|
79
79
|
.option("--last-name <name>", "your last name")
|
|
80
80
|
.option("--description <text>", "about you")
|
|
81
81
|
.option("--photo <file>", `a new profile photo — ${photoHelp(messenger)}`)
|
|
82
|
+
.option("--hide-phone", "leave the phone number out of the answer")
|
|
82
83
|
.action(async function () {
|
|
83
84
|
const context = messengerContext(this, messenger);
|
|
84
|
-
const { firstName, lastName, description, photo } = this.opts();
|
|
85
|
+
const { firstName, lastName, description, photo, hidePhone } = this.opts();
|
|
85
86
|
const upload = photo === undefined ? undefined : await readProfilePhoto(messenger, photo, context.env);
|
|
86
|
-
|
|
87
|
+
const changed = await context.withServices((services) => services.account.update({
|
|
87
88
|
...(firstName === undefined ? {} : { firstName }),
|
|
88
89
|
...(lastName === undefined ? {} : { lastName }),
|
|
89
90
|
...(description === undefined ? {} : { description }),
|
|
90
91
|
...(upload === undefined ? {} : { photo: upload }),
|
|
91
|
-
}))
|
|
92
|
+
}));
|
|
93
|
+
renderItem(this, context, hidePhone ? { ...changed, account: withoutPhone(changed.account) } : changed);
|
|
92
94
|
}))
|
|
93
95
|
.addCommand(accountSessionsCommand(messenger));
|
|
94
96
|
if (messenger.privacy === true)
|
|
@@ -20,6 +20,7 @@ export declare const inboxAnswer: (inbox: Inbox, hearing: Hearing | undefined, r
|
|
|
20
20
|
chat_title: string | null | undefined;
|
|
21
21
|
timestamp: string;
|
|
22
22
|
sender_name: string | null;
|
|
23
|
+
sender_is_me: boolean;
|
|
23
24
|
outgoing: boolean | null;
|
|
24
25
|
text: string;
|
|
25
26
|
transcript?: string | undefined;
|
|
@@ -43,6 +44,13 @@ export declare const inboxAnswer: (inbox: Inbox, hearing: Hearing | undefined, r
|
|
|
43
44
|
error?: string | undefined;
|
|
44
45
|
} | undefined;
|
|
45
46
|
local_path?: string | undefined;
|
|
47
|
+
contact?: {
|
|
48
|
+
name: string;
|
|
49
|
+
first_name?: string | undefined;
|
|
50
|
+
last_name?: string | undefined;
|
|
51
|
+
phone?: string | undefined;
|
|
52
|
+
user_id?: string | undefined;
|
|
53
|
+
} | undefined;
|
|
46
54
|
buttons?: {
|
|
47
55
|
kind: "app" | "callback" | "chat" | "clipboard" | "contact" | "link" | "location" | "message" | "other";
|
|
48
56
|
text: string;
|
|
@@ -67,6 +75,7 @@ export declare const reviewAnswer: (found: Review, hearing: Hearing | undefined,
|
|
|
67
75
|
chat_title: string | null | undefined;
|
|
68
76
|
timestamp: string;
|
|
69
77
|
sender_name: string | null;
|
|
78
|
+
sender_is_me: boolean;
|
|
70
79
|
outgoing: boolean | null;
|
|
71
80
|
text: string;
|
|
72
81
|
transcript?: string | undefined;
|
|
@@ -90,6 +99,13 @@ export declare const reviewAnswer: (found: Review, hearing: Hearing | undefined,
|
|
|
90
99
|
error?: string | undefined;
|
|
91
100
|
} | undefined;
|
|
92
101
|
local_path?: string | undefined;
|
|
102
|
+
contact?: {
|
|
103
|
+
name: string;
|
|
104
|
+
first_name?: string | undefined;
|
|
105
|
+
last_name?: string | undefined;
|
|
106
|
+
phone?: string | undefined;
|
|
107
|
+
user_id?: string | undefined;
|
|
108
|
+
} | undefined;
|
|
93
109
|
buttons?: {
|
|
94
110
|
kind: "app" | "callback" | "chat" | "clipboard" | "contact" | "link" | "location" | "message" | "other";
|
|
95
111
|
text: string;
|
|
@@ -34,13 +34,14 @@ export const catchUpQuery = (words, registry, command) => {
|
|
|
34
34
|
};
|
|
35
35
|
};
|
|
36
36
|
const summaryOf = (message, reader) => {
|
|
37
|
-
const { ref, chat_id, chat_title, timestamp, sender_name, outgoing, text, transcript, attachments } = messageItem(message, reader);
|
|
37
|
+
const { ref, chat_id, chat_title, timestamp, sender_name, sender_is_me, outgoing, text, transcript, attachments } = messageItem(message, reader);
|
|
38
38
|
return {
|
|
39
39
|
ref,
|
|
40
40
|
chat_id,
|
|
41
41
|
chat_title,
|
|
42
42
|
timestamp,
|
|
43
43
|
sender_name,
|
|
44
|
+
sender_is_me,
|
|
44
45
|
outgoing,
|
|
45
46
|
text,
|
|
46
47
|
...(transcript === undefined ? {} : { transcript }),
|
|
@@ -2,8 +2,8 @@ import { type QueryAst } from "@wirecat/cli-base/query";
|
|
|
2
2
|
import type { NextStep } from "@wirecat/cli-base/standards";
|
|
3
3
|
import type { Command } from "commander";
|
|
4
4
|
import type * as v from "valibot";
|
|
5
|
-
import type { Account, AccountSession, Chat, ChatCard, ChatEvent, Contact, Folder, GroupCard, GroupMember, InviteLink, JoinRequest, Member, PersonCard, PollVote, Topic } from "../../domain/models.js";
|
|
6
|
-
import type { account as accountSchema, chatEvent as chatEventSchema, chat as chatSchema, contact as contactSchema, folder as folderSchema, inviteLink as inviteLinkSchema, joinRequest as joinRequestSchema, member as memberSchema, pollVote as pollVoteSchema, topic as topicSchema } from "../../entities/index.js";
|
|
5
|
+
import type { Account, AccountSession, Chat, ChatCard, ChatEvent, Contact, Folder, GroupCard, GroupMember, InviteLink, JoinRequest, Member, PersonCard, PersonProfile, PollVote, Reactor, Topic } from "../../domain/models.js";
|
|
6
|
+
import type { account as accountSchema, chatEvent as chatEventSchema, chat as chatSchema, contact as contactSchema, folder as folderSchema, inviteLink as inviteLinkSchema, joinRequest as joinRequestSchema, member as memberSchema, pollVote as pollVoteSchema, reaction as reactionSchema, topic as topicSchema } from "../../entities/index.js";
|
|
7
7
|
import type { ChatDocument } from "../../services/chat-documents.js";
|
|
8
8
|
import type { FolderShown } from "../../services/folders.js";
|
|
9
9
|
import type { MemberEvent } from "../../services/member-history.js";
|
|
@@ -21,11 +21,17 @@ export declare const chatAnswer: (account: AccountKey, chat: ShownChat) => Out<t
|
|
|
21
21
|
export declare const memberAnswer: (member: Member | GroupMember | AuditedMember) => Out<typeof memberSchema>;
|
|
22
22
|
export declare const contactRef: (provider: string, id: string) => string;
|
|
23
23
|
export declare const contactAnswer: (account: AccountKey, contact: Contact | PersonCard) => Out<typeof contactSchema>;
|
|
24
|
+
/**
|
|
25
|
+
* `contacts show`: the card (the owner's alias and notes, the chats shared) with what the messenger says about the
|
|
26
|
+
* person, and in each shared chat how much of their writing the store holds.
|
|
27
|
+
*/
|
|
28
|
+
export declare const contactShown: (account: AccountKey, card: PersonCard, profile: PersonProfile) => Out<typeof contactSchema>;
|
|
24
29
|
export declare const chatEventAnswer: (chatId: string, event: ChatEvent) => Out<typeof chatEventSchema>;
|
|
25
30
|
export declare const memberEventAnswer: (chatId: string, event: MemberEvent) => Out<typeof chatEventSchema>;
|
|
26
31
|
export declare const inviteLinkAnswer: (link: InviteLink) => Out<typeof inviteLinkSchema>;
|
|
27
32
|
export declare const joinRequestAnswer: (request: JoinRequest) => Out<typeof joinRequestSchema>;
|
|
28
33
|
export declare const pollVoteAnswer: (vote: PollVote) => Out<typeof pollVoteSchema>;
|
|
34
|
+
export declare const reactorAnswer: (reactor: Reactor) => Out<typeof reactionSchema>;
|
|
29
35
|
export declare const topicAnswer: (topic: Topic) => Out<typeof topicSchema>;
|
|
30
36
|
export declare const folderAnswer: (folder: Folder | FolderShown) => Out<typeof folderSchema>;
|
|
31
37
|
/** A person's view of a list: one line per item. */
|
|
@@ -88,6 +88,44 @@ export const contactAnswer = (account, contact) => {
|
|
|
88
88
|
})),
|
|
89
89
|
});
|
|
90
90
|
};
|
|
91
|
+
/**
|
|
92
|
+
* `contacts show`: the card (the owner's alias and notes, the chats shared) with what the messenger says about the
|
|
93
|
+
* person, and in each shared chat how much of their writing the store holds.
|
|
94
|
+
*/
|
|
95
|
+
export const contactShown = (account, card, profile) => {
|
|
96
|
+
const { id: _id, name: _name, bio, chats, ...facts } = profile;
|
|
97
|
+
const listed = new Map(card.chats.map((chat) => [chat.id, chat]));
|
|
98
|
+
const active = new Set(chats.map(({ id }) => id));
|
|
99
|
+
const shared = [
|
|
100
|
+
...chats.map((chat) => ({
|
|
101
|
+
ref: chatRef(account, chat.id),
|
|
102
|
+
id: chat.id,
|
|
103
|
+
title: chat.title,
|
|
104
|
+
kind: chat.kind,
|
|
105
|
+
last_message_at: listed.get(chat.id)?.lastMessageAt ?? chat.lastAt,
|
|
106
|
+
their_messages: chat.theirMessages,
|
|
107
|
+
first_at: chat.firstAt,
|
|
108
|
+
last_at: chat.lastAt,
|
|
109
|
+
complete: chat.complete,
|
|
110
|
+
})),
|
|
111
|
+
...card.chats
|
|
112
|
+
.filter(({ id }) => !active.has(id))
|
|
113
|
+
.map((chat) => ({
|
|
114
|
+
ref: chatRef(account, chat.id),
|
|
115
|
+
id: chat.id,
|
|
116
|
+
title: chat.title,
|
|
117
|
+
kind: chat.kind,
|
|
118
|
+
last_message_at: chat.lastMessageAt,
|
|
119
|
+
})),
|
|
120
|
+
];
|
|
121
|
+
const answer = contactAnswer(account, card);
|
|
122
|
+
return {
|
|
123
|
+
...answer,
|
|
124
|
+
...snakeKeys(facts),
|
|
125
|
+
description: answer.description ?? bio,
|
|
126
|
+
chats: shared,
|
|
127
|
+
};
|
|
128
|
+
};
|
|
91
129
|
export const chatEventAnswer = (chatId, event) => defined({
|
|
92
130
|
chat_id: chatId,
|
|
93
131
|
time: event.timestamp,
|
|
@@ -130,6 +168,11 @@ export const pollVoteAnswer = (vote) => ({
|
|
|
130
168
|
answers: vote.answers,
|
|
131
169
|
voted_at: vote.votedAt,
|
|
132
170
|
});
|
|
171
|
+
export const reactorAnswer = (reactor) => ({
|
|
172
|
+
person: { id: reactor.person.id, name: reactor.person.name, username: reactor.person.username },
|
|
173
|
+
reaction: reactor.reaction,
|
|
174
|
+
reacted_at: reactor.reactedAt,
|
|
175
|
+
});
|
|
133
176
|
export const topicAnswer = (topic) => defined({
|
|
134
177
|
id: topic.id,
|
|
135
178
|
title: topic.title,
|
|
@@ -7,7 +7,7 @@ import { secretInput } from "../../runs/run-context.js";
|
|
|
7
7
|
import { levelFor } from "../../sends/permissions.js";
|
|
8
8
|
import { phoneOf } from "../../services/index.js";
|
|
9
9
|
import { dateWindow } from "../../services/moment.js";
|
|
10
|
-
import {
|
|
10
|
+
import { withoutPhone } from "../../services/people.js";
|
|
11
11
|
import { CHAT_MESSAGES, CONTEXT_BYTES, CONTEXT_MESSAGES } from "../../services/person-context.js";
|
|
12
12
|
import { SCOPES, TIMELINE_ITEMS } from "../../services/person-timeline.js";
|
|
13
13
|
import { readSecret } from "../../terminal/prompt.js";
|
|
@@ -19,7 +19,7 @@ import { positiveCount, window, withPaging } from "../paging.js";
|
|
|
19
19
|
import { casKey } from "../registry-keys.js";
|
|
20
20
|
import { commandAt, nextStep } from "../steps.js";
|
|
21
21
|
import { contactWriteCommands } from "./admin-contacts-command.js";
|
|
22
|
-
import { contactAnswer, lines, pageOf } from "./chat-answers.js";
|
|
22
|
+
import { contactAnswer, contactShown, lines, pageOf } from "./chat-answers.js";
|
|
23
23
|
import { messengerContext } from "./context.js";
|
|
24
24
|
import { hideNever } from "./lacks.js";
|
|
25
25
|
import { CONTACTS_QUERY, notesAllowed } from "./people-queries.js";
|
|
@@ -71,37 +71,32 @@ export const contactsCommand = (messenger) => {
|
|
|
71
71
|
}), lines(({ id, name, username, last_messaged_at }) => [id, name ?? "", username ? `@${username}` : "", last_messaged_at ?? ""].join(" ")));
|
|
72
72
|
}));
|
|
73
73
|
contacts.addCommand(annotate(annotate(new Command("show"), { effects: REMOTE_READ })
|
|
74
|
-
.
|
|
74
|
+
.summary("one person's profile, your alias and notes, and the chats you share")
|
|
75
|
+
.description("one person: what the messenger says about them — handles, flags, last seen, phone, when they registered — " +
|
|
76
|
+
"your alias, the chats you share, how many of their messages the store holds in each, and the earlier " +
|
|
77
|
+
"names and usernames the store saw them with; --offline answers from the store alone")
|
|
75
78
|
.argument("<person>", "their id, @username, or part of their name")
|
|
76
|
-
.option("--with-notes", "include your private notes, subject to contacts.notes.list permission")
|
|
79
|
+
.option("--with-notes", "include your private notes, subject to contacts.notes.list permission")
|
|
80
|
+
.option("--hide-phone", "leave the phone number out"), { output: { entity: "contact" } }).action(async function (person) {
|
|
77
81
|
const context = messengerContext(this, messenger);
|
|
78
|
-
const { withNotes } = this.opts();
|
|
82
|
+
const { withNotes, hidePhone } = this.opts();
|
|
79
83
|
if (withNotes && levelFor(context.settings.permissions, "contacts.notes.list").level === "deny")
|
|
80
84
|
throw new CliError("permission_error", "profile denies contacts.notes.list");
|
|
81
|
-
const { card, account } = await context.withServices(async (services) =>
|
|
82
|
-
card
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
"earlier names and usernames the store saw them with")
|
|
92
|
-
.argument("<person>", "their id, @username, or part of their name")
|
|
93
|
-
.option("--show-phone", "print the whole phone number")
|
|
94
|
-
.action(async function (person) {
|
|
95
|
-
const whole = this.opts().showPhone === true;
|
|
96
|
-
const context = messengerContext(this, messenger);
|
|
97
|
-
const found = await context.withServices((services) => services.people.profile(person));
|
|
98
|
-
const partial = found.chats.filter(({ complete }) => !complete);
|
|
99
|
-
renderAnswer(this, context, itemOf(snakeKeys(whole ? found : maskedAccount(found)), {
|
|
85
|
+
const { card, profile, account } = await context.withServices(async (services) => {
|
|
86
|
+
const card = await services.people.show(person, { notes: withNotes });
|
|
87
|
+
return {
|
|
88
|
+
card,
|
|
89
|
+
profile: await services.people.profile(person, card),
|
|
90
|
+
account: await services.chats.account(),
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
const partial = profile.chats.filter(({ complete }) => !complete);
|
|
94
|
+
renderAnswer(this, context, itemOf(contactShown(account, card, hidePhone ? withoutPhone(profile) : profile), {
|
|
100
95
|
next: syncsFirst(messenger)
|
|
101
96
|
? partial.map((one) => nextStep("messages.sync", { args: { chat: one.id } }))
|
|
102
97
|
: [],
|
|
103
98
|
}));
|
|
104
|
-
});
|
|
99
|
+
}));
|
|
105
100
|
const contextCommand = annotate(contacts.command("context"), {
|
|
106
101
|
effects: REMOTE_READ,
|
|
107
102
|
output: { entity: "contact_context" },
|
|
@@ -80,6 +80,8 @@ export interface Messenger extends ServiceMessenger {
|
|
|
80
80
|
pollQuiz?: boolean;
|
|
81
81
|
/** How many seconds after sending a poll may close by itself — `polls create --close-time`; none when unset. */
|
|
82
82
|
pollCloseSeconds?: readonly [min: number, max: number];
|
|
83
|
+
/** Whether `reactions list` shows who reacted to a message; no when unset. */
|
|
84
|
+
reactionsList?: boolean;
|
|
83
85
|
/** Whether `polls voters` lists who voted for what; no when unset. */
|
|
84
86
|
pollVoters?: boolean;
|
|
85
87
|
/** Whether a poll can be closed — `polls close`; yes when unset. WhatsApp's stay open. */
|
|
@@ -96,6 +96,13 @@ export declare const conversationShown: (account: AccountKey, { summary, message
|
|
|
96
96
|
error?: string | undefined;
|
|
97
97
|
} | undefined;
|
|
98
98
|
local_path?: string | undefined;
|
|
99
|
+
contact?: {
|
|
100
|
+
name: string;
|
|
101
|
+
first_name?: string | undefined;
|
|
102
|
+
last_name?: string | undefined;
|
|
103
|
+
phone?: string | undefined;
|
|
104
|
+
user_id?: string | undefined;
|
|
105
|
+
} | undefined;
|
|
99
106
|
buttons?: {
|
|
100
107
|
kind: "app" | "callback" | "chat" | "clipboard" | "contact" | "link" | "location" | "message" | "other";
|
|
101
108
|
text: string;
|
|
@@ -128,6 +135,13 @@ export declare const conversationShown: (account: AccountKey, { summary, message
|
|
|
128
135
|
error?: string | undefined;
|
|
129
136
|
} | undefined;
|
|
130
137
|
local_path?: string | undefined;
|
|
138
|
+
contact?: {
|
|
139
|
+
name: string;
|
|
140
|
+
first_name?: string | undefined;
|
|
141
|
+
last_name?: string | undefined;
|
|
142
|
+
phone?: string | undefined;
|
|
143
|
+
user_id?: string | undefined;
|
|
144
|
+
} | undefined;
|
|
131
145
|
buttons?: {
|
|
132
146
|
kind: "app" | "callback" | "chat" | "clipboard" | "contact" | "link" | "location" | "message" | "other";
|
|
133
147
|
text: string;
|
|
@@ -163,6 +177,13 @@ export declare const conversationShown: (account: AccountKey, { summary, message
|
|
|
163
177
|
error?: string | undefined;
|
|
164
178
|
} | undefined;
|
|
165
179
|
local_path?: string | undefined;
|
|
180
|
+
contact?: {
|
|
181
|
+
name: string;
|
|
182
|
+
first_name?: string | undefined;
|
|
183
|
+
last_name?: string | undefined;
|
|
184
|
+
phone?: string | undefined;
|
|
185
|
+
user_id?: string | undefined;
|
|
186
|
+
} | undefined;
|
|
166
187
|
buttons?: {
|
|
167
188
|
kind: "app" | "callback" | "chat" | "clipboard" | "contact" | "link" | "location" | "message" | "other";
|
|
168
189
|
text: string;
|
|
@@ -73,6 +73,13 @@ export declare const threadAnswer: ({ items, ...thread }: ThreadContext, reader:
|
|
|
73
73
|
error?: string | undefined;
|
|
74
74
|
} | undefined;
|
|
75
75
|
local_path?: string | undefined;
|
|
76
|
+
contact?: {
|
|
77
|
+
name: string;
|
|
78
|
+
first_name?: string | undefined;
|
|
79
|
+
last_name?: string | undefined;
|
|
80
|
+
phone?: string | undefined;
|
|
81
|
+
user_id?: string | undefined;
|
|
82
|
+
} | undefined;
|
|
76
83
|
buttons?: {
|
|
77
84
|
kind: "app" | "callback" | "chat" | "clipboard" | "contact" | "link" | "location" | "message" | "other";
|
|
78
85
|
text: string;
|
|
@@ -105,6 +112,13 @@ export declare const threadAnswer: ({ items, ...thread }: ThreadContext, reader:
|
|
|
105
112
|
error?: string | undefined;
|
|
106
113
|
} | undefined;
|
|
107
114
|
local_path?: string | undefined;
|
|
115
|
+
contact?: {
|
|
116
|
+
name: string;
|
|
117
|
+
first_name?: string | undefined;
|
|
118
|
+
last_name?: string | undefined;
|
|
119
|
+
phone?: string | undefined;
|
|
120
|
+
user_id?: string | undefined;
|
|
121
|
+
} | undefined;
|
|
108
122
|
buttons?: {
|
|
109
123
|
kind: "app" | "callback" | "chat" | "clipboard" | "contact" | "link" | "location" | "message" | "other";
|
|
110
124
|
text: string;
|
|
@@ -140,6 +154,13 @@ export declare const threadAnswer: ({ items, ...thread }: ThreadContext, reader:
|
|
|
140
154
|
error?: string | undefined;
|
|
141
155
|
} | undefined;
|
|
142
156
|
local_path?: string | undefined;
|
|
157
|
+
contact?: {
|
|
158
|
+
name: string;
|
|
159
|
+
first_name?: string | undefined;
|
|
160
|
+
last_name?: string | undefined;
|
|
161
|
+
phone?: string | undefined;
|
|
162
|
+
user_id?: string | undefined;
|
|
163
|
+
} | undefined;
|
|
143
164
|
buttons?: {
|
|
144
165
|
kind: "app" | "callback" | "chat" | "clipboard" | "contact" | "link" | "location" | "message" | "other";
|
|
145
166
|
text: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type * as v from "valibot";
|
|
2
|
-
import type
|
|
2
|
+
import { type Message, type MessageHit } from "../../domain/models.js";
|
|
3
3
|
import type { message as messageSchema } from "../../entities/message.js";
|
|
4
4
|
import type { MessengerAdapter } from "../../ports/messenger.js";
|
|
5
5
|
import type { AccountKey } from "../../store/store.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CliError } from "@wirecat/cli-base";
|
|
2
2
|
import { formatLocator, parseLocator } from "../../domain/locator.js";
|
|
3
|
+
import { senderIsMe, } from "../../domain/models.js";
|
|
3
4
|
const defined = (value) => Object.fromEntries(Object.entries(value).filter(([, one]) => one !== undefined));
|
|
4
5
|
const attachmentItem = (attachment) => defined({
|
|
5
6
|
kind: attachment.kind,
|
|
@@ -11,6 +12,14 @@ const attachmentItem = (attachment) => defined({
|
|
|
11
12
|
width: attachment.width,
|
|
12
13
|
height: attachment.height,
|
|
13
14
|
duration: attachment.duration,
|
|
15
|
+
contact: attachment.contact &&
|
|
16
|
+
defined({
|
|
17
|
+
name: attachment.contact.name,
|
|
18
|
+
first_name: attachment.contact.firstName,
|
|
19
|
+
last_name: attachment.contact.lastName,
|
|
20
|
+
phone: attachment.contact.phone,
|
|
21
|
+
user_id: attachment.contact.userId,
|
|
22
|
+
}),
|
|
14
23
|
buttons: attachment.buttons,
|
|
15
24
|
});
|
|
16
25
|
const quotedItem = (quoted) => quoted === null
|
|
@@ -42,8 +51,7 @@ export const messageItem = (message, reader) => {
|
|
|
42
51
|
sender_name: message.senderName,
|
|
43
52
|
sender_username: message.senderUsername,
|
|
44
53
|
sender_is_chat: message.senderIsChat,
|
|
45
|
-
|
|
46
|
-
sender_is_me: message.outgoing === true || (message.senderId !== null && String(message.senderId) === account),
|
|
54
|
+
sender_is_me: senderIsMe(message, account),
|
|
47
55
|
mentions: message.mentions,
|
|
48
56
|
timestamp: message.timestamp,
|
|
49
57
|
edited_at: message.editedAt,
|