beast-agent 2.39.0 → 2.41.0

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 (41) hide show
  1. package/package.json +1 -1
  2. package/src/agent/bots.js +2 -2
  3. package/src/agent/customtools.js +52 -2
  4. package/src/agent/defaulttools/mt5_barlar2/run.js +188 -0
  5. package/src/agent/defaulttools/mt5_barlar2/tool.json +23 -0
  6. package/src/agent/defaulttools/mt5_bekleyen/run.js +100 -0
  7. package/src/agent/defaulttools/mt5_bekleyen/tool.json +17 -0
  8. package/src/agent/defaulttools/mt5_durum/run.js +93 -0
  9. package/src/agent/defaulttools/mt5_durum/tool.json +10 -0
  10. package/src/agent/defaulttools/mt5_emir/run.js +98 -0
  11. package/src/agent/defaulttools/mt5_emir/tool.json +17 -0
  12. package/src/agent/defaulttools/mt5_emir_iptal/run.js +90 -0
  13. package/src/agent/defaulttools/mt5_emir_iptal/tool.json +12 -0
  14. package/src/agent/defaulttools/mt5_fiyat/run.js +87 -0
  15. package/src/agent/defaulttools/mt5_fiyat/tool.json +16 -0
  16. package/src/agent/defaulttools/mt5_gecmis/run.js +87 -0
  17. package/src/agent/defaulttools/mt5_gecmis/tool.json +12 -0
  18. package/src/agent/defaulttools/mt5_kapat/run.js +92 -0
  19. package/src/agent/defaulttools/mt5_kapat/tool.json +13 -0
  20. package/src/agent/defaulttools/mt5_m15_m5/m15m5.py +60 -0
  21. package/src/agent/defaulttools/mt5_m15_m5/run.js +73 -0
  22. package/src/agent/defaulttools/mt5_m15_m5/tool.json +10 -0
  23. package/src/agent/defaulttools/mt5_pozisyon_gecmis/run.js +144 -0
  24. package/src/agent/defaulttools/mt5_pozisyon_gecmis/tool.json +12 -0
  25. package/src/agent/defaulttools/mt5_shot/run.js +428 -0
  26. package/src/agent/defaulttools/mt5_shot/tool.json +20 -0
  27. package/src/agent/defaulttools/mt5_sltp/run.js +92 -0
  28. package/src/agent/defaulttools/mt5_sltp/tool.json +14 -0
  29. package/src/agent/engine.js +101 -16
  30. package/src/agent/financetools.js +1 -1
  31. package/src/agent/mt5/BeastFinance.mq5 +140 -3
  32. package/src/agent/mt5/BeastShot.tpl +0 -0
  33. package/src/agent/mt5setup.js +22 -0
  34. package/src/agent/opencode/agents.js +4 -3
  35. package/src/agent/seeds/mql5/SKILL.md +4 -2
  36. package/src/agent/tools.js +16 -0
  37. package/src/main.js +307 -39
  38. package/src/preload.js +6 -1
  39. package/src/renderer/index.html +6 -4
  40. package/src/renderer/renderer.js +115 -39
  41. package/src/renderer/style.css +27 -0
@@ -0,0 +1,92 @@
1
+ 'use strict';
2
+ // MT5 SL/TP GUNCELLE — stdin: JSON args · stdout: JSON sonuç
3
+ const { spawn } = require('child_process');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ /* TAŞINABİLİR YOL ÇÖZÜMÜ: Beast gömülü python → sistem python'ları → PATH.
8
+ Köprü dosyası %APPDATA%\beast\finance\mt5_bridge.py'den (veya BEAST_FINANCE_DIR)
9
+ okunur; ortam değişkenleriyle geçersiz kılınabilir. */
10
+ function resolvePython() {
11
+ const cands = [];
12
+ if (process.env.BEAST_PYTHON) cands.push({ exe: String(process.env.BEAST_PYTHON), args: [] });
13
+ if (process.env.APPDATA) cands.push({ exe: path.join(process.env.APPDATA, 'beast', 'py', 'python.exe'), args: [] });
14
+ for (const v of ['314', '313', '312', '311', '310']) cands.push({ exe: 'C:\\Python' + v + '\\python.exe', args: [] });
15
+ cands.push({ exe: 'python', args: [] }, { exe: 'py', args: ['-3'] });
16
+ for (const c of cands) {
17
+ if (c.exe === 'python' || c.exe === 'py') return c;
18
+ try { if (fs.existsSync(c.exe)) return c; } catch (e) {}
19
+ }
20
+ return { exe: 'python', args: [] };
21
+ }
22
+ function resolveBridge() {
23
+ const cands = [];
24
+ if (process.env.BEAST_BRIDGE) cands.push(String(process.env.BEAST_BRIDGE));
25
+ if (process.env.BEAST_FINANCE_DIR) cands.push(path.join(String(process.env.BEAST_FINANCE_DIR), 'mt5_bridge.py'));
26
+ if (process.env.APPDATA) cands.push(path.join(process.env.APPDATA, 'beast', 'finance', 'mt5_bridge.py'));
27
+ for (const p of cands) { try { if (p && fs.existsSync(p)) return p; } catch (e) {} }
28
+ return cands[0] || '';
29
+ }
30
+ const PYSPEC = resolvePython();
31
+ const PY = PYSPEC.exe;
32
+ const PY_ARGS = PYSPEC.args;
33
+ const BRIDGE = resolveBridge();
34
+
35
+ const TIMEOUT = 35000;
36
+
37
+ function call(requests) {
38
+ return new Promise((resolve) => {
39
+ let py;
40
+ try { py = spawn(PY, [...PY_ARGS, BRIDGE], { windowsHide: true, stdio: ['pipe', 'pipe', 'pipe'] }); }
41
+ catch (e) { return resolve({ ok: false, error: 'python baslatilamadi: ' + e.message }); }
42
+ const results = {};
43
+ let buf = '';
44
+ let errTail = '';
45
+ let settled = false;
46
+ const finish = (obj) => { if (!settled) { settled = true; clearTimeout(timer); try { py.kill(); } catch (e) {} resolve(obj); } };
47
+ const timer = setTimeout(() => finish({ ok: false, error: 'zaman asimi: MT5 terminali acik ve yanit veriyor mu?' }), TIMEOUT);
48
+ py.stdout.on('data', (d) => {
49
+ buf += d.toString('utf8');
50
+ let i;
51
+ while ((i = buf.indexOf('\n')) >= 0) {
52
+ const line = buf.slice(0, i).trim(); buf = buf.slice(i + 1);
53
+ if (!line) continue;
54
+ let o = null;
55
+ try { o = JSON.parse(line); } catch (e) { continue; }
56
+ if (o && o.event) continue;
57
+ if (o && typeof o.id === 'number' && Object.prototype.hasOwnProperty.call(o, 'ok')) {
58
+ results[o.id] = o;
59
+ if (Object.keys(results).length >= requests.length) {
60
+ const arr = requests.map((_, k) => results[k + 1]);
61
+ finish(arr.length === 1 ? arr[0] : { ok: true, results: arr });
62
+ }
63
+ }
64
+ }
65
+ });
66
+ py.stderr.on('data', (d) => { errTail = (errTail + d.toString('utf8')).slice(-800); });
67
+ py.on('error', (e) => finish({ ok: false, error: 'python baslatilamadi: ' + e.message }));
68
+ py.on('close', (code) => { if (Object.keys(results).length < requests.length) finish({ ok: false, error: 'bridge erken cikti code=' + code + ' ' + errTail }); });
69
+ requests.forEach((r, k) => py.stdin.write(JSON.stringify({ id: k + 1, method: r.method, params: r.params || {} }) + '\n'));
70
+ py.stdin.end();
71
+ });
72
+ }
73
+
74
+ (async function main() {
75
+ let args = {};
76
+ try { args = JSON.parse(fs.readFileSync(0, 'utf8') || '{}'); } catch (e) {}
77
+ const ticket = Number(args.ticket || 0);
78
+ if (!ticket) return console.log(JSON.stringify({ ok: false, error: 'ticket zorunlu' }));
79
+ if (args.sl === undefined && args.tp === undefined) return console.log(JSON.stringify({ ok: false, error: 'sl veya tp vermelisin' }));
80
+ const params = { ticket: ticket, sl: Number(args.sl || 0), tp: Number(args.tp || 0) };
81
+ const r = await call([{ method: 'modify', params: params }]);
82
+ if (r.ok && r.data && r.data.result) {
83
+ const res = r.data.result;
84
+ console.log(JSON.stringify({ ok: true, retcode: res.retcode, comment: res.comment, detay: r.data }));
85
+ } else {
86
+ console.log(JSON.stringify({ ok: false, error: r.error || 'SL/TP guncelleme reddedildi' }));
87
+ }
88
+ })();
89
+
90
+ /* PATCH 2026-09-10b: electron app-mode cocuk prosesi kapanmiyordu (90sn timeout).
91
+ stdout'un boruya bosalmasi icin kisa bekleme, sonra zorla cik. */
92
+ setTimeout(() => process.exit(0), 1500);
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "mt5_sltp",
3
+ "description": "Açık pozisyonun STOP LOSS / TAKE PROFIT seviyelerini günceller: ticket zorunlu, sl ve/veya tp verilir (0 = o seviyeyi kaldir). SL'siz pozisyon bırakmamak için risk yönetiminde kullanılır.",
4
+ "parameters": {
5
+ "type": "object",
6
+ "properties": {
7
+ "ticket": { "type": "number", "description": "Pozisyonun ticket numarasi" },
8
+ "sl": { "type": "number", "description": "Yeni stop loss fiyati (0 = kaldir)" },
9
+ "tp": { "type": "number", "description": "Yeni take profit fiyati (0 = kaldir)" }
10
+ },
11
+ "required": ["ticket"]
12
+ },
13
+ "updatedAt": "2026-09-09T18:48:00.000Z"
14
+ }
@@ -402,6 +402,7 @@ class Engine {
402
402
  if (nrBoot.unref) nrBoot.unref();
403
403
  skills.seedIfEmpty();
404
404
  agentdefs.seedIfEmpty();
405
+ try { customtools.seedDefaults(); } catch {} // varsayılan MT5 toolları (mt5_shot, mt5_barlar2, ...) — tüm oturumlara açılır
405
406
  }
