@openclaw/whatsapp 2026.7.2-beta.7 → 2026.8.1-beta.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.
- package/dist/{accounts-CSqLvCY5.js → accounts-BX2fZUyR.js} +1 -1
- package/dist/{action-runtime-BzfDFPbH.js → action-runtime-B4e3XFOY.js} +2 -2
- package/dist/action-runtime-api.js +1 -1
- package/dist/action-runtime.runtime.js +1 -1
- package/dist/{agent-tools-login-DE9MU98T.js → agent-tools-login-BjRpD-JQ.js} +5 -4
- package/dist/api.js +69 -127
- package/dist/{approval-handler.runtime-DrA59QSA.js → approval-handler.runtime-fgGZhALv.js} +4 -4
- package/dist/{approval-reactions-Cu66aYdq.js → approval-reactions-CmtJCxe_.js} +25 -73
- package/dist/auth-presence.js +1 -1
- package/dist/{auth-store-DcEpIOmE.js → auth-store-B_DQIdzp.js} +79 -12
- package/dist/call-tool-api.js +1 -1
- package/dist/{channel-Dg62olhy.js → channel-DJVQHz_V.js} +56 -160
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel-react-action-J_YtyMGX.js → channel-react-action-d6OacTNj.js} +3 -3
- package/dist/{channel.runtime-BP0xNmLi.js → channel.runtime-RxuNGZ7w.js} +4 -4
- package/dist/channel.setup-Cmvd967u.js +14 -0
- package/dist/{connection-controller-BOB2MVKY.js → connection-controller-CUyZgGpf.js} +2 -3
- package/dist/contract-api.js +2 -3
- package/dist/{creds-files-B1kSWtBg.js → creds-files-W6B3EMZ8.js} +17 -1
- package/dist/{directory-config-DalGrfGN.js → directory-config-Pc4f07wB.js} +3 -3
- package/dist/directory-contract-api.js +1 -1
- package/dist/doctor-contract-api.js +37 -2
- package/dist/{group-session-key-DVMZlO3x.js → group-session-key-DmFc_Cqi.js} +23 -4
- package/dist/light-runtime-api.js +2 -2
- package/dist/{login-CvY2Dhch.js → login-D6_rfxTZ.js} +4 -4
- package/dist/{login-qr-Bncpb6js.js → login-qr-B0VyVSqQ.js} +4 -4
- package/dist/login-qr-runtime.js +1 -1
- package/dist/{monitor-CfkaUSL2.js → monitor-BCe5Mm-1.js} +574 -163
- package/dist/{question-reactions-CRsnyoMK.js → question-reactions-D3eAeB0i.js} +29 -78
- package/dist/runtime-api.js +9 -9
- package/dist/runtime-group-policy-DeSRFXEV.js +11 -0
- package/dist/{send-api-7wk6eQyW.js → send-api-DimZST3E.js} +86 -107
- package/dist/{send-D37ddk22.js → send-prK8F7Vj.js} +277 -16
- package/dist/setup-entry.js +1 -8
- package/dist/{setup-finalize-BZucx24W.js → setup-finalize-D3n71Uyx.js} +4 -4
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{setup-surface-BkVcd769.js → setup-surface-BCZszf3l.js} +3 -3
- package/dist/{shared-CAxd15bp.js → shared-Dp9M3ZPX.js} +5 -6
- package/dist/{socket-close-DridEuzz.js → socket-close-09FojDO2.js} +4 -10
- package/openclaw.plugin.json +4 -0
- package/package.json +4 -5
- package/skills/wacli/SKILL.md +8 -1
- package/dist/access-control-pZcxTmd5.js +0 -363
- package/dist/approval-resolver-DoeBBt22.js +0 -16
- package/dist/channel.setup-pMwNVkCA.js +0 -19
- package/dist/identity-CPrT5aEU.js +0 -76
- package/dist/legacy-state-migrations-api.js +0 -2
- package/dist/state-migrations-CAMTrs2U.js +0 -33
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as resolveWhatsAppAccount, c as resolveMergedWhatsAppAccountConfig, s as resolveWhatsAppMediaMaxBytes } from "./accounts-
|
|
1
|
+
import { a as resolveWhatsAppAccount, c as resolveMergedWhatsAppAccountConfig, s as resolveWhatsAppMediaMaxBytes } from "./accounts-BX2fZUyR.js";
|
|
2
2
|
import { r as resolveDefaultWhatsAppAccountId } from "./account-ids-CB5SOWjc.js";
|
|
3
3
|
import { n as isWhatsAppNewsletterJid } from "./normalize-target-CugRyONv.js";
|
|
4
4
|
import { r as getWhatsAppConnectionController } from "./connection-controller-runtime-context-DG0tuYuw.js";
|
|
@@ -6,7 +6,7 @@ import "./normalize-C7Hkc_vE.js";
|
|
|
6
6
|
import { a as markdownToWhatsAppChunks, c as toWhatsappJid } from "./targets-runtime-TMk0lGuy.js";
|
|
7
7
|
import { a as stripToolCallXmlTags, i as sanitizeAssistantVisibleTextWithProfile, r as sanitizeAssistantVisibleText } from "./text-runtime-CaKLhowd.js";
|
|
8
8
|
import path from "node:path";
|
|
9
|
-
import { normalizeUniqueStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
9
|
+
import { normalizeStringEntries, normalizeUniqueStringEntries, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
10
10
|
import { resolveReactionLevel } from "openclaw/plugin-sdk/status-helpers";
|
|
11
11
|
import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime";
|
|
12
12
|
import { generateSecureUuid } from "openclaw/plugin-sdk/core";
|
|
@@ -17,9 +17,12 @@ import { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media";
|
|
|
17
17
|
import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
18
18
|
import { normalizePollInput } from "openclaw/plugin-sdk/poll-runtime";
|
|
19
19
|
import { resolveChunkMode, resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-chunking";
|
|
20
|
-
import { createSubsystemLogger, getChildLogger as getChildLogger$1 } from "openclaw/plugin-sdk/runtime-env";
|
|
20
|
+
import { createSubsystemLogger as createSubsystemLogger$1, getChildLogger as getChildLogger$1 } from "openclaw/plugin-sdk/runtime-env";
|
|
21
21
|
import { extensionForMime, mediaKindFromMime, mimeTypeFromFilePath, normalizeMimeType } from "openclaw/plugin-sdk/media-mime";
|
|
22
|
-
import {
|
|
22
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
23
|
+
import { recordChannelActivity } from "openclaw/plugin-sdk/channel-activity-runtime";
|
|
24
|
+
import { createChannelPartialDeliveryError, isChannelPartialDeliveryError } from "openclaw/plugin-sdk/channel-inbound";
|
|
25
|
+
import { createMessageReceiptFromOutboundResults, listMessageReceiptPlatformIds, sanitizeForPlainText } from "openclaw/plugin-sdk/channel-outbound";
|
|
23
26
|
import { MEDIA_FFMPEG_MAX_AUDIO_DURATION_SECS, transcodeAudioBufferToOpus } from "openclaw/plugin-sdk/media-runtime";
|
|
24
27
|
import { resolveOutboundMediaUrls } from "openclaw/plugin-sdk/reply-payload";
|
|
25
28
|
//#region extensions/whatsapp/src/reaction-level.ts
|
|
@@ -54,6 +57,245 @@ function stripAsciiControlCharacters(value) {
|
|
|
54
57
|
return stripped;
|
|
55
58
|
}
|
|
56
59
|
//#endregion
|
|
60
|
+
//#region extensions/whatsapp/src/inbound/send-result.ts
|
|
61
|
+
const activityAccountedWhatsAppSendResults = /* @__PURE__ */ new WeakSet();
|
|
62
|
+
const logicalWhatsAppDeliveryActivity = new AsyncLocalStorage();
|
|
63
|
+
/** Keep all separately produced platform sends inside one logical reply accounting scope. */
|
|
64
|
+
async function withWhatsAppLogicalDeliveryActivity(run) {
|
|
65
|
+
if (logicalWhatsAppDeliveryActivity.getStore()) return await run();
|
|
66
|
+
return await logicalWhatsAppDeliveryActivity.run({ accountedAccountIds: /* @__PURE__ */ new Set() }, run);
|
|
67
|
+
}
|
|
68
|
+
function resolveWhatsAppReceiptKind(kind) {
|
|
69
|
+
if (kind === "media" || kind === "text") return kind;
|
|
70
|
+
return "unknown";
|
|
71
|
+
}
|
|
72
|
+
function toReceiptSourceResult(key) {
|
|
73
|
+
return {
|
|
74
|
+
channel: "whatsapp",
|
|
75
|
+
messageId: key.id,
|
|
76
|
+
...key.remoteJid ? { toJid: key.remoteJid } : {},
|
|
77
|
+
meta: {
|
|
78
|
+
fromMe: key.fromMe,
|
|
79
|
+
participant: key.participant
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function createWhatsAppSendReceipt(kind, keys) {
|
|
84
|
+
return createMessageReceiptFromOutboundResults({
|
|
85
|
+
kind: resolveWhatsAppReceiptKind(kind),
|
|
86
|
+
results: keys.map(toReceiptSourceResult)
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function mergeWhatsAppReceiptSourceMetadata(sources) {
|
|
90
|
+
const defined = sources.filter((source) => Boolean(source));
|
|
91
|
+
const preferred = defined[0];
|
|
92
|
+
if (!preferred) return;
|
|
93
|
+
const merged = /* @__PURE__ */ new Map();
|
|
94
|
+
const meta = /* @__PURE__ */ new Map();
|
|
95
|
+
for (const source of defined.toReversed()) {
|
|
96
|
+
for (const [key, value] of Object.entries(source)) if (key !== "meta" && value !== void 0) merged.set(key, value);
|
|
97
|
+
for (const [key, value] of Object.entries(source.meta ?? {})) if (value !== void 0) meta.set(key, value);
|
|
98
|
+
}
|
|
99
|
+
const mergedSource = Object.assign({}, preferred, Object.fromEntries(merged));
|
|
100
|
+
if (meta.size > 0) mergedSource.meta = Object.fromEntries(meta);
|
|
101
|
+
else delete mergedSource.meta;
|
|
102
|
+
return mergedSource;
|
|
103
|
+
}
|
|
104
|
+
function enrichWhatsAppDeliveryReceipt(params) {
|
|
105
|
+
const seenPartIds = /* @__PURE__ */ new Set();
|
|
106
|
+
const parts = params.receipt.parts.flatMap((part) => {
|
|
107
|
+
if (seenPartIds.has(part.platformMessageId)) return [];
|
|
108
|
+
seenPartIds.add(part.platformMessageId);
|
|
109
|
+
const matchingParts = params.sources.flatMap((source) => source.parts.filter((candidate) => candidate.platformMessageId === part.platformMessageId));
|
|
110
|
+
const matchingRawSources = params.sources.flatMap((source) => source.raw?.filter((raw) => raw.messageId === part.platformMessageId) ?? []);
|
|
111
|
+
const raw = mergeWhatsAppReceiptSourceMetadata([
|
|
112
|
+
part.raw,
|
|
113
|
+
...matchingParts.map((candidate) => candidate.raw),
|
|
114
|
+
...matchingRawSources
|
|
115
|
+
]);
|
|
116
|
+
const threadId = part.threadId ?? matchingParts.find((candidate) => candidate.threadId)?.threadId;
|
|
117
|
+
const replyToId = part.replyToId ?? matchingParts.find((candidate) => candidate.replyToId)?.replyToId;
|
|
118
|
+
return [{
|
|
119
|
+
...part,
|
|
120
|
+
...threadId ? { threadId } : {},
|
|
121
|
+
...replyToId ? { replyToId } : {},
|
|
122
|
+
...raw ? { raw } : {}
|
|
123
|
+
}];
|
|
124
|
+
});
|
|
125
|
+
const threadId = params.receipt.threadId ?? params.sources.find((source) => source.threadId)?.threadId;
|
|
126
|
+
const replyToId = params.receipt.replyToId ?? params.sources.find((source) => source.replyToId)?.replyToId;
|
|
127
|
+
const editToken = params.receipt.editToken ?? params.sources.find((source) => source.editToken)?.editToken;
|
|
128
|
+
const deleteToken = params.receipt.deleteToken ?? params.sources.find((source) => source.deleteToken)?.deleteToken;
|
|
129
|
+
return {
|
|
130
|
+
...params.receipt,
|
|
131
|
+
parts,
|
|
132
|
+
raw: parts.map((part) => part.raw ?? {
|
|
133
|
+
channel: "whatsapp",
|
|
134
|
+
messageId: part.platformMessageId
|
|
135
|
+
}),
|
|
136
|
+
...threadId ? { threadId } : {},
|
|
137
|
+
...replyToId ? { replyToId } : {},
|
|
138
|
+
...editToken ? { editToken } : {},
|
|
139
|
+
...deleteToken ? { deleteToken } : {}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function normalizeKey(key) {
|
|
143
|
+
const id = typeof key?.id === "string" ? key.id.trim() : "";
|
|
144
|
+
if (!id) return;
|
|
145
|
+
return {
|
|
146
|
+
id,
|
|
147
|
+
remoteJid: key?.remoteJid,
|
|
148
|
+
fromMe: key?.fromMe,
|
|
149
|
+
participant: key?.participant
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function createWhatsAppProviderNotAcceptedError(kind) {
|
|
153
|
+
const cause = /* @__PURE__ */ new Error("Baileys returned no accepted message key.");
|
|
154
|
+
return new PlatformMessageNotDispatchedError(`WhatsApp ${kind} send was not accepted by the provider: ${cause.message}`, { cause });
|
|
155
|
+
}
|
|
156
|
+
function normalizeWhatsAppSendResult(result, kind) {
|
|
157
|
+
const key = normalizeKey(result?.key);
|
|
158
|
+
if (!key) throw createWhatsAppProviderNotAcceptedError(kind);
|
|
159
|
+
return {
|
|
160
|
+
kind,
|
|
161
|
+
messageId: key.id,
|
|
162
|
+
receipt: createWhatsAppSendReceipt(kind, [key]),
|
|
163
|
+
keys: [key],
|
|
164
|
+
providerAccepted: true
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/** Refuse synthetic ids from listener boundaries before callers create durable receipts. */
|
|
168
|
+
function requireWhatsAppAcceptedSendResult(result) {
|
|
169
|
+
if (result.providerAccepted && result.messageId !== "unknown" && result.keys.some((key) => key.id === result.messageId) && listWhatsAppSendResultMessageIds(result).includes(result.messageId)) return result;
|
|
170
|
+
throw createWhatsAppProviderNotAcceptedError(result.kind);
|
|
171
|
+
}
|
|
172
|
+
/** Persist accepted provider facts before account bookkeeping or later platform sends can fail. */
|
|
173
|
+
function rememberWhatsAppAcceptedSend(params) {
|
|
174
|
+
const accepted = requireWhatsAppAcceptedSendResult(params.result);
|
|
175
|
+
params.results.push(accepted);
|
|
176
|
+
if (params.results.length === 1) {
|
|
177
|
+
const deliveryActivity = logicalWhatsAppDeliveryActivity.getStore();
|
|
178
|
+
const alreadyAccounted = activityAccountedWhatsAppSendResults.has(accepted) || Boolean(deliveryActivity?.accountedAccountIds.has(params.accountId));
|
|
179
|
+
activityAccountedWhatsAppSendResults.add(accepted);
|
|
180
|
+
if (!alreadyAccounted) {
|
|
181
|
+
deliveryActivity?.accountedAccountIds.add(params.accountId);
|
|
182
|
+
recordChannelActivity({
|
|
183
|
+
channel: "whatsapp",
|
|
184
|
+
accountId: params.accountId,
|
|
185
|
+
direction: "outbound"
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return accepted;
|
|
190
|
+
}
|
|
191
|
+
/** Nested owners already attempted activity accounting before exposing accepted delivery. */
|
|
192
|
+
function rememberWhatsAppPartialSend(params) {
|
|
193
|
+
if (!isChannelPartialDeliveryError(params.error)) return false;
|
|
194
|
+
const delivery = params.error.deliveryResult;
|
|
195
|
+
const messageIds = uniqueStrings([...delivery.receipt ? listMessageReceiptPlatformIds(delivery.receipt) : [], ...normalizeStringEntries(delivery.messageIds ?? [])]).filter((messageId) => messageId !== "unknown");
|
|
196
|
+
const existingIds = new Set(params.results.flatMap(listWhatsAppSendResultMessageIds));
|
|
197
|
+
const acceptedIds = messageIds.filter((messageId) => !existingIds.has(messageId));
|
|
198
|
+
const messageId = acceptedIds[0];
|
|
199
|
+
if (!messageId) return false;
|
|
200
|
+
const receiptSources = [];
|
|
201
|
+
if (delivery.receipt) receiptSources.push({
|
|
202
|
+
channel: "whatsapp",
|
|
203
|
+
messageId,
|
|
204
|
+
receipt: delivery.receipt
|
|
205
|
+
});
|
|
206
|
+
const receiptIds = new Set(delivery.receipt ? listMessageReceiptPlatformIds(delivery.receipt) : []);
|
|
207
|
+
for (const acceptedId of acceptedIds) if (!receiptIds.has(acceptedId)) receiptSources.push({
|
|
208
|
+
channel: "whatsapp",
|
|
209
|
+
messageId: acceptedId
|
|
210
|
+
});
|
|
211
|
+
const receipt = createMessageReceiptFromOutboundResults({
|
|
212
|
+
kind: resolveWhatsAppReceiptKind(params.kind),
|
|
213
|
+
results: receiptSources
|
|
214
|
+
});
|
|
215
|
+
const accepted = requireWhatsAppAcceptedSendResult({
|
|
216
|
+
kind: params.kind,
|
|
217
|
+
messageId,
|
|
218
|
+
receipt,
|
|
219
|
+
keys: acceptedIds.map((id) => ({ id })),
|
|
220
|
+
providerAccepted: true
|
|
221
|
+
});
|
|
222
|
+
activityAccountedWhatsAppSendResults.add(accepted);
|
|
223
|
+
params.results.push(accepted);
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
/** Merge accepted local sends with nested partial receipts without inventing provider ids. */
|
|
227
|
+
function mergeWhatsAppAcceptedSendError(params) {
|
|
228
|
+
const nested = isChannelPartialDeliveryError(params.error) ? params.error.deliveryResult : void 0;
|
|
229
|
+
const receiptSources = [];
|
|
230
|
+
const recordedIds = /* @__PURE__ */ new Set();
|
|
231
|
+
for (const result of params.results) {
|
|
232
|
+
const resultIds = listWhatsAppSendResultMessageIds(result);
|
|
233
|
+
if (resultIds.every((messageId) => recordedIds.has(messageId))) continue;
|
|
234
|
+
receiptSources.push({
|
|
235
|
+
channel: "whatsapp",
|
|
236
|
+
messageId: result.messageId,
|
|
237
|
+
...result.receipt ? { receipt: result.receipt } : {}
|
|
238
|
+
});
|
|
239
|
+
for (const messageId of resultIds) recordedIds.add(messageId);
|
|
240
|
+
}
|
|
241
|
+
const unrecordedNestedIds = uniqueStrings([...nested?.receipt ? listMessageReceiptPlatformIds(nested.receipt) : [], ...normalizeStringEntries(nested?.messageIds ?? [])]).filter((messageId) => messageId !== "unknown").filter((messageId) => !recordedIds.has(messageId));
|
|
242
|
+
const nestedMessageId = unrecordedNestedIds[0];
|
|
243
|
+
if (nested?.receipt && nestedMessageId) {
|
|
244
|
+
receiptSources.push({
|
|
245
|
+
channel: "whatsapp",
|
|
246
|
+
messageId: nestedMessageId,
|
|
247
|
+
receipt: nested.receipt
|
|
248
|
+
});
|
|
249
|
+
for (const messageId of listMessageReceiptPlatformIds(nested.receipt)) recordedIds.add(messageId);
|
|
250
|
+
}
|
|
251
|
+
for (const messageId of unrecordedNestedIds) if (!recordedIds.has(messageId)) receiptSources.push({
|
|
252
|
+
channel: "whatsapp",
|
|
253
|
+
messageId
|
|
254
|
+
});
|
|
255
|
+
const receipt = enrichWhatsAppDeliveryReceipt({
|
|
256
|
+
receipt: createMessageReceiptFromOutboundResults({
|
|
257
|
+
kind: resolveWhatsAppReceiptKind(params.kind),
|
|
258
|
+
results: receiptSources
|
|
259
|
+
}),
|
|
260
|
+
sources: [...params.results.flatMap((result) => result.receipt ? [result.receipt] : []), ...nested?.receipt ? [nested.receipt] : []]
|
|
261
|
+
});
|
|
262
|
+
const messageIds = listMessageReceiptPlatformIds(receipt);
|
|
263
|
+
if (messageIds.length === 0) return params.error;
|
|
264
|
+
let cause = params.error;
|
|
265
|
+
const visitedPartialErrors = /* @__PURE__ */ new Set();
|
|
266
|
+
while (isChannelPartialDeliveryError(cause) && cause instanceof Error && cause.cause !== void 0 && !visitedPartialErrors.has(cause)) {
|
|
267
|
+
visitedPartialErrors.add(cause);
|
|
268
|
+
cause = cause.cause;
|
|
269
|
+
}
|
|
270
|
+
return createChannelPartialDeliveryError(cause, {
|
|
271
|
+
...nested,
|
|
272
|
+
messageIds,
|
|
273
|
+
receipt,
|
|
274
|
+
visibleReplySent: true
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
function combineWhatsAppSendResults(kind, results) {
|
|
278
|
+
const messageId = uniqueStrings(results.flatMap(listWhatsAppSendResultMessageIds))[0];
|
|
279
|
+
if (!messageId) throw createWhatsAppProviderNotAcceptedError(kind);
|
|
280
|
+
const keys = results.flatMap((result) => result.keys);
|
|
281
|
+
const combined = {
|
|
282
|
+
kind,
|
|
283
|
+
messageId,
|
|
284
|
+
receipt: createWhatsAppSendReceipt(kind, keys),
|
|
285
|
+
keys,
|
|
286
|
+
providerAccepted: results.some((result) => result.providerAccepted)
|
|
287
|
+
};
|
|
288
|
+
if (results.some((result) => activityAccountedWhatsAppSendResults.has(result))) activityAccountedWhatsAppSendResults.add(combined);
|
|
289
|
+
return combined;
|
|
290
|
+
}
|
|
291
|
+
function listWhatsAppSendResultMessageIds(result) {
|
|
292
|
+
const receiptIds = result.receipt ? listMessageReceiptPlatformIds(result.receipt) : [];
|
|
293
|
+
if (receiptIds.length > 0) return receiptIds;
|
|
294
|
+
const keyIds = normalizeStringEntries(result.keys.map((key) => key.id));
|
|
295
|
+
if (keyIds.length > 0) return uniqueStrings(keyIds);
|
|
296
|
+
return [];
|
|
297
|
+
}
|
|
298
|
+
//#endregion
|
|
57
299
|
//#region extensions/whatsapp/src/outbound-media-contract.ts
|
|
58
300
|
const WHATSAPP_VOICE_FILE_NAME = "voice.ogg";
|
|
59
301
|
const WHATSAPP_VOICE_SAMPLE_RATE_HZ = 48e3;
|
|
@@ -101,7 +343,7 @@ function inferWhatsAppMediaKind(media, resolvedContentType) {
|
|
|
101
343
|
function normalizeWhatsAppLoadedMedia(media, mediaUrl) {
|
|
102
344
|
const filenameMimeType = mimeTypeFromFilePath(media.fileName);
|
|
103
345
|
const normalizedContentType = normalizeMimeType(media.contentType);
|
|
104
|
-
const resolvedContentType = !normalizedContentType || normalizedContentType === "application/octet-stream" ? filenameMimeType ??
|
|
346
|
+
const resolvedContentType = !normalizedContentType || normalizedContentType === "application/octet-stream" ? filenameMimeType ?? normalizedContentType : normalizedContentType;
|
|
105
347
|
const kind = inferWhatsAppMediaKind(media, resolvedContentType);
|
|
106
348
|
const mimetype = kind === "audio" && isWhatsAppNativeVoiceAudio({
|
|
107
349
|
contentType: media.contentType,
|
|
@@ -167,13 +409,13 @@ function deriveWhatsAppDocumentFileName(mediaUrl) {
|
|
|
167
409
|
}
|
|
168
410
|
//#endregion
|
|
169
411
|
//#region extensions/whatsapp/src/send.ts
|
|
170
|
-
const outboundLog = createSubsystemLogger("gateway/channels/whatsapp").child("outbound");
|
|
412
|
+
const outboundLog = createSubsystemLogger$1("gateway/channels/whatsapp").child("outbound");
|
|
171
413
|
function supportsForcedDocumentDelivery(kind) {
|
|
172
414
|
return kind === "image" || kind === "video";
|
|
173
415
|
}
|
|
174
416
|
function buildWhatsAppMediaSendState(params) {
|
|
175
417
|
const { media, caption } = params;
|
|
176
|
-
const forceDocumentDelivery = Boolean(params.forceDocument && supportsForcedDocumentDelivery(media.kind));
|
|
418
|
+
const forceDocumentDelivery = Boolean(params.forceDocument && supportsForcedDocumentDelivery(media.kind)) || media.kind === "document" && (media.mimetype.startsWith("image/") || media.mimetype.startsWith("video/"));
|
|
177
419
|
let text = caption ?? "";
|
|
178
420
|
let documentFileName = media.kind === "document" ? media.fileName : void 0;
|
|
179
421
|
let visibleTextAfterVoice;
|
|
@@ -219,6 +461,9 @@ function resolveActualSentRemoteJid(result, fallbackJid) {
|
|
|
219
461
|
return fallbackJid;
|
|
220
462
|
}
|
|
221
463
|
async function sendMessageWhatsApp(to, body, options) {
|
|
464
|
+
return await withWhatsAppLogicalDeliveryActivity(() => sendMessageWhatsAppInActivityScope(to, body, options));
|
|
465
|
+
}
|
|
466
|
+
async function sendMessageWhatsAppInActivityScope(to, body, options) {
|
|
222
467
|
let text = options.preserveLeadingWhitespace ? body : normalizeWhatsAppPayloadText(body);
|
|
223
468
|
const jid = toWhatsappJid(to);
|
|
224
469
|
const mediaUrls = resolveAdditiveWhatsAppMediaUrls(options);
|
|
@@ -259,6 +504,7 @@ async function sendMessageWhatsApp(to, body, options) {
|
|
|
259
504
|
correlationId,
|
|
260
505
|
to: redactedTo
|
|
261
506
|
});
|
|
507
|
+
const acceptedResults = [];
|
|
262
508
|
try {
|
|
263
509
|
const redactedJid = redactIdentifier(jid);
|
|
264
510
|
let mediaBuffer;
|
|
@@ -295,7 +541,14 @@ async function sendMessageWhatsApp(to, body, options) {
|
|
|
295
541
|
}, "sending message");
|
|
296
542
|
if (!isWhatsAppNewsletterJid(jid)) {
|
|
297
543
|
await active.assertSendReady?.(to);
|
|
298
|
-
|
|
544
|
+
try {
|
|
545
|
+
await active.sendComposingTo(to);
|
|
546
|
+
} catch (err) {
|
|
547
|
+
logger.warn({
|
|
548
|
+
err: String(err),
|
|
549
|
+
jid: redactedJid
|
|
550
|
+
}, "failed to send composing presence; continuing message delivery");
|
|
551
|
+
}
|
|
299
552
|
}
|
|
300
553
|
const accountId = Boolean(options.accountId?.trim()) ? resolvedAccountId : void 0;
|
|
301
554
|
const sendOptions = options.gifPlayback || forceDocumentDelivery || accountId || documentFileName || options.quotedMessageKey ? {
|
|
@@ -305,8 +558,9 @@ async function sendMessageWhatsApp(to, body, options) {
|
|
|
305
558
|
...options.quotedMessageKey ? { quotedMessageKey: options.quotedMessageKey } : {},
|
|
306
559
|
accountId
|
|
307
560
|
} : void 0;
|
|
308
|
-
const result = sendOptions ? await active.sendMessage(to, text, mediaBuffer, mediaType, sendOptions) : await active.sendMessage(to, text, mediaBuffer, mediaType);
|
|
309
|
-
|
|
561
|
+
const result = requireWhatsAppAcceptedSendResult(sendOptions ? await active.sendMessage(to, text, mediaBuffer, mediaType, sendOptions) : await active.sendMessage(to, text, mediaBuffer, mediaType));
|
|
562
|
+
acceptedResults.push(result);
|
|
563
|
+
const messageId = result.messageId;
|
|
310
564
|
const sentRemoteJid = resolveActualSentRemoteJid(result, jid);
|
|
311
565
|
const trailingTextChunks = [visibleTextAfterVoice, ...textChunks].filter((chunk) => Boolean(chunk));
|
|
312
566
|
if (trailingTextChunks.length > 0) {
|
|
@@ -315,9 +569,10 @@ async function sendMessageWhatsApp(to, body, options) {
|
|
|
315
569
|
toJid: sentRemoteJid
|
|
316
570
|
});
|
|
317
571
|
for (const trailingText of trailingTextChunks) {
|
|
318
|
-
const trailingResult = sendOptions ? await active.sendMessage(to, trailingText, void 0, void 0, sendOptions) : await active.sendMessage(to, trailingText, void 0, void 0);
|
|
572
|
+
const trailingResult = requireWhatsAppAcceptedSendResult(sendOptions ? await active.sendMessage(to, trailingText, void 0, void 0, sendOptions) : await active.sendMessage(to, trailingText, void 0, void 0));
|
|
573
|
+
acceptedResults.push(trailingResult);
|
|
319
574
|
await options.onDeliveryResult?.({
|
|
320
|
-
messageId: trailingResult
|
|
575
|
+
messageId: trailingResult.messageId,
|
|
321
576
|
toJid: resolveActualSentRemoteJid(trailingResult, jid)
|
|
322
577
|
});
|
|
323
578
|
}
|
|
@@ -338,7 +593,12 @@ async function sendMessageWhatsApp(to, body, options) {
|
|
|
338
593
|
to: redactedTo,
|
|
339
594
|
hasMedia
|
|
340
595
|
}, "failed to send via web session");
|
|
341
|
-
|
|
596
|
+
const firstAccepted = acceptedResults[0];
|
|
597
|
+
throw mergeWhatsAppAcceptedSendError({
|
|
598
|
+
error: err,
|
|
599
|
+
kind: firstAccepted?.kind ?? (hasMedia ? "media" : "text"),
|
|
600
|
+
results: acceptedResults
|
|
601
|
+
});
|
|
342
602
|
}
|
|
343
603
|
}
|
|
344
604
|
async function sendTypingWhatsApp(to, options) {
|
|
@@ -413,7 +673,8 @@ async function sendPollWhatsApp(to, poll, options) {
|
|
|
413
673
|
maxSelections: normalized.maxSelections
|
|
414
674
|
}, "sending poll");
|
|
415
675
|
if (!isWhatsAppNewsletterJid(jid)) await active.assertSendReady?.(to);
|
|
416
|
-
const
|
|
676
|
+
const result = requireWhatsAppAcceptedSendResult(await active.sendPoll(to, normalized));
|
|
677
|
+
const messageId = result.messageId;
|
|
417
678
|
const durationMs = Date.now() - startedAt;
|
|
418
679
|
outboundLog.info(`Sent poll ${messageId} -> ${redactedJid} (${durationMs}ms)`);
|
|
419
680
|
logger.info({
|
|
@@ -422,7 +683,7 @@ async function sendPollWhatsApp(to, poll, options) {
|
|
|
422
683
|
}, "sent poll");
|
|
423
684
|
return {
|
|
424
685
|
messageId,
|
|
425
|
-
toJid: jid
|
|
686
|
+
toJid: resolveActualSentRemoteJid(result, jid)
|
|
426
687
|
};
|
|
427
688
|
} catch (err) {
|
|
428
689
|
logger.error({
|
|
@@ -433,4 +694,4 @@ async function sendPollWhatsApp(to, poll, options) {
|
|
|
433
694
|
}
|
|
434
695
|
}
|
|
435
696
|
//#endregion
|
|
436
|
-
export { normalizeWhatsAppOutboundPayload as a, prepareWhatsAppOutboundMedia as c, sendTypingWhatsApp as i,
|
|
697
|
+
export { resolveWhatsAppReactionLevel as _, normalizeWhatsAppOutboundPayload as a, prepareWhatsAppOutboundMedia as c, mergeWhatsAppAcceptedSendError as d, normalizeWhatsAppSendResult as f, resolveWhatsAppDocumentFileName as g, withWhatsAppLogicalDeliveryActivity as h, sendTypingWhatsApp as i, combineWhatsAppSendResults as l, rememberWhatsAppPartialSend as m, sendPollWhatsApp as n, normalizeWhatsAppPayloadText as o, rememberWhatsAppAcceptedSend as p, sendReactionWhatsApp as r, normalizeWhatsAppPayloadTextPreservingIndentation as s, sendMessageWhatsApp as t, listWhatsAppSendResultMessageIds as u };
|
package/dist/setup-entry.js
CHANGED
|
@@ -2,18 +2,11 @@ import { defineBundledChannelSetupEntry } from "openclaw/plugin-sdk/channel-entr
|
|
|
2
2
|
//#region extensions/whatsapp/setup-entry.ts
|
|
3
3
|
var setup_entry_default = defineBundledChannelSetupEntry({
|
|
4
4
|
importMetaUrl: import.meta.url,
|
|
5
|
-
features: {
|
|
6
|
-
legacyStateMigrations: true,
|
|
7
|
-
legacySessionSurfaces: true
|
|
8
|
-
},
|
|
5
|
+
features: { legacySessionSurfaces: true },
|
|
9
6
|
plugin: {
|
|
10
7
|
specifier: "./setup-plugin-api.js",
|
|
11
8
|
exportName: "whatsappSetupPlugin"
|
|
12
9
|
},
|
|
13
|
-
legacyStateMigrations: {
|
|
14
|
-
specifier: "./legacy-state-migrations-api.js",
|
|
15
|
-
exportName: "detectWhatsAppLegacyStateMigrations"
|
|
16
|
-
},
|
|
17
10
|
legacySessionSurface: {
|
|
18
11
|
specifier: "./legacy-session-surface-api.js",
|
|
19
12
|
exportName: "whatsappLegacySessionSurface"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { a as resolveWhatsAppAccount, o as resolveWhatsAppAuthDir } from "./accounts-
|
|
1
|
+
import { a as resolveWhatsAppAccount, o as resolveWhatsAppAuthDir } from "./accounts-BX2fZUyR.js";
|
|
2
2
|
import { r as resolveDefaultWhatsAppAccountId } from "./account-ids-CB5SOWjc.js";
|
|
3
|
-
import { r as hasWebCredsSync } from "./creds-files-
|
|
3
|
+
import { r as hasWebCredsSync } from "./creds-files-W6B3EMZ8.js";
|
|
4
4
|
import { a as normalizeWhatsAppAllowFromEntries, o as normalizeWhatsAppAllowFromEntry } from "./normalize-target-CugRyONv.js";
|
|
5
|
-
import { r as whatsappSetupAdapter } from "./shared-
|
|
5
|
+
import { r as whatsappSetupAdapter } from "./shared-Dp9M3ZPX.js";
|
|
6
6
|
import { DEFAULT_ACCOUNT_ID, createSetupTranslator, splitSetupEntries } from "openclaw/plugin-sdk/setup";
|
|
7
7
|
import { formatCliCommand, formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
|
|
8
8
|
//#region extensions/whatsapp/src/setup-finalize.ts
|
|
@@ -295,7 +295,7 @@ async function finalizeWhatsAppSetup(params) {
|
|
|
295
295
|
};
|
|
296
296
|
let loginWeb;
|
|
297
297
|
try {
|
|
298
|
-
({loginWeb} = await import("./login-
|
|
298
|
+
({loginWeb} = await import("./login-D6_rfxTZ.js").then((n) => n.n));
|
|
299
299
|
} catch (error) {
|
|
300
300
|
await reportLoginFailure(error);
|
|
301
301
|
}
|
package/dist/setup-plugin-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as whatsappSetupPlugin } from "./channel.setup-
|
|
1
|
+
import { t as whatsappSetupPlugin } from "./channel.setup-Cmvd967u.js";
|
|
2
2
|
export { whatsappSetupPlugin };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { o as resolveWhatsAppAuthDir } from "./accounts-
|
|
1
|
+
import { o as resolveWhatsAppAuthDir } from "./accounts-BX2fZUyR.js";
|
|
2
2
|
import { t as listAccountIds } from "./account-ids-CB5SOWjc.js";
|
|
3
|
-
import { a as formatWhatsAppWebAuthStatusState, h as readWebAuthState } from "./auth-store-
|
|
3
|
+
import { a as formatWhatsAppWebAuthStatusState, h as readWebAuthState } from "./auth-store-B_DQIdzp.js";
|
|
4
4
|
import { DEFAULT_ACCOUNT_ID, createSetupTranslator, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
|
|
5
5
|
//#region extensions/whatsapp/src/setup-surface.ts
|
|
6
6
|
const t = createSetupTranslator();
|
|
@@ -36,7 +36,7 @@ const whatsappSetupWizard = {
|
|
|
36
36
|
},
|
|
37
37
|
resolveShouldPromptAccountIds: ({ shouldPromptAccountIds }) => shouldPromptAccountIds,
|
|
38
38
|
credentials: [],
|
|
39
|
-
finalize: async (params) => await (await import("./setup-finalize-
|
|
39
|
+
finalize: async (params) => await (await import("./setup-finalize-D3n71Uyx.js")).finalizeWhatsAppSetup(params),
|
|
40
40
|
disable: (cfg) => setSetupChannelEnabled(cfg, channel, false),
|
|
41
41
|
onAccountRecorded: (accountId, options) => {
|
|
42
42
|
options?.onAccountId?.(channel, accountId);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as resolveWhatsAppAccount, n as hasAnyWhatsAppAuth } from "./accounts-
|
|
1
|
+
import { a as resolveWhatsAppAccount, n as hasAnyWhatsAppAuth } from "./accounts-BX2fZUyR.js";
|
|
2
2
|
import { r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./account-ids-CB5SOWjc.js";
|
|
3
3
|
import { a as normalizeWhatsAppAllowFromEntries } from "./normalize-target-CugRyONv.js";
|
|
4
4
|
import { t as WhatsAppChannelConfigSchema } from "./config-schema-BQP5YCeK.js";
|
|
@@ -20,14 +20,14 @@ import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter, createSco
|
|
|
20
20
|
import { createDelegatedSetupWizardProxy } from "openclaw/plugin-sdk/setup-runtime";
|
|
21
21
|
import { readChannelAllowFromStore } from "openclaw/plugin-sdk/channel-pairing";
|
|
22
22
|
//#region extensions/whatsapp/src/channel-runtime-loader.ts
|
|
23
|
-
const loadWhatsAppAuthStore = createLazyRuntimeModule(() => import("./auth-store-
|
|
23
|
+
const loadWhatsAppAuthStore = createLazyRuntimeModule(() => import("./auth-store-B_DQIdzp.js").then((n) => n.i));
|
|
24
24
|
async function readWhatsAppAccountLinkState(authDir) {
|
|
25
25
|
const state = await (await loadWhatsAppAuthStore()).readWebAuthState(authDir);
|
|
26
26
|
return state === "unstable" ? "unknown" : state;
|
|
27
27
|
}
|
|
28
28
|
const loadWhatsAppChannelRuntime = createLazyRuntimeModule(async () => {
|
|
29
29
|
await loadWhatsAppAuthStore();
|
|
30
|
-
return await import("./channel.runtime-
|
|
30
|
+
return await import("./channel.runtime-RxuNGZ7w.js");
|
|
31
31
|
});
|
|
32
32
|
//#endregion
|
|
33
33
|
//#region extensions/whatsapp/src/config-accessors.ts
|
|
@@ -115,7 +115,7 @@ async function applyWhatsAppSecurityConfigFixes(params) {
|
|
|
115
115
|
//#region extensions/whatsapp/src/shared.ts
|
|
116
116
|
const WHATSAPP_CHANNEL = "whatsapp";
|
|
117
117
|
async function loadWhatsAppSetupSurface() {
|
|
118
|
-
return await import("./setup-surface-
|
|
118
|
+
return await import("./setup-surface-BCZszf3l.js");
|
|
119
119
|
}
|
|
120
120
|
const whatsappSetupWizardProxy = createWhatsAppSetupWizardProxy(async () => (await loadWhatsAppSetupSurface()).whatsappSetupWizard);
|
|
121
121
|
const whatsappConfigAdapter = createScopedChannelConfigAdapter({
|
|
@@ -273,8 +273,7 @@ function createWhatsAppPluginBase(params) {
|
|
|
273
273
|
collectWarnings: collectWhatsAppSecurityWarnings
|
|
274
274
|
},
|
|
275
275
|
doctor: whatsappDoctor,
|
|
276
|
-
|
|
277
|
-
...params.setupContract ? { setupContract: params.setupContract } : {},
|
|
276
|
+
setupContract: params.setupContract,
|
|
278
277
|
groups: params.groups
|
|
279
278
|
});
|
|
280
279
|
return {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { c as resolveWebCredsPath, s as resolveWebCredsBackupPath, t as assertWebCredsPathRegularFileOrMissing } from "./creds-files-W6B3EMZ8.js";
|
|
2
|
+
import { A as enqueueCredsSave, M as waitForCredsSaveQueueWithTimeout, N as writeCredsJsonAtomically, P as writeWebCredsRawAtomically, b as restoreCredsFromBackupIfNeeded, u as readCredsJsonRaw, y as resolveDefaultWebAuthDir } from "./auth-store-B_DQIdzp.js";
|
|
3
3
|
import { n as getStatusCode } from "./session-errors-JuazczrA.js";
|
|
4
4
|
import { a as makeWASocket, i as makeCacheableSignalKeyStore, n as createBaileysSignalRepository, r as fetchLatestBaileysVersion, s as useMultiFileAuthState } from "./session.runtime-Nsqaehbd.js";
|
|
5
5
|
import { VERSION, formatCliCommand } from "openclaw/plugin-sdk/cli-runtime";
|
|
6
|
+
import { toErrorObject } from "openclaw/plugin-sdk/error-runtime";
|
|
6
7
|
import { danger, getChildLogger, success, toPinoLikeLogger } from "openclaw/plugin-sdk/runtime-env";
|
|
7
8
|
import { renderQrTerminal } from "openclaw/plugin-sdk/media-runtime";
|
|
8
9
|
import { ensureDir, resolveUserPath } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
@@ -541,7 +542,7 @@ async function waitForWaConnection(sock, options = { timeout: "none" }) {
|
|
|
541
542
|
}
|
|
542
543
|
if (update.connection === "close") {
|
|
543
544
|
cleanup();
|
|
544
|
-
reject(
|
|
545
|
+
reject(toErrorObject(update.lastDisconnect?.error ?? update.lastDisconnect ?? /* @__PURE__ */ new Error("Connection closed"), "Non-Error rejection"));
|
|
545
546
|
}
|
|
546
547
|
};
|
|
547
548
|
sock.ev.on("connection.update", handler);
|
|
@@ -558,13 +559,6 @@ async function waitForWaConnection(sock, options = { timeout: "none" }) {
|
|
|
558
559
|
function newConnectionId() {
|
|
559
560
|
return randomUUID();
|
|
560
561
|
}
|
|
561
|
-
function toLintErrorObject(value, fallbackMessage) {
|
|
562
|
-
if (value instanceof Error) return value;
|
|
563
|
-
if (typeof value === "string") return new Error(value);
|
|
564
|
-
const error = new Error(fallbackMessage, { cause: value });
|
|
565
|
-
if (typeof value === "object" && value !== null || typeof value === "function") Object.assign(error, value);
|
|
566
|
-
return error;
|
|
567
|
-
}
|
|
568
562
|
function createConnectionTimeoutError(timeoutMs) {
|
|
569
563
|
const error = /* @__PURE__ */ new Error(`WhatsApp connection timed out after ${timeoutMs}ms`);
|
|
570
564
|
Object.assign(error, { output: { statusCode: 408 } });
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/whatsapp",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.8.1-beta.2",
|
|
4
4
|
"description": "OpenClaw WhatsApp channel plugin for WhatsApp Web chats.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"typebox": "1.3.6"
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
|
-
"openclaw": ">=2026.
|
|
16
|
+
"openclaw": ">=2026.8.1-beta.2"
|
|
17
17
|
},
|
|
18
18
|
"peerDependenciesMeta": {
|
|
19
19
|
"openclaw": {
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
"setupEntry": "./dist/setup-entry.js",
|
|
28
28
|
"setupFeatures": {
|
|
29
29
|
"configPromotion": true,
|
|
30
|
-
"legacyStateMigrations": true,
|
|
31
30
|
"legacySessionSurfaces": true
|
|
32
31
|
},
|
|
33
32
|
"channel": {
|
|
@@ -66,10 +65,10 @@
|
|
|
66
65
|
"minHostVersion": ">=2026.4.25"
|
|
67
66
|
},
|
|
68
67
|
"compat": {
|
|
69
|
-
"pluginApi": ">=2026.
|
|
68
|
+
"pluginApi": ">=2026.8.1-beta.2"
|
|
70
69
|
},
|
|
71
70
|
"build": {
|
|
72
|
-
"openclawVersion": "2026.
|
|
71
|
+
"openclawVersion": "2026.8.1-beta.2"
|
|
73
72
|
},
|
|
74
73
|
"release": {
|
|
75
74
|
"publishToClawHub": true,
|
package/skills/wacli/SKILL.md
CHANGED
|
@@ -20,7 +20,7 @@ metadata:
|
|
|
20
20
|
{
|
|
21
21
|
"id": "go",
|
|
22
22
|
"kind": "go",
|
|
23
|
-
"module": "github.com/
|
|
23
|
+
"module": "github.com/openclaw/wacli/cmd/wacli@latest",
|
|
24
24
|
"bins": ["wacli"],
|
|
25
25
|
"label": "Install wacli (go)",
|
|
26
26
|
},
|
|
@@ -53,6 +53,12 @@ Find chats + messages
|
|
|
53
53
|
- `wacli messages search "query" --limit 20 --chat <jid>`
|
|
54
54
|
- `wacli messages search "invoice" --after 2025-01-01 --before 2025-12-31`
|
|
55
55
|
|
|
56
|
+
Inspect / verify messages
|
|
57
|
+
|
|
58
|
+
- `wacli messages show --chat <jid> --id <message_id> --json --full`
|
|
59
|
+
- `messages show` requires both `--chat` and `--id`; do not pass the message ID as a positional argument.
|
|
60
|
+
- After sending, verify the stored message when exact formatting matters, especially multiline text.
|
|
61
|
+
|
|
56
62
|
History backfill
|
|
57
63
|
|
|
58
64
|
- `wacli history backfill --chat <jid> --requests 2 --count 50`
|
|
@@ -62,6 +68,7 @@ Send
|
|
|
62
68
|
- Text: `wacli send text --to "+14155551212" --message "Hello! Are you free at 3pm?"`
|
|
63
69
|
- Group: `wacli send text --to "1234567890-123456789@g.us" --message "Running 5 min late."`
|
|
64
70
|
- File: `wacli send file --to "+14155551212" --file /path/agenda.pdf --caption "Agenda"`
|
|
71
|
+
- Multiline: `--message` is literal by default; pass `--message-escapes` to interpret `\n`, `\r`, `\t`.
|
|
65
72
|
|
|
66
73
|
Notes
|
|
67
74
|
|