natureco-cli 1.0.44 → 1.0.45

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "natureco-cli",
3
- "version": "1.0.44",
3
+ "version": "1.0.45",
4
4
  "description": "NatureCo AI Bot Terminal Interface",
5
5
  "main": "bin/natureco.js",
6
6
  "bin": {
@@ -194,6 +194,9 @@ async function startWhatsAppProvider(sessionDir, config) {
194
194
  const { state, saveCreds } = await useMultiFileAuthState(sessionDir);
195
195
  const { version } = await fetchLatestBaileysVersion();
196
196
 
197
+ // Track last bot reply to prevent infinite loop
198
+ let lastBotReply = '';
199
+
197
200
  const sock = makeWASocket({
198
201
  version,
199
202
  auth: state,
@@ -240,43 +243,47 @@ async function startWhatsAppProvider(sessionDir, config) {
240
243
  const remoteJid = msg.key.remoteJid || '';
241
244
  const isLID = remoteJid.includes('@lid');
242
245
 
243
- // Handle LID format (new WhatsApp format)
244
- if (isLID) {
245
- if (msg.key.fromMe) {
246
- log('whatsapp', 'LID format detected, fromMe=true, accepting message', 'cyan');
247
- } else {
248
- log('whatsapp', 'LID format detected, fromMe=false, blocked', 'yellow');
249
- continue;
250
- }
246
+ // Skip bot's own replies (fromMe=true and not LID, or matches last bot reply)
247
+ const messageText = msg.message?.conversation ||
248
+ msg.message?.extendedTextMessage?.text ||
249
+ msg.message?.imageMessage?.caption ||
250
+ msg.message?.videoMessage?.caption ||
251
+ msg.message?.buttonsResponseMessage?.selectedDisplayText ||
252
+ msg.message?.listResponseMessage?.title ||
253
+ msg.message?.ephemeralMessage?.message?.conversation ||
254
+ msg.message?.viewOnceMessage?.message?.conversation ||
255
+ '';
256
+
257
+ // Skip if this is the bot's own reply
258
+ if (msg.key.fromMe && !isLID) {
259
+ log('whatsapp', 'Skipping bot own reply (fromMe=true, not LID)', 'gray');
260
+ continue;
261
+ }
262
+
263
+ // Skip if message matches last bot reply (prevent loop)
264
+ if (messageText === lastBotReply && lastBotReply !== '') {
265
+ log('whatsapp', 'Skipping duplicate bot reply (matches last sent)', 'gray');
266
+ continue;
251
267
  }
252
268
 
253
- // If fromMe and LID, accept without further checks (own conversation)
254
- if (msg.key.fromMe && isLID) {
255
- log('whatsapp', 'Own conversation (fromMe + LID), processing...', 'cyan');
269
+ // Handle LID format (new WhatsApp format)
270
+ if (isLID && !msg.key.fromMe) {
271
+ log('whatsapp', 'LID format detected, fromMe=false, blocked', 'yellow');
272
+ continue;
256
273
  }
257
274
 
258
275
  const sender = remoteJid.split('@')[0].split(':')[0];
259
276
  const allowedNumbers = config.whatsappAllowedNumbers || [];
260
277
 
261
- // Log incoming number before access control
278
+ // Log incoming number
262
279
  log('whatsapp', `Incoming from: +${sender}, allowed: ${JSON.stringify(allowedNumbers)}`, 'gray');
263
280
 
264
- // Access control - compare last 10 digits (skip if fromMe + LID)
281
+ // Access control - skip if fromMe + LID (own conversation)
265
282
  if (!(msg.key.fromMe && isLID) && allowedNumbers.length > 0 && !allowedNumbers.some(n => numberMatches(n, sender))) {
266
283
  log('whatsapp', `blocked message from +${sender} (not in allowed list)`, 'yellow');
267
284
  continue;
268
285
  }
269
286
 
270
- const messageText = msg.message?.conversation ||
271
- msg.message?.extendedTextMessage?.text ||
272
- msg.message?.imageMessage?.caption ||
273
- msg.message?.videoMessage?.caption ||
274
- msg.message?.buttonsResponseMessage?.selectedDisplayText ||
275
- msg.message?.listResponseMessage?.title ||
276
- msg.message?.ephemeralMessage?.message?.conversation ||
277
- msg.message?.viewOnceMessage?.message?.conversation ||
278
- '';
279
-
280
287
  if (!messageText) {
281
288
  log('whatsapp', `Message without text content. Keys: ${Object.keys(msg.message || {}).join(', ')}`, 'gray');
282
289
  continue;
@@ -284,7 +291,6 @@ async function startWhatsAppProvider(sessionDir, config) {
284
291
 
285
292
  const ownNumber = sock.user?.id?.split(':')[0].replace('@s.whatsapp.net', '') || 'unknown';
286
293
  log('whatsapp', `Inbound message +${sender} -> +${ownNumber} (${messageText.length} chars)`, 'cyan');
287
- log('whatsapp', `Message: "${messageText.substring(0, 100)}${messageText.length > 100 ? '...' : ''}"`, 'gray');
288
294
 
289
295
  try {
290
296
  const { sendMessage } = require('../utils/api');
@@ -294,10 +300,13 @@ async function startWhatsAppProvider(sessionDir, config) {
294
300
  const reply = response?.reply || response?.message || '';
295
301
 
296
302
  if (reply) {
297
- log('whatsapp', `API response: "${reply.substring(0, 100)}${reply.length > 100 ? '...' : ''}"`, 'gray');
298
303
  log('whatsapp', 'Sending reply...', 'cyan');
299
304
 
300
305
  await sock.sendMessage(msg.key.remoteJid, { text: reply });
306
+
307
+ // Store last bot reply to prevent loop
308
+ lastBotReply = reply;
309
+
301
310
  log('whatsapp', `Reply sent (${reply.length} chars)`, 'green');
302
311
  } else {
303
312
  log('whatsapp', 'No reply from API', 'yellow');