406
407
 
407
408
  /* ---------- opencode agent.ts port: özel ajanlar ---------- */
@@ -1918,11 +1919,11 @@ class Engine {
1918
1919
  risk:
1919
1920
  'ROL: RİSK AJANI 🛡 — portföyün RİSK GÖZCÜSÜSÜN, İşlem AÇMAZSIN (mt5_trade/mt5_pending/mt5_close KULLANMA). Her turda: hesap + pozisyonlar + marj kullanımı → kaldıraç/exposure değerlendirmesi; SL\u2019siz pozisyon, limit aşımı, tek yönlü birikme, günlük kayıp hızı risklerini raporla; net düzeltme önerisi ver (hangi pozisyon küçültülmeli/kapatılmalı).',
1920
1921
  technic:
1921
- 'ROL: TEKNİK ANALİZ AJANI 📊 — fiyat yapısı uzmanısın, İşlem AÇMAZSIN (mt5_trade/mt5_pending/mt5_close KULLANMA). Her turda odak semboller için: trend/yapı, destek-direnç bölgeleri, momentum (mt5_market + mt5_history verisiyle); sembol başına AL/SAT/BEKLE + giriş/SL/TP fikri üret — trader bu öneriyi işleme çevirir.',
1922
+ 'ROL: TEKNİK ANALİZ AJANI 📊 — fiyat yapısı uzmanısın, İşlem AÇMAZSIN (mt5_trade/mt5_pending/mt5_close KULLANMA). Her turda odak semboller için: trend/yapı, destek-direnç bölgeleri, momentum (mt5_market + mt5_history verisiyle); sembol başına AL/SAT/BEKLE + giriş/SL/TP fikri üret — trader bu öneriyi işleme çevirir. Bulgularını mt5_ea action:"note" ile grafiğe ÇİZ (destek/direnç/SL/TP seviyeleri) ve tool__mt5_shot ile seviyelerin göründüğünü teyit et; önemli seviyeleri görselle birlikte agent_dm ile trader\'a/ekibe ilet — grafik üzerinde ortak karar alın.',
1922
1923
  macro:
1923
1924
  'ROL: MAKRO AJANI 🌍 — büyük resim uzmanısın, İşlem AÇMAZSIN (mt5_trade/mt5_pending/mt5_close KULLANMA). Her turda web_search ile güncel makro manşetleri + ekonomik takvim riskleri (faiz, CPI, jeopolitik); DXY/altın/petrol bağıntılarını odak sembollere çevir; sembol başına yön eğilimi + TEMKİN/BEKLE notu ver.',
1924
1925
  visual:
1925
- 'ROL: GÖRSEL ANALİZ AJANI 👁 — grafik/ekran görüntüsü uzmanısın, İşlem AÇMAZSIN (mt5_trade/mt5_pending/mt5_close KULLANMA). Her turda computer_look ile MT5 grafiğini yakala (gerekirse computer_act ile timeframe/zoom ayarla); web grafikleri için browser_open + browser_screenshot, görsel göremeyen metin-model isen ocr_read (source:"screen"/"browser") kullan. Gördüğün yapıyı yorumla: trend, formasyon, mum yapısı, destek-direnç ve SL/TP çizgileri; sembol başına GÖRSEL TEYİT + AL/SAT/BEKLE notu üret. Önemli bulguyu görseliyle birlikte agent_dm ile ANA TRADER\'a ya da ekibe bildir (yakaladığın grafiği paylaş).',
1926
+ 'ROL: GÖRSEL ANALİZ AJANI 👁 — grafik/ekran görüntüsü uzmanısın, İşlem AÇMAZSIN (mt5_trade/mt5_pending/mt5_close KULLANMA). MT5 grafiği için ÖNCE tool__mt5_shot kullan (BeastFinance EA "shot": gerçek grafik PNG + görsel SONRAKİ TURDA gözüne gelir; symbol/timeframe vererek başka sembol/periyot çekebilirsin; dönen path send_file ile gönderilebilir); gerekirse EA panosuna mt5_ea action:"note" ile plan/seviye yaz. web grafiklerinde browser_open + browser_screenshot; bilgisayar ekranı için computer_look; görsel göremeyen metin-model isen ocr_read (source:"screen"/"browser") kullan. Gördüğün yapıyı yorumla: trend, formasyon, mum yapısı, destek-direnç ve SL/TP çizgileri; sembol başına GÖRSEL TEYİT + AL/SAT/BEKLE notu üret. Önemli bulguyu GÖRSELİYLE paylaş: agent_dm image:true (son ekran görüntün) ya da image:"<mt5_shot path>" ile ANA TRADER\'a/ekibe gönder — karşı ajan görüntüyü GERÇEKTEN görür, AJAN DM panelinde açılır.',
1926
1927
  })[String((session && session.financeRole) || '')] || '';
