beast-agent 0.26.3 → 0.26.5
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 +1 -1
- package/src/agent/discord.js +22 -2
- package/src/agent/whatsapp.js +36 -6
- package/src/renderer/i18n.js +8 -4
- package/src/renderer/renderer.js +13 -2
package/package.json
CHANGED
package/src/agent/discord.js
CHANGED
|
@@ -48,6 +48,20 @@ function bodySnippet(data) {
|
|
|
48
48
|
return s ? ` — gövde: ${s.slice(0, 140)}` : '';
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/* Ağ engel sayfası tespiti: Discord API her zaman JSON döner — text/html veya
|
|
52
|
+
erişim-engelle sayfası gelirse ağ seviyesinde blok var demektir (Türkiye'de
|
|
53
|
+
Discord erişimi zaman zaman engellenir). Kullanıcıya net VPN yönlendirmesi. */
|
|
54
|
+
const VPN_HINT = 'Discord bu ağdan ERİŞİME ENGELLİ görünüyor — VPN açıp tekrar dene (engel sayfası döndü)';
|
|
55
|
+
|
|
56
|
+
function looksBlocked(ctype, data) {
|
|
57
|
+
const ct = String(ctype || '');
|
|
58
|
+
const body = String(data || '').slice(0, 4000);
|
|
59
|
+
return (
|
|
60
|
+
ct.includes('text/html') ||
|
|
61
|
+
/erisime[_ ]?engelle|erişime engelle|blocked|block_page/i.test(body)
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
51
65
|
class DiscordBridge {
|
|
52
66
|
constructor({ token, emit, onIncoming }) {
|
|
53
67
|
this.token = String(token || '').trim();
|
|
@@ -101,14 +115,17 @@ class DiscordBridge {
|
|
|
101
115
|
const data = await res.text();
|
|
102
116
|
let j = null;
|
|
103
117
|
try { j = data ? JSON.parse(data) : null; } catch {}
|
|
104
|
-
if (res.ok) return j;
|
|
118
|
+
if (res.ok && j !== null) return j;
|
|
119
|
+
if (j === null && looksBlocked(res.headers.get('content-type'), data)) {
|
|
120
|
+
throw new Error(VPN_HINT + bodySnippet(data));
|
|
121
|
+
}
|
|
105
122
|
throw new Error(
|
|
106
123
|
`discord ${path}: HTTP ${res.status}${j && j.message ? ' ' + j.message : ''}${bodySnippet(data)}`
|
|
107
124
|
);
|
|
108
125
|
} catch (e) {
|
|
109
126
|
/* kendi formatladığımız API hatasıysa yukarı taşı; transport hatasıysa
|
|
110
127
|
Node https yoluna düş (orada esnek TLS şansı var) */
|
|
111
|
-
if (/^discord
|
|
128
|
+
if (/^discord |Discord bu ağ/.test(String((e && e.message) || ''))) throw e;
|
|
112
129
|
}
|
|
113
130
|
}
|
|
114
131
|
|
|
@@ -134,6 +151,9 @@ class DiscordBridge {
|
|
|
134
151
|
let j = null;
|
|
135
152
|
try { j = data ? JSON.parse(data) : null; } catch {}
|
|
136
153
|
if (res.statusCode >= 200 && res.statusCode < 300 && j !== null) return resolve(j);
|
|
154
|
+
if (looksBlocked(ctype, data)) {
|
|
155
|
+
return reject(new Error(VPN_HINT + bodySnippet(data)));
|
|
156
|
+
}
|
|
137
157
|
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
138
158
|
return reject(new Error(`discord ${path}: bozuk yanıt (HTTP ${res.statusCode}${ctype ? ', ' + ctype : ''})${bodySnippet(data)}`));
|
|
139
159
|
}
|
package/src/agent/whatsapp.js
CHANGED
|
@@ -337,8 +337,20 @@ class WhatsAppBridge {
|
|
|
337
337
|
async _processIncoming(msg) {
|
|
338
338
|
try {
|
|
339
339
|
const jid = msg.key && msg.key.remoteJid;
|
|
340
|
-
if (!jid
|
|
340
|
+
if (!jid) return;
|
|
341
341
|
if (jid === 'status@broadcast' || jid.endsWith('@newsletter')) return;
|
|
342
|
+
/* botun kendi kimliği: telefon base'i + LID base'i (LID dönemi) */
|
|
343
|
+
const meBase = String(this._userIdRaw || '').split('@')[0].split(':')[0];
|
|
344
|
+
const lidBase = String((this.sock && this.sock.user && this.sock.user.lid) || '').split('@')[0].split(':')[0];
|
|
345
|
+
/* KENDİ KENDİNE SOHBET (Saved Messages): kullanıcı kendi numarasını izinliye
|
|
346
|
+
ekleyip kendi sohbetinden bota yazabilsin. Bu sohbetteki HER mesaj fromMe
|
|
347
|
+
gelir; botun KENDİ gönderdiği mesajlar (_tracked) filtrelenir → döngü yok.
|
|
348
|
+
Diğer sohbetlerdeki elle yazılan fromMe mesajları bot etkilenmesin diye yutulur. */
|
|
349
|
+
const selfChat = !!(meBase && (jid === meBase + '@s.whatsapp.net' || (lidBase && jid === lidBase + '@lid')));
|
|
350
|
+
if (msg.key.fromMe) {
|
|
351
|
+
if (this._tracked.has(String(msg.key.id))) return; // botun kendi cevabı — echo
|
|
352
|
+
if (!selfChat) return;
|
|
353
|
+
}
|
|
342
354
|
const isGroup = jid.endsWith('@g.us');
|
|
343
355
|
const participantJid = isGroup && msg.key.participant ? String(msg.key.participant) : '';
|
|
344
356
|
const mm = msg.message || {};
|
|
@@ -351,20 +363,35 @@ class WhatsAppBridge {
|
|
|
351
363
|
const t = String(text || '').trim();
|
|
352
364
|
|
|
353
365
|
// gruplarda bot'un kendisi @mention edilmiş mi
|
|
366
|
+
/* LİD DÖNEMİ UYARISI: mentionedJid artık çoğu zaman botun @lid numarasıyla
|
|
367
|
+
gelir (telefon JID'i DEĞİL) — bu yüzden yalnız meBase ile karşılaştırma
|
|
368
|
+
mention'ı ıskalıyordu. Şimdi: botun telefon base'i + LID base'i ikisiyle
|
|
369
|
+
de eşitlik aranır; contextInfo görsel/video/belge caption'larından da alınır. */
|
|
354
370
|
let mentioned = false;
|
|
355
371
|
if (isGroup) {
|
|
356
|
-
const ci =
|
|
372
|
+
const ci =
|
|
373
|
+
(mm.extendedTextMessage && mm.extendedTextMessage.contextInfo) ||
|
|
374
|
+
(mm.imageMessage && mm.imageMessage.contextInfo) ||
|
|
375
|
+
(mm.videoMessage && mm.videoMessage.contextInfo) ||
|
|
376
|
+
(mm.documentMessage && mm.documentMessage.contextInfo) ||
|
|
377
|
+
null;
|
|
357
378
|
const men = (ci && ci.mentionedJid) || [];
|
|
358
|
-
const
|
|
379
|
+
const baseOf = (j) => String(j || '').split('?')[0].split(':')[0].split('@')[0];
|
|
359
380
|
for (const m of men) {
|
|
360
|
-
|
|
381
|
+
const base = baseOf(m);
|
|
382
|
+
if (base && ((meBase && base === meBase) || (lidBase && base === lidBase))) {
|
|
361
383
|
mentioned = true;
|
|
362
384
|
break;
|
|
363
385
|
}
|
|
364
386
|
}
|
|
365
|
-
if (!mentioned && ci && ci.participant
|
|
366
|
-
|
|
387
|
+
if (!mentioned && ci && ci.participant) {
|
|
388
|
+
const pBase = baseOf(ci.participant);
|
|
389
|
+
if ((meBase && pBase === meBase) || (lidBase && pBase === lidBase)) {
|
|
390
|
+
mentioned = true; // mesajımıza reply verilmiş
|
|
391
|
+
}
|
|
367
392
|
}
|
|
393
|
+
/* metin yedeği: @<bot numarası> elle yazılmışsa da mention sayılır */
|
|
394
|
+
if (!mentioned && meBase && t.includes('@' + meBase)) mentioned = true;
|
|
368
395
|
}
|
|
369
396
|
|
|
370
397
|
// medya çıkarımı (varsa)
|
|
@@ -406,6 +433,9 @@ class WhatsAppBridge {
|
|
|
406
433
|
senderNum = (participantJid || jid).split('@')[0].split(':')[0];
|
|
407
434
|
if (!/^\d+$/.test(senderNum)) senderNum = '';
|
|
408
435
|
}
|
|
436
|
+
/* kendi kendine sohbette gönderen = botun telefon numarası — izin listesi
|
|
437
|
+
telefon numarasıyla eşleşsin (LID self-chat'te jid @lid olur) */
|
|
438
|
+
if (selfChat && meBase) senderNum = meBase;
|
|
409
439
|
this.onIncoming(jid, {
|
|
410
440
|
text: t,
|
|
411
441
|
media,
|
package/src/renderer/i18n.js
CHANGED
|
@@ -195,8 +195,9 @@
|
|
|
195
195
|
it_connect: 'QR ile Bağlan',
|
|
196
196
|
it_disconnect: 'Kes',
|
|
197
197
|
it_reset_pair: 'Eşlemeyi Sıfırla',
|
|
198
|
-
it_groups_on: 'WhatsApp gruplarında çalış
|
|
199
|
-
|
|
198
|
+
it_groups_on: 'WhatsApp gruplarında çalış',
|
|
199
|
+
it_groups_mention: 'Sadece @mention edilince cevap ver (grupta botu etiketle)',
|
|
200
|
+
it_groups_all: 'Grubun her mesajına karış',
|
|
200
201
|
it_allow_label: 'İzinli numaralar',
|
|
201
202
|
it_name_ph: 'İsim (zorunlu)',
|
|
202
203
|
it_num_ph: 'Numara 905xxxxxxxxx',
|
|
@@ -215,6 +216,7 @@
|
|
|
215
216
|
it_dc_token_bad: 'Token doğrulanamadı — Developer Portal\u2019dan aldığın tokenı kontrol et',
|
|
216
217
|
it_dc_id_ph: 'Kullanıcı ID veya @kullanıcı_adı',
|
|
217
218
|
it_dc_note: 'İzin listesi boşsa kimse cevap almaz. Bot oluşturma: discord.com/developers → New Application → Bot → Token. "MESSAGE CONTENT INTENT"i AÇ (yoksa mesajlar boş gelir). Sunucu daveti: OAuth2 → bot yetkisiyle. Kendi ID\u2019ni öğrenmek için geliştirici modunu açıp kendine sağ tıkla → ID\u2019yi kopyala.',
|
|
219
|
+
it_dc_vpn: 'Türkiye\u2019de Discord erişimi zaman zaman engellenir — bağlanamıyorsan VPN açıp tekrar dene.',
|
|
218
220
|
ev_h2: 'Olay Merkezi',
|
|
219
221
|
ev_sub: 'Cron\u2019suz canlı olaylar — kaynakları aç, abonelikleri agent kendisi kurar (event_subscribe). Tetiklenen olay ilgili sohbete düşer, cevap WhatsApp\u2019a gider.',
|
|
220
222
|
ev_on: 'Olay merkezi açık',
|
|
@@ -722,8 +724,9 @@
|
|
|
722
724
|
it_connect: 'Connect via QR',
|
|
723
725
|
it_disconnect: 'Disconnect',
|
|
724
726
|
it_reset_pair: 'Reset pairing',
|
|
725
|
-
it_groups_on: 'Work in WhatsApp groups
|
|
726
|
-
|
|
727
|
+
it_groups_on: 'Work in WhatsApp groups',
|
|
728
|
+
it_groups_mention: 'Reply only when @mentioned (tag the bot in the group)',
|
|
729
|
+
it_groups_all: 'Respond to every group message',
|
|
727
730
|
it_allow_label: 'Allowed numbers',
|
|
728
731
|
it_name_ph: 'Name (required)',
|
|
729
732
|
it_num_ph: 'Number 905xxxxxxxxx',
|
|
@@ -742,6 +745,7 @@
|
|
|
742
745
|
it_dc_token_bad: 'Token could not be verified — check the token from the Developer Portal',
|
|
743
746
|
it_dc_id_ph: 'User ID or @username',
|
|
744
747
|
it_dc_note: 'Empty allow list = nobody gets a reply. Create a bot: discord.com/developers → New Application → Bot → Token. Turn ON "MESSAGE CONTENT INTENT". Invite via OAuth2 bot URL. To learn your ID: enable developer mode, right-click yourself → Copy ID.',
|
|
748
|
+
it_dc_vpn: 'Discord may be blocked on some networks — if it won\u2019t connect, turn on a VPN and retry.',
|
|
745
749
|
ev_h2: 'Event Center',
|
|
746
750
|
ev_sub: 'Live events without cron — open sources, the agent sets up subscriptions itself (event_subscribe). The triggered event drops into the relevant chat, the reply goes to WhatsApp.',
|
|
747
751
|
ev_on: 'Event center on',
|
package/src/renderer/renderer.js
CHANGED
|
@@ -1498,7 +1498,8 @@ async function renderIntegrationsPane() {
|
|
|
1498
1498
|
</div>
|
|
1499
1499
|
<div style="height:14px"></div>
|
|
1500
1500
|
<label class="lock-row"><input type="checkbox" id="waGroupsOn" ${g.enabled ? 'checked' : ''}/><span>${_t('it_groups_on')}</span></label>
|
|
1501
|
-
<label class="lock-row" style="${g.enabled ? '' : 'opacity:.45'}"><input type="
|
|
1501
|
+
<label class="lock-row" style="${g.enabled ? '' : 'opacity:.45'}"><input type="radio" name="waGroupMode" id="waGroupsMention" ${g.mentionOnly !== false ? 'checked' : ''}/><span>${_t('it_groups_mention')}</span></label>
|
|
1502
|
+
<label class="lock-row" style="${g.enabled ? '' : 'opacity:.45'}"><input type="radio" name="waGroupMode" id="waGroupsAll" ${g.mentionOnly === false ? 'checked' : ''}/><span>${_t('it_groups_all')}</span></label>
|
|
1502
1503
|
<div class="divider"></div>
|
|
1503
1504
|
<label class="mem-label" style="margin-top:0">${_t('it_allow_label')}</label>
|
|
1504
1505
|
<div id="waAllowChips" class="chips-inline"></div>
|
|
@@ -1557,6 +1558,7 @@ async function renderIntegrationsPane() {
|
|
|
1557
1558
|
<div class="wa-actions" style="margin-top:6px">
|
|
1558
1559
|
<button id="dcStopBtn" class="btn ghost">${_t('it_disconnect')}</button>
|
|
1559
1560
|
</div>
|
|
1561
|
+
<div class="sub" style="margin-top:6px">ⓘ ${_t('it_dc_vpn')}</div>
|
|
1560
1562
|
<div class="divider"></div>
|
|
1561
1563
|
<label class="mem-label" style="margin-top:0">${_t('it_allow_label')} — Discord</label>
|
|
1562
1564
|
<div id="dcAllowChips" class="chips-inline"></div>
|
|
@@ -1570,16 +1572,25 @@ async function renderIntegrationsPane() {
|
|
|
1570
1572
|
</div>`;
|
|
1571
1573
|
|
|
1572
1574
|
const waGroupsOn = $('#waGroupsOn');
|
|
1575
|
+
const waGroupsMention = $('#waGroupsMention');
|
|
1573
1576
|
const waGroupsAll = $('#waGroupsAll');
|
|
1577
|
+
/* iki mod BİRBİRİNE HARIÇTİR: ya @mention ya her mesaja karışma (radio) */
|
|
1578
|
+
const syncGroupMode = () => {
|
|
1579
|
+
const op = waGroupsOn.checked ? '' : '.45';
|
|
1580
|
+
if (waGroupsMention) waGroupsMention.parentElement.style.opacity = op;
|
|
1581
|
+
if (waGroupsAll) waGroupsAll.parentElement.style.opacity = op;
|
|
1582
|
+
};
|
|
1574
1583
|
const saveGroups = async () => {
|
|
1575
1584
|
const r = await beast.waSetGroups({ enabled: waGroupsOn.checked, mentionOnly: !waGroupsAll.checked });
|
|
1576
1585
|
toast(r.enabled ? (r.mentionOnly ? 'Gruplar açık — @mention bekler' : 'Gruplar açık — tüm mesajlara karışır') : 'Gruplar kapalı');
|
|
1577
1586
|
};
|
|
1578
1587
|
waGroupsOn.addEventListener('change', async () => {
|
|
1579
|
-
|
|
1588
|
+
syncGroupMode();
|
|
1580
1589
|
await saveGroups();
|
|
1581
1590
|
});
|
|
1591
|
+
waGroupsMention.addEventListener('change', saveGroups);
|
|
1582
1592
|
waGroupsAll.addEventListener('change', saveGroups);
|
|
1593
|
+
syncGroupMode();
|
|
1583
1594
|
|
|
1584
1595
|
$('#waStartBtn').addEventListener('click', async () => {
|
|
1585
1596
|
toast('Bağlanıyor…');
|