beast-agent 2.5.1 → 2.6.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/package.json +1 -1
- package/src/agent/apps.js +587 -0
- package/src/agent/engine.js +39 -4
- package/src/agent/logger.js +138 -5
- package/src/agent/seed-apps/hesap-makinesi/app.json +11 -0
- package/src/agent/seed-apps/hesap-makinesi/main.js +41 -0
- package/src/agent/seed-apps/hesap-makinesi/ui/index.html +151 -0
- package/src/agent/watchers.js +25 -4
- package/src/agent/watext.js +1 -0
- package/src/main.js +196 -75
- package/src/preload.js +1 -0
- package/src/renderer/app-preload.js +20 -0
- package/src/renderer/i18n.js +10 -2
- package/src/renderer/index.html +2 -2
- package/src/renderer/renderer.js +51 -14
- package/src/renderer/style.css +8 -1
package/src/main.js
CHANGED
|
@@ -229,17 +229,20 @@ startHealthServer(); /* splash/boot aşamasından itibaren /health ayakta */
|
|
|
229
229
|
try { setSearchChain(settings.searchChain); } catch {}
|
|
230
230
|
try { setTinyfishKey(settings.tinyfishKey || null); } catch {}
|
|
231
231
|
let wa = null;
|
|
232
|
-
let waChats = new Map(); // jid -> aktif session id
|
|
232
|
+
let waChats = new Map(); // jid -> aktif session id (hepsi KANAL TEK OTURUMUNA bağlı)
|
|
233
|
+
let waSingleSid = null; // KANAL TEK OTURUMU: WhatsApp için BİR oturum — silinmedikçe hep aynı
|
|
233
234
|
let waHistory = new Map(); // jid -> [sid,...] bu sohbete ait tüm oturumlar
|
|
234
235
|
let waBcMode = new Set(); // jid -> BeastCode modu AKTİF (WhatsApp'tan uzaktan kodlama)
|
|
235
236
|
let waJidPn = new Map(); // jid -> gerçek telefon numarası (LID fallback için)
|
|
236
237
|
const WA_HISTORY_CAP = 20;
|
|
237
238
|
let tg = null;
|
|
238
|
-
let tgChats = new Map(); // telegram chatId -> aktif session id
|
|
239
|
+
let tgChats = new Map(); // telegram chatId -> aktif session id (hepsi KANAL TEK OTURUMUNA bağlı)
|
|
240
|
+
let tgSingleSid = null; // KANAL TEK OTURUMU: Telegram için BİR oturum
|
|
239
241
|
let tgHistory = new Map(); // chatId -> [sid,...]
|
|
240
242
|
const TG_HISTORY_CAP = 20;
|
|
241
243
|
let dc = null;
|
|
242
|
-
let dcChats = new Map(); // discord channelId -> aktif session id
|
|
244
|
+
let dcChats = new Map(); // discord channelId -> aktif session id (hepsi KANAL TEK OTURUMUNA bağlı)
|
|
245
|
+
let dcSingleSid = null; // KANAL TEK OTURUMU: Discord için BİR oturum
|
|
243
246
|
let dcHistory = new Map(); // channelId -> [sid,...]
|
|
244
247
|
const DC_HISTORY_CAP = 20;
|
|
245
248
|
const DC_CHATS_FILE = path.join(APP_DIR, 'dc-chats.json');
|
|
@@ -278,6 +281,8 @@ try {
|
|
|
278
281
|
if (!h.includes(s)) h.push(s);
|
|
279
282
|
waHistory.set(j, h.slice(-WA_HISTORY_CAP));
|
|
280
283
|
}
|
|
284
|
+
/* kanal tek oturumu: kayıtlı aktif id (geçersizse ensure yeniden seçer) */
|
|
285
|
+
if (typeof raw.active === 'string' && raw.active) waSingleSid = raw.active;
|
|
281
286
|
/* BeastCode modu: hangi sohbetler uzaktan kodlama yapıyor */
|
|
282
287
|
if (Array.isArray(raw.bcMode)) {
|
|
283
288
|
for (const j of raw.bcMode) if (typeof j === 'string') waBcMode.add(j);
|
|
@@ -293,6 +298,7 @@ function saveWaChats() {
|
|
|
293
298
|
chats: Object.fromEntries(waChats),
|
|
294
299
|
history: Object.fromEntries([...waHistory.entries()].map(([j, a]) => [j, a.slice(-WA_HISTORY_CAP)])),
|
|
295
300
|
bcMode: [...waBcMode],
|
|
301
|
+
active: waSingleSid || '',
|
|
296
302
|
})
|
|
297
303
|
);
|
|
298
304
|
} catch {}
|
|
@@ -1268,12 +1274,26 @@ async function tryWaSlash(jid, rawText, senderNum, payload0) {
|
|
|
1268
1274
|
if (cmd === 'help') {
|
|
1269
1275
|
out = waSlashHelp();
|
|
1270
1276
|
} else if (cmd === 'new') {
|
|
1277
|
+
/* /new: kanalın TEK oturumunu kapat, yenisini aç — aynı anda iki
|
|
1278
|
+
WhatsApp sohbet oturumu olmaz; eski oturum silinir */
|
|
1279
|
+
const oldSid = waSingleSid || waChats.get(jid) || '';
|
|
1280
|
+
if (oldSid) {
|
|
1281
|
+
let olds = null;
|
|
1282
|
+
try { olds = engine.cache.get(oldSid) || null; } catch {}
|
|
1283
|
+
if (!olds || !olds.bcCode) {
|
|
1284
|
+
/* Beast Code panel oturumuysa dokunma — yalnız pointer taşınır */
|
|
1285
|
+
try { engine.deleteSession(oldSid); } catch {}
|
|
1286
|
+
for (const [j, h] of waHistory.entries()) waHistory.set(j, h.filter((x) => x !== oldSid));
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1271
1289
|
const v = engine.createSession();
|
|
1290
|
+
waSingleSid = v.id;
|
|
1291
|
+
for (const j of [...waChats.keys()]) waChats.set(j, v.id);
|
|
1272
1292
|
waChats.set(jid, v.id);
|
|
1273
1293
|
waRememberSession(jid, v.id);
|
|
1274
1294
|
saveWaChats();
|
|
1275
1295
|
wa.setWatchJids([...waChats.keys()]);
|
|
1276
|
-
out = `*Yeni oturum* \`${v.code}\` açıldı —
|
|
1296
|
+
out = `*Yeni oturum* \`${v.code}\` açıldı — eski oturum kapatıldı, artık buradan devam.\nVar olan başka oturuma geçiş: \`/open <kod>\``;
|
|
1277
1297
|
} else if (cmd === 'open') {
|
|
1278
1298
|
if (!arg) {
|
|
1279
1299
|
out = 'Kullanım: `/open <kod>` — kodları görmek için /sessions';
|
|
@@ -1282,7 +1302,9 @@ async function tryWaSlash(jid, rawText, senderNum, payload0) {
|
|
|
1282
1302
|
if (!hit) {
|
|
1283
1303
|
out = `\`${arg.toUpperCase()}\` kodlu oturum bulunamadı. Listeyi görmek için /sessions`;
|
|
1284
1304
|
} else {
|
|
1285
|
-
|
|
1305
|
+
/* /open: kanal TEK oturumunu bu oturuma çevirir — tüm jid'ler bağlanır */
|
|
1306
|
+
waSingleSid = hit.id;
|
|
1307
|
+
for (const j of [...waChats.keys()]) waChats.set(j, hit.id);
|
|
1286
1308
|
waRememberSession(jid, hit.id);
|
|
1287
1309
|
saveWaChats();
|
|
1288
1310
|
wa.setWatchJids([...waChats.keys()]);
|
|
@@ -1564,14 +1586,15 @@ async function tryWaSlash(jid, rawText, senderNum, payload0) {
|
|
|
1564
1586
|
try { engine.interrupt(sid, 'kullanıcı /beastagent ile sohbet moduna döndü'); } catch {}
|
|
1565
1587
|
}
|
|
1566
1588
|
waBcMode.delete(jid);
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1589
|
+
/* KANAL TEK OTURUMU: yeni oturum AÇILMAZ — sohbet oturumuna dönülür
|
|
1590
|
+
(silinmediyse hep aynı; ilk kez ise burada oluşur) */
|
|
1591
|
+
const chatSid = ensureWaSession(jid);
|
|
1592
|
+
const chatS = engine.cache.get(chatSid);
|
|
1570
1593
|
saveWaChats();
|
|
1571
1594
|
if (wa) wa.setWatchJids([...waChats.keys()]);
|
|
1572
1595
|
emitWaEventSafe({ type: 'bc-screen', on: false });
|
|
1573
1596
|
out =
|
|
1574
|
-
`*💬 Sohbet moduna dönüldü* — masaüstünde chat ekranı açıldı,
|
|
1597
|
+
`*💬 Sohbet moduna dönüldü* — masaüstünde chat ekranı açıldı, sohbet oturumu \`${(chatS && chatS.code) || '?'}\`.\n` +
|
|
1575
1598
|
`Kodlar duruyor: \`${waBcWorkspace()}\`\n` +
|
|
1576
1599
|
`Tekrar kodlamak için: /beastcode`;
|
|
1577
1600
|
}
|
|
@@ -1682,19 +1705,58 @@ function waGroupSenderInfo(payload) {
|
|
|
1682
1705
|
return { label, name: (hitP && hitP.name) || '', isOwner: !!(hitP && hitP.owner) };
|
|
1683
1706
|
}
|
|
1684
1707
|
|
|
1685
|
-
/*
|
|
1708
|
+
/* ---------- KANAL TEK OTURUMU (WA/TG/DC) ----------
|
|
1709
|
+
Her kanalın BİR aktif sohbet oturumu vardır; eskisi silinmedikçe hep
|
|
1710
|
+
AYNI oturumdan devam edilir — Beast kendi kendine oturum kapatıp
|
|
1711
|
+
yenisiyle değiştirmez. Yenisi yalnızca: (1) kayıtlı oturum dosyası
|
|
1712
|
+
yoksa (kullanıcı UI'dan sildi), (2) kullanıcı WA'da /new yazarsa.
|
|
1713
|
+
Masaüstü chat UI'daki "+ Yeni Sohbet" bu kuralın dışındadır. */
|
|
1714
|
+
function sessionFileAlive(sid) {
|
|
1715
|
+
try {
|
|
1716
|
+
return !!sid && fs.existsSync(path.join(engine.sessionsDir, String(sid) + '.jsonl'));
|
|
1717
|
+
} catch {
|
|
1718
|
+
return false;
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
/* kanalın yaşayan tek oturumunu döndürür; geçersizse eski bağlamdan devralır,
|
|
1723
|
+
o da yoksa (ilk kullanım) yeni açar ve tüm jid'leri ona bağlar */
|
|
1686
1724
|
function ensureWaSession(jid) {
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1725
|
+
if (!waSingleSid || !sessionFileAlive(waSingleSid)) {
|
|
1726
|
+
let best = '';
|
|
1727
|
+
let bestTs = '';
|
|
1728
|
+
for (const c of new Set([...waChats.values(), waSingleSid])) {
|
|
1729
|
+
if (!c || !sessionFileAlive(c)) continue;
|
|
1730
|
+
let ts = '';
|
|
1731
|
+
try {
|
|
1732
|
+
const s = engine.cache.get(c) || engine._load(c);
|
|
1733
|
+
ts = String((s && s.updatedAt) || '');
|
|
1734
|
+
} catch {}
|
|
1735
|
+
if (!best || ts > bestTs) {
|
|
1736
|
+
best = c;
|
|
1737
|
+
bestTs = ts;
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
waSingleSid = best || engine.createSession().id;
|
|
1741
|
+
saveWaChats();
|
|
1742
|
+
}
|
|
1743
|
+
let dirty = false;
|
|
1744
|
+
for (const [j, s] of waChats.entries()) {
|
|
1745
|
+
if (s !== waSingleSid) {
|
|
1746
|
+
waChats.set(j, waSingleSid);
|
|
1747
|
+
dirty = true;
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
if (jid != null && waChats.get(String(jid)) !== waSingleSid) {
|
|
1751
|
+
waChats.set(String(jid), waSingleSid);
|
|
1752
|
+
dirty = true;
|
|
1753
|
+
}
|
|
1754
|
+
waRememberSession(String(jid), waSingleSid);
|
|
1755
|
+
if (dirty) {
|
|
1692
1756
|
saveWaChats();
|
|
1693
1757
|
if (wa) wa.setWatchJids([...waChats.keys()]);
|
|
1694
|
-
} else {
|
|
1695
|
-
waRememberSession(jid, sid);
|
|
1696
1758
|
}
|
|
1697
|
-
return
|
|
1759
|
+
return waSingleSid;
|
|
1698
1760
|
}
|
|
1699
1761
|
|
|
1700
1762
|
/* ---------- GRUP BAĞLAM AKIŞI (mentionOnly + seeAll) ----------
|
|
@@ -2232,7 +2294,7 @@ async function processWaMessage(jid, payload, senderNum, requeues = 0) {
|
|
|
2232
2294
|
waLog(`skip flush: izinli eşleşme yok (sender=+${senderNum || '?'})`);
|
|
2233
2295
|
return;
|
|
2234
2296
|
}
|
|
2235
|
-
let sid = waChats.get(jid);
|
|
2297
|
+
let sid = waChats.get(jid) || waSingleSid;
|
|
2236
2298
|
if (sid && engine.isBusy(sid)) {
|
|
2237
2299
|
/* oturum hâlâ önceki işle uğraşıyor — KAYBETME: sınırı kaldırdık,
|
|
2238
2300
|
iş bitene dek her debounce turunda yeniden deneriz; kullanıcıya
|
|
@@ -2246,16 +2308,8 @@ async function processWaMessage(jid, payload, senderNum, requeues = 0) {
|
|
|
2246
2308
|
if (!isGroup && requeues > 0) {
|
|
2247
2309
|
// retry sonrası izin yeniden kontrol edilir (yukarıda hit zaten alınıyor)
|
|
2248
2310
|
}
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
sid = v.id;
|
|
2252
|
-
waChats.set(jid, sid);
|
|
2253
|
-
waRememberSession(jid, sid);
|
|
2254
|
-
saveWaChats();
|
|
2255
|
-
if (wa) wa.setWatchJids([...waChats.keys()]);
|
|
2256
|
-
} else {
|
|
2257
|
-
waRememberSession(jid, sid);
|
|
2258
|
-
}
|
|
2311
|
+
/* KANAL TEK OTURUMU: eskisi silinmedikçe hep aynı oturumdan devam */
|
|
2312
|
+
sid = ensureWaSession(jid);
|
|
2259
2313
|
// Cevap verilecek — karşı telefonda "yazıyor…" göstergesi (medya işlenene dek sürer)
|
|
2260
2314
|
wa.setComposing(jid, true);
|
|
2261
2315
|
// Kişi bazlı granül izin: all/web/read/chat
|
|
@@ -2462,6 +2516,8 @@ function ensureWa() {
|
|
|
2462
2516
|
if (Array.isArray(arr)) tgHistory.set(c, arr.filter((x) => typeof x === 'string').slice(-TG_HISTORY_CAP));
|
|
2463
2517
|
}
|
|
2464
2518
|
}
|
|
2519
|
+
/* kanal tek oturumu: kayıtlı aktif id (geçersizse ensure yeniden seçer) */
|
|
2520
|
+
if (raw && typeof raw.active === 'string' && raw.active) tgSingleSid = raw.active;
|
|
2465
2521
|
for (const [c, s] of tgChats.entries()) {
|
|
2466
2522
|
const h = tgHistory.get(c) || [];
|
|
2467
2523
|
if (!h.includes(s)) h.push(s);
|
|
@@ -2477,6 +2533,7 @@ function saveTgChats() {
|
|
|
2477
2533
|
JSON.stringify({
|
|
2478
2534
|
chats: Object.fromEntries(tgChats),
|
|
2479
2535
|
history: Object.fromEntries([...tgHistory.entries()].map(([c, a]) => [c, a.slice(-TG_HISTORY_CAP)])),
|
|
2536
|
+
active: tgSingleSid || '',
|
|
2480
2537
|
})
|
|
2481
2538
|
);
|
|
2482
2539
|
} catch {}
|
|
@@ -2549,21 +2606,14 @@ async function processTgMessage(chatId, payload, requeues = 0) {
|
|
|
2549
2606
|
tgLog(`skip flush: izinli eşleşme yok (sender=${payload.senderId || '?'})`);
|
|
2550
2607
|
return;
|
|
2551
2608
|
}
|
|
2552
|
-
let sid = tgChats.get(chatId);
|
|
2609
|
+
let sid = tgChats.get(chatId) || tgSingleSid;
|
|
2553
2610
|
if (sid && engine.isBusy(sid)) {
|
|
2554
2611
|
/* oturum meşgul — WA ile aynı: kaybetme, iş bitene dek yeniden dene */
|
|
2555
2612
|
await new Promise((r) => setTimeout(r, TG_DEBOUNCE_MS));
|
|
2556
2613
|
return processTgMessage(chatId, payload, requeues + 1);
|
|
2557
2614
|
}
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
sid = v.id;
|
|
2561
|
-
tgChats.set(chatId, sid);
|
|
2562
|
-
tgRememberSession(chatId, sid);
|
|
2563
|
-
saveTgChats();
|
|
2564
|
-
} else {
|
|
2565
|
-
tgRememberSession(chatId, sid);
|
|
2566
|
-
}
|
|
2615
|
+
/* KANAL TEK OTURUMU: eskisi silinmedikçe hep aynı oturumdan devam */
|
|
2616
|
+
sid = ensureTgSession(chatId);
|
|
2567
2617
|
/* Kişi bazlı granül izin: all/web/read/chat */
|
|
2568
2618
|
let perm = hit.perm || (hit.lockdown ? 'chat' : 'all');
|
|
2569
2619
|
engine.setSessionPerm(sid, perm);
|
|
@@ -2686,6 +2736,8 @@ function dcFind(senderId, username) {
|
|
|
2686
2736
|
if (Array.isArray(arr)) dcHistory.set(c, arr.filter((x) => typeof x === 'string').slice(-DC_HISTORY_CAP));
|
|
2687
2737
|
}
|
|
2688
2738
|
}
|
|
2739
|
+
/* kanal tek oturumu: kayıtlı aktif id (geçersizse ensure yeniden seçer) */
|
|
2740
|
+
if (raw && typeof raw.active === 'string' && raw.active) dcSingleSid = raw.active;
|
|
2689
2741
|
for (const [c, s] of dcChats.entries()) {
|
|
2690
2742
|
const h = dcHistory.get(c) || [];
|
|
2691
2743
|
if (!h.includes(s)) h.push(s);
|
|
@@ -2701,6 +2753,7 @@ function saveDcChats() {
|
|
|
2701
2753
|
JSON.stringify({
|
|
2702
2754
|
chats: Object.fromEntries(dcChats),
|
|
2703
2755
|
history: Object.fromEntries([...dcHistory.entries()].map(([c, a]) => [c, a.slice(-DC_HISTORY_CAP)])),
|
|
2756
|
+
active: dcSingleSid || '',
|
|
2704
2757
|
})
|
|
2705
2758
|
);
|
|
2706
2759
|
} catch {}
|
|
@@ -2767,21 +2820,14 @@ async function processDcMessage(channelId, payload) {
|
|
|
2767
2820
|
dcLog(`skip flush: izinli eşleşme yok (sender=${payload.senderId || '?'})`);
|
|
2768
2821
|
return;
|
|
2769
2822
|
}
|
|
2770
|
-
let sid = dcChats.get(channelId);
|
|
2823
|
+
let sid = dcChats.get(channelId) || dcSingleSid;
|
|
2771
2824
|
if (sid && engine.isBusy(sid)) {
|
|
2772
2825
|
/* oturum meşgul — WA/TG ile aynı: kaybetme, iş bitene dek yeniden dene */
|
|
2773
2826
|
await new Promise((r) => setTimeout(r, DC_DEBOUNCE_MS));
|
|
2774
2827
|
return processDcMessage(channelId, payload, 1);
|
|
2775
2828
|
}
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
sid = v.id;
|
|
2779
|
-
dcChats.set(channelId, sid);
|
|
2780
|
-
dcRememberSession(channelId, sid);
|
|
2781
|
-
saveDcChats();
|
|
2782
|
-
} else {
|
|
2783
|
-
dcRememberSession(channelId, sid);
|
|
2784
|
-
}
|
|
2829
|
+
/* KANAL TEK OTURUMU: eskisi silinmedikçe hep aynı oturumdan devam */
|
|
2830
|
+
sid = ensureDcSession(channelId);
|
|
2785
2831
|
/* Kişi bazlı granül izin: all/web/read/chat */
|
|
2786
2832
|
let perm = hit.perm || (hit.lockdown ? 'chat' : 'all');
|
|
2787
2833
|
engine.setSessionPerm(sid, perm);
|
|
@@ -3430,6 +3476,11 @@ function browserW() {
|
|
|
3430
3476
|
try { return win.getContentSize()[0]; } catch { return 0; }
|
|
3431
3477
|
}
|
|
3432
3478
|
|
|
3479
|
+
/* Tarayıcı gizleme ÖZELLİĞİ: Ayarlar → Web Arama'dan açılır, VARSAYILAN KAPALI.
|
|
3480
|
+
Kapalıyken tarayıcı her zaman görünür; açıkken göz ikonu gizle/göster yapar. */
|
|
3481
|
+
function browserHideEnabled() { return settings.browserHide === true; }
|
|
3482
|
+
function browserHeadlessPref() { return browserHideEnabled() && settings.browserHeadless === true; }
|
|
3483
|
+
|
|
3433
3484
|
function browserShownWidth(w) {
|
|
3434
3485
|
const avail = Math.max(320, w - 320);
|
|
3435
3486
|
/* MOBİL ÖNİZLEME: siluet + çerçeve payı — siluet tam otursun (phone-mode'dan önce) */
|
|
@@ -3708,12 +3759,13 @@ function setBrowserOpen(v, forceVisible) {
|
|
|
3708
3759
|
}
|
|
3709
3760
|
|
|
3710
3761
|
// AÇMA — görünürlük: forceVisible true/false ise onu uygula;
|
|
3711
|
-
// belirtilmemişse kullanıcı tercihi
|
|
3762
|
+
// belirtilmemişse kullanıcı tercihi belirler. Tarayıcı gizleme ÖZELLİĞİ
|
|
3763
|
+
// (settings.browserHide) kapalıysa tercih ne olursa olsun tarayıcı GÖRÜNÜR açılır.
|
|
3712
3764
|
// PARALEL AJANLAR (bg oturum) her zaman forceVisible=false ile çağırır →
|
|
3713
3765
|
// tarayıcı gizli modda çalışır, kullanıcı ekranı ve ajan konsolu rahatsız edilmez.
|
|
3714
3766
|
browser.open = true;
|
|
3715
3767
|
browser.visible =
|
|
3716
|
-
forceVisible === true ? true : forceVisible === false ? false :
|
|
3768
|
+
forceVisible === true ? true : forceVisible === false ? false : !browserHeadlessPref();
|
|
3717
3769
|
ensureBrowser();
|
|
3718
3770
|
if (!browser.started) {
|
|
3719
3771
|
browser.started = true;
|
|
@@ -4614,7 +4666,7 @@ function resyncBrowserUi() {
|
|
|
4614
4666
|
layoutBrowser(); resyncBrowserUi();
|
|
4615
4667
|
setTimeout(() => { try { layoutBrowser(); resyncBrowserUi(); } catch {} }, 80);
|
|
4616
4668
|
setTimeout(() => { try { layoutBrowser(); resyncBrowserUi(); } catch {} }, 300);
|
|
4617
|
-
});
|
|
4669
|
+
});
|
|
4618
4670
|
win.on('show', layoutBrowser);
|
|
4619
4671
|
// X'e basınca gizle — tepside yaşamaya devam, WhatsApp bağlantısı sürer
|
|
4620
4672
|
win.on('close', (e) => {
|
|
@@ -6330,13 +6382,19 @@ function empatiLlmCompose(prompt) {
|
|
|
6330
6382
|
const PROACTIVE_MARK = '🫡 *Beast proaktif:*';
|
|
6331
6383
|
|
|
6332
6384
|
/* bildirimin ALTINA YAZILAN KAYNAK: haberin gerçek linki varsa o, yoksa kaynak adı.
|
|
6333
|
-
Kullanıcı "bu proje neymiş?" diye sorduğunda linkten bulabilsin.
|
|
6385
|
+
Kullanıcı "bu proje neymiş?" diye sorduğunda linkten bulabilsin.
|
|
6386
|
+
TEK SATIR kuralı: satır sonu/boşluklar temizlenir, uzunsa sona "..." gelir. */
|
|
6334
6387
|
function empatiSourceLine(ev) {
|
|
6335
6388
|
if (!ev) return '';
|
|
6336
|
-
const
|
|
6337
|
-
|
|
6338
|
-
const
|
|
6339
|
-
|
|
6389
|
+
const oneLine = (s) =>
|
|
6390
|
+
String(s || '').replace(/\s*\n+\s*/g, ' ').replace(/\s{2,}/g, ' ').trim();
|
|
6391
|
+
const ELLIPSIS = '...';
|
|
6392
|
+
const cap = (s, max) =>
|
|
6393
|
+
oneLine(s).length > max ? oneLine(s).slice(0, max - ELLIPSIS.length) + ELLIPSIS : oneLine(s);
|
|
6394
|
+
const url = oneLine(ev.url);
|
|
6395
|
+
if (/^https?:\/\//i.test(url)) return '🔗 ' + cap(url, 100);
|
|
6396
|
+
const src = oneLine(ev.source);
|
|
6397
|
+
return src ? '🔗 kaynak: ' + cap(src, 80) : '';
|
|
6340
6398
|
}
|
|
6341
6399
|
|
|
6342
6400
|
function empatiInjectToSession(sid, out) {
|
|
@@ -6360,28 +6418,74 @@ function empatiInjectText(ev, out) {
|
|
|
6360
6418
|
);
|
|
6361
6419
|
}
|
|
6362
6420
|
|
|
6363
|
-
/*
|
|
6421
|
+
/* kanalın yaşayan tek oturumu (WA kuralının aynısı — Telegram/Discord) */
|
|
6364
6422
|
function ensureTgSession(chatId) {
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6423
|
+
if (!tgSingleSid || !sessionFileAlive(tgSingleSid)) {
|
|
6424
|
+
let best = '';
|
|
6425
|
+
let bestTs = '';
|
|
6426
|
+
for (const c of new Set([...tgChats.values(), tgSingleSid])) {
|
|
6427
|
+
if (!c || !sessionFileAlive(c)) continue;
|
|
6428
|
+
let ts = '';
|
|
6429
|
+
try {
|
|
6430
|
+
const s = engine.cache.get(c) || engine._load(c);
|
|
6431
|
+
ts = String((s && s.updatedAt) || '');
|
|
6432
|
+
} catch {}
|
|
6433
|
+
if (!best || ts > bestTs) {
|
|
6434
|
+
best = c;
|
|
6435
|
+
bestTs = ts;
|
|
6436
|
+
}
|
|
6437
|
+
}
|
|
6438
|
+
tgSingleSid = best || engine.createSession().id;
|
|
6371
6439
|
saveTgChats();
|
|
6372
6440
|
}
|
|
6373
|
-
|
|
6441
|
+
let dirty = false;
|
|
6442
|
+
for (const [c, s] of tgChats.entries()) {
|
|
6443
|
+
if (s !== tgSingleSid) {
|
|
6444
|
+
tgChats.set(c, tgSingleSid);
|
|
6445
|
+
dirty = true;
|
|
6446
|
+
}
|
|
6447
|
+
}
|
|
6448
|
+
if (chatId != null && tgChats.get(String(chatId)) !== tgSingleSid) {
|
|
6449
|
+
tgChats.set(String(chatId), tgSingleSid);
|
|
6450
|
+
dirty = true;
|
|
6451
|
+
}
|
|
6452
|
+
tgRememberSession(String(chatId), tgSingleSid);
|
|
6453
|
+
if (dirty) saveTgChats();
|
|
6454
|
+
return tgSingleSid;
|
|
6374
6455
|
}
|
|
6375
6456
|
function ensureDcSession(channelId) {
|
|
6376
|
-
|
|
6377
|
-
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6457
|
+
if (!dcSingleSid || !sessionFileAlive(dcSingleSid)) {
|
|
6458
|
+
let best = '';
|
|
6459
|
+
let bestTs = '';
|
|
6460
|
+
for (const c of new Set([...dcChats.values(), dcSingleSid])) {
|
|
6461
|
+
if (!c || !sessionFileAlive(c)) continue;
|
|
6462
|
+
let ts = '';
|
|
6463
|
+
try {
|
|
6464
|
+
const s = engine.cache.get(c) || engine._load(c);
|
|
6465
|
+
ts = String((s && s.updatedAt) || '');
|
|
6466
|
+
} catch {}
|
|
6467
|
+
if (!best || ts > bestTs) {
|
|
6468
|
+
best = c;
|
|
6469
|
+
bestTs = ts;
|
|
6470
|
+
}
|
|
6471
|
+
}
|
|
6472
|
+
dcSingleSid = best || engine.createSession().id;
|
|
6382
6473
|
saveDcChats();
|
|
6383
6474
|
}
|
|
6384
|
-
|
|
6475
|
+
let dirty = false;
|
|
6476
|
+
for (const [c, s] of dcChats.entries()) {
|
|
6477
|
+
if (s !== dcSingleSid) {
|
|
6478
|
+
dcChats.set(c, dcSingleSid);
|
|
6479
|
+
dirty = true;
|
|
6480
|
+
}
|
|
6481
|
+
}
|
|
6482
|
+
if (channelId != null && dcChats.get(String(channelId)) !== dcSingleSid) {
|
|
6483
|
+
dcChats.set(String(channelId), dcSingleSid);
|
|
6484
|
+
dirty = true;
|
|
6485
|
+
}
|
|
6486
|
+
dcRememberSession(String(channelId), dcSingleSid);
|
|
6487
|
+
if (dirty) saveDcChats();
|
|
6488
|
+
return dcSingleSid;
|
|
6385
6489
|
}
|
|
6386
6490
|
|
|
6387
6491
|
/* Masaüstü yedeği: en güncel (bg/bot-DM'siz, meşgul olmayan) sohbet — yoksa yeni */
|
|
@@ -6601,9 +6705,11 @@ ipcMain.handle('browser:toggle', () => {
|
|
|
6601
6705
|
setBrowserOpen(!browser.open, true);
|
|
6602
6706
|
return { open: browser.open, visible: browser.visible };
|
|
6603
6707
|
});
|
|
6604
|
-
/* göz ikonu: ajan tarayıcısını görünür/gizli yap
|
|
6605
|
-
|
|
6708
|
+
/* göz ikonu: ajan tarayıcısını görünür/gizli yap — yalnızca gizleme özelliği
|
|
6709
|
+
(Ayarlar → Web Arama) açıkken etkilidir; özellik kapalıysa hep görünür */
|
|
6710
|
+
ipcMain.handle('browser:shown:get', () => ({ shown: !browserHeadlessPref(), enabled: browserHideEnabled() }));
|
|
6606
6711
|
ipcMain.handle('browser:shown:set', (_e, v) => {
|
|
6712
|
+
if (!browserHideEnabled()) return { shown: true, enabled: false };
|
|
6607
6713
|
settings.browserHeadless = !v;
|
|
6608
6714
|
saveSettings();
|
|
6609
6715
|
if (browser.open) {
|
|
@@ -6611,7 +6717,22 @@ ipcMain.handle('browser:shown:set', (_e, v) => {
|
|
|
6611
6717
|
layoutBrowser();
|
|
6612
6718
|
browserEmit({ open: true, width: browserShownWidth(browserW()) });
|
|
6613
6719
|
}
|
|
6614
|
-
return { shown: !!v };
|
|
6720
|
+
return { shown: !!v, enabled: true };
|
|
6721
|
+
});
|
|
6722
|
+
/* gizleme özelliği anahtarı: kapalıyken göz ikonu yok + tarayıcı zorla görünür */
|
|
6723
|
+
ipcMain.handle('browser:hide:set', (_e, v) => {
|
|
6724
|
+
settings.browserHide = !!v;
|
|
6725
|
+
if (settings.browserHide) {
|
|
6726
|
+
/* özellik yeni açıldı → görünür başla, kullanıcı gözle istediğinde gizler */
|
|
6727
|
+
settings.browserHeadless = false;
|
|
6728
|
+
}
|
|
6729
|
+
saveSettings();
|
|
6730
|
+
if (!browserHideEnabled() && browser.open) {
|
|
6731
|
+
browser.visible = true;
|
|
6732
|
+
layoutBrowser();
|
|
6733
|
+
browserEmit({ open: true, width: browserShownWidth(browserW()) });
|
|
6734
|
+
}
|
|
6735
|
+
return { enabled: browserHideEnabled(), shown: !browserHeadlessPref() };
|
|
6615
6736
|
});
|
|
6616
6737
|
ipcMain.handle('browser:navigate', (_e, url) => browserNavigate(url));
|
|
6617
6738
|
ipcMain.handle('browser:ctrl', (_e, action) => {
|
package/src/preload.js
CHANGED
|
@@ -73,6 +73,7 @@ contextBridge.exposeInMainWorld('beast', {
|
|
|
73
73
|
toggleBrowser: () => ipcRenderer.invoke('browser:toggle'),
|
|
74
74
|
browserShownGet: () => ipcRenderer.invoke('browser:shown:get'),
|
|
75
75
|
browserShownSet: (v) => ipcRenderer.invoke('browser:shown:set', v),
|
|
76
|
+
browserHideSet: (v) => ipcRenderer.invoke('browser:hide:set', v),
|
|
76
77
|
terminalToggle: () => ipcRenderer.invoke('terminal:toggle'),
|
|
77
78
|
terminalRun: (cmd, shell) => ipcRenderer.invoke('terminal:run', { cmd, shell }),
|
|
78
79
|
terminalStop: () => ipcRenderer.invoke('terminal:stop'),
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/* Beast App webview köprüsü: app UI'ları (file://) contextBridge üzerinden
|
|
4
|
+
window.beastApp API'sini görür. App kimliği webview src'sindeki ?appid=
|
|
5
|
+
parametresinden okunur; main tarafı id'yi yeniden doğrular. */
|
|
6
|
+
|
|
7
|
+
const { contextBridge, ipcRenderer } = require('electron');
|
|
8
|
+
|
|
9
|
+
let appId = '';
|
|
10
|
+
try {
|
|
11
|
+
appId = String(new URLSearchParams(window.location.search).get('appid') || '');
|
|
12
|
+
} catch {}
|
|
13
|
+
|
|
14
|
+
contextBridge.exposeInMainWorld('beastApp', {
|
|
15
|
+
id: appId,
|
|
16
|
+
storageGet: (key, dflt) => ipcRenderer.invoke('appui:storage:get', { appId, key, dflt }),
|
|
17
|
+
storageSet: (key, value) => ipcRenderer.invoke('appui:storage:set', { appId, key, value }),
|
|
18
|
+
notify: (text) => ipcRenderer.invoke('appui:notify', { appId, text }),
|
|
19
|
+
info: () => ipcRenderer.invoke('appui:info', appId),
|
|
20
|
+
});
|
package/src/renderer/i18n.js
CHANGED
|
@@ -311,7 +311,6 @@
|
|
|
311
311
|
ev_price_ph: 'Fiyat sembolü (örn PAXGUSDT)',
|
|
312
312
|
ev_save: 'Kaydet',
|
|
313
313
|
ev_price_sub: 'boş sembol = fiyat feed kapalı (Binance miniTicker)',
|
|
314
|
-
ev_token_copy: 'token kopyala',
|
|
315
314
|
ev_subs_h3: 'Aktif Abonelikler',
|
|
316
315
|
ev_no_sub: 'Abonelik yok — agent\u2019a "mail gelince haber ver" ya da "fiyat X altına inerse bağır" de, kendisi kurar.',
|
|
317
316
|
ev_on_toast: 'Olay merkezi açık',
|
|
@@ -354,6 +353,11 @@
|
|
|
354
353
|
so_engine_searxng: 'SearXNG (yerel — beast searxng)',
|
|
355
354
|
so_engine_python: 'Python Çoklu-Motor (ddgs/DDG/Bing/Mojeek)',
|
|
356
355
|
so_saved_toast: 'Arama sırası kaydedildi',
|
|
356
|
+
bh_h2: 'Tarayıcı Gizleme',
|
|
357
|
+
bh_sub: 'Ajan aramalarını görünür panel yerine gizli pencerede çalıştırır. Açıkken üst çubukta göz ikonu çıkar — göz açıkken aramalar panelde izlenir, kapalıyken gizli çalışır.',
|
|
358
|
+
bh_label: 'Tarayıcı gizleme özelliği',
|
|
359
|
+
bh_on_toast: 'Tarayıcı gizleme açık — göz ikonu üst çubukta',
|
|
360
|
+
bh_off_toast: 'Tarayıcı gizleme kapandı — tarayıcı her zaman görünür',
|
|
357
361
|
ws_save: 'Kaydet',
|
|
358
362
|
ws_clear: 'Anahtarı Sil',
|
|
359
363
|
ws_note: 'Anahtar maskeli tutulur; yenisini yazıp kaydettiğinde eskisinin yerine geçer. Boş kaydet: mevcut anahtar korunur.',
|
|
@@ -936,7 +940,6 @@
|
|
|
936
940
|
ev_price_ph: 'Price symbol (e.g. PAXGUSDT)',
|
|
937
941
|
ev_save: 'Save',
|
|
938
942
|
ev_price_sub: 'empty symbol = price feed off (Binance miniTicker)',
|
|
939
|
-
ev_token_copy: 'copy token',
|
|
940
943
|
ev_subs_h3: 'Active Subscriptions',
|
|
941
944
|
ev_no_sub: 'No subscriptions — tell the agent "notify me on mail" or "shout if price drops below X" and it sets one up.',
|
|
942
945
|
ev_on_toast: 'Event center on',
|
|
@@ -979,6 +982,11 @@
|
|
|
979
982
|
so_engine_searxng: 'SearXNG (local — beast searxng)',
|
|
980
983
|
so_engine_python: 'Python Multi-Engine (ddgs/DDG/Bing/Mojeek)',
|
|
981
984
|
so_saved_toast: 'Search order saved',
|
|
985
|
+
bh_h2: 'Browser Hiding',
|
|
986
|
+
bh_sub: 'Run agent searches in a hidden window instead of the visible panel. When on, an eye icon appears in the top bar — eye open searches are watched in the panel, eye closed runs hidden.',
|
|
987
|
+
bh_label: 'Browser hiding feature',
|
|
988
|
+
bh_on_toast: 'Browser hiding on — eye icon in the top bar',
|
|
989
|
+
bh_off_toast: 'Browser hiding off — browser always visible',
|
|
982
990
|
ws_save: 'Save',
|
|
983
991
|
ws_clear: 'Delete Key',
|
|
984
992
|
ws_note: 'The key is kept masked; saving a new one replaces the old. Saving empty keeps the current key.',
|
package/src/renderer/index.html
CHANGED
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
<header id="topbar">
|
|
60
60
|
<span id="botChip" title="Aktif bot">🦁 Beast</span>
|
|
61
61
|
<div id="modelDD" class="dd">
|
|
62
|
-
<button id="modelBtn" class="dd-btn" title="Model seç" data-i18n-title="tipModel"><span id="modelBtnLabel">Model</span
|
|
62
|
+
<button id="modelBtn" class="dd-btn" title="Model seç" data-i18n-title="tipModel"><span id="modelBtnLabel">Model</span></button>
|
|
63
63
|
<div id="modelMenu" class="dd-menu" hidden>
|
|
64
64
|
<input id="modelFilter" class="dd-filter" placeholder="Model ara…" autocomplete="off" />
|
|
65
65
|
<div id="modelList" class="dd-list"></div>
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
<button id="cronBtn" class="dd-btn dd-icon-btn" title="Cron Görevler" data-i18n-title="tipCron">⏱︎</button>
|
|
88
88
|
<button id="termCBtn" class="dd-btn dd-icon-btn" title="CMD terminali" data-i18n-title="tipTermC">❯︎</button>
|
|
89
89
|
<button id="browserBtn" class="dd-btn dd-icon-btn" title="Dahili tarayıcı" data-i18n-title="tipBrowser">⧉</button>
|
|
90
|
-
<button id="eyeBtn" class="dd-btn dd-icon-btn" title="Ajan tarayıcısı görünür/gizli — göz açıkken aramalar panelde izlenir, kapalıyken gizli çalışır" data-i18n-title="tipEye"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/><line class="eye-slash" x1="4" y1="4" x2="20" y2="20"/></svg></button>
|
|
90
|
+
<button id="eyeBtn" class="dd-btn dd-icon-btn" hidden title="Ajan tarayıcısı görünür/gizli — göz açıkken aramalar panelde izlenir, kapalıyken gizli çalışır" data-i18n-title="tipEye"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/><line class="eye-slash" x1="4" y1="4" x2="20" y2="20"/></svg></button>
|
|
91
91
|
<div class="drag-spacer"></div>
|
|
92
92
|
<div class="win-controls" id="winControls">
|
|
93
93
|
<button id="winMin" title="Simge durumunda küçült" data-i18n-title="tip_win_min">─︎</button>
|