plogme 2.0.0 → 2.0.1

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.
@@ -1863,6 +1863,7 @@ export const makeChatsSocket = (config) => {
1863
1863
  getUserDisclosures,
1864
1864
  acceptTosNotice,
1865
1865
  reportSpam,
1866
+ toggleGroupHistory,
1866
1867
  getOptOutList,
1867
1868
  signPrivateCredential,
1868
1869
  getPushConfig,
@@ -16,6 +16,7 @@ import { buildMergedTcTokenIndexWrite, isTcTokenExpired, resolveIssuanceJid, res
16
16
  import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, getBizBinaryNode, isHostedLidUser, isHostedPnUser, isJidBot, isJidGroup, isJidMetaAI, isJidNewsletter, isLidUser, isPnUser, jidDecode, jidEncode, jidNormalizedUser, PSA_WID, S_WHATSAPP_NET } from '../WABinary/index.js';
17
17
  import { USyncQuery, USyncUser } from '../WAUSync/index.js';
18
18
  import { captureUnifiedResponse, generateCodeBlockContent, generateLatexContent, generateListContent, generateTableContent, generateUnifiedResponseContent } from '../Utils/message-composer.js';
19
+ import { BotCapabilityType, buildBotRichResponse } from '../Utils/bot-capabilities.js';
19
20
  import { Baron } from './interactive-handler.js';
20
21
  import { collectMetaAIBotParticipantJids, isMetaAIBotResponse, META_AI_BOT_JID } from './aigroups.js';
21
22
  import { makeUsernameSocket } from './username.js';
@@ -1371,10 +1372,20 @@ export const makeMessagesSocket = (config) => {
1371
1372
  },
1372
1373
  // Additive Nexus-compatible AI-rich helpers. Existing Gen4/table/grid/carousel APIs remain unchanged.
1373
1374
  sendRichMedia: async (jid, content = {}, quoted, options = {}) => {
1374
- const message = prepareRichResponseMessage({ ...content, noDonation: options.noDonation ?? true });
1375
- const messageId = generateMessageIDV2(jid);
1376
- await relayMessage(jid, message, { messageId });
1377
- return { message, messageId };
1375
+ const contentMessage = prepareRichResponseMessage({ ...content, noDonation: options.noDonation ?? true });
1376
+ const generated = generateWAMessageFromContent(jid, contentMessage, {
1377
+ logger,
1378
+ userJid: authState.creds.me?.id,
1379
+ messageId: options.messageId || generateMessageIDV2(jid),
1380
+ quoted,
1381
+ ...options
1382
+ });
1383
+ await relayMessage(jid, generated.message, {
1384
+ messageId: generated.key.id,
1385
+ useCachedGroupMetadata: options.useCachedGroupMetadata,
1386
+ statusJidList: options.statusJidList
1387
+ });
1388
+ return { ...generated, messageId: generated.key.id };
1378
1389
  },
1379
1390
  /**
1380
1391
  * Send a native AI image/video generation card. The returned messageId
@@ -1447,18 +1458,38 @@ export const makeMessagesSocket = (config) => {
1447
1458
  else {
1448
1459
  throw new Boom('sendRichAIResponse: unknown content type — expected table, list, codeBlock or latex');
1449
1460
  }
1450
- const { message, messageId } = generated;
1451
- await relayMessage(jid, message, { messageId });
1452
- return { message, messageId };
1461
+ const fullMsg = generateWAMessageFromContent(jid, generated.message, {
1462
+ logger,
1463
+ userJid: authState.creds.me?.id,
1464
+ messageId: options.messageId || generated.messageId || generateMessageIDV2(jid),
1465
+ quoted,
1466
+ ...options
1467
+ });
1468
+ await relayMessage(jid, fullMsg.message, {
1469
+ messageId: fullMsg.key.id,
1470
+ useCachedGroupMetadata: options.useCachedGroupMetadata,
1471
+ statusJidList: options.statusJidList
1472
+ });
1473
+ return fullMsg;
1453
1474
  },
1454
1475
  captureAndResendUnifiedResponse: async (jid, metaAiMsg, quoted) => {
1455
1476
  const captured = captureUnifiedResponse(metaAiMsg);
1456
1477
  if (!captured) {
1457
1478
  throw new Boom('captureAndResendUnifiedResponse: message contains no unifiedResponse data');
1458
1479
  }
1459
- const { message, messageId } = generateUnifiedResponseContent(quoted, captured);
1460
- await relayMessage(jid, message, { messageId });
1461
- return { message, messageId };
1480
+ const generated = generateUnifiedResponseContent(quoted, captured);
1481
+ const fullMsg = generateWAMessageFromContent(jid, generated.message, {
1482
+ logger,
1483
+ userJid: authState.creds.me?.id,
1484
+ messageId: generated.messageId || generateMessageIDV2(jid),
1485
+ quoted
1486
+ });
1487
+ await relayMessage(jid, fullMsg.message, {
1488
+ messageId: fullMsg.key.id,
1489
+ useCachedGroupMetadata: options?.useCachedGroupMetadata,
1490
+ statusJidList: options?.statusJidList
1491
+ });
1492
+ return fullMsg;
1462
1493
  },
1463
1494
  updateMediaMessage: async (message) => {
1464
1495
  const content = assertMediaContent(message.message);
@@ -2322,10 +2353,30 @@ export const makeMessagesSocket = (config) => {
2322
2353
  socket.sendBotCommand = async (jid, content = {}, options = {}) => {
2323
2354
  if (!jid) throw new Boom('sendBotCommand requires a target JID', { statusCode: 400 });
2324
2355
  const { text = 'Bot command test', commandName = '', commandDescription = '', commandPrompt = '', botJid = '867051314767696@bot' } = content;
2325
- const wrapped = {
2326
- messageContextInfo: { botMetadata: { commandMetadata: { commandName, commandDescription, commandPrompt } } },
2327
- botForwardedMessage: { message: { richResponseMessage: { messageType: 1, submessages: [{ messageType: 2, messageText: text }], contextInfo: { isForwarded: true, forwardingScore: 1, forwardedAiBotMessageInfo: { botJid }, forwardOrigin: 4 } } } }
2328
- };
2356
+ const wrapped = buildBotRichResponse({ text, botJid, botMetadata: { commandMetadata: { commandName, commandDescription, commandPrompt } } });
2357
+ const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
2358
+ await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, statusJidList: options.statusJidList });
2359
+ return fullMsg;
2360
+ };
2361
+ /** Sends a planning/execution-plan rich response with WAProto capabilities. */
2362
+ socket.sendBotPlanning = async (jid, content = {}, options = {}) => {
2363
+ if (!jid) throw new Boom('sendBotPlanning requires a target JID', { statusCode: 400 });
2364
+ const { text = 'Execution plan', steps = [], queryPlan = true, botJid = '867051314767696@bot' } = content;
2365
+ const submessages = [
2366
+ { messageType: proto.AIRichResponseSubMessageType.AI_RICH_RESPONSE_TEXT, messageText: text },
2367
+ ...steps.map(step => ({
2368
+ messageType: proto.AIRichResponseSubMessageType.AI_RICH_RESPONSE_TEXT,
2369
+ messageText: typeof step === 'string' ? step : `${step.title || step.name || 'Step'}${step.body ? `: ${step.body}` : ''}`
2370
+ }))
2371
+ ];
2372
+ const wrapped = buildBotRichResponse({
2373
+ botJid,
2374
+ submessages,
2375
+ capabilities: [
2376
+ BotCapabilityType.AGENTIC_PLANNING,
2377
+ ...(queryPlan ? [BotCapabilityType.QUERY_PLAN] : [])
2378
+ ]
2379
+ });
2329
2380
  const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
2330
2381
  await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, statusJidList: options.statusJidList });
