beast-agent 2.37.1 → 2.38.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/engine.js +17 -10
- package/src/main.js +16 -7
- package/src/renderer/index.html +18 -11
- package/src/renderer/renderer.js +136 -21
- package/src/renderer/style.css +24 -0
package/package.json
CHANGED
package/src/agent/engine.js
CHANGED
|
@@ -1919,18 +1919,25 @@ class Engine {
|
|
|
1919
1919
|
macro:
|
|
1920
1920
|
'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.',
|
|
1921
1921
|
})[String((session && session.financeRole) || '')] || '';
|
|
1922
|
-
/* ROL → SKILL eşleştirmesi (ayarlar modalı):
|
|
1923
|
-
|
|
1924
|
-
|
|
1922
|
+
/* ROL → SKILL eşleştirmesi (ayarlar modalı): rol başına TEK ve ZORUNLU
|
|
1923
|
+
skill. Seçili SKILL.md'nin TAM GÖVDESİ prompta gömülür — ajan skill
|
|
1924
|
+
aracını çağırmayı atlasa bile prosedür KESİN uygulanır. Eşleştirme
|
|
1925
|
+
boşsa satır eklenmez; ajan skill'i göreve göre kendi seçer (SKILLS). */
|
|
1925
1926
|
const roleSkills = Array.isArray(session && session.financeRoleSkills)
|
|
1926
|
-
? session.financeRoleSkills.map((s) => String(s || '').trim()).filter(Boolean).slice(0,
|
|
1927
|
+
? session.financeRoleSkills.map((s) => String(s || '').trim()).filter(Boolean).slice(0, 1)
|
|
1927
1928
|
: [];
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1929
|
+
let roleSkillBlock = '';
|
|
1930
|
+
if (roleBlock && roleSkills.length) {
|
|
1931
|
+
const roleSkillName = roleSkills[0];
|
|
1932
|
+
const sb = this._skillBody({ name: roleSkillName });
|
|
1933
|
+
roleSkillBlock =
|
|
1934
|
+
` Bu rolün ZORUNLU skill'i: skill("${roleSkillName}")` +
|
|
1935
|
+
(sb && sb.ok && sb.content
|
|
1936
|
+
? ' — aşağıda TAM prosedürü verilmiştir; HER TURDA birebir uygula (ayrıca okumana gerek yok):\n\n' +
|
|
1937
|
+
`===== SKILL: ${roleSkillName} =====\n${sb.content}\n===== /SKILL =====`
|
|
1938
|
+
: ' — ilk turda bu skill\'i mutlaka oku ve prosedürüne birebir uy.');
|
|
1939
|
+
}
|
|
1940
|
+
const roleBlockFull = roleBlock ? roleBlock + roleSkillBlock : '';
|
|
1934
1941
|
/* FİNANS EKİBİ: tüm finance ajanları tek DM grubundadır — sohbet grup
|
|
1935
1942
|
thread'inde toplanır (ayrı ayrı 1:1 thread'lere dağılmaz) */
|
|
1936
1943
|
const finJob = this._bgJobs && this._bgJobs.get(String(session && session.id));
|
package/src/main.js
CHANGED
|
@@ -8477,10 +8477,9 @@ function finCfg() {
|
|
|
8477
8477
|
f.analysisAuto = true;
|
|
8478
8478
|
if (!Number.isFinite(Number(f.analysisCount))) f.analysisCount = 2;
|
|
8479
8479
|
f.analysisCount = Math.max(0, Math.min(FIN_ROLES_AUTO.length, Math.round(Number(f.analysisCount) || 0)));
|
|
8480
|
-
/* ROL → SKILL eşleştirmesi:
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
doldurduğu varsayılanlar bir kez temizlenir. */
|
|
8480
|
+
/* ROL → SKILL eşleştirmesi: rol başına TEK skill — modalda zorunlu tek
|
|
8481
|
+
seçim yapılır. Eski çoklu seçimlerden yalnız İLKİ korunur (göç). Skill
|
|
8482
|
+
adları kurulu katalogdan gelir. */
|
|
8484
8483
|
if (f.roleSkillsDefaultsCleared !== true) {
|
|
8485
8484
|
f.roleSkills = {};
|
|
8486
8485
|
f.roleSkillsDefaultsCleared = true;
|
|
@@ -8488,7 +8487,7 @@ function finCfg() {
|
|
|
8488
8487
|
if (!f.roleSkills || typeof f.roleSkills !== 'object') f.roleSkills = {};
|
|
8489
8488
|
for (const d of FIN_ROLES) {
|
|
8490
8489
|
const cur = Array.isArray(f.roleSkills[d.id]) ? f.roleSkills[d.id] : [];
|
|
8491
|
-
f.roleSkills[d.id] = cur.map((s) => String(s || '').trim()).filter(Boolean).slice(0,
|
|
8490
|
+
f.roleSkills[d.id] = cur.map((s) => String(s || '').trim()).filter(Boolean).slice(0, 1);
|
|
8492
8491
|
}
|
|
8493
8492
|
if (!Number(f.intervalSec)) f.intervalSec = 120;
|
|
8494
8493
|
if (!Number(f.maxLot)) f.maxLot = 0.1;
|
|
@@ -9713,12 +9712,22 @@ ipcMain.handle('finance:settings', async (_e, patch) => {
|
|
|
9713
9712
|
if (p.analysisTeam !== undefined) f.analysisTeam = finRolesValid(p.analysisTeam);
|
|
9714
9713
|
if (p.analysisAuto !== undefined) f.analysisAuto = !!p.analysisAuto;
|
|
9715
9714
|
if (p.analysisCount !== undefined) f.analysisCount = Math.max(0, Math.min(FIN_ROLES_AUTO.length, Math.round(Number(p.analysisCount) || 0)));
|
|
9716
|
-
/* ROL → SKILL eşleştirmesi güncellemesi (modal) */
|
|
9715
|
+
/* ROL → SKILL eşleştirmesi güncellemesi (modal): rol başına TEK skill */
|
|
9717
9716
|
if (p.roleSkills !== undefined && p.roleSkills && typeof p.roleSkills === 'object') {
|
|
9718
9717
|
for (const d of FIN_ROLES) {
|
|
9719
9718
|
if (p.roleSkills[d.id] === undefined) continue;
|
|
9720
9719
|
f.roleSkills[d.id] = (Array.isArray(p.roleSkills[d.id]) ? p.roleSkills[d.id] : [])
|
|
9721
|
-
.map((s) => String(s || '').trim()).filter(Boolean).slice(0,
|
|
9720
|
+
.map((s) => String(s || '').trim()).filter(Boolean).slice(0, 1);
|
|
9721
|
+
}
|
|
9722
|
+
/* koşan rol ajanlarını da tazele — seçim sonraki turdan itibaren sistem
|
|
9723
|
+
promptuna girer (ajanı durdurmaya gerek yok) */
|
|
9724
|
+
if (financeState.agents && engine) {
|
|
9725
|
+
for (const [sid, a] of financeState.agents) {
|
|
9726
|
+
try {
|
|
9727
|
+
const ss = engine.cache.get(sid);
|
|
9728
|
+
if (ss && a && a.role) finApplyTraderFields(ss, a.symbols, a.role);
|
|
9729
|
+
} catch {}
|
|
9730
|
+
}
|
|
9722
9731
|
}
|
|
9723
9732
|
}
|
|
9724
9733
|
if (p.pythonPath !== undefined) f.pythonPath = String(p.pythonPath || '').trim();
|
package/src/renderer/index.html
CHANGED
|
@@ -153,7 +153,7 @@
|
|
|
153
153
|
<button id="finSettings" title="Görünüm ayarları — bölümleri göster/gizle">⚙</button>
|
|
154
154
|
</div>
|
|
155
155
|
<div id="finBody">
|
|
156
|
-
<div class="fin-card">
|
|
156
|
+
<div class="fin-card" data-fin-card="account">
|
|
157
157
|
<div class="fin-card-title">HESAP</div>
|
|
158
158
|
<div class="fin-grid">
|
|
159
159
|
<div class="fin-kv"><span>Bakiye</span><b id="finBalance">—</b></div>
|
|
@@ -162,8 +162,8 @@
|
|
|
162
162
|
<div class="fin-kv"><span>Serbest Marj</span><b id="finFree">—</b></div>
|
|
163
163
|
</div>
|
|
164
164
|
</div>
|
|
165
|
-
<div class="fin-card fin-card-trader">
|
|
166
|
-
<div class="fin-card-title">TRADE AJANI <span id="finTraderDot" class="fin-dot off" title="Trader durumu"></span><span class="file-spacer"></span><button id="finModelRefreshBtn" title="Modelleri yeniden çek — eksik/güncel modelleri tazeler">⟳</button><button id="finSkillsBtn" title="Rol → skill eşleştirmesi —
|
|
165
|
+
<div class="fin-card fin-card-trader" data-fin-card="trader">
|
|
166
|
+
<div class="fin-card-title">TRADE AJANI <span id="finTraderDot" class="fin-dot off" title="Trader durumu"></span><span class="file-spacer"></span><button id="finModelRefreshBtn" title="Modelleri yeniden çek — eksik/güncel modelleri tazeler">⟳</button><button id="finSkillsBtn" title="Rol → skill eşleştirmesi — her role ZORUNLU tek skill (ajan her turda onu okur)">⚙</button></div>
|
|
167
167
|
<div class="fin-field">
|
|
168
168
|
<span>Model</span>
|
|
169
169
|
<select id="finTraderModel" title="Trader ajanının modeli — farklı API/model seçilebilir"></select>
|
|
@@ -195,7 +195,7 @@
|
|
|
195
195
|
</div>
|
|
196
196
|
<div id="finTraderStatus">Kapalı</div>
|
|
197
197
|
</div>
|
|
198
|
-
<div class="fin-card" id="finRiskCard" hidden>
|
|
198
|
+
<div class="fin-card" id="finRiskCard" data-fin-card="risk" hidden>
|
|
199
199
|
<div class="fin-card-title">RİSK OTOMASYONU <span id="finWatchDot" class="fin-dot off" title="Koruma döngüsü"></span><span id="finWatchInfo" class="fin-hint"></span></div>
|
|
200
200
|
<div class="fin-field fin-check">
|
|
201
201
|
<label title="5 saniyelik döngü: +R'da SL'yi başabaşa çeker, trailing uygular, kısmi TP alır — ajan turunu beklemez">
|
|
@@ -224,6 +224,10 @@
|
|
|
224
224
|
<option value="flatten">Durdur + hepsini kapat</option>
|
|
225
225
|
</select>
|
|
226
226
|
</div>
|
|
227
|
+
<div id="finAlertList" class="fin-alerts"><div class="fin-empty">Aktif fiyat alarmı yok</div></div>
|
|
228
|
+
</div>
|
|
229
|
+
<div class="fin-card" id="finNotifyCard" data-fin-card="notify" hidden>
|
|
230
|
+
<div class="fin-card-title">BİLDİRİM <span class="fin-hint">— kanal seçimi ve olay filtresi</span></div>
|
|
227
231
|
<div class="fin-field">
|
|
228
232
|
<span>Bildirim kanalı</span>
|
|
229
233
|
<select id="finNotifyTarget" title="Emir/işlem bildirimleri bu kanala gider; panel ve masaüstü toast her zaman çalışır">
|
|
@@ -239,9 +243,8 @@
|
|
|
239
243
|
<input id="finNotifyTradeOnly" type="checkbox" checked /> Kanala sadece emir/işlem olayları gelsin (alarm gelmez)
|
|
240
244
|
</label>
|
|
241
245
|
</div>
|
|
242
|
-
<div id="finAlertList" class="fin-alerts"><div class="fin-empty">Aktif fiyat alarmı yok</div></div>
|
|
243
246
|
</div>
|
|
244
|
-
<div class="fin-card" id="finPerfCard" hidden>
|
|
247
|
+
<div class="fin-card" id="finPerfCard" data-fin-card="perf" hidden>
|
|
245
248
|
<div class="fin-card-title">PERFORMANS <span id="finStatsInfo" class="fin-hint"></span><span class="file-spacer"></span><button id="finReportBtn" title="Haftalık rapor üret — istatistik + işlem günlüğü + ajan değerlendirmesi">📄 Rapor</button></div>
|
|
246
249
|
<div id="finEquityChart" class="fin-equity"></div>
|
|
247
250
|
<div class="fin-grid">
|
|
@@ -253,13 +256,13 @@
|
|
|
253
256
|
<div class="fin-kv"><span>İşlem (90g)</span><b id="finStatTrades">—</b></div>
|
|
254
257
|
</div>
|
|
255
258
|
</div>
|
|
256
|
-
<div class="fin-card">
|
|
259
|
+
<div class="fin-card" data-fin-card="positions">
|
|
257
260
|
<div class="fin-card-title">POZİSYONLAR <span id="finPosCount"></span></div>
|
|
258
261
|
<div id="finPosList"><div class="fin-empty">Açık pozisyon yok</div></div>
|
|
259
262
|
<div class="fin-sect-title">BEKLEYEN EMİRLER <span id="finOrdCount"></span></div>
|
|
260
263
|
<div id="finOrdList"><div class="fin-empty">Bekleyen emir yok</div></div>
|
|
261
264
|
</div>
|
|
262
|
-
<div class="fin-card">
|
|
265
|
+
<div class="fin-card" data-fin-card="market">
|
|
263
266
|
<div class="fin-card-title">
|
|
264
267
|
PİYASA
|
|
265
268
|
<span class="file-spacer"></span>
|
|
@@ -268,7 +271,7 @@
|
|
|
268
271
|
</div>
|
|
269
272
|
<div id="finSymList"><div class="fin-empty">—</div></div>
|
|
270
273
|
</div>
|
|
271
|
-
<div class="fin-card fin-grow" id="finFlowCard" hidden>
|
|
274
|
+
<div class="fin-card fin-grow" id="finFlowCard" data-fin-card="flow" hidden>
|
|
272
275
|
<div class="fin-card-title">AKIŞ</div>
|
|
273
276
|
<div id="finLog"></div>
|
|
274
277
|
</div>
|
|
@@ -758,7 +761,7 @@
|
|
|
758
761
|
</div>
|
|
759
762
|
<div class="mini-body">
|
|
760
763
|
<div id="finSkillsList" class="mini-list"></div>
|
|
761
|
-
<div class="fin-sym-hint"
|
|
764
|
+
<div class="fin-sym-hint">Her rol için TEK skill ZORUNLUDUR — aynı role birden fazla skill seçilemez. Seçili skill kaldırılamaz; değiştirmek için başka bir skill'e tıkla. Seçim, koşan ajanlar dahil sonraki turdan itibaren rol ajanının sistem promptuna zorunlu skill olarak girer.</div>
|
|
762
765
|
</div>
|
|
763
766
|
</div>
|
|
764
767
|
</div>
|
|
@@ -770,11 +773,15 @@
|
|
|
770
773
|
<button class="mini-close" id="finSettingsClose" title="Kapat">×</button>
|
|
771
774
|
</div>
|
|
772
775
|
<div class="mini-body">
|
|
773
|
-
<div class="fin-set-hint">Varsayılan olarak
|
|
776
|
+
<div class="fin-set-hint">Varsayılan olarak dört bölüm de gizlidir — açmak tamamen isteğe bağlıdır. Seçim bilgisayarda hatırlanır. Risk otomasyonu gizliyken AKTİF OLMAZ.</div>
|
|
774
777
|
<label class="fin-set-row" title="BE + trailing + kısmi TP koruması, günlük limitler, fiyat alarmları bölümü">
|
|
775
778
|
<input id="finShowRisk" type="checkbox" />
|
|
776
779
|
<span class="fsr-main"><b>RİSK OTOMASYONU</b><i>BE + trailing + kısmi TP, günlük limitler, alarmlar</i></span>
|
|
777
780
|
</label>
|
|
781
|
+
<label class="fin-set-row" title="Bildirim kanalı (WhatsApp/Telegram/Discord) ve hangi olayların gönderileceği bölümü">
|
|
782
|
+
<input id="finShowNotify" type="checkbox" />
|
|
783
|
+
<span class="fsr-main"><b>BİLDİRİM</b><i>Kanal seçimi, emir/alarm olay filtresi</i></span>
|
|
784
|
+
</label>
|
|
778
785
|
<label class="fin-set-row" title="Equity grafiği + günlük/haftalık istatistikler + haftalık rapor bölümü">
|
|
779
786
|
<input id="finShowPerf" type="checkbox" />
|
|
780
787
|
<span class="fsr-main"><b>PERFORMANS</b><i>Equity grafiği, istatistikler, haftalık rapor</i></span>
|
package/src/renderer/renderer.js
CHANGED
|
@@ -162,6 +162,7 @@ const els = {
|
|
|
162
162
|
stSplit: $('#stSplit'),
|
|
163
163
|
finBtn: $('#finBtn'),
|
|
164
164
|
finPanel: $('#finPanel'),
|
|
165
|
+
finBody: $('#finBody'),
|
|
165
166
|
finDot: $('#finDot'),
|
|
166
167
|
finTerm: $('#finTerm'),
|
|
167
168
|
finReconnect: $('#finReconnect'),
|
|
@@ -169,9 +170,11 @@ const els = {
|
|
|
169
170
|
finSettingsOverlay: $('#finSettingsOverlay'),
|
|
170
171
|
finSettingsClose: $('#finSettingsClose'),
|
|
171
172
|
finShowRisk: $('#finShowRisk'),
|
|
173
|
+
finShowNotify: $('#finShowNotify'),
|
|
172
174
|
finShowPerf: $('#finShowPerf'),
|
|
173
175
|
finShowFlow: $('#finShowFlow'),
|
|
174
176
|
finRiskCard: $('#finRiskCard'),
|
|
177
|
+
finNotifyCard: $('#finNotifyCard'),
|
|
175
178
|
finPerfCard: $('#finPerfCard'),
|
|
176
179
|
finFlowCard: $('#finFlowCard'),
|
|
177
180
|
finBalance: $('#finBalance'),
|
|
@@ -4947,7 +4950,9 @@ async function refreshAgentsPane() {
|
|
|
4947
4950
|
kullanıcı çalışırken elle kapatırsa ezilmez; dahili tarayıcı ve IDE modu
|
|
4948
4951
|
açıkken karışılmaz — orada railBtn ile elle açılır)
|
|
4949
4952
|
- Tüm işler bitince otomatik KAPANIR (yalnız açılışı biz yaptıysak;
|
|
4950
|
-
kullanıcı elle açtıysa açık kalır)
|
|
4953
|
+
kullanıcı elle açtıysa açık kalır). BEAST FINANCE istisnası: trade ajanı
|
|
4954
|
+
durdurulunca konsol KAPANMAZ — duran ajanların raporları/geçmişi görünür
|
|
4955
|
+
kalsın; kullanıcı isterse railBtn ile kendisi kapatır. */
|
|
4951
4956
|
function maybeAutoOpenRail() {
|
|
4952
4957
|
const hasRunning = agentState.jobs.some((j) => j.status === 'running');
|
|
4953
4958
|
const hidden = document.body.classList.contains('rail-hidden');
|
|
@@ -4957,7 +4962,8 @@ function maybeAutoOpenRail() {
|
|
|
4957
4962
|
railPrefBeforeBrowser = true;
|
|
4958
4963
|
}
|
|
4959
4964
|
if (!hasRunning && agentState.autoOpened && !hidden &&
|
|
4960
|
-
!railManualOpen && !document.body.classList.contains('browser-open')
|
|
4965
|
+
!railManualOpen && !document.body.classList.contains('browser-open') &&
|
|
4966
|
+
!financeModeOn()) {
|
|
4961
4967
|
toggleRail(true);
|
|
4962
4968
|
railManualOpen = false;
|
|
4963
4969
|
}
|
|
@@ -9691,15 +9697,16 @@ function finStrategyFlush() {
|
|
|
9691
9697
|
}
|
|
9692
9698
|
|
|
9693
9699
|
/* ---------- GÖRÜNÜM AYARLARI (isteğe bağlı bölümler) ----------
|
|
9694
|
-
RİSK OTOMASYONU + PERFORMANS + AKIŞ varsayılan GİZLİ; açmak
|
|
9695
|
-
Seçim localStorage'da hatırlanır. Risk otomasyonu gizliyken
|
|
9696
|
-
AKTİF OLMAZ — kart yeniden gösterilince kutucuktan açılabilir. */
|
|
9700
|
+
RİSK OTOMASYONU + BİLDİRİM + PERFORMANS + AKIŞ varsayılan GİZLİ; açmak
|
|
9701
|
+
isteğe bağlı. Seçim localStorage'da hatırlanır. Risk otomasyonu gizliyken
|
|
9702
|
+
watchdog AKTİF OLMAZ — kart yeniden gösterilince kutucuktan açılabilir. */
|
|
9697
9703
|
const finViewKey = 'beast.financeView';
|
|
9698
|
-
const finView = { risk: false, perf: false, flow: false };
|
|
9704
|
+
const finView = { risk: false, notify: false, perf: false, flow: false };
|
|
9699
9705
|
try {
|
|
9700
9706
|
const v = JSON.parse(localStorage.getItem(finViewKey) || 'null');
|
|
9701
9707
|
if (v && typeof v === 'object') {
|
|
9702
9708
|
finView.risk = v.risk === true;
|
|
9709
|
+
finView.notify = v.notify === true;
|
|
9703
9710
|
finView.perf = v.perf === true;
|
|
9704
9711
|
finView.flow = v.flow === true;
|
|
9705
9712
|
}
|
|
@@ -9707,15 +9714,18 @@ try {
|
|
|
9707
9714
|
|
|
9708
9715
|
function finViewPaint() {
|
|
9709
9716
|
if (els.finRiskCard) els.finRiskCard.hidden = !finView.risk;
|
|
9717
|
+
if (els.finNotifyCard) els.finNotifyCard.hidden = !finView.notify;
|
|
9710
9718
|
if (els.finPerfCard) els.finPerfCard.hidden = !finView.perf;
|
|
9711
9719
|
if (els.finFlowCard) els.finFlowCard.hidden = !finView.flow;
|
|
9712
9720
|
if (els.finShowRisk) els.finShowRisk.checked = finView.risk;
|
|
9721
|
+
if (els.finShowNotify) els.finShowNotify.checked = finView.notify;
|
|
9713
9722
|
if (els.finShowPerf) els.finShowPerf.checked = finView.perf;
|
|
9714
9723
|
if (els.finShowFlow) els.finShowFlow.checked = finView.flow;
|
|
9715
9724
|
const row = (cb) => cb && cb.closest('.fin-set-row');
|
|
9716
9725
|
const r1 = row(els.finShowRisk); if (r1) r1.classList.toggle('on', finView.risk);
|
|
9717
|
-
const r2 = row(els.
|
|
9718
|
-
const r3 = row(els.
|
|
9726
|
+
const r2 = row(els.finShowNotify); if (r2) r2.classList.toggle('on', finView.notify);
|
|
9727
|
+
const r3 = row(els.finShowPerf); if (r3) r3.classList.toggle('on', finView.perf);
|
|
9728
|
+
const r4 = row(els.finShowFlow); if (r4) r4.classList.toggle('on', finView.flow);
|
|
9719
9729
|
}
|
|
9720
9730
|
|
|
9721
9731
|
function finViewApply() {
|
|
@@ -9741,7 +9751,8 @@ function finViewToggle(key, on) {
|
|
|
9741
9751
|
? 'RİSK OTOMASYONU gösteriliyor — aktif etmek için karttaki kutucuğu işaretle'
|
|
9742
9752
|
: 'RİSK OTOMASYONU gizlendi ve kapatıldı');
|
|
9743
9753
|
} else {
|
|
9744
|
-
|
|
9754
|
+
const label = key === 'notify' ? 'BİLDİRİM' : key === 'perf' ? 'PERFORMANS' : 'AKIŞ';
|
|
9755
|
+
toast(label + (on ? ' bölümü gösteriliyor' : ' bölümü gizlendi'));
|
|
9745
9756
|
}
|
|
9746
9757
|
if (financeModeOn()) finSnapshot();
|
|
9747
9758
|
}
|
|
@@ -9757,10 +9768,105 @@ if (els.finSettingsOverlay) {
|
|
|
9757
9768
|
});
|
|
9758
9769
|
}
|
|
9759
9770
|
if (els.finShowRisk) els.finShowRisk.addEventListener('change', () => finViewToggle('risk', els.finShowRisk.checked));
|
|
9771
|
+
if (els.finShowNotify) els.finShowNotify.addEventListener('change', () => finViewToggle('notify', els.finShowNotify.checked));
|
|
9760
9772
|
if (els.finShowPerf) els.finShowPerf.addEventListener('change', () => finViewToggle('perf', els.finShowPerf.checked));
|
|
9761
9773
|
if (els.finShowFlow) els.finShowFlow.addEventListener('change', () => finViewToggle('flow', els.finShowFlow.checked));
|
|
9762
9774
|
finViewApply();
|
|
9763
9775
|
|
|
9776
|
+
/* ---------- BÖLÜM SIRALAMA (sürükle-bırak) ----------
|
|
9777
|
+
Kartların sol üstündeki tutamak (⠿) ile bölümlerin yerini değiştir;
|
|
9778
|
+
sıra localStorage'a yazılır — panel kapatılıp açılsa da korunur. */
|
|
9779
|
+
const finOrderKey = 'beast.financeOrder';
|
|
9780
|
+
let finDragCard = null;
|
|
9781
|
+
|
|
9782
|
+
function finOrderLoad() {
|
|
9783
|
+
try {
|
|
9784
|
+
const v = JSON.parse(localStorage.getItem(finOrderKey) || 'null');
|
|
9785
|
+
return Array.isArray(v) ? v.map(String).filter(Boolean) : [];
|
|
9786
|
+
} catch { return []; }
|
|
9787
|
+
}
|
|
9788
|
+
|
|
9789
|
+
function finOrderApply() {
|
|
9790
|
+
const body = els.finBody;
|
|
9791
|
+
if (!body) return;
|
|
9792
|
+
const cards = [...body.querySelectorAll(':scope > .fin-card')];
|
|
9793
|
+
const byKey = new Map();
|
|
9794
|
+
for (const c of cards) if (c.dataset.finCard) byKey.set(c.dataset.finCard, c);
|
|
9795
|
+
for (const key of finOrderLoad()) {
|
|
9796
|
+
const c = byKey.get(key);
|
|
9797
|
+
if (c) { body.appendChild(c); byKey.delete(key); }
|
|
9798
|
+
}
|
|
9799
|
+
for (const c of byKey.values()) body.appendChild(c); /* yeni kartlar sona */
|
|
9800
|
+
}
|
|
9801
|
+
|
|
9802
|
+
function finOrderSave() {
|
|
9803
|
+
const body = els.finBody;
|
|
9804
|
+
if (!body) return;
|
|
9805
|
+
const keys = [...body.querySelectorAll(':scope > .fin-card')]
|
|
9806
|
+
.map((c) => c.dataset.finCard)
|
|
9807
|
+
.filter(Boolean);
|
|
9808
|
+
try { localStorage.setItem(finOrderKey, JSON.stringify(keys)); } catch {}
|
|
9809
|
+
}
|
|
9810
|
+
|
|
9811
|
+
function finCardsInit() {
|
|
9812
|
+
const body = els.finBody;
|
|
9813
|
+
if (!body) return;
|
|
9814
|
+
finOrderApply();
|
|
9815
|
+
const cards = [...body.querySelectorAll(':scope > .fin-card')];
|
|
9816
|
+
for (const card of cards) {
|
|
9817
|
+
const title = card.querySelector('.fin-card-title');
|
|
9818
|
+
if (!title) continue;
|
|
9819
|
+
const grip = document.createElement('span');
|
|
9820
|
+
grip.className = 'fin-grip';
|
|
9821
|
+
grip.title = 'Sürükle-bırak: bölümün yerini değiştir';
|
|
9822
|
+
grip.textContent = '⠿';
|
|
9823
|
+
title.prepend(grip);
|
|
9824
|
+
grip.addEventListener('mousedown', () => { card.draggable = true; });
|
|
9825
|
+
card.addEventListener('dragstart', (e) => {
|
|
9826
|
+
finDragCard = card;
|
|
9827
|
+
card.classList.add('fin-dragging');
|
|
9828
|
+
try {
|
|
9829
|
+
e.dataTransfer.effectAllowed = 'move';
|
|
9830
|
+
e.dataTransfer.setData('text/plain', card.dataset.finCard || '');
|
|
9831
|
+
} catch {}
|
|
9832
|
+
});
|
|
9833
|
+
card.addEventListener('dragend', () => {
|
|
9834
|
+
finDragCard = null;
|
|
9835
|
+
card.draggable = false;
|
|
9836
|
+
card.classList.remove('fin-dragging');
|
|
9837
|
+
body.querySelectorAll('.fin-drop-top, .fin-drop-bottom')
|
|
9838
|
+
.forEach((x) => x.classList.remove('fin-drop-top', 'fin-drop-bottom'));
|
|
9839
|
+
finOrderSave();
|
|
9840
|
+
});
|
|
9841
|
+
card.addEventListener('dragover', (e) => {
|
|
9842
|
+
if (!finDragCard || finDragCard === card) return;
|
|
9843
|
+
e.preventDefault();
|
|
9844
|
+
try { e.dataTransfer.dropEffect = 'move'; } catch {}
|
|
9845
|
+
const r = card.getBoundingClientRect();
|
|
9846
|
+
const after = e.clientY > r.top + r.height / 2;
|
|
9847
|
+
body.querySelectorAll('.fin-drop-top, .fin-drop-bottom')
|
|
9848
|
+
.forEach((x) => x.classList.remove('fin-drop-top', 'fin-drop-bottom'));
|
|
9849
|
+
card.classList.add(after ? 'fin-drop-bottom' : 'fin-drop-top');
|
|
9850
|
+
});
|
|
9851
|
+
card.addEventListener('dragleave', () => card.classList.remove('fin-drop-top', 'fin-drop-bottom'));
|
|
9852
|
+
card.addEventListener('drop', (e) => {
|
|
9853
|
+
e.preventDefault();
|
|
9854
|
+
if (!finDragCard || finDragCard === card) return;
|
|
9855
|
+
const r = card.getBoundingClientRect();
|
|
9856
|
+
const after = e.clientY > r.top + r.height / 2;
|
|
9857
|
+
if (after) card.after(finDragCard);
|
|
9858
|
+
else card.before(finDragCard);
|
|
9859
|
+
card.classList.remove('fin-drop-top', 'fin-drop-bottom');
|
|
9860
|
+
finOrderSave();
|
|
9861
|
+
});
|
|
9862
|
+
}
|
|
9863
|
+
document.addEventListener('mouseup', () => {
|
|
9864
|
+
if (finDragCard) return;
|
|
9865
|
+
body.querySelectorAll('.fin-card[draggable="true"]').forEach((c) => { c.draggable = false; });
|
|
9866
|
+
});
|
|
9867
|
+
}
|
|
9868
|
+
finCardsInit();
|
|
9869
|
+
|
|
9764
9870
|
if (els.finInterval) els.finInterval.addEventListener('change', () => {
|
|
9765
9871
|
const v = Math.max(30, Math.min(3600, Math.round(Number(els.finInterval.value) || 120)));
|
|
9766
9872
|
els.finInterval.value = v;
|
|
@@ -10068,31 +10174,40 @@ function finRenderSkills() {
|
|
|
10068
10174
|
head.innerHTML =
|
|
10069
10175
|
'<b>' + escapeHtml(String(r.label || r.id)) + '</b>' +
|
|
10070
10176
|
'<span>' + escapeHtml(String(r.desc || '').slice(0, 110)) + '</span>';
|
|
10177
|
+
const cur = Array.isArray(map[r.id]) ? map[r.id].map((x) => String(x || '').trim()).filter(Boolean) : [];
|
|
10178
|
+
const active = cur.length ? cur[0] : '';
|
|
10179
|
+
if (!active) {
|
|
10180
|
+
const warn = document.createElement('span');
|
|
10181
|
+
warn.className = 'fin-skill-req';
|
|
10182
|
+
warn.textContent = 'ZORUNLU — skill seçilmedi';
|
|
10183
|
+
head.appendChild(warn);
|
|
10184
|
+
}
|
|
10071
10185
|
row.appendChild(head);
|
|
10072
10186
|
const chips = document.createElement('div');
|
|
10073
10187
|
chips.className = 'fin-skill-chips';
|
|
10074
10188
|
for (const s of finSkillNames) {
|
|
10075
|
-
const
|
|
10189
|
+
const on = active === s.name;
|
|
10076
10190
|
const chip = document.createElement('label');
|
|
10077
|
-
chip.className = 'fin-skill-chip' + (
|
|
10191
|
+
chip.className = 'fin-skill-chip' + (on ? ' on' : '');
|
|
10078
10192
|
chip.title = s.description || s.name;
|
|
10079
10193
|
const cb = document.createElement('input');
|
|
10080
|
-
cb.type = '
|
|
10081
|
-
cb.
|
|
10194
|
+
cb.type = 'radio';
|
|
10195
|
+
cb.name = 'fin-skill-role-' + r.id;
|
|
10196
|
+
cb.checked = on;
|
|
10197
|
+
/* TEK + ZORUNLU: yeni skill seçilir; mevcut seçim kaldırılamaz */
|
|
10082
10198
|
cb.addEventListener('change', () => {
|
|
10083
|
-
|
|
10084
|
-
|
|
10085
|
-
: [];
|
|
10086
|
-
const set = new Set(liveBase);
|
|
10087
|
-
if (cb.checked) set.add(s.name); else set.delete(s.name);
|
|
10088
|
-
const next = [...set];
|
|
10199
|
+
if (!cb.checked) return;
|
|
10200
|
+
const next = [s.name];
|
|
10089
10201
|
/* yerel önbelleğe anında yaz — 3 sn'lik snapshot eski değeri geri getirmesin */
|
|
10090
10202
|
finCfgCache = finCfgCache || {};
|
|
10091
10203
|
finCfgCache.roleSkills = finCfgCache.roleSkills || {};
|
|
10092
10204
|
finCfgCache.roleSkills[r.id] = next;
|
|
10093
|
-
chip.classList.
|
|
10205
|
+
chips.querySelectorAll('.fin-skill-chip').forEach((el) => el.classList.remove('on'));
|
|
10206
|
+
chip.classList.add('on');
|
|
10207
|
+
const w = head.querySelector('.fin-skill-req');
|
|
10208
|
+
if (w) w.remove();
|
|
10094
10209
|
finSaveCfg({ roleSkills: { [r.id]: next } });
|
|
10095
|
-
toast((r.label || r.id) + ' → ' +
|
|
10210
|
+
toast((r.label || r.id) + ' → ' + s.name + ' (zorunlu tek skill)');
|
|
10096
10211
|
});
|
|
10097
10212
|
chip.appendChild(cb);
|
|
10098
10213
|
chip.appendChild(document.createTextNode(s.name));
|
package/src/renderer/style.css
CHANGED
|
@@ -4816,6 +4816,22 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
|
|
|
4816
4816
|
align-items: center;
|
|
4817
4817
|
gap: 6px;
|
|
4818
4818
|
}
|
|
4819
|
+
.fin-grip {
|
|
4820
|
+
flex: none;
|
|
4821
|
+
cursor: grab;
|
|
4822
|
+
color: var(--muted);
|
|
4823
|
+
font-size: 12px;
|
|
4824
|
+
line-height: 1;
|
|
4825
|
+
letter-spacing: -1px;
|
|
4826
|
+
opacity: 0.7;
|
|
4827
|
+
user-select: none;
|
|
4828
|
+
-webkit-user-select: none;
|
|
4829
|
+
}
|
|
4830
|
+
.fin-grip:hover { color: var(--accent); opacity: 1; }
|
|
4831
|
+
.fin-grip:active { cursor: grabbing; }
|
|
4832
|
+
.fin-card.fin-dragging { opacity: 0.45; border-style: dashed; }
|
|
4833
|
+
.fin-card.fin-drop-top { box-shadow: 0 -3px 0 0 var(--accent); }
|
|
4834
|
+
.fin-card.fin-drop-bottom { box-shadow: 0 3px 0 0 var(--accent); }
|
|
4819
4835
|
|
|
4820
4836
|
.fin-grid {
|
|
4821
4837
|
display: grid;
|
|
@@ -5209,6 +5225,14 @@ body.finance-mode #composerWrap { margin-right: var(--finW, 400px); }
|
|
|
5209
5225
|
.fin-skill-role-head { display: flex; flex-direction: column; gap: 1px; margin-bottom: 7px; }
|
|
5210
5226
|
.fin-skill-role-head b { font-size: 11.5px; color: var(--text); }
|
|
5211
5227
|
.fin-skill-role-head span { font-size: 10px; color: var(--muted); }
|
|
5228
|
+
.fin-skill-req {
|
|
5229
|
+
align-self: flex-start;
|
|
5230
|
+
margin-top: 2px;
|
|
5231
|
+
font-size: 9.5px;
|
|
5232
|
+
font-weight: 800;
|
|
5233
|
+
letter-spacing: 0.5px;
|
|
5234
|
+
color: #ef4444;
|
|
5235
|
+
}
|
|
5212
5236
|
.fin-skill-chips { display: flex; flex-wrap: wrap; gap: 4px; }
|
|
5213
5237
|
.fin-skill-chip {
|
|
5214
5238
|
display: inline-flex;
|