beast-agent 2.44.7 → 2.44.8

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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/src/cron.js +14 -4
  3. package/src/main.js +99 -57
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "beast-agent",
3
3
  "productName": "Beast Agent",
4
- "version": "2.44.7",
4
+ "version": "2.44.8",
5
5
  "description": "Ultra-fast local agent shell for Windows.",
6
6
  "author": "algokodcom (AlgoKod)",
7
7
  "license": "MIT",
package/src/cron.js CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  /* Beast cron: zamanlanmış görevler (%APPDATA%\beast\cron.json).
4
4
  5 alanlı cron ifadeleri: dakika saat ayGunu ay haftaGunu
5
- Desteklenen sözdizimi: * , - / sayılar. Saat geldiğinde onFire tetiklenir. */
5
+ Desteklenen sözdizimi: * , - / sayılar. Saat geldiğinde onFire tetiklenir.
6
+ DİKKAT: görevler OTURUMA BAĞLI DEĞİLDİR — sessionId/oturum kodu tutulmaz;
7
+ çalıştırma ve teslimat her kanalın TEK oturumu üzerinden yapılır (main). */
6
8
 
7
9
  const fs = require('fs');
8
10
  const path = require('path');
@@ -24,6 +26,14 @@ function load() {
24
26
  try {
25
27
  const raw = JSON.parse(fs.readFileSync(file(), 'utf8'));
26
28
  jobs = Array.isArray(raw.jobs) ? raw.jobs : [];
29
+ /* ESKİ KAYIT GÖÇÜ: görevler artık oturuma bağlı değil — eski sessionId
30
+ (ve varsa oturum kodu) diskte kalırsa görev yanlışlıkla bir oturuma
31
+ çakılı sanılır; yükleme sırasında temizlenir. */
32
+ for (const j of jobs) {
33
+ if (!j || typeof j !== 'object') continue;
34
+ delete j.sessionId;
35
+ delete j.sessionCode;
36
+ }
27
37
  } catch {
28
38
  jobs = [];
29
39
  }
@@ -136,7 +146,7 @@ function list() {
136
146
  return jobs.map((j) => ({ ...j }));
137
147
  }
138
148
 
139
- function add({ name, schedule, prompt, once, sessionId, kind }) {
149
+ function add({ name, schedule, prompt, once, kind }) {
140
150
  const n = String(name || '').trim().slice(0, 80) || 'Görev';
141
151
  const s = String(schedule || '').trim();
142
152
  const p = String(prompt || '').trim().slice(0, 4000);
@@ -148,7 +158,6 @@ function add({ name, schedule, prompt, once, sessionId, kind }) {
148
158
  name: n,
149
159
  schedule: s,
150
160
  prompt: p,
151
- sessionId: sessionId || null,
152
161
  once: !!once,
153
162
  enabled: true,
154
163
  ...(k ? { kind: k } : {}),
@@ -164,7 +173,8 @@ function add({ name, schedule, prompt, once, sessionId, kind }) {
164
173
  function update(id, patch) {
165
174
  const job = jobs.find((j) => j.id === id);
166
175
  if (!job) return { ok: false, error: 'görev bulunamadı' };
167
- if (patch.sessionId !== undefined) job.sessionId = patch.sessionId;
176
+ delete job.sessionId;
177
+ delete job.sessionCode;
168
178
  if (patch.name !== undefined) job.name = String(patch.name).trim().slice(0, 80) || job.name;
169
179
  if (patch.prompt !== undefined) {
170
180
  const p = String(patch.prompt).trim().slice(0, 4000);
package/src/main.js CHANGED
@@ -1944,7 +1944,8 @@ function ensureWaSession(jid) {
1944
1944
  waChats.set(String(jid), waSingleSid);
1945
1945
  dirty = true;
1946
1946
  }
1947
- waRememberSession(String(jid), waSingleSid);
1947
+ /* jid'siz çağrı (cron taban oturumu) sohbet geçmişini kirletmez */
1948
+ if (jid != null) waRememberSession(String(jid), waSingleSid);
1948
1949
  if (dirty) {
1949
1950
  saveWaChats();
1950
1951
  if (wa) wa.setWatchJids([...waChats.keys()]);
@@ -2194,7 +2195,6 @@ function scheduleReminder({ when, message, sessionId, repeat }) {
2194
2195
  schedule: s.schedule,
2195
2196
  prompt: `[TEKRARLI HATIRLATMA] Kullanıcıya şunu hatırlat: "${msg}". Kısaca ve nazikçe bildir.`,
2196
2197
  kind: 'reminder',
2197
- sessionId: sessionId || undefined,
2198
2198
  });
2199
2199
  if (!r.ok) return r;
2200
2200
  waLog(`tekrarlı hatırlatma kuruldu id=${r.job.id} schedule=${s.schedule} sid=${sessionId || '-'}`);
@@ -2210,7 +2210,6 @@ function scheduleReminder({ when, message, sessionId, repeat }) {
2210
2210
  prompt: `[HATIRLATMA ZAMANI] Kullanıcıya şunu hatırlat: "${msg}". Kısaca ve nazikçe bildir.`,
2211
2211
  kind: 'reminder',
2212
2212
  once: true,
2213
- sessionId: sessionId || undefined,
2214
2213
  });
2215
2214
  if (!r.ok) return r;
2216
2215
  waLog(`reminder kuruldu id=${r.job.id} at=${d.toISOString()} sid=${sessionId || '-'}`);
@@ -3357,8 +3356,14 @@ function reloadBackend() {
3357
3356
  });
3358
3357
  } catch {}
3359
3358
  }
3359
+ /* CRON CEVABI AYRIMI: bu done/error cron işine aitse bekleme kaydını
3360
+ BURADA düş. Cron cevabı normal kanal akışından DEĞİL, aşağıdaki tek
3361
+ noktadan TÜM bağlı entegrasyonlara (WA base + TG + DC) yansıtılır —
3362
+ böylece ham cevap + önekli cevap çift gönderimi olmaz. */
3363
+ const cjob =
3364
+ ev.type === 'done' || ev.type === 'error' ? cronAnswerPendingTake(ev.sessionId) : null;
3360
3365
  // WhatsApp oturumlarının son cevabını geri gönder (metin + opsiyonel ses)
3361
- if ((ev.type === 'done' || ev.type === 'error') && wa && wa.connected) {
3366
+ if ((ev.type === 'done' || ev.type === 'error') && !cjob && wa && wa.connected) {
3362
3367
  const wajid = waReplyJid(ev.sessionId);
3363
3368
  if (wajid) {
3364
3369
  (async () => {
@@ -3417,7 +3422,7 @@ function reloadBackend() {
3417
3422
  }
3418
3423
  }
3419
3424
  // Telegram oturumlarının son cevabını geri gönder (WA ile aynı akış)
3420
- if ((ev.type === 'done' || ev.type === 'error') && tg && tg.connected) {
3425
+ if ((ev.type === 'done' || ev.type === 'error') && !cjob && tg && tg.connected) {
3421
3426
  const hitT = [...tgChats.entries()].find(([, s]) => s === ev.sessionId);
3422
3427
  if (hitT) {
3423
3428
  const tgid = hitT[0];
@@ -3438,7 +3443,7 @@ function reloadBackend() {
3438
3443
  }
3439
3444
  }
3440
3445
  // Discord oturumlarının son cevabını geri gönder (TG ile aynı akış)
3441
- if ((ev.type === 'done' || ev.type === 'error') && dc && dc.connected) {
3446
+ if ((ev.type === 'done' || ev.type === 'error') && !cjob && dc && dc.connected) {
3442
3447
  const hitD = [...dcChats.entries()].find(([, s]) => s === ev.sessionId);
3443
3448
  if (hitD) {
3444
3449
  const dchid = hitD[0];
@@ -3458,34 +3463,32 @@ function reloadBackend() {
3458
3463
  })();
3459
3464
  }
3460
3465
  }
3461
- /* CRON → TÜM AKTİF ENTEGRASYONLAR: cron işi bittiğinde cevap (ya da
3462
- hata) sahibin bağlı olduğu her kanala yansıtılır — WA + Telegram +
3463
- Discord. Aynı kanal hem cron oturumuna bağlıysa TEK cevap alır.
3464
- Bayat (TTL aşımı) bekleme kaydı Take ile düşer, yansıtılmaz. */
3465
- if (ev.type === 'done' || ev.type === 'error') {
3466
- const cjob = cronAnswerPendingTake(ev.sessionId);
3467
- if (cjob && !ev.aborted) {
3468
- (async () => {
3469
- try {
3470
- let txt = '';
3471
- if (ev.type === 'error') {
3472
- txt = '⚠️ [cron: ' + String((cjob && cjob.name) || 'görev') + ']\nHata: ' + String(ev.error || '').slice(0, 200);
3473
- } else {
3474
- const s = engine.openSession(ev.sessionId);
3475
- const lastA = [...s.messages].reverse().find((m) => m.role === 'assistant' && m.content);
3476
- txt = typeof (lastA && lastA.content) === 'string' ? lastA.content : '';
3477
- if (txt.trim()) txt = '⏰ [cron: ' + String((cjob && cjob.name) || 'görev') + ']\n' + txt;
3478
- }
3479
- if (!txt.trim()) return;
3480
- for (const m of cronMirrorTargets(String(ev.sessionId))) {
3481
- try { await m.send(txt); } catch {}
3482
- }
3483
- } catch {}
3484
- })();
3485
- }
3466
+ /* CRON → TÜM BAĞLI ENTEGRASYONLAR: cron işi bittiğinde cevap (ya da
3467
+ hata) WhatsApp (base) + Telegram + Discord'un hepsine yansıtılır.
3468
+ Yansıtma yalnız cron oturumunun KENDİ kanalına yapılmaz (orası ham
3469
+ cevabı normal akıştan alır). Bayat (TTL aşımı) kayıt Take ile
3470
+ düşer, yansıtılmaz. */
3471
+ if (cjob && !ev.aborted) {
3472
+ (async () => {
3473
+ try {
3474
+ let txt = '';
3475
+ if (ev.type === 'error') {
3476
+ txt = '⚠️ [cron: ' + String((cjob && cjob.name) || 'görev') + ']\nHata: ' + String(ev.error || '').slice(0, 200);
3477
+ } else {
3478
+ const s = engine.openSession(ev.sessionId);
3479
+ const lastA = [...s.messages].reverse().find((m) => m.role === 'assistant' && m.content);
3480
+ txt = typeof (lastA && lastA.content) === 'string' ? lastA.content : '';
3481
+ if (txt.trim()) txt = '⏰ [cron: ' + String((cjob && cjob.name) || 'görev') + ']\n' + txt;
3482
+ }
3483
+ if (!txt.trim()) return;
3484
+ for (const m of cronMirrorTargets(String(ev.sessionId))) {
3485
+ try { await m.send(txt); } catch {}
3486
+ }
3487
+ } catch {}
3488
+ })();
3486
3489
  }
3487
3490
  },
3488
- });
3491
+ });
3489
3492
  /* PANEL RUN köprüsü: ajanın panel_run aracı → ÇALIŞTIR panelindeki yönetilen
3490
3493
  süreç koşucusu (sandbox:run IPC ile aynı makine). */
3491
3494
  engine.sbRunHook = sbRunStartManaged;
@@ -6943,7 +6946,7 @@ function cronAnswerPendingTake(sid) {
6943
6946
  return job;
6944
6947
  }
6945
6948
 
6946
- /* OTOMATİK YENİ SOHBET YOK: cron/izleyici/fallout tetiklendiğinde oturum
6949
+ /* OTOMATİK YENİ SOHBET YOK: izleyici/fallout tetiklendiğinde oturum
6947
6950
  seçimi — kayıtlı id'nin DOSYASI hâlâ duruyorsa O, değilse EN GÜNCEL
6948
6951
  (meşgul olmayan) oturum kullanılır; hiç oturum yoksa (ilk kurulum) yeni
6949
6952
  açılır. Böylece soldaki sohbet geçmişine "+ Yeni Sohbet" olmadan hayalet
@@ -6951,7 +6954,7 @@ function cronAnswerPendingTake(sid) {
6951
6954
  DİKKAT: _load(id) silinmiş oturum için bile boş bir hayalet nesne
6952
6955
  üretip truthy döner — canlılık kontrolü MUTLAKA sessionFileAlive ile
6953
6956
  yapılır (ensureWa/Tg/DcSession ile aynı kural). Ayrıca meşgul oturuma
6954
- send() mesajı DÜŞÜRÜR (false döner, cron cevabı kaybolur) — o yüzden
6957
+ send() mesajı DÜŞÜRÜR (false döner, cevap kaybolur) — o yüzden
6955
6958
  meşgul oturumlar da atlanır. */
6956
6959
  function reuseOrLatestSession(preferredId) {
6957
6960
  const sid = String(preferredId || '');
@@ -6969,9 +6972,38 @@ function reuseOrLatestSession(preferredId) {
6969
6972
  return engine.createSession().id;
6970
6973
  }
6971
6974
 
6972
- /* Yansıtma hedefleri: bağlı WA (owner numarası), Telegram ve Discord
6973
- (owner işaretli kayıt; tek kayıt varsa o). Cron oturumunun KENDİ
6974
- kanalına yansıtmayız — cevabı zaten kendi akışından alır (çift yok). */
6975
+ /* CRON TABAN OTURUMU: cron işleri hiçbir oturuma/sessionId'ye BAĞLI DEĞİL.
6976
+ Her kanalın TEK oturumu vardır — taban sırası: bağlı WhatsApp → bağlı
6977
+ Telegram → bağlı Discord → en güncel masaüstü oturumu. WhatsApp
6978
+ kullanılmayan kurulumlarda cron altyapısı Telegram/Discord üzerinden
6979
+ yaşar; hiçbiri yoksa masaüstü sohbete düşer. */
6980
+ function cronBaseSession() {
6981
+ try {
6982
+ if (wa && wa.connected) {
6983
+ if (waSingleSid && sessionFileAlive(waSingleSid)) return waSingleSid;
6984
+ return ensureWaSession();
6985
+ }
6986
+ } catch {}
6987
+ try {
6988
+ if (tg && tg.connected) {
6989
+ if (tgSingleSid && sessionFileAlive(tgSingleSid)) return tgSingleSid;
6990
+ return ensureTgSession();
6991
+ }
6992
+ } catch {}
6993
+ try {
6994
+ if (dc && dc.connected) {
6995
+ if (dcSingleSid && sessionFileAlive(dcSingleSid)) return dcSingleSid;
6996
+ return ensureDcSession();
6997
+ }
6998
+ } catch {}
6999
+ return reuseOrLatestSession('');
7000
+ }
7001
+
7002
+ /* Yansıtma hedefleri: cron cevabı BAĞLI TÜM entegrasyonlara dağıtılır —
7003
+ WhatsApp (base) + Telegram + Discord. Her kanalın TEK oturumu vardır;
7004
+ hedef önce o oturuma bağlı sohbet, yoksa kayıtlı sahip/sahipleridir.
7005
+ Cron oturumunun KENDİ kanalına yansıtılmaz — cevabı zaten kendi normal
7006
+ akışından alır (çift gönderim olmaz). */
6975
7007
  function tgOwnerIds() {
6976
7008
  const list = settings.tgAllow || [];
6977
7009
  const objs = list.filter((e) => e && typeof e === 'object' && e.id && e.id !== '*');
@@ -6985,30 +7017,39 @@ function dcOwnerIds() {
6985
7017
  return owner ? [String(owner.id)] : [];
6986
7018
  }
6987
7019
  function cronMirrorTargets(cronSid) {
7020
+ const sid = String(cronSid || '');
6988
7021
  const out = [];
7022
+ /* WHATSAPP (base): normal akış cron oturumuna bağlı sohbete gönderir;
7023
+ bağlı sohbet yoksa (normal akış gönderemez) base sohbet/sahip numarası
7024
+ hedeflenir — cevap kaybolmaz. */
6989
7025
  try {
6990
- if (wa && wa.connected) {
7026
+ if (wa && wa.connected && !waReplyJid(sid)) {
6991
7027
  const own = waOwnerNum();
6992
- if (own) {
6993
- const jid = own + '@s.whatsapp.net';
6994
- const bound = [...waChats.entries()].some(([j, s]) => j === jid && String(s) === String(cronSid));
6995
- if (!bound) out.push({ kind: 'wa', send: (t) => sendWaSafe(jid, t) });
6996
- }
7028
+ const jid = waReplyJid(waSingleSid) || (own ? own + '@s.whatsapp.net' : '');
7029
+ if (jid) out.push({ kind: 'wa', send: (t) => sendWaSafe(jid, t) });
6997
7030
  }
6998
7031
  } catch {}
7032
+ /* TELEGRAM: normal akış cron oturumuna bağlı sohbete gönderir; o yoksa
7033
+ kanalın tek oturumuna bağlı sohbet(ler), yoksa sahip kaydı hedeflenir */
6999
7034
  try {
7000
- if (tg && tg.connected) {
7001
- for (const id of tgOwnerIds()) {
7002
- const bound = [...tgChats.entries()].some(([c, s]) => String(c) === String(id) && String(s) === String(cronSid));
7003
- if (!bound) out.push({ kind: 'tg', send: (t) => sendTgSafe(id, t) });
7035
+ if (tg && tg.connected && ![...tgChats.values()].some((s) => String(s) === sid)) {
7036
+ const bound = [...tgChats.entries()]
7037
+ .filter(([, s]) => String(s) === String(tgSingleSid))
7038
+ .map(([c]) => c);
7039
+ for (const id of (bound.length ? bound : tgOwnerIds())) {
7040
+ out.push({ kind: 'tg', send: (t) => sendTgSafe(id, t) });
7004
7041
  }
7005
7042
  }
7006
7043
  } catch {}
7044
+ /* DISCORD: normal akış cron oturumuna bağlı kanala gönderir; o yoksa
7045
+ kanalın tek oturumuna bağlı kanal(lar), yoksa sahip kaydı hedeflenir */
7007
7046
  try {
7008
- if (dc && dc.connected) {
7009
- for (const id of dcOwnerIds()) {
7010
- const bound = [...dcChats.entries()].some(([c, s]) => String(c) === String(id) && String(s) === String(cronSid));
7011
- if (!bound) out.push({ kind: 'dc', send: (t) => sendDcSafe(id, t) });
7047
+ if (dc && dc.connected && ![...dcChats.values()].some((s) => String(s) === sid)) {
7048
+ const bound = [...dcChats.entries()]
7049
+ .filter(([, s]) => String(s) === String(dcSingleSid))
7050
+ .map(([c]) => c);
7051
+ for (const id of (bound.length ? bound : dcOwnerIds())) {
7052
+ out.push({ kind: 'dc', send: (t) => sendDcSafe(id, t) });
7012
7053
  }
7013
7054
  }
7014
7055
  } catch {}
@@ -7023,10 +7064,9 @@ function cronFire(job) {
7023
7064
  return;
7024
7065
  }
7025
7066
  try {
7026
- const sid = reuseOrLatestSession(job.sessionId);
7027
- if (sid !== String(job.sessionId || '')) {
7028
- cron.update(job.id, { sessionId: sid });
7029
- }
7067
+ /* OTURUMSUZ ÇALIŞTIRMA: taban oturum WA → TG → DC → masaüstü sırasıyla
7068
+ seçilir; cevap done olayında TÜM bağlı entegrasyonlara yansıtılır. */
7069
+ const sid = cronBaseSession();
7030
7070
  cronAnswerPendingSet(sid, job);
7031
7071
  const sent = engine.send(sid, {
7032
7072
  text: `[cron: ${job.name}]\n${job.prompt}`,
@@ -7328,7 +7368,8 @@ function ensureTgSession(chatId) {
7328
7368
  tgChats.set(String(chatId), tgSingleSid);
7329
7369
  dirty = true;
7330
7370
  }
7331
- tgRememberSession(String(chatId), tgSingleSid);
7371
+ /* id'siz çağrı (cron taban oturumu) sohbet geçmişini kirletmez */
7372
+ if (chatId != null) tgRememberSession(String(chatId), tgSingleSid);
7332
7373
  if (dirty) saveTgChats();
7333
7374
  return tgSingleSid;
7334
7375
  }
@@ -7362,7 +7403,8 @@ function ensureDcSession(channelId) {
7362
7403
  dcChats.set(String(channelId), dcSingleSid);
7363
7404
  dirty = true;
7364
7405
  }
7365
- dcRememberSession(String(channelId), dcSingleSid);
7406
+ /* id'siz çağrı (cron taban oturumu) sohbet geçmişini kirletmez */
7407
+ if (channelId != null) dcRememberSession(String(channelId), dcSingleSid);
7366
7408
  if (dirty) saveDcChats();
7367
7409
  return dcSingleSid;
7368
7410
  }