2331
2382
  return fullMsg;
@@ -2334,10 +2385,17 @@ export const makeMessagesSocket = (config) => {
2334
2385
  socket.sendBotToolResult = async (jid, content = {}, options = {}) => {
2335
2386
  if (!jid) throw new Boom('sendBotToolResult requires a target JID', { statusCode: 400 });
2336
2387
  const { text = 'Bot tool result test', toolCallId = `tool-${Date.now()}`, resolutionData, resolutionDataSerialized, botJid = '867051314767696@bot' } = content;
2337
- const wrapped = {
2338
- messageContextInfo: { botMetadata: { resolvedToolCallMetadata: { toolCallId, resolutionDataSerialized: resolutionDataSerialized ?? JSON.stringify(resolutionData ?? {}) } } },
2339
- botForwardedMessage: { message: { richResponseMessage: { messageType: 1, submessages: [{ messageType: 2, messageText: text }], contextInfo: { isForwarded: true, forwardingScore: 1, forwardedAiBotMessageInfo: { botJid }, forwardOrigin: 4 } } } }
2340
- };
2388
+ const wrapped = buildBotRichResponse({
2389
+ text,
2390
+ botJid,
2391
+ capabilities: [BotCapabilityType.AGENTIC_PLANNING],
2392
+ botMetadata: {
2393
+ resolvedToolCallMetadata: {
2394
+ toolCallId,
2395
+ resolutionDataSerialized: resolutionDataSerialized ?? JSON.stringify(resolutionData ?? {})
2396
+ }
2397
+ }
2398
+ });
2341
2399
  const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
2342
2400
  await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, statusJidList: options.statusJidList });