1927
1928
  /* ROL → SKILL eşleştirmesi (ayarlar modalı): rol başına TEK ve ZORUNLU
1928
1929
  skill; ANA TRADER için ayrıca PLAYBOOK skill'i (roleSkills.trader).
@@ -1962,19 +1963,22 @@ class Engine {
1962
1963
  (roleBlockFull ? roleBlockFull + '\n' : '') +
1963
1964
  (teamLine || '') +
1964
1965
  'MT5 ARAÇLARI: mt5_status (bağlantı), mt5_account (hesap), mt5_market (canlı fiyat), mt5_positions (açık pozisyonlar), mt5_orders (bekleyen emirler), mt5_history (kapanan işlemler), mt5_ea (BeastFinance grafik panosu: status/ping/chart/note), mt5_trade (piyasa emri), mt5_close (kapat), mt5_modify (SL/TP), mt5_pending (bekleyen emir), mt5_cancel (emir iptal).\n' +
1965
- 'BEASTFINANCE EA (OTOMATİK GRAFİK UZMANI — ENTEGRASYON KANALI): MT5 terminaline bağlanıldığında BeastFinance uzman danışmanı İLK GRAFİĞE OTOMATİK yüklenir, AutoTrading izni açılır (kurulum sistem tarafından yapılır; elle ekleme gerekmez). Grafik panosu + seviye çizgileri + dosya köprüsü (beast_ea.json / beast_cmd.json / beast_note.json) bu EA üzerinden yürür: entegrasyon işlerinde (status/ping/chart/note) mt5_ea kullan; yazdığın not ve çizgiler computer_look screenshot\'ında görünür, entegrasyon bildirimleriyle birlikte çalışır.\n' +
1966
+ 'KİŞİSEL MT5 ARAÇLARI (VARSAYILAN KURULU — tool__* tüm oturumlarda çağrılabilir): tool__mt5_shot (grafikten GERÇEK PNG + görsel ajana enjekte — grafik işlerinde BİRİNCİL), tool__mt5_barlar2 (OHLC mumlar, köprüsüz), tool__mt5_m15_m5 (GOLD M15+M5 hazır paket), tool__mt5_fiyat, tool__mt5_durum (hesap+pozisyon+emir tek çağrı), tool__mt5_gecmis, tool__mt5_pozisyon_gecmis, tool__mt5_sltp, tool__mt5_kapat, tool__mt5_bekleyen, tool__mt5_emir, tool__mt5_emir_iptal.\n' +
1967
+ 'BEASTFINANCE EA (OTOMATİK GRAFİK UZMANI — ENTEGRASYON KANALI): MT5 terminaline bağlanıldığında BeastFinance uzman danışmanı İLK GRAFİĞE OTOMATİK yüklenir, AutoTrading izni açılır (kurulum sistem tarafından yapılır; elle ekleme gerekmez). Grafik panosu + seviye çizgileri + dosya köprüsü (beast_ea.json / beast_cmd.json / beast_note.json) bu EA üzerinden yürür: entegrasyon işlerinde (status/ping/chart/note) mt5_ea kullan; ekran görüntüsü işlerinde tool__mt5_shot ("shot" komutu — gerçek PNG + ajan görseli) birincildir. Yazdığın not ve çizgiler tool__mt5_shot ve computer_look screenshot\'ında GÖRÜNÜR.\n' +
1966
1968
  'YETKİLERİN (AÇIK — çekinmeden kullan):\n' +
1967
1969
  '- skill: kurulu SKILL.md kataloğunu oku ve uygula — tool yazmadan ÖNCE skill("tool-yazma"), MT5 tarafı işlerden ÖNCE skill("mql5") oku ve prosedürüne birebir uy.\n' +
1968
1970
  '- Kişisel tool yazma: %APPDATA%\\beast\\tools\\<slug>\\ içine tool.json + run.js yaz (write_file/edit_file); run_command ile çıktısını (JSON, ok alanlı) doğrula → tool__<slug> ANINDA tüm finance ajanlarında çağrılabilir olur.\n' +
1969
1971
  '- MQL5: MT5 tarafında script/gösterge/EA yaz (write_file), metaeditor64.exe /compile ile derle, MQL5\\Files dosya köprüsüyle veriyi Beast\'e taşı; kullanıcıya çalıştırma adımını açıkça söyle.\n' +
1970
1972
  '- Yerleşik araçlar: run_command, python_run, read_file/write_file/edit_file, web_search/deep_search, browser_*, computer_look (ekran görüntüsü) — hepsi açık.\n' +
1971
- 'GRAFİK & EKRAN GÖRÜNTÜSÜ (karar öncesi görsel doğrulama):\n' +
1972
- '- computer_look: masaüstü ekranını yakalar — MT5 grafiği SONRAKİ turda görsel olarak önüne gelir; trend/formasyon/mum yapısı + SL/TP çizgilerini doğrudan gör. Önemli işlem kararından önce grafiği gözle doğrula.\n' +
1973
- '- mt5_ea action:"note": grafiğe kısa analiz/plan metni + seviye çizgileri (destek/direnç/SL/TP) yazar — BeastFinance EA panosu computer_look screenshot\'ında GÖRÜNÜR; entegrasyon bildirimleriyle birlikte kullan.\n' +
1974
- '- browser_screenshot: web tabanlı grafikler (TradingView, Investing, MQL5) — browser_open ile aç, ekran görüntüsünü incele.\n' +
1975
- '- Görsel göremiyorsan (metin-model) ocr_read kullan: source:"screen" masaüstünü, source:"browser" paneli OCR ile okur; grafikteki fiyat/seviyeleri metne çevirir.\n' +
1973
+ 'GRAFİK & GÖRSEL DOĞRULAMA (karar öncesi — vazgeçilmez):\n' +
1974
+ '- tool__mt5_shot: MT5 grafiğinin GERÇEK PNG\'si (BeastFinance EA "shot" komutu). Görsel SONRAKİ TURDA gözüne gelir; aktif grafikte Beast panosu + mt5_ea note ile çizilen seviyeler GÖRÜNÜR. symbol/timeframe ver → EA geçici grafik açıp o sembol/periyottan çeker; dönen path send_file ile kullanıcıya gönderilebilir. Grafik analizinde İLK tercih budur.\n' +
1975
+ '- mt5_ea action:"note": grafiğe kısa plan metni + yatay seviye çizgileri yazar (destek/direnç/SL/TP) — sonra tool__mt5_shot ile çekip seviyelerin doğru yerde olduğunu GÖRSEL doğrula.\n' +
1976
+ '- computer_look: tüm masaüstü ekranı (MT5 dışı pencereler dahil); browser_screenshot: web grafikleri (TradingView/Investing) — browser_open ile aç.\n' +
1977
+ '- Görsel göremiyorsan (metin-model) ocr_read (source:"screen"/"browser") ile grafikteki fiyat/seviyeleri metne çevir.\n' +
1976
1978
  '- Grafikte gezinme/ölçek: computer_act ile timeframe, scroll, zoom (arka planda çalışır — kullanıcının faresini çalmaz).\n' +
1977
- '- EKSİK ARAÇ: özel grafik aracı gerekiyorsa (ör. MT5 grafiğini PNG dosyasına kaydetme, çoklu timeframe tek görüntü, indikatör paneli okuma) VAR SAYMA — tool_request ile TOOL botuna yazdır (doğrulanınca tool__<ad> olarak ANINDA çağrılır); küçük aracı skill("tool-yazma") prosedürüyle kendin de yazabilirsin.\n' +
1979
+ '- EKİPLE GÖRSEL PAYLAŞIM: chart PNG\'sini agent_dm image:true (son görüntün) ya da image:"<dosya yolu>" (ör. tool__mt5_shot dönen path) ile trader/ekibe gönder — karşı ajan görüntüyü GERÇEKTEN görür, AJAN DM panelinde açılır. Ortak kararlarda grafiği paylaşmak zorunlu disiplindir.\n' +
1980
+ '- PARALEL EKİP AKIŞI: teknik ajan seviyeleri hesaplar → mt5_ea note ile grafiğe çizer; görsel ajan tool__mt5_shot ile çekip TEYİT eder ve agent_dm ile görseli trader\'a atar; risk ajanı aynı görsel üzerinden SL/TP yerleşimini denetler; trader kararı işleme çevirir. Aynı sembolde koşan ajanlar tek DM grubunda (agent_dm group) toplanır — çelişen hareket etme.\n' +
1981
+ '- EKSİK ARAÇ: özel grafik aracı gerekiyorsa (ör. çoklu timeframe tek görüntü, indikatör paneli okuma) VAR SAYMA — tool_request ile TOOL botuna yazdır (doğrulanınca tool__<ad> olarak ANINDA çağrılır); küçük aracı skill("tool-yazma") prosedürüyle kendin de yazabilirsin.\n' +
1978
1982
  'VERİ AKIŞI (her değerlendirmede): mt5_account + mt5_positions + mt5_market çağrılarını AYNI turda PARALEL ver; gerekiyorsa mt5_history ile son işlemleri gör.\n' +
1979
1983
  'PARALEL + KOORDİNASYON: uzun araştırma/işleri run_background ile paralel finance işçisine devret (parent finance olduğu için işçi mt5 okuma araçlarını görür); koşan ajanlarla konuşmak için agent_dm (to: ajan başlığındaki anahtar kelime, örn "GOLD"; ortak karar için group: "İSİM" ile grup sohbeti kur — mesaj tüm üyelere düşer). Görevin bitince DM/grup sohbetleri otomatik KAPANIR (geçmiş panelde kalır).\n' +
1980
1984
  (symbols ? `İZLEME LİSTESİ: ${symbols}\n` : '') +
@@ -2049,7 +2053,7 @@ class Engine {
2049
2053
  if (bctx) {
2050
2054
  parts.push(
2051
2055
  '# MT5 / BEAST FINANCE ENTEGRASYONU\n' +
2052
- 'Beast Finance açıldığında MT5 terminaline bağlanılır; BeastFinance.mq5 uzman danışmanı İLK GRAFİĞE OTOMATİK kurulur ve AutoTrading açılır. Grafik/entegrasyon işleri bu EA üzerinden yürür (heartbeat beast_ea.json, komut köprüsü beast_cmd.json, grafik panosu/seviyeler beast_note.json; finance oturumlarında mt5_ea status/ping/chart/note) — pano ve çizgiler screenshot\'larda görünür. Elle EA ekleme varsayma; eksik araç gerekiyorsa Tool botuna tool_request at.'
2056
+ 'Beast Finance açıldığında MT5 terminaline bağlanılır; BeastFinance.mq5 uzman danışmanı İLK GRAFİĞE OTOMATİK kurulur ve AutoTrading açılır. Grafik/entegrasyon işleri bu EA üzerinden yürür (heartbeat beast_ea.json, komut köprüsü beast_cmd.json, grafik panosu/seviyeler beast_note.json; finance oturumlarında mt5_ea status/ping/chart/note). Grafik görseli için varsayılan kurulu tool__mt5_shot kullan (EA "shot" komutu: gerçek PNG + görsel ajana enjekte edilir; path send_file/agent_dm ile paylaşılabilir) — pano ve çizgiler bu screenshot\'ta görünür. Elle EA ekleme varsayma; eksik araç gerekiyorsa Tool botuna tool_request at.'
2053
2057
  );
2054
2058
  }
2055
2059
  /* opencode instruction port (ajan modu): workspace AGENTS/CLAUDE/CONTEXT
@@ -2102,6 +2106,7 @@ class Engine {
2102
2106
  ? 'Bağımsız alt-işleri run_background ile PARALEL ajana devret; işi KENDİN YÜRÜTME — emri ver, takip et, raporla.'
2103
2107
  : 'Bağımsız alt-işleri delegate_task ile devret; kendi başına halledebileceğin işleri devretme.',
2104
2108
  'Güncel/dış bilgi gerekiyorsa web_search kullan (zincir DAHİLİ tarayıcıyla başlar — gerçek Chromium ile Google); hızlı ham metin okuması için webfetch (veya http_fetch) kullan.',
2109
+ 'KULLANICI GITHUB REPO ADRESİ/LİNKİ VERİRSE (github.com/owner/repo) ya da "şu repoyu indir/kur/çalıştır" derse sandbox_repo aracını kullan: action=indir → Beast Sandbox\'a (~/Beast-Sandbox) klonlar; ardından action=kur (bağımlılıklar) ve action=baslat (çalıştır) ile devam et — uzun sürse bile tur KİLİTLENMEZ, çıktı Sandbox ÇALIŞTIR panelinde canlı akar, localhost adresi sağdaki dahili tarayıcıda otomatik açılır. Sonucu kullanıcıya tek cümleyle bildir (repo, komut, çalışıyor mu).',
2105
2110
  'DERİN ARAŞTIRMA: web_search\u2019in sonucu yetersizse/istenen bilgi listede YOKSA aramayı tekrar tekrar deneme yerine deep_search kullan — 1-4 sorgu varyantını (eş anlamlı, Türkçe+İngilizce yazımlar) PARALEL aratır ve ilk sayfaları GİZLİ gerçek Chromium\u2019da açıp tam metin okur (paneli açmaz, kullanıcıyı rahatsız etmez; JS/SPA sayfalar çalışır). Fiyat karşılaştırma, çok kaynaklı araştırma, "her şeyi bul" işleri ve Türkçe sorgularda sonuç zayıfsa doğrudan deep_search seç. read_top=0 verirsen yalnız harmanlanmış sonuç listesi döner.',
2106
2111
  'ARAMA-DİSİPLİN: bir bilgiyi 2-3 denemede bulamazsan TAKILMA — farklı bir açıya/sorguya geç, yine yoksa bulabildiğin kısmi bilgiyle cevap ver ve neyi bulamadığını açıkça söyle. Kapalı/gizli içerik (private profil, login arkası veri) peşinde KOŞMA — bulunamayacağı belliyse hemen vazgeç.',
2107
2112
  'TARAYICI VARSAYILANI (ZORUNLU): kullanıcı "şu siteyi aç", "bunu ara / google\u2019da ara", "şu sayfaya git" gibi bir web isteği verdiğinde HEP DAHİLİ TARAYICIYI KULLAN (browser_open ile aç → açılış yanıtında hazır snapshot gelir → ref numaralarıyla browser_click/browser_type/browser_select ile hareket et; HER eylem yanıtında taze snapshot döner — ayrıca browser_snapshot çağırma, yanıttaki refleri kullan; browser_read ile metin oku; sadece görsel yerleşim/grafik gerekiyorsa browser_screenshot çek). Tarih/saat alanlarını (type=date/time) browser_type ile DÜZ METİN yaz ("15.03.2026", "2026-03-15") — takvimden tıklamaya çalışma, alan programatik ayarlanır. Panel ekranın sağında açılır ve kullanıcı da sayfayı anında görür; JS/login/SPA/dinamik içerik için idealdir. Bu kural TÜM oturumları kapsar — masaüstü sohbeti ve çok kullanıcılı botlar (WhatsApp vb.) dahil.' +
@@ -4324,7 +4329,7 @@ class Engine {
4324
4329
  const imgMsg = {
4325
4330
  role: 'user',
4326
4331
  content: [
4327
- { type: 'text', text: '[tarayıcı ekran görüntüsü — bu kareyi analiz et ve devam et]' },
4332
+ { type: 'text', text: '[araç görseli — bu kareyi analiz et ve devam et]' },
4328
4333
  { type: 'image_url', image_url: { url: injectedImage } },
4329
4334
  ],
4330
4335
  };
@@ -5006,6 +5011,51 @@ const skills = require('./skills');
5006
5011
  return { ...r, via };
5007
5012
  }
5008
5013
 
5014
+ /* Sandbox köprüsü (main.js hook'ları): ana sohbetteki ajan sandbox_repo
5015
+ aracıyla repo indirir/kurar/çalıştırır — Sandbox paneliyle AYNI makine.
5016
+ Kur/Başlat yönetilen süreçtir: tur kilitlenmez, çıktı panelde akar,
5017
+ localhost adresi sağdaki dahili tarayıcıda açılır. */
5018
+ async _sandboxRepo(args) {
5019
+ const action = String((args && args.action) || '').trim().toLowerCase();
5020
+ const repo = String((args && args.repo) || '').trim();
5021
+ if (action === 'indir') {
5022
+ if (typeof this.sbCloneHook !== 'function') return { ok: false, error: 'sandbox köprüsü yok' };
5023
+ const r = await this.sbCloneHook(repo);
5024
+ if (!r || !r.ok) return r || { ok: false, error: 'klonlanamadı' };
5025
+ let info = null;
5026
+ try { if (typeof this.sbDetectHook === 'function') info = this.sbDetectHook(r.folder); } catch {}
5027
+ return {
5028
+ ok: true,
5029
+ name: r.name,
5030
+ folder: r.folder,
5031
+ detected: info ? { kind: info.kind, label: info.label, install: info.install, run: info.run } : undefined,
5032
+ note:
5033
+ 'Repo "' + r.name + '" → ' + r.folder + ' klasörüne indirildi. Kurmak için sandbox_repo action=kur, çalıştırmak için action=baslat; kullanıcı Sandbox panelindeki Kur/Başlat butonlarını da kullanabilir.',
5034
+ };
5035
+ }
5036
+ if (action !== 'kur' && action !== 'baslat' && action !== 'durdur') {
5037
+ return { ok: false, error: 'action şunlardan biri olmalı: indir | kur | baslat | durdur' };
5038
+ }
5039
+ let folder = '';
5040
+ try { if (typeof this.sbFolderHook === 'function') folder = String(this.sbFolderHook(repo) || ''); } catch {}
5041
+ if (!folder) return { ok: false, error: 'repo bulunamadı — önce sandbox_repo action=indir ile indir ya da Sandbox panelinden bir repo seç' };
5042
+ if (action === 'kur') {
5043
+ if (typeof this.sbInstallHook !== 'function') return { ok: false, error: 'sandbox köprüsü yok' };
5044
+ const r = this.sbInstallHook(folder);
5045
+ if (!r || !r.ok) return r || { ok: false, error: 'kurulum başlatılamadı' };
5046
+ return { ok: true, folder, command: r.cmd, note: 'Kurulum ÇALIŞTIR panelinde başladı: ' + r.cmd + ' — çıktı panelde canlı akar; bitince kullanıcıya bildir, sonra action=baslat.' };
5047
+ }
5048
+ if (action === 'baslat') {
5049
+ if (typeof this.sbStartHook !== 'function') return { ok: false, error: 'sandbox köprüsü yok' };
5050
+ const r = this.sbStartHook(folder, 'run');
5051
+ if (!r || !r.ok) return r || { ok: false, error: 'başlatılamadı' };
5052
+ return { ok: true, folder, command: r.cmd, note: 'Süreç ÇALIŞTIR panelinde başladı: ' + r.cmd + '. Dev server adresi yakalanınca sağdaki dahili tarayıcıda otomatik açılır; durdurmak için action=durdur.' };
5053
+ }
5054
+ if (typeof this.sbStopHook !== 'function') return { ok: false, error: 'sandbox köprüsü yok' };
5055
+ const stopped = !!this.sbStopHook(folder);
5056
+ return { ok: true, folder, wasRunning: stopped, note: stopped ? 'Süreç durduruldu.' : 'Bu repoda çalışan bir süreç yoktu.' };
5057
+ }
5058
+
5009
5059
  async _subExecTool(name, args, signal) {
5010
5060
  try {
5011
5061
  const blocked = this._guardTool(name, args);
@@ -5020,6 +5070,7 @@ const skills = require('./skills');
5020
5070
  });
