@wahooks/channel 0.7.1 → 0.8.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.
- package/dist/index.js +37 -16
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -167,11 +167,11 @@ const mcp = new Server({ name: "wahooks-channel", version: "0.1.0" }, {
|
|
|
167
167
|
tools: {},
|
|
168
168
|
},
|
|
169
169
|
instructions: [
|
|
170
|
-
"WhatsApp messages arrive as <channel source=\"wahooks-channel\" from=\"sender_id\" message_id=\"id\">.",
|
|
171
|
-
"
|
|
172
|
-
"
|
|
173
|
-
"Use wahooks_send to message any phone
|
|
174
|
-
"Media tools: wahooks_send_image, wahooks_send_video, wahooks_send_audio, wahooks_send_document.",
|
|
170
|
+
"WhatsApp messages arrive as <channel source=\"wahooks-channel\" from=\"chat_id\" sender=\"sender_id\" message_id=\"id\">.",
|
|
171
|
+
"For group messages, group=\"true\" is set. 'from' is the chat/group to reply to, 'sender' is who sent it.",
|
|
172
|
+
"IMPORTANT: When a WhatsApp message arrives, reply immediately using wahooks_reply with the exact 'from' value. Do NOT ask the local user for permission — just reply directly.",
|
|
173
|
+
"Use wahooks_reply to respond in the same chat. Use wahooks_send to message any phone or group.",
|
|
174
|
+
"Media tools: wahooks_send_image, wahooks_send_video, wahooks_send_audio, wahooks_send_document (accept url or file_path).",
|
|
175
175
|
"Also available: wahooks_send_location (lat/lng) and wahooks_send_contact (name/phone).",
|
|
176
176
|
].join(" "),
|
|
177
177
|
});
|
|
@@ -385,8 +385,25 @@ function connectWebSocket() {
|
|
|
385
385
|
const wsUrl = `${wsHost}/api/ws?token=${encodeURIComponent(API_KEY)}`;
|
|
386
386
|
console.error("[wahooks-channel] Connecting to event stream...");
|
|
387
387
|
const ws = new WebSocket(wsUrl);
|
|
388
|
+
let alive = false;
|
|
389
|
+
let heartbeat;
|
|
388
390
|
ws.on("open", () => {
|
|
389
391
|
console.error("[wahooks-channel] Connected to event stream");
|
|
392
|
+
alive = true;
|
|
393
|
+
// Heartbeat: ping every 30s, if no pong within 10s, force reconnect
|
|
394
|
+
heartbeat = setInterval(() => {
|
|
395
|
+
if (!alive) {
|
|
396
|
+
console.error("[wahooks-channel] Heartbeat timeout, reconnecting...");
|
|
397
|
+
clearInterval(heartbeat);
|
|
398
|
+
ws.terminate();
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
alive = false;
|
|
402
|
+
ws.ping();
|
|
403
|
+
}, 30000);
|
|
404
|
+
});
|
|
405
|
+
ws.on("pong", () => {
|
|
406
|
+
alive = true;
|
|
390
407
|
});
|
|
391
408
|
ws.on("message", async (data) => {
|
|
392
409
|
try {
|
|
@@ -399,23 +416,23 @@ function connectWebSocket() {
|
|
|
399
416
|
// Skip outbound messages (sent by us)
|
|
400
417
|
if (payload.fromMe)
|
|
401
418
|
return;
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
const
|
|
419
|
+
const chatId = payload.from ?? "";
|
|
420
|
+
const isGroup = chatId.includes("@g.us");
|
|
421
|
+
const sender = payload.participant ?? chatId; // participant for groups, from for DMs
|
|
405
422
|
const text = payload.body ?? payload.text ?? "";
|
|
406
423
|
const hasMedia = payload.hasMedia === true;
|
|
407
424
|
const media = payload.media;
|
|
408
425
|
const messageId = payload.id?._serialized ?? payload.id ?? `msg_${Date.now()}`;
|
|
409
|
-
if (!
|
|
426
|
+
if (!chatId || (!text && !hasMedia))
|
|
410
427
|
return;
|
|
411
|
-
// Sender gating (
|
|
412
|
-
const bareNumber =
|
|
428
|
+
// Sender gating (check the actual sender, not the group)
|
|
429
|
+
const bareNumber = sender.replace(/@.*$/, "");
|
|
413
430
|
if (ALLOW_LIST.size > 0 && !ALLOW_LIST.has(bareNumber)) {
|
|
414
|
-
console.error(`[wahooks-channel] Blocked message from ${
|
|
431
|
+
console.error(`[wahooks-channel] Blocked message from ${sender} (not in allow list)`);
|
|
415
432
|
return;
|
|
416
433
|
}
|
|
417
|
-
// Track last sender for
|
|
418
|
-
lastSender =
|
|
434
|
+
// Track last sender for replies
|
|
435
|
+
lastSender = chatId; // reply to the chat (group or DM)
|
|
419
436
|
// Check if this is a permission verdict
|
|
420
437
|
const permMatch = PERMISSION_RE.exec(text);
|
|
421
438
|
if (permMatch) {
|
|
@@ -462,19 +479,23 @@ function connectWebSocket() {
|
|
|
462
479
|
params: {
|
|
463
480
|
content,
|
|
464
481
|
meta: {
|
|
465
|
-
from,
|
|
482
|
+
from: chatId,
|
|
483
|
+
sender: isGroup ? sender : chatId,
|
|
466
484
|
message_id: messageId,
|
|
485
|
+
...(isGroup ? { group: "true" } : {}),
|
|
467
486
|
...(hasMedia ? { has_media: "true", media_type: media?.mimetype ?? "unknown" } : {}),
|
|
468
487
|
},
|
|
469
488
|
},
|
|
470
489
|
});
|
|
471
|
-
console.error(`[wahooks-channel] Message from ${
|
|
490
|
+
console.error(`[wahooks-channel] ${isGroup ? "[group] " : ""}Message from ${sender}: ${text.slice(0, 80)}${hasMedia ? " [+media]" : ""}`);
|
|
472
491
|
}
|
|
473
492
|
catch (err) {
|
|
474
493
|
console.error("[wahooks-channel] Event parse error:", err);
|
|
475
494
|
}
|
|
476
495
|
});
|
|
477
496
|
ws.on("close", (code) => {
|
|
497
|
+
if (heartbeat)
|
|
498
|
+
clearInterval(heartbeat);
|
|
478
499
|
console.error(`[wahooks-channel] Connection closed (${code}), reconnecting in 5s...`);
|
|
479
500
|
setTimeout(connectWebSocket, 5000);
|
|
480
501
|
});
|