2343
2401
  return fullMsg;
@@ -2375,6 +2433,11 @@ export const makeMessagesSocket = (config) => {
2375
2433
  cards: normalizedCards
2376
2434
  }, options);
2377
2435
  };
2436
+ /**
2437
+ * Compatibility entry point for the former Gen4/grid menu.
2438
+ * This is additive: sendRichButtonGrid remains unchanged for existing callers.
2439
+ */
2440
+ socket.HoldOn = async (jid, grid, options = {}) => socket.sendRichButtonGrid(jid, grid, options);
2378
2441
  socket.sendWhatsAppFlow = async (jid, flow, options = {}) => {
2379
2442
  const { text, footer, image, caption, ...flowOptions } = flow || {};
2380
2443
  const button = makeWhatsAppFlowButton(flowOptions);
@@ -1,3 +1,4 @@
1
+ import { Boom } from '@hapi/boom';
1
2
  import { proto } from '../../WAProto/index.js';
2
3
  import { QueryIds, XWAPaths } from '../Types/index.js';
3
4
  import { generateProfilePicture } from '../Utils/messages-media.js';
@@ -34,6 +35,15 @@ const parseNewsletterMetadata = (result) => {
34
35
  }
35
36
  return null;
36
37
  };
38
+ const normalizeNewsletterInviteCode = (value) => {
39
+ if (typeof value !== 'string' || !value.trim()) {
40
+ throw new Boom('newsletterGetInviteInfo requires a non-empty invite code or URL', { statusCode: 400 });
41
+ }
42
+ return value.trim()
43
+ .replace(/^https?:\/\/(?:www\.)?whatsapp\.com\/channel\//i, '')
44
+ .replace(/^https?:\/\/wa\.me\/channel\//i, '')
45
+ .split(/[/?#]/, 1)[0];
46
+ };
37
47
  export const makeNewsletterSocket = (config) => {
38
48
  const sock = makeAIGroupsSocket(config);
39
49
  const { query, generateMessageTag } = sock;
@@ -72,6 +82,12 @@ export const makeNewsletterSocket = (config) => {
72
82
  return executeWMexQuery({}, QueryIds.SUBSCRIBED, XWAPaths.xwa2_newsletter_subscribed);
73
83
  },
74
84
  newsletterMetadata: async (type, key) => {
85
+ if (typeof type !== 'string' || !type.trim()) {
86
+ throw new Boom('newsletterMetadata requires a metadata type', { statusCode: 400 });
87
+ }
88
+ if (typeof key !== 'string' || !key.trim()) {
89
+ throw new Boom('newsletterMetadata requires a metadata key', { statusCode: 400 });
90
+ }
75
91
  const variables = {
76
92
  fetch_creation_time: true,
77
93
  fetch_full_image: true,
@@ -84,6 +100,14 @@ export const makeNewsletterSocket = (config) => {
84
100
  const result = await executeWMexQuery(variables, QueryIds.METADATA, XWAPaths.xwa2_newsletter_metadata);
85
101
  return parseNewsletterMetadata(result);
86
102
  },
103
+ newsletterGetInviteInfo: async (inviteCodeOrUrl) => {
104
+ const inviteCode = normalizeNewsletterInviteCode(inviteCodeOrUrl);
105
+ return executeWMexQuery(
106
+ { input: { key: inviteCode, type: 'INVITE' }, fetch_creation_time: true, fetch_full_image: true, fetch_viewer_metadata: true },
107
+ QueryIds.METADATA,
108
+ XWAPaths.xwa2_newsletter_metadata
109
+ ).then(parseNewsletterMetadata);
110
+ },
87
111
  newsletterFollow: (jid) => {
88
112
  return executeWMexQuery({ newsletter_id: jid }, QueryIds.FOLLOW, XWAPaths.xwa2_newsletter_join_v2);
89
113
  },
@@ -110,11 +134,21 @@ export const makeNewsletterSocket = (config) => {
110
134
  return await newsletterUpdate(jid, { picture: '' });
111
135
  },
112
136
  newsletterReactMessage: async (jid, serverId, reaction) => {
137
+ if (typeof jid !== 'string' || !jid.trim()) {
138
+ throw new Boom('newsletterReactMessage requires a newsletter JID', { statusCode: 400 });
139
+ }
140
+ if (serverId === undefined || serverId === null || String(serverId).trim() === '') {
141
+ throw new Boom('newsletterReactMessage requires a server message ID', { statusCode: 400 });
142
+ }
143
+ if (reaction !== undefined && reaction !== null && typeof reaction !== 'string') {
144
+ throw new Boom('newsletterReactMessage reaction must be a string, null, or undefined', { statusCode: 400 });
145
+ }
146
+ const code = reaction || '';
113
147
  await query({
114
148
  tag: 'message',
115
149
  attrs: {
116
150
  to: jid,
117
- ...(reaction ? {} : { edit: '7' }),
151
+ ...(code ? {} : { edit: '7' }),
118
152
  type: 'reaction',
119
153
  server_id: serverId,
120
154
  id: generateMessageTag()
@@ -122,7 +156,7 @@ export const makeNewsletterSocket = (config) => {
122
156
  content: [
123
157
  {
124
158
  tag: 'reaction',
125
- attrs: reaction ? { code: reaction } : {}
159
+ attrs: code ? { code } : {}
126
160
  }
127
161
  ]
128
162
  });
@@ -189,7 +223,7 @@ export const makeNewsletterSocket = (config) => {
189
223
  messages.push(fullMessage);
190
224
  }
191
225
  catch (error) {
192
- logger.error({ error }, 'Failed to decode newsletter message');
226
+ sock.logger?.error?.({ error }, 'Failed to decode newsletter message');
193
227
  }
194
228
  }
195
229
  return messages;
@@ -0,0 +1,84 @@
1
+ import { proto } from '../../WAProto/index.js';
2
+
3
+ /**
4
+ * Numeric capability values exposed by WAProto.BotCapabilityMetadata.
5
+ * Keep this derived from the generated protobuf so callers cannot drift from
6
+ * the checked-in schema.
7
+ */
8
+ export const BotCapabilityType = proto.BotCapabilityMetadata.BotCapabilityType;
9
+
10
+ const capabilityNames = new Set(
11
+ Object.keys(BotCapabilityType).filter(name => Number.isNaN(Number(name)))
12
+ );
13
+
14
+ /** Normalize enum names/numbers and reject unknown capability values. */
15
+ export const normalizeBotCapabilities = (capabilities = []) => {
16
+ if (!Array.isArray(capabilities)) {
17
+ throw new TypeError('capabilities must be an array');
18
+ }
19
+ const values = capabilities.map(capability => {
20
+ if (typeof capability === 'string') {
21
+ if (!capabilityNames.has(capability)) {
22
+ throw new TypeError(`Unknown bot capability: ${capability}`);
23
+ }
24
+ return BotCapabilityType[capability];
25
+ }
26
+ if (Number.isInteger(capability) && BotCapabilityType[capability] !== undefined) {
27
+ return capability;
28
+ }
29
+ throw new TypeError(`Invalid bot capability: ${String(capability)}`);
30
+ });
31
+ return [...new Set(values)];
32
+ };
33
+
34
+ export const buildBotCapabilityMetadata = (capabilities = []) => ({
35
+ capabilities: normalizeBotCapabilities(capabilities)
36
+ });
37
+
38
+ /**
39
+ * Build the canonical wrapper used by WhatsApp's bot rich-response messages.
40
+ * The capability list is deliberately explicit; unknown or duplicate values
41
+ * are never put on the wire.
42
+ */
43
+ export const buildBotRichResponse = ({
44
+ text,
45
+ submessages,
46
+ capabilities = [],
47
+ botMetadata = {},
48
+ botJid = '867051314767696@bot',
49
+ richResponse = {}
50
+ } = {}) => {
51
+ const resolvedSubmessages = submessages || (text == null ? [] : [{
52
+ messageType: proto.AIRichResponseSubMessageType.AI_RICH_RESPONSE_TEXT,
53
+ messageText: String(text)
54
+ }]);
55
+ return {
56
+ messageContextInfo: {
57
+ botMetadata: {
58
+ ...botMetadata,
59
+ capabilityMetadata: buildBotCapabilityMetadata(capabilities)
60
+ }
61
+ },
62
+ botForwardedMessage: {
63
+ message: {
64
+ richResponseMessage: {
65
+ messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
66
+ submessages: resolvedSubmessages,
67
+ ...richResponse,
68
+ contextInfo: {
69
+ isForwarded: true,
70
+ forwardingScore: 1,
71
+ forwardedAiBotMessageInfo: { botJid },
72
+ forwardOrigin: 4,
73
+ ...(richResponse.contextInfo || {})
74
+ }
75
+ }
76
+ }
77
+ }
78
+ };
79
+ };
80
+
81
+ export const capability = (name) => {
82
+ if (!capabilityNames.has(name)) throw new TypeError(`Unknown bot capability: ${name}`);
83
+ return BotCapabilityType[name];
84
+ };
@@ -1 +1,25 @@
1
- const _0x5dbd5a=_0x4193;(function(_0x397f60,_0x361fcf){const _0x9cf7fd=_0x4193,_0x4bb7c2=_0x397f60();while(!![]){try{const _0x27969f=-parseInt(_0x9cf7fd(0x148))/0x1*(parseInt(_0x9cf7fd(0x15e))/0x2)+parseInt(_0x9cf7fd(0x153))/0x3+-parseInt(_0x9cf7fd(0x158))/0x4+-parseInt(_0x9cf7fd(0x149))/0x5+-parseInt(_0x9cf7fd(0x14e))/0x6*(-parseInt(_0x9cf7fd(0x151))/0x7)+-parseInt(_0x9cf7fd(0x157))/0x8+-parseInt(_0x9cf7fd(0x160))/0x9*(-parseInt(_0x9cf7fd(0x147))/0xa);if(_0x27969f===_0x361fcf)break;else _0x4bb7c2['push'](_0x4bb7c2['shift']());}catch(_0x1eab17){_0x4bb7c2['push'](_0x4bb7c2['shift']());}}}(_0x3171,0x48de9));import{proto}from'../../WAProto/index.js';import{LIBRARY_NAME}from'../Defaults/index.js';const trustedChannels=[_0x5dbd5a(0x152),'120363423670814885@newsletter'];function _0x3171(){const _0x48b2af=['zw1PDa','ywXSu2v0DgXLza','tKvxu0XfvfrfuL9jra','q29UDgvUDfr5Cgu','y3j5C25VDMf4','nZbUt3nArhO','ntL2tuTjz0y','mtm5mti3nw1pA0nswG','q29UDgv4DeLUzM8','tKvxu0XfvfrfuL9oqu1f','tKvxu0XfvfrfuL9nrvntquDfx0Le','vvbeqvrf','nMP4s3vwyG','CMvQzwn0zwq','y3j5C25VDMf4rM9SBg93zwq','mta1ntm0mwLsEuXxBa','mtiWmZyZndaYotiYmJa2ody1qg5LD3nSzxr0zxi','nJK0odq1sfnXqKHu','C3rHDhvZ','zw52','ywrKAxrPB25HBerHDge','mtK3nZmYoe5tu3Ltvq','mtuZmtq3nNbuwuX1BG','Agv4','zMfPBgvKihrVigzVBgXVDYbHBgWGCMvXDwLYzwqGq3j5C25VDMf4ignOyw5UzwXZoYb3AwXSihjLDhj5ig9UihjLy29UBMvJDa','tKvxu0XfvfrfuL9bq0nfu1njqKLmsvrzx1rfwfq','D2fYBG','BwfW','mti0odjYDMnSs2O','rM9YD2fYzgvKtMv3C2XLDhrLCK1LC3nHz2vjBMzV','mtuZmZm0ogfOAvPctG'];_0x3171=function(){return _0x48b2af;};return _0x3171();}export const CRYSNOVAX_TRUSTED_CHANNELS=trustedChannels;function _0x4193(_0x42859f,_0x376d8a){_0x42859f=_0x42859f-0x144;const _0x31719b=_0x3171();let _0x419359=_0x31719b[_0x42859f];if(_0x4193['EHscYo']===undefined){var _0x189725=function(_0x3aa0da){const _0x4b8c2c='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x3cd68e='',_0xe254e9='';for(let _0x1a1e70=0x0,_0x380b42,_0x1773cb,_0x2d5ad9=0x0;_0x1773cb=_0x3aa0da['charAt'](_0x2d5ad9++);~_0x1773cb&&(_0x380b42=_0x1a1e70%0x4?_0x380b42*0x40+_0x1773cb:_0x1773cb,_0x1a1e70++%0x4)?_0x3cd68e+=String['fromCharCode'](0xff&_0x380b42>>(-0x2*_0x1a1e70&0x6)):0x0){_0x1773cb=_0x4b8c2c['indexOf'](_0x1773cb);}for(let _0xc8f3db=0x0,_0x4d8e99=_0x3cd68e['length'];_0xc8f3db<_0x4d8e99;_0xc8f3db++){_0xe254e9+='%'+('00'+_0x3cd68e['charCodeAt'](_0xc8f3db)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0xe254e9);};_0x4193['gCCzEv']=_0x189725,_0x4193['DIFEaK']={},_0x4193['EHscYo']=!![];}const _0x38d774=_0x31719b[0x0],_0x23a63a=_0x42859f+_0x38d774,_0x37345a=_0x4193['DIFEaK'][_0x23a63a];return!_0x37345a?(_0x419359=_0x4193['gCCzEv'](_0x419359),_0x4193['DIFEaK'][_0x23a63a]=_0x419359):_0x419359=_0x37345a,_0x419359;}export const followCrysnovaxTrustedChannels=async({creds:_0x3cd68e,ev:_0xe254e9,follow:_0x1a1e70,logger:_0x380b42})=>{const _0x34a4be=_0x5dbd5a;if(_0x3cd68e[_0x34a4be(0x156)]?.[_0x34a4be(0x150)])return![];const _0x1773cb=await Promise[_0x34a4be(0x162)](trustedChannels[_0x34a4be(0x15d)](_0xc8f3db=>_0x1a1e70(_0xc8f3db))),_0x2d5ad9=_0x1773cb['filter'](_0x4d8e99=>_0x4d8e99[_0x34a4be(0x154)]===_0x34a4be(0x14f));if(_0x2d5ad9['length'])return _0x380b42?.[_0x34a4be(0x15c)]?.({'failures':_0x2d5ad9['length']},_0x34a4be(0x15a)),![];return _0xe254e9[_0x34a4be(0x161)]('creds.update',{'additionalData':{..._0x3cd68e['additionalData'],'crysnovaxFollowed':!![]}}),!![];};export const getMediaChannelAnnotations=()=>[{'polygonVertices':[{'x':60.71664810180664,'y':-36.39784622192383},{'x':-16.710189819335938,'y':49.263675689697266},{'x':-56.585853576660156,'y':37.85963439941406},{'x':20.840980529785156,'y':-47.80188751220703}],'newsletter':{'newsletterJid':process[_0x5dbd5a(0x155)][_0x5dbd5a(0x144)]||_0x5dbd5a(0x152),'serverMessageId':process[_0x5dbd5a(0x155)][_0x5dbd5a(0x14c)]||Buffer['from']('313033',_0x5dbd5a(0x159))['toString'](),'newsletterName':process[_0x5dbd5a(0x155)][_0x5dbd5a(0x14b)]||_0x5dbd5a(0x146),'contentType':proto[_0x5dbd5a(0x14a)][_0x5dbd5a(0x15f)][_0x5dbd5a(0x145)][_0x5dbd5a(0x14d)],'accessibilityText':process['env'][_0x5dbd5a(0x15b)]||LIBRARY_NAME}}];
1
+ import { proto } from '../../WAProto/index.js';
2
+ import { LIBRARY_NAME } from '../Defaults/index.js';
3
+
4
+ /**
5
+ * Media-channel annotation attached to eligible image and video uploads.
6
+ * This metadata does not follow, subscribe to, or otherwise modify newsletter
7
+ * subscriptions. Users who want channel updates must join channels manually.
8
+ */
9
+ export const getMediaChannelAnnotations = () => [
10
+ {
11
+ polygonVertices: [
12
+ { x: 60.71664810180664, y: -36.39784622192383 },
13
+ { x: -16.710189819335938, y: 49.263675689697266 },
14
+ { x: -56.585853576660156, y: 37.85963439941406 },
15
+ { x: 20.840980529785156, y: -47.80188751220703 }
16
+ ],
17
+ newsletter: {
18
+ newsletterJid: process.env.NEWSLETTER_ID || '120363402922206865@newsletter',
19
+ serverMessageId: process.env.NEWSLETTER_MESSAGE_ID || Buffer.from('313033', 'hex').toString(),
20
+ newsletterName: process.env.NEWSLETTER_NAME || 'crysnovax',
21
+ contentType: proto.ContextInfo.ForwardedNewsletterMessageInfo.ContentType.UPDATE,
22
+ accessibilityText: process.env.NEWSLETTER_ACCESSIBILITY_TEXT || LIBRARY_NAME
23
+ }
24
+ }
25
+ ];
@@ -6,6 +6,7 @@ export * from './messages-media.js';
6
6
  export * from './rich-message-utils.js';
7
7
  export * from './meta-compositing.js';
8
8
  export * from './bot-planning-replay.js';
9
+ export * from './bot-capabilities.js';
9
10
  export * from './welcome-flow.js';
10
11
  export * from './message-composer.js';
11
12
  export * from './consumer-application.js';
@@ -1097,6 +1097,11 @@ export const generateWAMessageContent = async (message, options) => {
1097
1097
  else if (hasNonNullishProperty(message, 'chatTheme')) {
1098
1098
  const theme = message.chatTheme || {};
1099
1099
  const themeSetting = {};
1100
+ if (theme.colorSchemeId || theme.chatThemeId) {
1101
+ const colorSchemeId = theme.colorSchemeId ||
1102
+ (String(theme.chatThemeId).includes('@') ? theme.chatThemeId : `${theme.chatThemeId}@Tonal`);
1103
+ themeSetting.colorSchemeId = String(colorSchemeId);
1104
+ }
1100
1105
  if (theme.animatedWallpaper) {
1101
1106
  const wallpaper = theme.animatedWallpaper;
1102
1107
  themeSetting.animatedWallpaper = proto.Message.ChatAnimatedWallpaper.fromObject({
@@ -1453,7 +1458,7 @@ export const generateWAMessageContent = async (message, options) => {
1453
1458
  delete externalAdReply.subTitle;
1454
1459
  delete externalAdReply.largeThumbnail;
1455
1460
  delete externalAdReply.url;
1456
- if ('contextInfo' in key && !!key.contextInfo) {
1461
+ if (key && 'contextInfo' in key && !!key.contextInfo) {
1457
1462
  key.contextInfo.externalAdReply = { ...key.contextInfo.externalAdReply, ...externalAdReply };
1458
1463
  }
1459
1464
  else if (key) {
@@ -1483,7 +1488,7 @@ export const generateWAMessageContent = async (message, options) => {
1483
1488
  if (hasOptionalProperty(message, 'contextInfo') && !!message.contextInfo) {
1484
1489
  const messageType = Object.keys(m)[0];
1485
1490
  const key = m[messageType];
1486
- if ('contextInfo' in key && !!key.contextInfo) {
1491
+ if (key && 'contextInfo' in key && !!key.contextInfo) {
1487
1492
  key.contextInfo = { ...key.contextInfo, ...message.contextInfo };
1488
1493
  }
1489
1494
  else if (key) {
@@ -1494,7 +1499,7 @@ export const generateWAMessageContent = async (message, options) => {
1494
1499
  if (hasOptionalProperty(message, 'groupStatus') && !!message.groupStatus) {
1495
1500
  const messageType = Object.keys(m)[0];
1496
1501
  const key = m[messageType];
1497
- if ('contextInfo' in key && !!key.contextInfo) {
1502
+ if (key && 'contextInfo' in key && !!key.contextInfo) {
1498
1503
  key.contextInfo.isGroupStatus = message.groupStatus;
1499
1504
  }
1500
1505
  else if (key) {
@@ -1520,7 +1525,7 @@ export const generateWAMessageContent = async (message, options) => {
1520
1525
  m = { viewOnceMessage: { message: m } };
1521
1526
  }
1522
1527
  else if (mediaSpoiler && mediaSpoilerMode === 'native') {
1523
- if ('contextInfo' in key && !!key.contextInfo) {
1528
+ if (key && 'contextInfo' in key && !!key.contextInfo) {
1524
1529
  key.contextInfo.isSpoiler = true;
1525
1530
  }
1526
1531
  else if (key) {
@@ -1564,7 +1569,7 @@ export const generateWAMessageContent = async (message, options) => {
1564
1569
  participant: '0@s.whatsapp.net',
1565
1570
  remoteJid: '0@s.whatsapp.net'
1566
1571
  };
1567
- if ('contextInfo' in key && !!key.contextInfo) {
1572
+ if (key && 'contextInfo' in key && !!key.contextInfo) {
1568
1573
  key.contextInfo = { ...key.contextInfo, ...verifiedContext };
1569
1574
  }
1570
1575
  else if (key) {
@@ -1663,7 +1668,7 @@ export const generateWAMessageFromContent = (jid, message, options) => {
1663
1668
  if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
1664
1669
  delete quotedContent.contextInfo;
1665
1670
  }
1666
- const contextInfo = ('contextInfo' in innerMessage[key] && innerMessage[key]?.contextInfo) || {};
1671
+ const contextInfo = (innerMessage[key] && 'contextInfo' in innerMessage[key] && innerMessage[key]?.contextInfo) || {};
1667
1672
  contextInfo.participant = jidNormalizedUser(participant);
1668
1673
  contextInfo.stanzaId = quoted.key.id;
1669
1674
  contextInfo.quotedMessage = quotedMsg;
@@ -14,6 +14,7 @@
14
14
 
15
15
  import { proto } from '../../WAProto/index.js';
16
16
  import { BOT_RENDERING_CONFIG_METADATA } from '../Defaults/index.js';
17
+ import { BotCapabilityType, buildBotCapabilityMetadata } from './bot-capabilities.js';
17
18
  import { delay } from './generics.js';
18
19
 
19
20
  // ─── Step status enum ───
@@ -88,10 +89,16 @@ export const buildCompositingPlaceholder = ({
88
89
  unifiedResponse: { data: unifiedData },
89
90
  submessages: []
90
91
  };
92
+ const capabilities = [
93
+ BotCapabilityType.PROGRESS_INDICATOR,
94
+ ...(steps.length ? [BotCapabilityType.AGENTIC_PLANNING] : []),
95
+ ...(steps.some(step => step.queryPlan || step.type === 'query') ? [BotCapabilityType.QUERY_PLAN] : [])
96
+ ];
91
97
 
92
98
  return {
93
99
  messageContextInfo: {
94
100
  botMetadata: {
101
+ capabilityMetadata: buildBotCapabilityMetadata(capabilities),
95
102
  pluginMetadata: {},
96
103
  progressIndicatorMetadata,
97
104
  botRenderingConfigMetadata: BOT_RENDERING_CONFIG_METADATA,
package/lib/index.d.ts CHANGED
@@ -266,8 +266,14 @@ export interface WASocket {
266
266
  sendBotDiagnostics(jid: string, content?: { text?: string; botBackend?: number; toolsUsed?: string[]; isThinking?: boolean; botJid?: string }, options?: Record<string, unknown>): Promise<unknown>;
267
267
  /** Send a rich response with experimental bot command metadata. */
268
268
  sendBotCommand(jid: string, content?: { text?: string; commandName?: string; commandDescription?: string; commandPrompt?: string; botJid?: string }, options?: Record<string, unknown>): Promise<unknown>;
269
+ /** Send an agentic execution plan, advertising AGENTIC_PLANNING and QUERY_PLAN. */
270
+ sendBotPlanning(jid: string, content?: { text?: string; steps?: Array<string | { title?: string; name?: string; body?: string }>; queryPlan?: boolean; botJid?: string }, options?: Record<string, unknown>): Promise<unknown>;
269
271
  /** Send a rich response with experimental resolved tool-call metadata. */
270
272
  sendBotToolResult(jid: string, content?: { text?: string; toolCallId?: string; resolutionData?: unknown; resolutionDataSerialized?: string; botJid?: string }, options?: Record<string, unknown>): Promise<unknown>;
273
+ /** Resolve a WhatsApp Channel invite code or invite URL to channel metadata. */
274
+ newsletterGetInviteInfo(inviteCodeOrUrl: string): Promise<Record<string, unknown> | null>;
275
+ /** React to a Channel post; pass an empty string, null, or undefined to remove the reaction. */
276
+ newsletterReactMessage(jid: string, serverId: string | number, reaction?: string | null): Promise<void>;
271
277
  /** Send Markdown text containing blockquotes in a forwarded GenAI rich response. */
272
278
  sendMarkdownQuote(jid: string, content?: { text?: string; copyText?: string; copyLabel?: string; alignment?: 'END' | 'START' | 'CENTER' }, options?: Record<string, unknown>): Promise<unknown>;
273
279
  /** Send Markdown blockquotes followed by a GenAI COPY_TO_CLIPBOARD action. */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "plogme",
3
- "version": "2.0.0",
4
- "description": "Production-ready Baileys fork \u2689 with AI groups, Meta AI prompting, safe compositing fallbacks, rich responses, interactive messages, albums, newsletters, and communities \u2014 without antiban wrappers.",
3
+ "version": "2.0.1",
4
+ "description": "Production-ready Baileys fork ⚉ with AI groups, Meta AI prompting, safe compositing fallbacks, rich responses, interactive messages, albums, newsletters, and communities — without antiban wrappers.",
5
5
  "main": "lib/index.js",
6
6
  "type": "module",
7
7
  "scripts": {