5021
5071
  }
5022
5072
  if (name === 'ocr_read') return JSON.stringify(await this._ocrRead(args || {}, signal));
5073
+ if (name === 'sandbox_repo') return JSON.stringify(await this._sandboxRepo(args || {}));
5023
5074
  /* opencode general-agent portu: alt-ajan da edit/grep/glob kullanır.
5024
5075
  MT5 (mt5_*) araçları da tools.exec'e geçer (finance işçileri/danışma). */
5025
5076
  if (!(name === 'run_command' || name === 'read_file' || name === 'write_file' || name === 'edit_file' ||
@@ -5561,6 +5612,9 @@ const skills = require('./skills');
5561
5612
  const n = Number((args && args.max_results) || 8);
5562
5613
  return JSON.stringify(await this._webSearchChain(q, n, sessionId, signal));
5563
5614
  }
5615
+ if (name === 'sandbox_repo') {
5616
+ return JSON.stringify(await this._sandboxRepo(args || {}));
5617
+ }
5564
5618
  if (name === 'ocr_read') {
5565
5619
  return JSON.stringify(await this._ocrRead(args || {}, signal, sessionId));
5566
5620
  }
@@ -5723,7 +5777,7 @@ const AGENT_DM_DEF = {
5723
5777
  function: {
5724
5778
  name: 'agent_dm',
5725
5779
  description:
5726
- 'Send a short DM to another running agent (parallel agents / finance agents) to coordinate: share findings, ask status, warn about risk, hand off work, and MAKE JOINT DECISIONS. `to` = target session id OR a keyword from the agent title (e.g. "GOLD", "Trader"). `topic` = short subject label — replies to the same topic stay in the SAME conversation thread, so ALWAYS reuse the topic you were DMed with when replying. `group` = optional group-chat name (e.g. "GOLD EKIP"): creates or reuses a group conversation, adds the target agent as a member, and your message is delivered to EVERY member — use groups when a decision needs multiple agents. `image:true` attaches your last screenshot (fresh capture if none) — the receiving agent and the AJAN DM panel see it as an actual image; use it to share chart/screen findings.',
5780
+ 'Send a short DM to another running agent (parallel agents / finance agents) to coordinate: share findings, ask status, warn about risk, hand off work, and MAKE JOINT DECISIONS. `to` = target session id OR a keyword from the agent title (e.g. "GOLD", "Trader"). `topic` = short subject label — replies to the same topic stay in the SAME conversation thread, so ALWAYS reuse the topic you were DMed with when replying. `group` = optional group-chat name (e.g. "GOLD EKIP"): creates or reuses a group conversation, adds the target agent as a member, and your message is delivered to EVERY member — use groups when a decision needs multiple agents. `image` shares a chart/screen as an attachment the receiving agent REALLY sees and the AJAN DM panel shows: true = your last screenshot (fresh capture if none); a file path (e.g. the tool__mt5_shot "path") or a data URL = that exact image.',
5727
5781
  parameters: {
5728
5782
  type: 'object',
5729
5783
  properties: {
@@ -5731,7 +5785,7 @@ const AGENT_DM_DEF = {
5731
5785
  topic: { type: 'string', description: 'Short subject label for the conversation thread, e.g. "GOLD pozisyon riski"' },
5732
5786
  message: { type: 'string', description: 'Short message (1-3 sentences)' },
5733
5787
  group: { type: 'string', description: 'Optional group-chat name — send to ALL members of that group (creates it on first use, adds the target agent)' },
5734
- image: { type: 'boolean', description: 'true ise son ekran görüntünü mesaja iliştirir (yoksa taze ekran yakalar) — panelde ve karşı ajanda görsel olarak açılır; grafik/ekran bulgusunu paylaşmak için kullan' },
5788
+ image: { type: ['boolean', 'string'], description: 'true = son ekran görüntün (yoksa taze yakalar); dosya yolu (ör. tool__mt5_shot dönen PNG path) ya da data:image URL = o görsel iliştirilir. Panelde ve karşı ajanda GÖRÜNÜR; grafik/ekran bulgusunu paylaşmak için kullan' },
5735
5789
  },
5736
5790
  required: ['message'],
5737
5791
  },
@@ -6547,9 +6601,17 @@ Engine.prototype._agentDmSend = async function (fromSid, args) {
6547
6601
  const to = String((args && args.to) || '').trim();
6548
6602
  const text = String((args && args.message) || '').trim().slice(0, 1200);
6549
6603
  if (!text) return { ok: false, error: 'mesaj boş' };
6550
- /* GÖRSEL DM: son ekran görüntüsü (yoksa taze yakalama) mesaja iliştirilir */
6551
- const withImage = !!(args && args.image);
6552
- const image = withImage ? await this._agentDmCaptureImage(fromSid) : '';
6604
+ /* GÖRSEL DM: image:true → son ekran görüntüsü (yoksa taze yakalama);
6605
+ image:"<dosya yolu>" ya da data URL → o görsel BİREBİR iliştirilir
6606
+ (ör. tool__mt5_shot dönen PNG path'i). Karşı ajan görüntüyü görür. */
6607
+ const imgArg = args && args.image;
6608
+ let image = '';
6609
+ if (typeof imgArg === 'string' && imgArg.trim()) {
6610
+ const s = imgArg.trim();
6611
+ image = /^data:image\//i.test(s) ? s : this._agentDmImageFromFile(s);
6612
+ } else if (imgArg === true || imgArg === 'true') {
6613
+ image = await this._agentDmCaptureImage(fromSid);
6614
+ }
6553
6615
  const groupName = String((args && args.group) || '').replace(/\s+/g, ' ').trim().slice(0, 40);
6554
6616
  const jobs = this._bgJobs || new Map();
6555
6617
  const fromJob = jobs.get(String(fromSid));
@@ -6722,6 +6784,29 @@ Engine.prototype._agentDmSend = async function (fromSid, args) {
6722
6784
  }
6723
6785
  };
6724
6786
 
6787
+ /* AJAN DM görseli (dosyadan): png/jpg/webp/gif dosyasını data URL'e çevirir.
6788
+ Send_file kapısına takılmadan (ör. tool__mt5_shot path'i) görsel paylaşımı;
6789
+ 2.5MB üstü DM kaydını şişirmesin diye atlanır. */
6790
+ Engine.prototype._agentDmImageFromFile = function (p) {
6791
+ try {
6792
+ const fp = String(p || '').trim();
6793
+ if (!fp) return '';
6794
+ const ext = path.extname(fp).toLowerCase();
6795
+ const mime =
6796
+ ext === '.png' ? 'image/png'
6797
+ : ext === '.jpg' || ext === '.jpeg' ? 'image/jpeg'
6798
+ : ext === '.webp' ? 'image/webp'
6799
+ : ext === '.gif' ? 'image/gif'
6800
+ : '';
6801
+ if (!mime) return '';
6802
+ const buf = fs.readFileSync(fp);
6803
+ if (!buf.length || buf.length > 2500000) return '';
6804
+ return 'data:' + mime + ';base64,' + buf.toString('base64');
6805
+ } catch {
6806
+ return '';
6807
+ }
6808
+ };
6809
+
6725
6810
  /* AJAN DM görseli: gönderenin oturumundaki EN SON ekran görüntüsünü (yoksa
6726
6811
  taze yakalama) data URL olarak döndürür. Çok büyük görseller DM kaydını
6727
6812
  şişirmesin diye 2.5MB üstü atlanır. */
@@ -229,7 +229,7 @@ const definitions = NAMES.map((name) => {
229
229
  },
230
230
  mt5_ea: {
231
231
  description:
232
- 'BEASTFINANCE EA KÖPRÜSÜ (grafikte çalışan uzman danışman): action:"status" → EA heartbeat (yüklü mü, AutoTrading/EA izni, equity, pozisyon, son ack); "ping" → EA canlı yanıt; "chart" → aktif grafiğin sembol/periyot/fiyat/spread bilgisi; "note" → {symbol?, text, levels:[{price,label}]} grafik panosuna not + yatay seviye çizgileri yazar. NOT: yazdığın pano ve çizgiler görsel ajanın computer_look screenshot\'ında GÖRÜNÜR — grafik analizini/planını panoya yazıp screenshot ile doğrula; entegrasyon bildirimleriyle birlikte kullan.',
232
+ 'BEASTFINANCE EA KÖPRÜSÜ (grafikte çalışan uzman danışman): action:"status" → EA heartbeat (yüklü mü, AutoTrading/EA izni, equity, pozisyon, son ack); "ping" → EA canlı yanıt; "chart" → aktif grafiğin sembol/periyot/fiyat/spread bilgisi; "note" → {symbol?, text, levels:[{price,label}]} grafik panosuna not + yatay seviye çizgileri yazar. NOT: yazdığın pano ve çizgiler görsel ajanın screenshot\'ında GÖRÜNÜR — GERÇEK grafik PNG\'si için varsayılan kurulu tool__mt5_shot kullan (EA "shot" komutu; görsel ajanın gözüne gelir), seviyeleri çizdikten sonra tool__mt5_shot ile görsel doğrula; grafiği agent_dm image ile ekibe paylaş.',
233
233
  parameters: {
234
234
  type: 'object',
235
235
  properties: {
@@ -170,9 +170,10 @@ void ApplyLevels(const string raw)
170
170
  if(end < 0) return;
171
171
  string body = StringSubstr(raw, arr + 1, end - arr - 1);
172
172
 
173
- string names[];
174
- int n = 0;
175
- int pos = 0;
173
+ string names[];
174
+ ArrayResize(names, 64); /* FIX: dizi boyutlandirilmadan atama EA'yi dusuruyordu */
175
+ int n = 0;
176
+ int pos = 0;
176
177
  while(pos < StringLen(body))
177
178
  {
178
179
  int p = StringFind(body, "\"price\"", pos);
@@ -279,6 +280,96 @@ void ProcessCommands()
279
280
  RefreshPanel();
280
281
  result = "{\"note\":true}";
281
282
  }
283
+ else if(cmd == "shot")
284
+ {
285
+ /* ChartScreenShot -> MQL5\Files\<file> (png/gif/bmp). params:
286
+ file, width, height, timeframe (M15/H1/...), symbol (bos=aktif grafik)
287
+ Aktif grafik zaten istenen sembol+periyot ise ondan cekilir
288
+ (Beast panosu + seviye cizgileri gorunur); degilse gecici grafik acilir. */
289
+ string file = JsonGet(raw, "file");
290
+ if(StringLen(file) == 0) file = "beast_shot.png";
291
+ int w = (int)StringToInteger(JsonGet(raw, "width"));
292
+ int hh = (int)StringToInteger(JsonGet(raw, "height"));
293
+ if(w <= 0) w = 1600;
294
+ if(hh <= 0) hh = 900;
295
+
296
+ string symTxt = JsonGet(raw, "symbol");
297
+ string tfTxt = JsonGet(raw, "timeframe");
298
+
299
+ long cid = ChartID();
300
+ string symNow = ChartSymbol(cid);
301
+ ENUM_TIMEFRAMES tfNow = (ENUM_TIMEFRAMES)ChartPeriod(cid);
302
+
303
+ string symWant = symNow;
304
+ if(StringLen(symTxt) > 0 && StringCompare(symTxt, symNow) != 0)
305
+ {
306
+ if(SymbolSelect(symTxt, true)) symWant = symTxt;
307
+ }
308
+ if(SymbolSelect(symWant, true) == false)
309
+ {
310
+ ok = false;
311
+ err = "sembol bulunamadi: " + symWant;
312
+ }
313
+
314
+ ENUM_TIMEFRAMES tfWant = TfFromText(tfTxt);
315
+ ENUM_TIMEFRAMES tfUse = (tfWant == PERIOD_CURRENT) ? tfNow : tfWant;
316
+ bool tempChart = false;
317
+ bool tplApplied = false;
318
+ bool themeOk = false;
319
+ int bgNow = -1;
320
+
321
+ if(ok && (symWant != symNow || tfUse != tfNow))
322
+ {
323
+ long newId = ChartOpen(symWant, tfUse);
324
+ if(newId == 0)
325
+ {
326
+ ok = false;
327
+ err = "gecici grafik acilamadi: " + symWant;
328
+ }
329
+ else
330
+ {
331
+ cid = newId;
332
+ tempChart = true;
333
+ /* temiz gorunum: BeastFinance.tpl temasi (EA blogu cikarilmis BeastShot.tpl) */
334
+ string tpl = JsonGet(raw, "template");
335
+ if(StringLen(tpl) == 0) tpl = "BeastShot";
336
+ if(StringFind(tpl, ".") < 0) tpl = tpl + ".tpl";
337
+ bool tplOk = false;
338
+ if(StringCompare(tpl, "none.tpl") != 0)
339
+ {
340
+ tplOk = ChartApplyTemplate(cid, tpl);
341
+ ChartRedraw(cid);
342
+ Sleep(700);
343
+ }
344
+ /* sablon sembol/periyot degistirdiyse geri al */
345
+ if(StringCompare(ChartSymbol(cid), symWant) != 0 || (ENUM_TIMEFRAMES)ChartPeriod(cid) != tfUse)
346
+ ChartSetSymbolPeriod(cid, symWant, tfUse);
347
+ /* sablon bulunamasa da gorunum ayni olsun -> acik tema renklerini zorla */
348
+ themeOk = ApplyLightTheme(cid);
349
+ bgNow = (int)ChartGetInteger(cid, CHART_COLOR_BACKGROUND);
350
+ tplApplied = tplOk;
351
+ }
352
+ }
353
+
354
+ if(ok)
355
+ {
356
+ ChartRedraw(cid);
357
+ Sleep(1200); /* mumlar/olcek otursun */
358
+ ChartRedraw(cid);
359
+ Sleep(200);
360
+ if(!ChartScreenShot(cid, file, w, hh, ALIGN_RIGHT))
361
+ {
362
+ ok = false;
363
+ err = "screenshot basarisiz, hata=" + IntegerToString(GetLastError());
364
+ }
365
+ else
366
+ {
367
+ result = StringFormat("{\"file\":\"%s\",\"width\":%d,\"height\":%d,\"symbol\":\"%s\",\"period\":%d,\"temp_chart\":%s,\"template_applied\":%s,\"theme_ok\":%s,\"bg\":%d}",
368
+ JStr(file), w, hh, symWant, (int)tfUse, (tempChart ? "true" : "false"), (tplApplied ? "true" : "false"), (themeOk ? "true" : "false"), bgNow);
369
+ }
370
+ }
371
+ if(tempChart) ChartClose(cid);
372
+ }
282
373
  else
283
374
  {
284
375
  ok = false;
@@ -287,4 +378,50 @@ void ProcessCommands()
287
378
  WriteAck(id, cmd, ok, err, result);
288
379
  FileDelete(CmdFile);
289
380
  }
381
+
382
+ /* BeastFinance.tpl acik tema renklerini grafige uygular (sablon bulunamazsa da garanti) */
383
+ bool ApplyLightTheme(const long cid)
384
+ {
385
+ bool okAll = true;
386
+ okAll = ChartSetInteger(cid, CHART_COLOR_BACKGROUND, (long)16449525) && okAll;
387
+ okAll = ChartSetInteger(cid, CHART_COLOR_FOREGROUND, (long)0) && okAll;
388
+ okAll = ChartSetInteger(cid, CHART_COLOR_GRID, (long)12632256) && okAll;
389
+ okAll = ChartSetInteger(cid, CHART_COLOR_CHART_UP, (long)13434880) && okAll;
390
+ okAll = ChartSetInteger(cid, CHART_COLOR_CHART_DOWN, (long)0) && okAll;
391
+ okAll = ChartSetInteger(cid, CHART_COLOR_CHART_LINE, (long)0) && okAll;
392
+ okAll = ChartSetInteger(cid, CHART_COLOR_CANDLE_BULL, (long)13434880) && okAll;
393
+ okAll = ChartSetInteger(cid, CHART_COLOR_CANDLE_BEAR, (long)0) && okAll;
394
+ okAll = ChartSetInteger(cid, CHART_COLOR_VOLUME, (long)32768) && okAll;
395
+ okAll = ChartSetInteger(cid, CHART_COLOR_BID, (long)12632256) && okAll;
396
+ okAll = ChartSetInteger(cid, CHART_COLOR_ASK, (long)12632256) && okAll;
397
+ okAll = ChartSetInteger(cid, CHART_COLOR_LAST, (long)12632256) && okAll;
398
+ okAll = ChartSetInteger(cid, CHART_COLOR_STOP_LEVEL, (long)17919) && okAll;
399
+ okAll = ChartSetInteger(cid, CHART_MODE, CHART_CANDLES) && okAll;
400
+ okAll = ChartSetInteger(cid, CHART_SHOW_GRID, false) && okAll;
401
+ okAll = ChartSetInteger(cid, CHART_SHOW_OHLC, true) && okAll;
402
+ okAll = ChartSetInteger(cid, CHART_SHOW_BID_LINE, false) && okAll;
403
+ okAll = ChartSetInteger(cid, CHART_SHOW_ASK_LINE, false) && okAll;
404
+ okAll = ChartSetInteger(cid, CHART_SHOW_LAST_LINE, true) && okAll;
405
+ ChartRedraw(cid);
406
+ return okAll;
407
+ }
408
+
409
+ /* "M15"/"H1"/"15"/"60" gibi metni ENUM_TIMEFRAMES'e cevirir */
410
+ ENUM_TIMEFRAMES TfFromText(const string t)
411
+ {
412
+ string s = t;
413
+ StringTrimLeft(s);
414
+ StringTrimRight(s);
415
+ StringToUpper(s);
416
+ if(s == "M1" || s == "1") return PERIOD_M1;
417
+ if(s == "M5" || s == "5") return PERIOD_M5;
418
+ if(s == "M15" || s == "15") return PERIOD_M15;
419
+ if(s == "M30" || s == "30") return PERIOD_M30;
420
+ if(s == "H1" || s == "60") return PERIOD_H1;
421
+ if(s == "H4" || s == "240") return PERIOD_H4;
422
+ if(s == "D1" || s == "1440") return PERIOD_D1;
423
+ if(s == "W1") return PERIOD_W1;
424
+ if(s == "MN1") return PERIOD_MN1;
425
+ return PERIOD_CURRENT;
426
+ }
290
427
  //+------------------------------------------------------------------+
Binary file
@@ -493,6 +493,28 @@ function runSetup({ dataPath, terminalExe = '', force = false } = {}) {
493
493
  steps.push('Aktif profil grafiği bulunamadı — EA Navigator\'dan elle sürüklenebilir');
494
494
  }
495
495
 
496
+ /* 4c) BeastShot.tpl: mt5_shot geçici grafik açtığında uyguladığı temiz açık-tema
497
+ şablonu (EA bloğu yok) — kaynaktan kopyalanır; mt5_shot varsayılanı bunu arar. */
498
+ try {
499
+ const tplSrc = path.join(__dirname, 'mt5', 'BeastShot.tpl');
500
+ if (fs.existsSync(tplSrc)) {
501
+ const tplDir2 = path.join(mql5, 'Profiles', 'Templates');
502
+ const tplDst = path.join(tplDir2, 'BeastShot.tpl');
503
+ fs.mkdirSync(tplDir2, { recursive: true });
504
+ let same = false;
505
+ try { same = fs.readFileSync(tplDst).equals(fs.readFileSync(tplSrc)); } catch {}
506
+ if (!same) {
507
+ fs.copyFileSync(tplSrc, tplDst);
508
+ steps.push('Grafik şablonu yazıldı: ' + tplDst);
509
+ result.changed = true;
510
+ } else {
511
+ steps.push('Grafik şablonu güncel: ' + tplDst);
512
+ }
513
+ }
514
+ } catch (e) {
515
+ steps.push('Grafik şablonu yazılamadı: ' + String((e && e.message) || e));
516
+ }
517
+
496
518
  const running = terminalRunning();
497
519
  result.restartRequired = running && result.changed;
498
520
  if (result.restartRequired) steps.push('Değişiklikler MT5 yeniden başlatılınca etkinleşir');
@@ -130,9 +130,10 @@ function build(opts = {}) {
130
130
  user
131
131
  ),
132
132
  prompt: [
133
- 'BEAST SANDBOX MODUNDASIN: GitHub\u2019dan indirilmi\u015f A\u00c7IK KAYNAK bir repo klas\u00f6r\u00fcndesin (Beast-Sandbox). Bu kodun sahibi de\u011filsin \u2014 hazir bir di\u015f proje; repo sahibinin konvansiyonlarina uy, gereksiz yeniden bi\u00e7imlendirme yapma.',
134
- '\u0130\u015fe README + paket bildirim dosyalar\u0131yla ba\u015fla (list/glob); ba\u011f\u0131ml\u0131l\u0131klar kurulu de\u011filse \u00f6nce kurulum komutunu \u00e7al\u0131\u015ft\u0131r (npm install vb.).',
135
- 'UZUN S\u00dcREL\u0130 sunucu/s\u00fcre\u00e7 (npm start, npm run dev, python app.py vb.) bash ile ASLA ba\u015flatma \u2014 tur kilitlenir; kullan\u0131c\u0131 \u00e7al\u0131\u015ft\u0131rmak isterse panel_run arac\u0131yla \u00c7ALI\u015eTIR paneline b\u0131rak (\u00e7\u0131kt\u0131 orada canl\u0131 akar) ve adresi kullan\u0131c\u0131ya bildir. panel_run yaln\u0131z B\u0130R s\u00fcre\u00e7 \u00e7al\u0131\u015ft\u0131r\u0131r.',
133
+ 'BEAST SANDBOX MODUNDASIN: GitHub\u2019dan indirilmi\u015f A\u00c7IK KAYNAK bir repo klas\u00f6r\u00fcndesin (Beast-Sandbox). Bu kodun sahibi de\u011filsin \u2014 haz\u0131r bir d\u0131\u015f proje; repo sahibinin konvansiyonlar\u0131na uy, gereksiz yeniden bi\u00e7imlendirme yapma.',
134
+ 'PANEL: \u00c7ALI\u015eTIR b\u00f6l\u00fcm\u00fcndeki Kur/Ba\u015flat/Dev butonlar\u0131 proje tipini OTOMAT\u0130K alg\u0131lar (package.json scripts + npm/pnpm/yarn/bun kilidi; requirements.txt/pyproject + uv; Cargo.toml; go.mod; statik index.html) ve do\u011fru komutu do\u011frudan \u00e7al\u0131\u015ft\u0131r\u0131r. \u00d6zel komut kutusu ad-hoc komut \u00e7al\u0131\u015ft\u0131r\u0131r; kaydet butonu o komutu repo i\u00e7in kal\u0131c\u0131 ba\u015flatma komutu yapar. Kullan\u0131c\u0131 butonla ba\u015flatt\u0131ysa \u00e7\u0131kt\u0131 panelde canl\u0131 akar, localhost adresi yakalan\u0131nca sa\u011fdaki dahili taray\u0131c\u0131da otomatik a\u00e7\u0131l\u0131r.',
135
+ '\u0130\u015fe README + paket bildirim dosyalar\u0131yla ba\u015fla (list/glob); kullan\u0131c\u0131 Kur demediyse ba\u011f\u0131ml\u0131l\u0131klar\u0131 sen kurabilirsin (npm install, pip install -r requirements.txt vb.). Kur/Ba\u015flat ba\u015far\u0131s\u0131z olursa ger\u00e7ek hatay\u0131 g\u00f6rmek i\u00e7in ayn\u0131 komutu bash ile \u00e7al\u0131\u015ft\u0131r, nedenini bul, gerekiyorsa d\u00fczelt ve kullan\u0131c\u0131ya do\u011fru \u00f6zel komutu s\u00f6yle (kutuya yaz\u0131p kaydetsin).',
136
+ 'UZUN S\u00dcREL\u0130 sunucu/s\u00fcre\u00e7 (npm start, npm run dev, python app.py vb.) bash ile ASLA ba\u015flatma \u2014 tur kilitlenir; kullan\u0131c\u0131 senden isterse panel_run ile ba\u015flat (\u00e7\u0131kt\u0131 panelde akar, adres sa\u011fda a\u00e7\u0131l\u0131r). Repo ba\u015f\u0131na TEK s\u00fcre\u00e7: kullan\u0131c\u0131 zaten ba\u015flatt\u0131ysa panel_run hata verir \u2014 kullan\u0131c\u0131ya \u00f6nce Durdur demesini s\u00f6yle.',
136
137
  ].join('\n'),
137
138
  mode: 'all',
138
139
  native: false,
@@ -62,11 +62,13 @@ Yani MT5 entegrasyonu yazarken EA'yı SIFIRDAN YAZMA, elle iliştirme varsayma
62
62
  | Dosya (MQL5\Files) | Yön | İçerik |
63
63
  |---|---|---|
64
64
  | `beast_ea.json` | EA → Beast | heartbeat: version, symbol, period, equity/balance, `terminal_trade_allowed`, `mql_trade_allowed`, positions, note |
65
- | `beast_cmd.json` | Beast → EA | komut: `{id, cmd, params}` — desteklenen: ping / chart / status / note |
65
+ | `beast_cmd.json` | Beast → EA | komut: `{id, cmd, params}` — desteklenen: ping / chart / status / note / shot |
66
66
  | `beast_cmd_ack.json` | EA → Beast | komut sonucu: `{ok, id, cmd, result|error}` |
67
67
  | `beast_note.json` | Beast → EA | grafik panosu: `{symbol?, text, levels:[{price,label}]}` — pano + yatay çizgiler; screenshot'ta görünür |
68
68
 
69
- - Finance oturumlarındaki ajan aracı: `mt5_ea` (action: status|ping|chart|note).
69
+ - GRAFİK GÖRÜNTÜSÜ: `shot` komutu `{file, width, height, symbol?, timeframe?, template?}` alır — ChartScreenShot ile GERÇEK PNG üretir. Aktif grafik istenen sembol/periyot ile aynıysa panoyu + seviye çizgilerini içerir; farklıysa EA `ChartOpen` + `BeastShot.tpl` (açık tema, EA bloğu yok) ile geçici grafik açıp kapatır. Bu komutu sarmalayan VARSAYILAN araç `tool__mt5_shot`'tır: PNG'yi çağıran ajana görsel olarak enjekte eder, `path` döndürür (send_file / agent_dm image ile paylaşılır). Seviyeleri grafikte göstermek için önce `mt5_ea note`, sonra `tool__mt5_shot` çağır — paralel ekipte teknik ajan seviyeleri çizer, görsel ajan screenshot ile teyit edip trader'a atar.
70
+
71
+ - Finance oturumlarındaki ajan aracı: `mt5_ea` (action: status|ping|chart|note); grafik PNG'si için varsayılan `tool__mt5_shot` (tüm oturumlarda açık).
70
72
  - Yeni MT5 entegrasyonu gerekiyorsa ÖNCE bu köprüyü GENİŞLET: EA'da `ProcessCommands()` içine yeni komut + Beast tarafında `mt5_ea` / python `ea_cmd`. Sıfırdan EA yazma.
71
73
  - EA kaynağı Beast uygulamasında `src/agent/mt5/BeastFinance.mq5`; güncelleme oradan yapılır, setup yeniden derler.
72
74
  - Derleme hatalarında dosya kodlaması UTF-16 (`FILE_UNICODE`) kullanılır; MQL5'te `FILE_UTF8` yoktur.
@@ -1613,6 +1613,22 @@ const definitions = [
1613
1613
  },
1614
1614
  },
1615
1615
  },
1616
+ {
1617
+ type: 'function',
1618
+ function: {
1619
+ name: 'sandbox_repo',
1620
+ description:
1621
+ 'Beast Sandbox yönetimi — kullanıcı GitHub repo adresi/linki verdiğinde ya da indirilmiş bir repoyu kurmak/çalıştırmak istediğinde kullan. action=indir: repoyu ~/Beast-Sandbox klasörüne klonlar (owner/repo ya da tam URL); action=kur: algılanan kurulum komutunu (npm install, pip install -r requirements.txt, uv sync, cargo fetch, go mod download) ÇALIŞTIR panelinde başlatır; action=baslat: algılanan çalıştırma komutunu başlatır (npm run dev, python app.py vb.) — localhost adresi yakalanınca sağdaki dahili tarayıcıda otomatik açılır; action=durdur: repodaki çalışan süreci durdurur. Kur/Başlat turu KİLİTLEMEZ, çıktı panelde canlı akar. repo alanı boşsa panelde son kullanılan repo kullanılır.',
1622
+ parameters: {
1623
+ type: 'object',
1624
+ properties: {
1625
+ action: { type: 'string', enum: ['indir', 'kur', 'baslat', 'durdur'], description: 'Yapılacak işlem' },
1626
+ repo: { type: 'string', description: 'GitHub adresi (owner/repo ya da tam URL) ya da repo adı/klasör yolu; son kullanılan repo için boş bırak' },
1627
+ },
1628
+ required: ['action'],
1629
+ },
1630
+ },
1631
+ },
1616
1632
  {
1617
1633
  type: 'function',
1618
1634
  function: {