beast-agent 2.6.5 → 2.6.7
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/memory.js +139 -26
- package/src/agent/nightref.js +15 -0
- package/src/renderer/i18n.js +4 -0
- package/src/renderer/index.html +12 -0
- package/src/renderer/renderer.js +76 -12
- package/src/renderer/style.css +17 -0
package/package.json
CHANGED
package/src/agent/memory.js
CHANGED
|
@@ -265,67 +265,180 @@ function removeRule(textOrIndex) {
|
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
/* ---------- bellek hijyeni (#5) ----------
|
|
268
|
-
MEMORY.md: dedup +
|
|
268
|
+
MEMORY.md: yakın-kayıt dedup + gürültü temizliği + eskime. LLM'siz
|
|
269
|
+
deterministik — gece yansıması 429/limit'e takılsa bile memory sadeleşir. */
|
|
269
270
|
|
|
270
271
|
const MEMORY_CAP = 400; // maksimum kayıt sayısı
|
|
271
272
|
const MEMORY_MAX_AGE_DAYS = 120; // hiç skor üretmeyen kayıtların ömrü
|
|
272
273
|
|
|
273
|
-
|
|
274
|
-
|
|
274
|
+
/* kelime-kümesi benzerliği: fold + stopword temiz. "adı Batuhan, hitap kanka"
|
|
275
|
+
≡ "kullanıcı Batuhan Bozoklu, hitap 'kanka'" gibi TEKRARLARI yakalar. */
|
|
276
|
+
const MEM_STOP = new Set(
|
|
277
|
+
('ve veya ya ile için ama fakat da de ki mi mi mu mü bir bu şu o en daha çok az olarak gibi sonra önce yeni son ' +
|
|
278
|
+
'the a an of in on to for and or is are was were be been at by with as it its this that from').split(' ')
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
function lineTokens(s) {
|
|
282
|
+
const words = fold(s)
|
|
283
|
+
.replace(/[^a-z0-9]+/g, ' ')
|
|
284
|
+
.split(' ')
|
|
285
|
+
.filter((w) => w.length > 1 && !MEM_STOP.has(w) && !/^kullanici/.test(w));
|
|
286
|
+
return new Set(words.slice(0, 30));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function linesSimilar(a, b) {
|
|
290
|
+
const A = lineTokens(a);
|
|
291
|
+
const B = lineTokens(b);
|
|
292
|
+
if (!A.size || !B.size) return false;
|
|
293
|
+
let inter = 0;
|
|
294
|
+
for (const t of A) if (B.has(t)) inter++;
|
|
295
|
+
if (!inter) return false;
|
|
296
|
+
const min = Math.min(A.size, B.size);
|
|
297
|
+
return inter / min >= 0.7 || inter / (A.size + B.size - inter) >= 0.6;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/* 'X'i sildi / X ile ilgilenmiyor' beyanı — aynı X için eski kurulum satırları düşürülür */
|
|
301
|
+
const RETIRE_DECL_RE = /(indirdikten sonra sildi|bilerek sildi|art[i]?k ilgilenmiyor|ilgilenmiyor)/i;
|
|
302
|
+
const INSTALL_VERB_RE = /(indiriyor|indirdi|indirmek|kuruyor|kurulu|kurulum|y[kü]kl)/i;
|
|
303
|
+
|
|
304
|
+
function retiredToolNames(list) {
|
|
305
|
+
const retired = new Set();
|
|
306
|
+
for (const l of list) {
|
|
307
|
+
if (!RETIRE_DECL_RE.test(l)) continue;
|
|
308
|
+
for (const w of String(l).match(/[A-Za-z][A-Za-z0-9-]{2,}/g) || []) {
|
|
309
|
+
const f = fold(w);
|
|
310
|
+
if (!MEM_STOP.has(f) && f.length >= 4) retired.add(f);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return retired;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/* repo/araç indirme-inceleme günlüğü: kalıcı profil değil, bir kez değdi */
|
|
317
|
+
function isRepoNoise(l) {
|
|
318
|
+
if (RETIRE_DECL_RE.test(l)) return false; /* emeklilik beyanı değerli — korunur */
|
|
319
|
+
if (/(repo|github)/i.test(l) && /(indir|incel|kopya|kar[sş]ıla[sş]tır|ilgilen)/i.test(l)) return true;
|
|
320
|
+
if (/ilgilen/i.test(l) && /(inceliyor|kar[sş]ıla[sş]tır)/i.test(l)) return true;
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/** Duplike + yakın-kayıt + gürültü + çok eski kayıtları temizler.
|
|
325
|
+
deep: LLM'siz temizlik katmanı (yakın-kayıt birleştirme — SON kopya kazanır). */
|
|
326
|
+
function hygiene({ maxAgeDays = MEMORY_MAX_AGE_DAYS, cap = MEMORY_CAP, deep = true } = {}) {
|
|
275
327
|
const list = entries();
|
|
276
328
|
if (!list.length) return { ok: true, removed: 0, reason: 'boş' };
|
|
277
|
-
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
329
|
+
let working = list.slice();
|
|
330
|
+
const dropped = [];
|
|
331
|
+
|
|
332
|
+
/* 0) birebir dedup — her modda (ucuz) */
|
|
333
|
+
{
|
|
334
|
+
const seen = new Set();
|
|
335
|
+
working = working.filter((l) => {
|
|
336
|
+
const key = fold(l).replace(/[^a-z0-9]+/g, ' ').trim();
|
|
337
|
+
if (seen.has(key)) {
|
|
338
|
+
dropped.push(l);
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
seen.add(key);
|
|
342
|
+
return true;
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (deep) {
|
|
347
|
+
/* 1) emekli araç beyanları: 'X'i sildi/ilgilenmiyor' → X'in eski kurulum satırları düşer */
|
|
348
|
+
const retired = retiredToolNames(working);
|
|
349
|
+
if (retired.size) {
|
|
350
|
+
working = working.filter((l) => {
|
|
351
|
+
if (RETIRE_DECL_RE.test(l)) return true; /* beyanın kendisi korunur */
|
|
352
|
+
if (!INSTALL_VERB_RE.test(l)) return true;
|
|
353
|
+
for (const t of lineTokens(l)) {
|
|
354
|
+
if (retired.has(t)) {
|
|
355
|
+
dropped.push(l);
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return true;
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
/* 2) repo/araç gürültüsü */
|
|
363
|
+
working = working.filter((l) => {
|
|
364
|
+
if (isRepoNoise(l)) {
|
|
365
|
+
dropped.push(l);
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
return true;
|
|
369
|
+
});
|
|
370
|
+
/* 3) yakın-kayıt dedup — aynı şeyin yeniden yazımı TEK satırda; SON kopya kazanır (en taze) */
|
|
371
|
+
const kept2 = [];
|
|
372
|
+
for (const l of working) {
|
|
373
|
+
const idx = kept2.findIndex((k) => linesSimilar(k, l));
|
|
374
|
+
if (idx >= 0) {
|
|
375
|
+
dropped.push(kept2[idx]);
|
|
376
|
+
kept2[idx] = l;
|
|
377
|
+
} else {
|
|
378
|
+
kept2.push(l);
|
|
379
|
+
}
|
|
285
380
|
}
|
|
286
|
-
|
|
287
|
-
kept.push(l);
|
|
381
|
+
working = kept2;
|
|
288
382
|
}
|
|
383
|
+
|
|
289
384
|
let aged = 0;
|
|
290
|
-
if (
|
|
385
|
+
if (working.length > cap || maxAgeDays > 0) {
|
|
291
386
|
/* tarih etiketli olmayanlar en eski kabul edilir (append-only başlangıç) */
|
|
292
387
|
const cut = Date.now() - maxAgeDays * 86400000;
|
|
293
388
|
const filtered = [];
|
|
294
389
|
/* kronolojik varsayım: dosya sırası = ekleme sırası */
|
|
295
|
-
const overflow = Math.max(0,
|
|
296
|
-
|
|
390
|
+
const overflow = Math.max(0, working.length - cap);
|
|
391
|
+
working.forEach((l, idx) => {
|
|
297
392
|
const m = l.match(/\b(\d{4}-\d{2}-\d{2})\b/);
|
|
298
393
|
const tooOld = m && new Date(m[1]).getTime() < cut;
|
|
299
|
-
if (tooOld && idx <
|
|
394
|
+
if (tooOld && idx < working.length - 20) { // son 20 kayıt asla yaşla silinmez
|
|
300
395
|
aged++;
|
|
301
396
|
return;
|
|
302
397
|
}
|
|
303
398
|
if (overflow > 0 && idx < overflow) {
|
|
304
399
|
// kap aşımı: en eskilerden düş ama yine de son 20 korunur
|
|
305
|
-
if (idx <
|
|
400
|
+
if (idx < working.length - 20) {
|
|
306
401
|
aged++;
|
|
307
402
|
return;
|
|
308
403
|
}
|
|
309
404
|
}
|
|
310
405
|
filtered.push(l);
|
|
311
406
|
});
|
|
312
|
-
return writeKept(filtered,
|
|
407
|
+
return writeKept(list, filtered, dropped.length + aged);
|
|
313
408
|
}
|
|
314
|
-
return writeKept(
|
|
409
|
+
return writeKept(list, working, dropped.length + aged);
|
|
315
410
|
}
|
|
316
411
|
|
|
317
|
-
function writeKept(kept, removedCount) {
|
|
412
|
+
function writeKept(originalList, kept, removedCount) {
|
|
318
413
|
try {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
414
|
+
/* yedek: hijyen geri alınabilir olsun (nightref backups klasörü ortak) */
|
|
415
|
+
if (removedCount > 0 && originalList.length) {
|
|
416
|
+
try {
|
|
417
|
+
const dir = path.join(memDir(), 'backups');
|
|
418
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
419
|
+
fs.writeFileSync(
|
|
420
|
+
path.join(dir, 'MEMORY-hygiene-' + new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19) + '.md'),
|
|
421
|
+
originalList.map((l) => '- ' + l).join('\n') + '\n',
|
|
422
|
+
'utf8'
|
|
423
|
+
);
|
|
424
|
+
} catch {}
|
|
425
|
+
}
|
|
426
|
+
/* save() → mem0 store'u satırlardan yeniden kurar (ham yazımda store bayat kalırdı) */
|
|
427
|
+
const w = save('MEMORY.md', kept.map((l) => '- ' + l).join('\n') + (kept.length ? '\n' : ''));
|
|
428
|
+
if (w && !w.ok) return { ok: false, error: w.error || 'yazılamadı' };
|
|
429
|
+
return { ok: true, removed: removedCount, remaining: kept.length, ...(droppedPreview(originalList, kept)) };
|
|
324
430
|
} catch (e) {
|
|
325
431
|
return { ok: false, error: String((e && e.message) || e) };
|
|
326
432
|
}
|
|
327
433
|
}
|
|
328
434
|
|
|
435
|
+
/* silinenleri özet olarak döndür (admin/araç yanıtı + audit) — ilk 40 */
|
|
436
|
+
function droppedPreview(originalList, kept) {
|
|
437
|
+
const keptSet = new Set(kept);
|
|
438
|
+
const gone = originalList.filter((l) => !keptSet.has(l)).slice(0, 40);
|
|
439
|
+
return gone.length ? { dropped: gone } : {};
|
|
440
|
+
}
|
|
441
|
+
|
|
329
442
|
/* ---------- #12 kişilik kalibrasyonu ----------
|
|
330
443
|
Kullanıcının konuşma tarzından üslup imzası çıkarır, SOUL.md'ye ekler.
|
|
331
444
|
İlk hafta mesajlar birikince "dijital ikiz" ton yakalanır. */
|
package/src/agent/nightref.js
CHANGED
|
@@ -318,6 +318,20 @@ async function run(deps) {
|
|
|
318
318
|
report.notes.push('bugün değerli transkript yok — öğrenme adımı atlandı');
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
+
/* 2b) LLM'siz derin hijyen: yakın-kayıt dedup + gürültü temizliği.
|
|
322
|
+
LLM (429/limit) çökse bile memory her yansımada sadeleşir. */
|
|
323
|
+
if (deps.memory && typeof deps.memory.hygiene === 'function') {
|
|
324
|
+
try {
|
|
325
|
+
const h = deps.memory.hygiene({ deep: true });
|
|
326
|
+
if (h && typeof h.removed === 'number' && h.removed > 0) {
|
|
327
|
+
report.hygiene = { removed: h.removed, remaining: h.remaining || 0 };
|
|
328
|
+
report.notes.push('derin hijyen: ' + h.removed + ' kayıt temizlendi');
|
|
329
|
+
}
|
|
330
|
+
} catch (e) {
|
|
331
|
+
report.errors.push('hijyen: ' + String((e && e.message) || e).slice(0, 100));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
321
335
|
/* 3) memory sıkılaştırma: drop/merge kararları → yedek → uygula */
|
|
322
336
|
const entriesNow = deps.memory.entries();
|
|
323
337
|
if (!noLlm && entriesNow.length >= CONSOLIDATE_MIN) {
|
|
@@ -401,6 +415,7 @@ async function run(deps) {
|
|
|
401
415
|
? '\n## İlgi alanları (günlük çıkarım)\n' + report.interests.labels.map((l) => '- ' + l).join('\n') + '\n'
|
|
402
416
|
: '') +
|
|
403
417
|
'\n## Bellek bakımı\n' +
|
|
418
|
+
(report.hygiene ? '- Derin hijyen (LLM\u2019siz): ' + report.hygiene.removed + ' kayıt temizlendi\n' : '') +
|
|
404
419
|
'- Kayıt: ' + m.before + ' → ' + m.after + ' (düşülen ' + m.dropped + ', ' + m.merged + ' kayıt birleşti)\n' +
|
|
405
420
|
'- Boyut: ' + m.charsBefore + ' → ' + m.charsAfter + ' char (~' + m.tokensSaved + ' token tasarruf)\n' +
|
|
406
421
|
(report.notes.length ? '- Not: ' + report.notes.join('; ') + '\n' : '') +
|
package/src/renderer/i18n.js
CHANGED
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
tip_net_offline: 'İnternet: yok — bağlantı dönünce işler otomatik sürer',
|
|
24
24
|
sess_drag: 'Sürükleyerek sırayı değiştir',
|
|
25
25
|
sess_del_confirm: 'Bu sohbet oturumunu silmek istediğine emin misin?',
|
|
26
|
+
cf_ok: 'Evet, sil',
|
|
27
|
+
cf_cancel: 'Vazgeç',
|
|
26
28
|
tipWatch: 'İzleyiciler (Watchers)',
|
|
27
29
|
tipCron: 'Cron Görevler',
|
|
28
30
|
tip_light: 'Açık tema',
|
|
@@ -653,6 +655,8 @@
|
|
|
653
655
|
tip_net_online: 'Internet: connected',
|
|
654
656
|
tip_net_offline: 'Internet: offline — work resumes automatically once the connection returns',
|
|
655
657
|
sess_drag: 'Drag to reorder',
|
|
658
|
+
cf_ok: 'Yes, delete',
|
|
659
|
+
cf_cancel: 'Cancel',
|
|
656
660
|
tipWatch: 'Watchers',
|
|
657
661
|
tipCron: 'Cron Jobs',
|
|
658
662
|
tip_light: 'Light theme',
|
package/src/renderer/index.html
CHANGED
|
@@ -452,6 +452,18 @@
|
|
|
452
452
|
|
|
453
453
|
<div id="fileCtxMenu" hidden></div>
|
|
454
454
|
|
|
455
|
+
<!-- in-app onay penceresi: window.confirm Electron/Windows'ta input focus'unu
|
|
456
|
+
bozuyor (electron#31917) — native dialog YOK, hepsi bu modaldan döner -->
|
|
457
|
+
<div id="confirmOverlay" class="mini-overlay" hidden>
|
|
458
|
+
<div class="confirm-dialog">
|
|
459
|
+
<div id="confirmText" class="confirm-text"></div>
|
|
460
|
+
<div class="confirm-btns">
|
|
461
|
+
<button id="confirmCancel" class="btn ghost"></button>
|
|
462
|
+
<button id="confirmOk" class="btn danger"></button>
|
|
463
|
+
</div>
|
|
464
|
+
</div>
|
|
465
|
+
</div>
|
|
466
|
+
|
|
455
467
|
<input type="file" id="fileInput" multiple hidden
|
|
456
468
|
accept="image/*,.txt,.md,.json,.csv,.log,.js,.ts,.py,.ps1,.bat,.cmd,.html,.css,.yaml,.yml,.xml,.ini" />
|
|
457
469
|
|
package/src/renderer/renderer.js
CHANGED
|
@@ -362,6 +362,33 @@ function toast(msg) {
|
|
|
362
362
|
}, 2200);
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
+
/* IN-APP CONFIRM: window.confirm Electron/Windows'ta kapanınca input focus'unu
|
|
366
|
+
bozuyor (electron#31917 — yazma kabul etmez, klavye ölür). Native dialog
|
|
367
|
+
HİÇ açılmaz; bu modal söz verir (promise) ve kapanınca odağı geri verir. */
|
|
368
|
+
let confirmResolve = null;
|
|
369
|
+
function uiConfirm(msg, okLabel, cancelLabel) {
|
|
370
|
+
return new Promise((resolve) => {
|
|
371
|
+
const ov = $('#confirmOverlay');
|
|
372
|
+
if (!ov) { resolve(window.confirm(msg)); return; }
|
|
373
|
+
$('#confirmText').textContent = String(msg || '');
|
|
374
|
+
$('#confirmOk').textContent = okLabel || _t('cf_ok');
|
|
375
|
+
$('#confirmCancel').textContent = cancelLabel || _t('cf_cancel');
|
|
376
|
+
ov.hidden = false;
|
|
377
|
+
confirmResolve = resolve;
|
|
378
|
+
$('#confirmOk').focus();
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
function closeConfirm(result) {
|
|
382
|
+
const ov = $('#confirmOverlay');
|
|
383
|
+
if (ov) ov.hidden = true;
|
|
384
|
+
if (confirmResolve) {
|
|
385
|
+
const r = confirmResolve;
|
|
386
|
+
confirmResolve = null;
|
|
387
|
+
r(result);
|
|
388
|
+
els.input.focus(); /* odayı input'a geri ver — yazma asla kilitli kalmasın */
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
365
392
|
/* ---------------- messages ---------------- */
|
|
366
393
|
|
|
367
394
|
function addUserBubble(content, atts) {
|
|
@@ -829,12 +856,23 @@ async function renderSessions(list) {
|
|
|
829
856
|
row.addEventListener('click', () => openSession(s.id));
|
|
830
857
|
row.querySelector('.sess-del').addEventListener('click', async (e) => {
|
|
831
858
|
e.stopPropagation();
|
|
832
|
-
|
|
859
|
+
const ok = await uiConfirm(
|
|
860
|
+
(_t('sess_del_confirm') || 'Bu sohbet oturumunu silmek istediğine emin misin?') + '\n\n' + (s.title || 'Yeni Sohbet')
|
|
861
|
+
);
|
|
862
|
+
if (!ok) return;
|
|
833
863
|
await beast.deleteSession(s.id);
|
|
834
864
|
if (s.id === activeId) {
|
|
865
|
+
/* aktif sohbet silindi: ÖLÜ UÇ bırakma — taze oturum aç, input yazılabilir
|
|
866
|
+
kalsın (activeId null kalırsa sendCurrent sessizce return eder) */
|
|
835
867
|
activeId = null;
|
|
868
|
+
streamEl = null;
|
|
836
869
|
els.msgs.innerHTML = '';
|
|
837
870
|
showEmpty(true);
|
|
871
|
+
try {
|
|
872
|
+
const created = await beast.createSession();
|
|
873
|
+
await openSession(created.id);
|
|
874
|
+
} catch {}
|
|
875
|
+
els.input.focus();
|
|
838
876
|
}
|
|
839
877
|
sessionOrder = sessionOrder.filter((x) => x !== s.id);
|
|
840
878
|
refreshSessions();
|
|
@@ -4400,8 +4438,8 @@ function renderBotSettings(pane, b) {
|
|
|
4400
4438
|
else toast(r.error || _t('bot_save_fail'));
|
|
4401
4439
|
});
|
|
4402
4440
|
const delBtn = $('#bDel');
|
|
4403
|
-
|
|
4404
|
-
|
|
4441
|
+
if (delBtn) delBtn.addEventListener('click', async () => {
|
|
4442
|
+
if (!(await uiConfirm(_ti('bot_confirm_del', b.name)))) return;
|
|
4405
4443
|
const r = await beast.botsRemove(b.id);
|
|
4406
4444
|
if (r.ok) {
|
|
4407
4445
|
/* bot silme sonrası main otomatik restart atar — yeniden çizmeye kalkışma */
|
|
@@ -4943,7 +4981,13 @@ function onEvent(ev) {
|
|
|
4943
4981
|
ingestAgentActivity(ev);
|
|
4944
4982
|
return;
|
|
4945
4983
|
}
|
|
4946
|
-
if (ev.type === 'done' || ev.type === 'error')
|
|
4984
|
+
if (ev.type === 'done' || ev.type === 'error') {
|
|
4985
|
+
/* başka oturumun işi bitti (silinen oturum dahil): busy'i de bırak —
|
|
4986
|
+
yoksa stopBtn görünür kalır, sonraki mesajlar 'kuyruğa eklendi'
|
|
4987
|
+
deyip sonsuza dek bekler (sohbet silince kilitlenme bu yüzden) */
|
|
4988
|
+
if (busy) setBusy(false);
|
|
4989
|
+
refreshSessions();
|
|
4990
|
+
}
|
|
4947
4991
|
return;
|
|
4948
4992
|
}
|
|
4949
4993
|
|
|
@@ -5791,11 +5835,30 @@ async function init() {
|
|
|
5791
5835
|
}
|
|
5792
5836
|
|
|
5793
5837
|
els.newChat.addEventListener('click', async () => {
|
|
5794
|
-
|
|
5795
|
-
|
|
5838
|
+
try {
|
|
5839
|
+
const created = await beast.createSession();
|
|
5840
|
+
await openSession(created.id);
|
|
5841
|
+
} catch (e) {
|
|
5842
|
+
toast('Yeni sohbet açılamadı: ' + ((e && e.message) || e));
|
|
5843
|
+
}
|
|
5796
5844
|
els.input.focus();
|
|
5797
5845
|
});
|
|
5798
5846
|
|
|
5847
|
+
/* in-app confirm modal düğmeleri + Enter/Esc kısayolları */
|
|
5848
|
+
{
|
|
5849
|
+
const ok = $('#confirmOk');
|
|
5850
|
+
const cancel = $('#confirmCancel');
|
|
5851
|
+
const ov = $('#confirmOverlay');
|
|
5852
|
+
if (ok && cancel && ov) {
|
|
5853
|
+
ok.addEventListener('click', () => closeConfirm(true));
|
|
5854
|
+
cancel.addEventListener('click', () => closeConfirm(false));
|
|
5855
|
+
ov.addEventListener('keydown', (e) => {
|
|
5856
|
+
if (e.key === 'Escape') { e.stopPropagation(); closeConfirm(false); }
|
|
5857
|
+
else if (e.key === 'Enter') { e.stopPropagation(); closeConfirm(true); }
|
|
5858
|
+
});
|
|
5859
|
+
}
|
|
5860
|
+
}
|
|
5861
|
+
|
|
5799
5862
|
/* custom pencere butonları: küçült / büyüt / kapat — main'e window:ctrl ile gider.
|
|
5800
5863
|
Büyüt ikonu maximize/unmaximize olayıyla senkron (□ / ❐). */
|
|
5801
5864
|
const winMin = $('#winMin');
|
|
@@ -6052,7 +6115,7 @@ async function init() {
|
|
|
6052
6115
|
});
|
|
6053
6116
|
if (els.railClear) {
|
|
6054
6117
|
els.railClear.addEventListener('click', async () => {
|
|
6055
|
-
if (!
|
|
6118
|
+
if (!(await uiConfirm('TÜM paralel ajan geçmişi silinsin mi?\n(Çalışan ajanlar da iptal edilir — geri alınamaz)'))) return;
|
|
6056
6119
|
try {
|
|
6057
6120
|
const r = await beast.agentsClearAll();
|
|
6058
6121
|
if (r && r.ok) toast('Paralel ajan geçmişi silindi' + (r.removed ? ' — ' + r.removed + ' iş' : ''));
|
|
@@ -7616,15 +7679,16 @@ async function codeOpen(rel) {
|
|
|
7616
7679
|
els.codeTa.focus();
|
|
7617
7680
|
}
|
|
7618
7681
|
|
|
7619
|
-
function codeClose(i) {
|
|
7682
|
+
async function codeClose(i) {
|
|
7620
7683
|
if (i < 0 || i >= codeTabs.length) return;
|
|
7621
7684
|
/* KAYIT DİSİPLİNİ: düzenlemeler yalnız Kaydet/Ctrl+S ile diske yazılır.
|
|
7622
7685
|
Kaydedilmemiş sekme kapatılırken kullanıcıya sorulur — sessiz kayıp yok. */
|
|
7623
7686
|
if (codeTabs[i].dirty) {
|
|
7624
|
-
const ok =
|
|
7687
|
+
const ok = await uiConfirm(
|
|
7625
7688
|
'"' + codeTabs[i].rel + '" kaydedilmedi.\n\n' +
|
|
7626
7689
|
'Tamam = kaydetmeden kapat\n' +
|
|
7627
|
-
'İptal = editörde kal (kaydetmek için Ctrl+S)'
|
|
7690
|
+
'İptal = editörde kal (kaydetmek için Ctrl+S)',
|
|
7691
|
+
'Kaydetmeden kapat'
|
|
7628
7692
|
);
|
|
7629
7693
|
if (!ok) return;
|
|
7630
7694
|
}
|
|
@@ -8217,7 +8281,7 @@ function bcResetPanel() {
|
|
|
8217
8281
|
/* TEK oturum silme — onay sorulur */
|
|
8218
8282
|
async function bcDeleteHistory(id, title) {
|
|
8219
8283
|
if (!id) return;
|
|
8220
|
-
if (!
|
|
8284
|
+
if (!(await uiConfirm('"' + (title || 'Beast Code oturumu') + '" silinsin mi?\n\nBu işlem geri alınamaz.'))) return;
|
|
8221
8285
|
const r = await beast.bcDelete(id).catch(() => null);
|
|
8222
8286
|
if (!r || !r.ok) { toast((r && r.error) || 'silinemedi'); return; }
|
|
8223
8287
|
if (bcSessionId === id) {
|
|
@@ -8234,7 +8298,7 @@ if (els.bcHistClear) els.bcHistClear.addEventListener('click', async () => {
|
|
|
8234
8298
|
const r0 = await beast.bcHistory().catch(() => null);
|
|
8235
8299
|
const n = r0 && r0.ok ? (r0.items || []).length : 0;
|
|
8236
8300
|
if (!n) { toast('Silinecek oturum yok'); return; }
|
|
8237
|
-
if (!
|
|
8301
|
+
if (!(await uiConfirm(n + ' Beast Code oturumunun TÜMÜ silinsin mi?\n\nBu işlem geri alınamaz.'))) return;
|
|
8238
8302
|
const r = await beast.bcDeleteAll().catch(() => null);
|
|
8239
8303
|
if (!r || !r.ok) { toast((r && r.error) || 'silinemedi'); return; }
|
|
8240
8304
|
/* aktif oturum da silindiyse panel tazelensin */
|
package/src/renderer/style.css
CHANGED
|
@@ -1575,6 +1575,23 @@ body.browser-open #settingsDialog { width: min(70vw, calc(100vw - var(--bw, 480p
|
|
|
1575
1575
|
}
|
|
1576
1576
|
.btn:hover { filter: brightness(1.08); }
|
|
1577
1577
|
.btn.ghost { background: var(--panel2); color: var(--text); border: 1px solid var(--border); }
|
|
1578
|
+
.btn.danger { background: var(--err); color: var(--bg); }
|
|
1579
|
+
|
|
1580
|
+
/* in-app confirm (window.confirm Electron'ta input focus'unu bozuyor) */
|
|
1581
|
+
.confirm-dialog {
|
|
1582
|
+
width: min(420px, 88vw);
|
|
1583
|
+
background: var(--bg);
|
|
1584
|
+
border: 1px solid var(--border);
|
|
1585
|
+
border-radius: 14px;
|
|
1586
|
+
padding: 18px 20px 16px;
|
|
1587
|
+
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.25);
|
|
1588
|
+
display: flex;
|
|
1589
|
+
flex-direction: column;
|
|
1590
|
+
gap: 14px;
|
|
1591
|
+
}
|
|
1592
|
+
.confirm-text { font-size: 13.5px; line-height: 1.5; white-space: pre-wrap; word-break: break-word; }
|
|
1593
|
+
.confirm-btns { display: flex; justify-content: flex-end; gap: 8px; }
|
|
1594
|
+
.confirm-btns .btn { margin-top: 0; }
|
|
1578
1595
|
|
|
1579
1596
|
.inp {
|
|
1580
1597
|
width: 100%;
|