beast-agent 2.30.0 → 2.30.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "beast-agent",
3
3
  "productName": "Beast Agent",
4
- "version": "2.30.0",
4
+ "version": "2.30.2",
5
5
  "description": "Ultra-fast local agent shell for Windows.",
6
6
  "author": "algokodcom (AlgoKod)",
7
7
  "license": "MIT",
@@ -2494,7 +2494,6 @@ class Engine {
2494
2494
  korunur — sadece içerik temizlenir, önek cache bozulmaz. Döndürür: kazanılan token */
2495
2495
  _pruneSession(session) {
2496
2496
  try {
2497
- if (this.ctrls.has(session.id)) return 0;
2498
2497
  const msgs = session.messages;
2499
2498
  let total = 0, pruned = 0, turns = 0;
2500
2499
  const targets = [];
@@ -2585,7 +2584,10 @@ class Engine {
2585
2584
  `- kullanıcının hedefleri ve net talepleri\n` +
2586
2585
  `- alınan kararlar, önemli bilgi parçaları (isim, sayı, dosya/klasör yolu, hata ve çözümü)\n` +
2587
2586
  `- tamamlanan işler ve sonuçları\n` +
2588
- `Madde madde yaz, en fazla 120 kelime, başlık/selamlama yok. Alakasız ayrıntıyı at.\n\n` +
2587
+ (session.finance
2588
+ ? `- FİNANS İŞLEMLERİ (KRİTİK, atlama): açılan/kapatılan/güncellenen pozisyonlar — sembol, yön (AL/SAT), lot, giriş/SL/TP, kâr/zarar ve gerekçe; sonraki turlarda birebir hatırlanmalı\n`
2589
+ : '') +
2590
+ `Madde madde yaz, en fazla ${session.finance ? 180 : 120} kelime, başlık/selamlama yok. Alakasız ayrıntıyı at.\n\n` +
2589
2591
  `# SOHBET PARÇASI\n${transcript}`;
2590
2592
  const res = await chatOnce(
2591
2593
  this.sel,
@@ -2687,6 +2689,25 @@ class Engine {
2687
2689
  }
2688
2690
  }
2689
2691
 
2692
+ /* SÜREKLİ ajan DM INBOX (bkz. flushPendingReports): tur aralığında biriken
2693
+ DM'ler yeni tur AÇMAZ; sıradaki planlı turun mesajına tek blok olarak
2694
+ eklenir — ajan-ajan sonsuz DM ping-pong'u ve bağlam şişmesi engellenir. */
2695
+ try {
2696
+ const jobRec = this._bgJobs && this._bgJobs.get(String(sessionId));
2697
+ if (jobRec && Array.isArray(jobRec.dmInbox) && jobRec.dmInbox.length) {
2698
+ const inbox = jobRec.dmInbox.splice(0);
2699
+ const boxText = inbox.join('\n\n').slice(0, 6000);
2700
+ const prefix =
2701
+ `[BEKLEYEN AJAN DM'LERİ — ${inbox.length} mesaj]\n${boxText}\n` +
2702
+ `(Tur aralığında biriken DM'ler. Bu turda değerlendir; yalnızca aksiyon/cevap GEREKİYORSA agent_dm ile TEK kısa cevap ver — teşekkür/onay/ack mesajı YAZMA.)\n\n`;
2703
+ if (typeof msg.content === 'string') {
2704
+ msg.content = prefix + msg.content;
2705
+ } else if (Array.isArray(msg.content) && msg.content[0] && typeof msg.content[0].text === 'string') {
2706
+ msg.content[0] = { ...msg.content[0], text: prefix + msg.content[0].text };
2707
+ }
2708
+ }
2709
+ } catch {}
2710
+
2690
2711
  if (!String(typeof msg.content === 'string' ? msg.content : msg.content[0].text || '').trim()) return false;
2691
2712
  /* #12 kişilik kalibrasyonu: kullanıcı cümlelerini örnek havuzuna düşür (Beast Code hariç — hız) */
2692
2713
  if (!s.bcCode) {
@@ -3514,10 +3535,22 @@ class Engine {
3514
3535
  this._pendingReports = [];
3515
3536
  return;
3516
3537
  }
3538
+ const job = this._bgJobs && this._bgJobs.get(String(sessionId));
3539
+ /* SÜREKLİ ajan (Beast Finance): DM/rapor teslimi YENİ TUR AÇMAZ — aksi
3540
+ halde ajanlar birbirine DM attıkça sonsuz tur döngüsü doğar (bağlam
3541
+ şişer, ajan hiç dinlenmez). Mesaj inbox'a yazılır; bir sonraki PLANLI
3542
+ turda send() tarafından tek blok halinde enjekte edilir. */
3543
+ const continuous = !!(job && job.continuous);
3517
3544
  const rest = [];
3518
3545
  for (const r of this._pendingReports) {
3519
3546
  if (r.parentId !== sessionId) { rest.push(r); continue; }
3520
3547
  if (this._deletedSessions && this._deletedSessions.has(sessionId)) continue;
3548
+ if (continuous) {
3549
+ job.dmInbox = job.dmInbox || [];
3550
+ job.dmInbox.push(String(r.text || '').slice(0, 4000));
3551
+ if (job.dmInbox.length > 20) job.dmInbox.splice(0, job.dmInbox.length - 20);
3552
+ continue;
3553
+ }
3521
3554
  if (this.isBusy(sessionId)) { rest.push(r); continue; }
3522
3555
  let sent = false;
3523
3556
  try { sent = !!this.send(sessionId, { text: r.text }); } catch {}
@@ -3558,8 +3591,10 @@ class Engine {
3558
3591
  _bgTrim(session) {
3559
3592
  const max = Engine.BG_KEEP_MSGS;
3560
3593
  const msgs = session.messages;
3561
- /* bg işleri + Beast Code: uzun geçmiş payload'ı şişirip yavaşlatır */
3562
- if ((!session.bgJob && !session.bcCode) || msgs.length <= max) return;
3594
+ /* bg işleri + Beast Code + SÜREKLİ finance ajanları: uzun geçmiş payload'ı
3595
+ şişirip yavaşlatır — finance ajanları binlerce tur döndüğü için bağlam
3596
+ tavanı onlara da şart */
3597
+ if ((!session.bgJob && !session.bcCode && !session.finance) || msgs.length <= max) return;
3563
3598
  let keep = msgs.slice(-max);
3564
3599
  /* GÜVENLİ SINIR: kesim bir assistant(tool_calls) + tool sonuç çiftini BÖLMESİN.
3565
3600
  Yetim 'tool' mesajı ya da sonuçları pencere dışında kalan tool_calls'lı
@@ -6394,7 +6429,7 @@ Engine.prototype._agentDmSend = function (fromSid, args) {
6394
6429
  parentId: m,
6395
6430
  text:
6396
6431
  `[AJAN DM (grup: "${g.title}") — ${dm.fromTitle} · konu: "${topic}"]\n${text}\n` +
6397
- `(Cevabını agent_dm aracıyla ver — group: "${g.title}", to: "${dm.fromTitle}", topic: "${topic}")`,
6432
+ `(Cevap yalnızca aksiyon/karar GEREKİYORSA ver — agent_dm group: "${g.title}", to: "${dm.fromTitle}", topic: "${topic}"; teşekkür/onay yazma.)`,
6398
6433
  });
6399
6434
  this.flushPendingReports(m);
6400
6435
  }
@@ -6419,7 +6454,7 @@ Engine.prototype._agentDmSend = function (fromSid, args) {
6419
6454
  parentId: target,
6420
6455
  text:
6421
6456
  `[AJAN DM — ${dm.fromTitle} · konu: "${topic}"]\n${text}\n` +
6422
- `(Cevabını agent_dm aracıyla ver — to: "${dm.fromTitle}", topic: "${topic}")`,
6457
+ `(Cevap yalnızca aksiyon/karar GEREKİYORSA ver — agent_dm to: "${dm.fromTitle}", topic: "${topic}"; teşekkür/onay yazma.)`,
6423
6458
  });
6424
6459
  this.flushPendingReports(target);
6425
6460
  }
package/src/main.js CHANGED
@@ -8323,8 +8323,12 @@ function finCfg() {
8323
8323
  /* OTOMATİK İŞLEM hep açık — kullanıcı onay kutusu KALDIRILDI: trade ajanının
8324
8324
  amacı zaten işlem açmak; onay sorulmaz, limitler (max lot/pozisyon) korur */
8325
8325
  f.allowTrading = true;
8326
- if (typeof f.analysisAuto !== 'boolean') f.analysisAuto = true; /* sayıya göre otomatik atama */
8327
- if (!Number(f.analysisCount)) f.analysisCount = 2; /* varsayılan: 2 uzman ajan */
8326
+ /* ANALİZ EKİBİ ARTIK SADECE SAYI: elle rol seçimi kaldırıldı — atama daima
8327
+ otomatik (Teknik → Risk → Haber). 0 = ekip kapalı GEÇERLİ değerdir;
8328
+ yalnız eksik/bozuk değerde varsayılan 2'ye düşülür. */
8329
+ f.analysisAuto = true;
8330
+ if (!Number.isFinite(Number(f.analysisCount))) f.analysisCount = 2;
8331
+ f.analysisCount = Math.max(0, Math.min(FIN_ROLES_AUTO.length, Math.round(Number(f.analysisCount) || 0)));
8328
8332
  if (!Number(f.intervalSec)) f.intervalSec = 120;
8329
8333
  if (!Number(f.maxLot)) f.maxLot = 0.1;
8330
8334
  if (f.maxPositions == null) f.maxPositions = 3;
@@ -8767,6 +8771,7 @@ ipcMain.handle('finance:snapshot', async () => {
8767
8771
  let account = st.account || null;
8768
8772
  let positions = [];
8769
8773
  let orders = [];
8774
+ let ordersError = '';
8770
8775
  let symbols = [];
8771
8776
  if (st.running) {
8772
8777
  const [a, p, o, sy] = await Promise.all([
@@ -8778,6 +8783,7 @@ ipcMain.handle('finance:snapshot', async () => {
8778
8783
  if (a && a.ok) account = a.data && a.data.account;
8779
8784
  if (p && p.ok) positions = (p.data && p.data.positions) || [];
8780
8785
  if (o && o.ok) orders = (o.data && o.data.orders) || [];
8786
+ else if (o && o.error) ordersError = String(o.error).slice(0, 200);
8781
8787
  if (sy && sy.ok) symbols = (sy.data && sy.data.symbols) || [];
8782
8788
  }
8783
8789
  const busy = financeState.traderSid && engine ? engine.isBusy(financeState.traderSid) : false;
@@ -8787,9 +8793,11 @@ ipcMain.handle('finance:snapshot', async () => {
8787
8793
  account,
8788
8794
  positions,
8789
8795
  orders,
8796
+ ordersError,
8790
8797
  symbols,
8791
8798
  cfg: f,
8792
8799
  roles: FIN_ROLES,
8800
+ rolesAuto: FIN_ROLES_AUTO,
8793
8801
  trader: { on: financeState.traderOn, busy, rounds: financeState.traderRounds, lastAt: financeState.lastRoundAt },
8794
8802
  };
8795
8803
  });
@@ -163,15 +163,27 @@
163
163
  </div>
164
164
  <div class="fin-card fin-card-trader">
165
165
  <div class="fin-card-title">TRADE AJANI <span id="finTraderDot" class="fin-dot off" title="Trader durumu"></span></div>
166
- <div class="fin-row"><select id="finTraderModel" title="Trader ajanının modeli — farklı API/model seçilebilir"></select></div>
167
- <div class="fin-row fin-mini">
168
- <label>Tur (sn)</label><input id="finInterval" type="number" min="30" max="3600" step="10" />
169
- <label>Max lot</label><input id="finMaxLot" type="number" min="0.01" max="100" step="0.01" />
166
+ <div class="fin-field">
167
+ <span>Model</span>
168
+ <select id="finTraderModel" title="Trader ajanının modeli — farklı API/model seçilebilir"></select>
170
169
  </div>
171
- <div class="fin-row fin-mini"><label>Semboller</label><button id="finSymBtn" class="fin-sym-select" title="MT5 sembol listesinden seç — tıkla">&#8230;</button></div>
172
- <div class="fin-row fin-roles-row">
173
- <label>Analiz ekibi</label>
174
- <div id="finRoles" class="fin-roles" title="Trader&#39;ın yanında koşacak uzman ajanlar — tüm skill + mt5 erişimli, işlem açmazlar"></div>
170
+ <div class="fin-grid2">
171
+ <div class="fin-field">
172
+ <span>Tur (sn)</span>
173
+ <input id="finInterval" type="number" min="30" max="3600" step="10" />
174
+ </div>
175
+ <div class="fin-field">
176
+ <span>Max lot</span>
177
+ <input id="finMaxLot" type="number" min="0.01" max="100" step="0.01" />
178
+ </div>
179
+ </div>
180
+ <div class="fin-field">
181
+ <span>Semboller</span>
182
+ <button id="finSymBtn" class="fin-sym-select" title="MT5 sembol listesinden seç — tıkla">&#8230;</button>
183
+ </div>
184
+ <div class="fin-field">
185
+ <span>Analiz ekibi <i class="fin-hint">— sadece sayı seç, rolleri sistem otomatik atar</i></span>
186
+ <div id="finRoles" class="fin-roles" title="Trader&#39;ın yanında koşacak uzman ajan SAYISI — roller otomatik atanır (Teknik → Risk → Haber); işlem açmazlar"></div>
175
187
  </div>
176
188
  <div class="fin-row fin-btn-row">
177
189
  <button id="finTraderBtn" class="fin-start">&#9654;&#xFE0E; Ajanı Başlat</button>
@@ -181,9 +193,7 @@
181
193
  <div class="fin-card">
182
194
  <div class="fin-card-title">POZİSYONLAR <span id="finPosCount"></span></div>
183
195
  <div id="finPosList"><div class="fin-empty">Açık pozisyon yok</div></div>
184
- </div>
185
- <div class="fin-card">
186
- <div class="fin-card-title">BEKLEYEN EMİRLER <span id="finOrdCount"></span></div>
196
+ <div class="fin-sect-title">BEKLEYEN EMİRLER <span id="finOrdCount"></span></div>
187
197
  <div id="finOrdList"><div class="fin-empty">Bekleyen emir yok</div></div>
188
198
  </div>
189
199
  <div class="fin-card">
@@ -8888,14 +8888,14 @@ const FIN_ORDER_TYPES = {
8888
8888
  7: { t: 'SELL STP-LMT', c: 'sell' },
8889
8889
  };
8890
8890
 
8891
- function finRenderOrders(list) {
8891
+ function finRenderOrders(list, err) {
8892
8892
  if (!els.finOrdList) return;
8893
8893
  els.finOrdList.textContent = '';
8894
8894
  if (els.finOrdCount) els.finOrdCount.textContent = list && list.length ? '(' + list.length + ')' : '';
8895
8895
  if (!list || !list.length) {
8896
8896
  const d = document.createElement('div');
8897
8897
  d.className = 'fin-empty';
8898
- d.textContent = 'Bekleyen emir yok';
8898
+ d.textContent = err ? 'Emir listesi alınamadı: ' + err : 'Bekleyen emir yok';
8899
8899
  els.finOrdList.appendChild(d);
8900
8900
  return;
8901
8901
  }
@@ -8994,89 +8994,60 @@ function finTraderInputsSet(cfg) {
8994
8994
  if (els.finTraderModel && ae !== els.finTraderModel && cfg.traderSel) els.finTraderModel.value = cfg.traderSel;
8995
8995
  }
8996
8996
 
8997
- /* ANALİZ EKİBİ: trader yanında koşacak uzman ajan rolleri — İKİ MOD:
8998
- (1) OTOMATİK: sadece SAYI gir → gereklı ajanları sistem kendisi ata;
8999
- (2) ELLE SEÇ: rol kutucukları (Risk / Teknik / Haber-Makro) çoklu seçilir.
9000
- Katalog sunucudan (finance snapshot/state.roles) gelir, yerel yedek var. */
8997
+ /* ANALİZ EKİBİ: SADECE SAYI seçilir — rolleri sistem otomatik atar
8998
+ (FIN_ROLES_AUTO sırası: Teknik → Risk → Haber). Elle rol kutucukları
8999
+ kaldırıldı; analysisAuto sunucuda daima açık. Katalog sunucudan gelir. */
9001
9000
  let finRolesCatalog = [
9002
9001
  { id: 'risk', label: 'Risk Ajanı', desc: 'marj/kaldıraç/SL disiplini, exposure ve günlük kayıp hızı denetimi' },
9003
9002
  { id: 'technic', label: 'Teknik Analiz', desc: 'trend/yapı/destek-direnç/momentum okuma, AL-SAT-BEKLE önerileri' },
9004
9003
  { id: 'macro', label: 'Haber / Makro', desc: 'haber akışı + ekonomik takvim, DXY/emtia bağıntıları, yön eğilimi' },
9005
9004
  ];
9005
+ let finRolesAuto = ['technic', 'risk', 'macro'];
9006
9006
  let finRolesDirty = false; /* tık→kaydet arası snapshot ezmesin */
9007
9007
  let finRolesSyncTimer = null;
9008
9008
 
9009
- function finRolesSel() {
9010
- const box = els.finRoles;
9011
- return box ? [...box.querySelectorAll('input[data-role]:checked')].map((cb) => cb.dataset.role) : [];
9009
+ function finRoleLabel(id) {
9010
+ const d = (finRolesCatalog || []).find((x) => x.id === String(id || ''));
9011
+ return d ? d.label : String(id || '');
9012
9012
  }
9013
9013
 
9014
9014
  function finRenderRoles(cfg) {
9015
9015
  const box = els.finRoles;
9016
9016
  if (!box) return;
9017
9017
  if (finRolesDirty) return; /* bekleyen kullanıcı değişikliği korunur */
9018
- const auto = !!(cfg && cfg.analysisAuto);
9019
- const count = Math.max(0, Math.round(Number(cfg && cfg.analysisCount) || 0));
9020
- const sel = cfg && Array.isArray(cfg.analysisTeam) ? cfg.analysisTeam : [];
9018
+ const max = Math.max(1, (finRolesAuto || []).length || 3);
9019
+ const count = Math.max(0, Math.min(max, Math.round(Number(cfg && cfg.analysisCount) || 0)));
9021
9020
  box.innerHTML = '';
9022
-
9023
- /* OTOMATİK çipi + sayı girişi */
9024
- const autoLab = document.createElement('label');
9025
- autoLab.className = 'fin-role fin-role-auto';
9026
- autoLab.title = 'Rol seçmeden SAYI gir — gereklı ajanları sistem otomatik atar (teknik → risk → haber sırası)';
9027
- const autoCb = document.createElement('input');
9028
- autoCb.type = 'checkbox';
9029
- autoCb.checked = auto;
9030
- autoLab.appendChild(autoCb);
9031
- autoLab.appendChild(document.createTextNode('⚙ Otomatik'));
9032
- autoCb.addEventListener('change', () => {
9033
- finRolesDirty = true;
9034
- finSaveCfg({ analysisAuto: autoCb.checked });
9035
- toast(autoCb.checked ? 'Analiz ekibi OTOMATİK — sayı kadar gereklı ajan atanır' : 'Analiz ekibi ELLE SEÇİM moduna geçti');
9036
- clearTimeout(finRolesSyncTimer);
9037
- finRolesSyncTimer = setTimeout(() => { finRolesDirty = false; finSnapshot(); }, 900);
9038
- });
9039
- box.appendChild(autoLab);
9040
-
9021
+ const wrap = document.createElement('div');
9022
+ wrap.className = 'fin-team';
9041
9023
  const cnt = document.createElement('input');
9042
9024
  cnt.type = 'number';
9043
9025
  cnt.className = 'fin-role-count';
9044
9026
  cnt.min = '0';
9045
- cnt.max = String(finRolesCatalog.length);
9027
+ cnt.max = String(max);
9046
9028
  cnt.step = '1';
9047
- cnt.value = String(count || 0);
9048
- cnt.title = 'Otomatik mod: kaç uzman ajan koşacak (0 = ekip yok)';
9049
- cnt.disabled = !auto;
9029
+ cnt.value = String(count);
9030
+ cnt.title = 'Kaç uzman ajan koşacak (0 = ekip yok, en fazla ' + max + '). Roller otomatik atanır.';
9031
+ const hint = document.createElement('span');
9032
+ hint.className = 'fin-team-hint';
9033
+ const names = (n) => finRolesAuto.slice(0, n).map(finRoleLabel);
9034
+ const paint = (n) => {
9035
+ hint.textContent = n > 0 ? 'otomatik: ' + names(n).join(' · ') : 'ekip kapalı — sadece trader koşar';
9036
+ };
9050
9037
  cnt.addEventListener('change', () => {
9038
+ const n = Math.max(0, Math.min(max, Math.round(Number(cnt.value) || 0)));
9039
+ cnt.value = String(n);
9051
9040
  finRolesDirty = true;
9052
- finSaveCfg({ analysisCount: Math.max(0, Math.round(Number(cnt.value) || 0)) });
9053
- toast('Analiz ekibi: ' + (Math.round(Number(cnt.value) || 0) || 'kapalı') + ' uzman ajan (otomatik)');
9041
+ finSaveCfg({ analysisAuto: true, analysisCount: n });
9042
+ paint(n);
9043
+ toast(n ? 'Analiz ekibi: ' + n + ' ajan — ' + names(n).join(', ') : 'Analiz ekibi kapatıldı');
9054
9044
  clearTimeout(finRolesSyncTimer);
9055
9045
  finRolesSyncTimer = setTimeout(() => { finRolesDirty = false; finSnapshot(); }, 900);
9056
9046
  });
9057
- box.appendChild(cnt);
9058
-
9059
- /* rol kutucukları — otomatik moddayken pasif */
9060
- for (const r of finRolesCatalog) {
9061
- const lab = document.createElement('label');
9062
- lab.className = 'fin-role';
9063
- const cb = document.createElement('input');
9064
- cb.type = 'checkbox';
9065
- cb.dataset.role = r.id;
9066
- cb.checked = sel.includes(r.id);
9067
- cb.disabled = auto;
9068
- cb.title = r.desc + ' — tüm skill + mt5 erişimli, işlem açmaz';
9069
- lab.appendChild(cb);
9070
- lab.appendChild(document.createTextNode(r.label));
9071
- cb.addEventListener('change', () => {
9072
- finRolesDirty = true;
9073
- finSaveCfg({ analysisTeam: finRolesSel() });
9074
- toast(r.label + (cb.checked ? ' ekibe eklendi — sonraki başlatışta koşar' : ' ekipten çıkarıldı'));
9075
- clearTimeout(finRolesSyncTimer);
9076
- finRolesSyncTimer = setTimeout(() => { finRolesDirty = false; finSnapshot(); }, 900);
9077
- });
9078
- box.appendChild(lab);
9079
- }
9047
+ paint(count);
9048
+ wrap.appendChild(cnt);
9049
+ wrap.appendChild(hint);
9050
+ box.appendChild(wrap);
9080
9051
  }
9081
9052
 
9082
9053
  function finRenderTrader(trader, cfg) {
@@ -9141,9 +9112,10 @@ async function finSnapshot() {
9141
9112
  finSetDot(b.connected ? true : b.running ? 'busy' : false, b);
9142
9113
  finRenderAccount(r.account);
9143
9114
  finRenderPositions(r.positions || []);
9144
- finRenderOrders(r.orders || []);
9115
+ finRenderOrders(r.orders || [], r.ordersError || '');
9145
9116
  finRenderSymbols(r.symbols || []);
9146
9117
  if (Array.isArray(r.roles) && r.roles.length) finRolesCatalog = r.roles;
9118
+ if (Array.isArray(r.rolesAuto) && r.rolesAuto.length) finRolesAuto = r.rolesAuto;
9147
9119
  finTraderInputsSet(r.cfg);
9148
9120
  finRenderRoles(r.cfg);
9149
9121
  finRenderTrader(r.trader, r.cfg);
@@ -9258,9 +9230,7 @@ if (els.finTraderBtn) {
9258
9230
  else if (r && r.ok) {
9259
9231
  const cfg = (await beast.financeState().catch(() => null));
9260
9232
  const c = (cfg && cfg.cfg) || {};
9261
- const team = c.analysisAuto
9262
- ? Math.round(Number(c.analysisCount) || 0)
9263
- : finRolesSel().length;
9233
+ const team = Math.round(Number(c.analysisCount) || 0);
9264
9234
  toast(team ? 'Trade ajanı + analiz ekibi (' + team + ' uzman) başladı — turlar panelde izlenir' : 'Trade ajanı başladı — turlar panelde izlenir');
9265
9235
  }
9266
9236
  }
@@ -4833,6 +4833,49 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
4833
4833
  }
4834
4834
  .fin-row input:focus, .fin-row select:focus { border-color: var(--accent); outline: none; }
4835
4835
 
4836
+ /* TRADE AJANI formu — etiket üstte, kontrol altta; tur/max lot 2 kolon */
4837
+ .fin-field { display: flex; flex-direction: column; gap: 3px; min-width: 0; margin-bottom: 8px; }
4838
+ .fin-field > span { font-size: 10px; color: var(--muted); }
4839
+ .fin-field input, .fin-field select {
4840
+ width: 100%;
4841
+ min-width: 0;
4842
+ background: var(--panel2);
4843
+ border: 1px solid var(--border);
4844
+ color: var(--text);
4845
+ font-size: 12px;
4846
+ padding: 4px 7px;
4847
+ border-radius: 6px;
4848
+ }
4849
+ .fin-field input:focus, .fin-field select:focus { border-color: var(--accent); outline: none; }
4850
+ .fin-field .fin-sym-select { width: 100%; }
4851
+ .fin-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
4852
+ .fin-grid2 .fin-field { margin-bottom: 8px; }
4853
+ .fin-hint { font-style: normal; opacity: 0.75; }
4854
+ /* ekib sayısı + otomatik atama özeti */
4855
+ .fin-team { display: flex; align-items: center; gap: 8px; min-width: 0; }
4856
+ .fin-team-hint {
4857
+ flex: 1;
4858
+ min-width: 0;
4859
+ font-size: 10.5px;
4860
+ color: var(--muted);
4861
+ white-space: nowrap;
4862
+ overflow: hidden;
4863
+ text-overflow: ellipsis;
4864
+ }
4865
+ /* POZİSYONLAR kartı içi bölüm başlığı (bekleyen emirler) */
4866
+ .fin-sect-title {
4867
+ display: flex;
4868
+ align-items: center;
4869
+ gap: 6px;
4870
+ margin: 9px 0 6px;
4871
+ padding-top: 8px;
4872
+ border-top: 1px dashed var(--border);
4873
+ font-size: 10px;
4874
+ font-weight: 800;
4875
+ letter-spacing: 1px;
4876
+ color: var(--muted);
4877
+ }
4878
+
4836
4879
  /* TRADE AJANI sembol seçme düğmesi — tıklayınca MT5 sembol seçici açılır */
4837
4880
  .fin-sym-select {
4838
4881
  flex: 1;
@@ -4887,15 +4930,15 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
4887
4930
  .fin-role input:disabled { opacity: 0.45; cursor: default; }
4888
4931
  .fin-role-auto { font-weight: 700; }
4889
4932
  /* Otomatik moddaki SAYI girişi */
4890
- .fin-role-count {
4891
- flex: none; width: 44px;
4933
+ .fin-field .fin-role-count {
4934
+ flex: none; width: 52px;
4892
4935
  background: var(--panel2); color: var(--text);
4893
4936
  border: 1px solid var(--border); border-radius: 8px;
4894
- font-size: 11px; font-weight: 700; text-align: center;
4895
- padding: 2px 3px;
4937
+ font-size: 12px; font-weight: 700; text-align: center;
4938
+ padding: 3px 3px;
4896
4939
  }
4897
- .fin-role-count:focus { border-color: var(--accent); outline: none; }
4898
- .fin-role-count:disabled { opacity: 0.45; }
4940
+ .fin-field .fin-role-count:focus { border-color: var(--accent); outline: none; }
4941
+ .fin-field .fin-role-count:disabled { opacity: 0.45; }
4899
4942
  .fin-start {
4900
4943
  flex: none;
4901
4944
  background: var(--accent);