beast-agent 0.24.5 → 0.25.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 +68 -96
- package/src/agent/tools.js +1 -1
- package/src/main.js +226 -60
- package/src/preload.js +1 -1
- package/src/renderer/i18n.js +2 -4
- package/src/renderer/index.html +45 -9
- package/src/renderer/renderer.js +351 -143
- package/src/renderer/style.css +195 -30
package/src/renderer/renderer.js
CHANGED
|
@@ -58,8 +58,6 @@ const els = {
|
|
|
58
58
|
bbShot: $('#bbShot'),
|
|
59
59
|
bbClose: $('#bbClose'),
|
|
60
60
|
bbResize: $('#bbResize'),
|
|
61
|
-
termBtn: $('#termBtn'),
|
|
62
|
-
termGBtn: $('#termGBtn'),
|
|
63
61
|
termCBtn: $('#termCBtn'),
|
|
64
62
|
termPanel: $('#termPanel'),
|
|
65
63
|
termCwd: $('#termCwd'),
|
|
@@ -114,8 +112,8 @@ let streamEl = null;
|
|
|
114
112
|
let streamRaw = '';
|
|
115
113
|
let renderQueued = false;
|
|
116
114
|
|
|
117
|
-
/* #19 sağ panel tercih durumu (tarayıcı açılmadan önceki) */
|
|
118
|
-
let railPrefBeforeBrowser =
|
|
115
|
+
/* #19 sağ panel tercih durumu (tarayıcı açılmadan önceki) — panel varsayılan KAPALI */
|
|
116
|
+
let railPrefBeforeBrowser = false;
|
|
119
117
|
|
|
120
118
|
function toggleRail(hide) {
|
|
121
119
|
document.body.classList.toggle('rail-hidden', !!hide);
|
|
@@ -285,11 +283,18 @@ function setBusy(b) {
|
|
|
285
283
|
}
|
|
286
284
|
|
|
287
285
|
let toastTimer = null;
|
|
286
|
+
let toastHideTimer = null;
|
|
288
287
|
function toast(msg) {
|
|
288
|
+
/* akış içi balon: göster → fade-in, süre dolunca fade-out → tamamen gizle (yer kaplamasın) */
|
|
289
289
|
els.toast.textContent = msg;
|
|
290
|
-
els.toast.
|
|
290
|
+
els.toast.hidden = false;
|
|
291
|
+
requestAnimationFrame(() => els.toast.classList.add('show'));
|
|
291
292
|
clearTimeout(toastTimer);
|
|
292
|
-
|
|
293
|
+
clearTimeout(toastHideTimer);
|
|
294
|
+
toastTimer = setTimeout(() => {
|
|
295
|
+
els.toast.classList.remove('show');
|
|
296
|
+
toastHideTimer = setTimeout(() => { els.toast.hidden = true; }, 260);
|
|
297
|
+
}, 2200);
|
|
293
298
|
}
|
|
294
299
|
|
|
295
300
|
/* ---------------- messages ---------------- */
|
|
@@ -497,15 +502,12 @@ async function renderSessions(list) {
|
|
|
497
502
|
async function refreshSessions() {
|
|
498
503
|
await renderSessions(await beast.listSessions());
|
|
499
504
|
renderBotCards(); // bot kartlarındaki numara/sayı etiketleri de tazelensin
|
|
500
|
-
renderGuestBotMenu(); // davet menüsü (aktif bot/bot listesi değişmiş olabilir)
|
|
501
505
|
}
|
|
502
506
|
|
|
503
507
|
async function openSession(id) {
|
|
504
508
|
activeId = id;
|
|
505
509
|
streamEl = null;
|
|
506
510
|
const s = await beast.openSession(id);
|
|
507
|
-
activeGuests = Array.isArray(s.guests) ? s.guests : [];
|
|
508
|
-
renderGuestBotMenu();
|
|
509
511
|
els.msgs.innerHTML = '';
|
|
510
512
|
showEmpty(s.messages.length === 0);
|
|
511
513
|
renderTodos(s.todos || []);
|
|
@@ -2462,47 +2464,6 @@ let botsCache = [];
|
|
|
2462
2464
|
let botPageId = null; // null = genel bakış (Tüm Botlar)
|
|
2463
2465
|
let botPageStats = [];
|
|
2464
2466
|
let activeBotId = 'beast'; // masaüstü UI'ının şu an hangi botta olduğu (varsayılan: ilk bot/Beast)
|
|
2465
|
-
let activeGuests = []; // aktif ana sohbete davetli botlar [{id, code, name}]
|
|
2466
|
-
|
|
2467
|
-
/* ANA SOHBETE BOT DAVETİ: yalnız admin bottayken görünür (composer'daki 🤖 ikonu);
|
|
2468
|
-
davetli botlar session'a kaydedilir, ajan bot_dm aracıyla onlara danışır */
|
|
2469
|
-
function renderGuestBotMenu() {
|
|
2470
|
-
const btn = $('#guestBotBtn');
|
|
2471
|
-
const menu = $('#guestBotMenu');
|
|
2472
|
-
if (!btn || !menu) return;
|
|
2473
|
-
const isAdmin = activeBotId === 'beast';
|
|
2474
|
-
const show = isAdmin && !!activeId;
|
|
2475
|
-
/* DİKKAT: hidden ATTRIBUTUE'sünü kaldırmak şart — style.display ile açılmaz */
|
|
2476
|
-
btn.hidden = !show;
|
|
2477
|
-
if (!show) { menu.hidden = true; return; }
|
|
2478
|
-
const candidates = botsCache.filter((b) => !b.admin && b.vis !== false);
|
|
2479
|
-
menu.innerHTML = '';
|
|
2480
|
-
if (!candidates.length) {
|
|
2481
|
-
/* bot hiç yoksa yönlendir + tek tıkla oluştur; bot varsa da davet edilebilir değilse bilgi ver */
|
|
2482
|
-
const nonAdmin = botsCache.filter((b) => !b.admin).length;
|
|
2483
|
-
menu.innerHTML = nonAdmin
|
|
2484
|
-
? '<div class="dd-empty">Davet edilebilir görünür bot yok</div>'
|
|
2485
|
-
: '<div class="dd-empty">Henüz bot yok — <a href="#" id="gbCreate" style="color:var(--accent);font-weight:700">bot oluştur</a></div>';
|
|
2486
|
-
const cr = menu.querySelector('#gbCreate');
|
|
2487
|
-
if (cr) cr.addEventListener('click', (e) => { e.preventDefault(); menu.hidden = true; botAddClick(); });
|
|
2488
|
-
return;
|
|
2489
|
-
}
|
|
2490
|
-
for (const b of candidates) {
|
|
2491
|
-
const invited = activeGuests.some((g) => g.id === b.id);
|
|
2492
|
-
const item = document.createElement('div');
|
|
2493
|
-
item.className = 'dd-item';
|
|
2494
|
-
item.innerHTML = `${b.icon} ${escapeHtml(b.name)} <span style="float:right;color:var(--muted)">${invited ? '✓ davetli' : '+ davet et'}</span>`;
|
|
2495
|
-
item.addEventListener('click', async () => {
|
|
2496
|
-
const next = invited ? activeGuests.filter((g) => g.id !== b.id) : [...activeGuests, { id: b.id, code: b.code || '', name: b.name }];
|
|
2497
|
-
activeGuests = next;
|
|
2498
|
-
await beast.sessionSetGuests(activeId, next).catch(() => {});
|
|
2499
|
-
renderGuestBotMenu();
|
|
2500
|
-
toast(invited ? `${b.name} davetten çıkarıldı` : `${b.name} sohbete davet edildi — ajan gerektiğinde ona danışacak`);
|
|
2501
|
-
menu.hidden = true;
|
|
2502
|
-
});
|
|
2503
|
-
menu.appendChild(item);
|
|
2504
|
-
}
|
|
2505
|
-
}
|
|
2506
2467
|
|
|
2507
2468
|
async function refreshBots() {
|
|
2508
2469
|
try {
|
|
@@ -2833,9 +2794,6 @@ function renderBotSettings(pane, b) {
|
|
|
2833
2794
|
<div class="bot-checks" style="margin-bottom:6px">
|
|
2834
2795
|
<label><input type="checkbox" id="bExtBrowser" ${b.extBrowser ? 'checked' : ''}/> ${_t('bot_ext_browser')}</label>
|
|
2835
2796
|
</div>
|
|
2836
|
-
<div class="bot-checks" style="margin-bottom:6px">
|
|
2837
|
-
<label><input type="checkbox" id="bVis" ${b.vis !== false ? 'checked' : ''}/> ${_t('bot_vis')}</label>
|
|
2838
|
-
</div>
|
|
2839
2797
|
<div class="form-grid">
|
|
2840
2798
|
<div>
|
|
2841
2799
|
<label class="mem-label" style="margin-top:0">${_t('bot_def_browser')}</label>
|
|
@@ -2896,7 +2854,6 @@ function renderBotSettings(pane, b) {
|
|
|
2896
2854
|
prompt: $('#bPrompt').value,
|
|
2897
2855
|
seeBots: [...f.querySelectorAll('#bSee input:checked')].map((c) => c.dataset.see),
|
|
2898
2856
|
extBrowser: $('#bExtBrowser').checked,
|
|
2899
|
-
vis: f.querySelector('#bVis') ? f.querySelector('#bVis').checked : true,
|
|
2900
2857
|
browserDefault: $('#bBrDef').value,
|
|
2901
2858
|
extCommand: $('#bBrCmd').value.trim(),
|
|
2902
2859
|
numbers: (b.numbers || []).map((n) => n.num),
|
|
@@ -3055,6 +3012,7 @@ function renderBotAdd(pane) {
|
|
|
3055
3012
|
|
|
3056
3013
|
const agentState = {
|
|
3057
3014
|
jobs: [],
|
|
3015
|
+
autoOpened: false, // konsol bu turda otomatik açıldı mı (boştan-çalışıyor geçişi)
|
|
3058
3016
|
last: new Map(), // bgSessionId -> son aktivite metni
|
|
3059
3017
|
runningIds: new Set(),
|
|
3060
3018
|
expanded: new Set(), // detayı açık kartlar
|
|
@@ -3082,11 +3040,26 @@ function scheduleAgentsRender() {
|
|
|
3082
3040
|
|
|
3083
3041
|
async function refreshAgentsPane() {
|
|
3084
3042
|
try { agentState.jobs = (await beast.agentsList()) || []; } catch {}
|
|
3043
|
+
/* açılışta ajanlar zaten çalışıyorsa konsolu otomatik aç */
|
|
3044
|
+
maybeAutoOpenRail();
|
|
3085
3045
|
updateAgentIds();
|
|
3086
3046
|
renderAgentsPane();
|
|
3087
3047
|
renderAgentRail();
|
|
3088
3048
|
}
|
|
3089
3049
|
|
|
3050
|
+
/* ajanlar çalışmaya başladığında sağdaki Paralel Ajan konsolu otomatik açılır
|
|
3051
|
+
(yalnız boştan-çalışıyor geçişinde; kullanıcı çalışırken elle kapatırsa ezilmez,
|
|
3052
|
+
dahili tarayıcı açıkken de karışılmaz) */
|
|
3053
|
+
function maybeAutoOpenRail() {
|
|
3054
|
+
const hasRunning = agentState.jobs.some((j) => j.status === 'running');
|
|
3055
|
+
if (hasRunning && !agentState.autoOpened && document.body.classList.contains('rail-hidden') &&
|
|
3056
|
+
!document.body.classList.contains('browser-open')) {
|
|
3057
|
+
toggleRail(false);
|
|
3058
|
+
railPrefBeforeBrowser = true;
|
|
3059
|
+
}
|
|
3060
|
+
agentState.autoOpened = hasRunning;
|
|
3061
|
+
}
|
|
3062
|
+
|
|
3090
3063
|
function ingestAgentActivity(ev) {
|
|
3091
3064
|
const id = ev.sessionId;
|
|
3092
3065
|
let label = agentState.last.get(id) || '';
|
|
@@ -3347,6 +3320,7 @@ function onEvent(ev) {
|
|
|
3347
3320
|
}
|
|
3348
3321
|
if (ev.type === 'agents') {
|
|
3349
3322
|
agentState.jobs = ev.jobs || [];
|
|
3323
|
+
maybeAutoOpenRail();
|
|
3350
3324
|
updateAgentIds();
|
|
3351
3325
|
scheduleAgentsRender();
|
|
3352
3326
|
return;
|
|
@@ -3465,12 +3439,18 @@ function onEvent(ev) {
|
|
|
3465
3439
|
case 'done':
|
|
3466
3440
|
closeChatToolGroup();
|
|
3467
3441
|
setBusy(false);
|
|
3442
|
+
setStatus(''); /* son durum balonu ("düşünüyor…" vb.) yapışmasın */
|
|
3443
|
+
/* cevabın SONU görünsün: markdown son render sonrası iki kez en alta kilitle */
|
|
3444
|
+
scrollDown(true);
|
|
3445
|
+
setTimeout(() => scrollDown(true), 80);
|
|
3446
|
+
setTimeout(() => scrollDown(true), 260);
|
|
3468
3447
|
refreshSessions();
|
|
3469
3448
|
els.input.focus();
|
|
3470
3449
|
break;
|
|
3471
3450
|
case 'error':
|
|
3472
3451
|
closeChatToolGroup();
|
|
3473
3452
|
setBusy(false);
|
|
3453
|
+
setStatus('');
|
|
3474
3454
|
addErrorBubble(ev.error);
|
|
3475
3455
|
refreshSessions();
|
|
3476
3456
|
break;
|
|
@@ -3512,23 +3492,19 @@ let termBannerDone = false;
|
|
|
3512
3492
|
let termRunning = false;
|
|
3513
3493
|
let termHist = [];
|
|
3514
3494
|
let termHistIdx = -1;
|
|
3515
|
-
let termShell = '
|
|
3495
|
+
let termShell = 'cmd';
|
|
3516
3496
|
const TERM_MAX_LINES = 800;
|
|
3517
3497
|
|
|
3518
|
-
/* terminal
|
|
3498
|
+
/* terminal kabuğu: yalnız CMD (PowerShell/Git Bash kaldırıldı) */
|
|
3519
3499
|
const TERM_SHELLS = {
|
|
3520
|
-
|
|
3521
|
-
bash: { label: 'Git Bash', prompt: 'bash $' },
|
|
3522
|
-
cmd: { label: 'CMD', prompt: 'C>' },
|
|
3500
|
+
cmd: { label: 'CMD', prompt: 'CMD>' },
|
|
3523
3501
|
};
|
|
3524
3502
|
|
|
3525
3503
|
function termSetShell(s) {
|
|
3526
|
-
if (!TERM_SHELLS[s]) s = '
|
|
3504
|
+
if (!TERM_SHELLS[s]) s = 'cmd';
|
|
3527
3505
|
const changed = termShell !== s;
|
|
3528
3506
|
termShell = s;
|
|
3529
3507
|
if (els.termPrompt) els.termPrompt.textContent = TERM_SHELLS[s].prompt;
|
|
3530
|
-
if (els.termBtn) els.termBtn.classList.toggle('on', termOpen && s === 'powershell');
|
|
3531
|
-
if (els.termGBtn) els.termGBtn.classList.toggle('on', termOpen && s === 'bash');
|
|
3532
3508
|
if (els.termCBtn) els.termCBtn.classList.toggle('on', termOpen && s === 'cmd');
|
|
3533
3509
|
if (changed && termOpen && termBannerDone) termLine('t-sys', 'Kabuk: ' + TERM_SHELLS[s].label);
|
|
3534
3510
|
}
|
|
@@ -3573,7 +3549,7 @@ function termBanner(cwd) {
|
|
|
3573
3549
|
els.termCwd.title = cwd || '';
|
|
3574
3550
|
termLine('t-sys', 'Beast Terminal — çalışma klasörü: ' + (cwd || '?'));
|
|
3575
3551
|
termLine('t-sys', 'Kabuk: ' + TERM_SHELLS[termShell].label + ' · Ajanlar çalışırken araç çağrıları ve çıktıları burada canlı akar.', false);
|
|
3576
|
-
termLine('t-dim', 'Komut yaz, Enter\'a bas — her komut workspace\'te ayrı süreçle çalışır.
|
|
3552
|
+
termLine('t-dim', 'Komut yaz, Enter\'a bas — her komut workspace\'te ayrı süreçle çalışır. Kabuk: CMD.', false);
|
|
3577
3553
|
}
|
|
3578
3554
|
|
|
3579
3555
|
function termShortTool(name, args) {
|
|
@@ -3608,7 +3584,7 @@ function termCmdDone(ev) {
|
|
|
3608
3584
|
}
|
|
3609
3585
|
|
|
3610
3586
|
async function termToggle(shell) {
|
|
3611
|
-
const want = TERM_SHELLS[shell] ? shell : '
|
|
3587
|
+
const want = TERM_SHELLS[shell] ? shell : 'cmd';
|
|
3612
3588
|
/* aynı kabuk butonuna tekrar basıldıysa paneli kapat */
|
|
3613
3589
|
if (termOpen && termShell === want) {
|
|
3614
3590
|
termSetOpen(false);
|
|
@@ -3635,7 +3611,7 @@ function termRunCurrent() {
|
|
|
3635
3611
|
termHist.push(cmd);
|
|
3636
3612
|
if (termHist.length > 100) termHist.shift();
|
|
3637
3613
|
termHistIdx = termHist.length;
|
|
3638
|
-
termLine('t-cmd', '
|
|
3614
|
+
termLine('t-cmd', TERM_SHELLS[termShell].prompt + ' ' + cmd);
|
|
3639
3615
|
termRunning = true;
|
|
3640
3616
|
els.termStop.hidden = false;
|
|
3641
3617
|
beast.terminalRun(cmd, termShell).then((r) => {
|
|
@@ -4075,6 +4051,7 @@ function openCron() { refreshCron(); }
|
|
|
4075
4051
|
|
|
4076
4052
|
async function init() {
|
|
4077
4053
|
beast.onEvent(onEvent);
|
|
4054
|
+
toggleRail(true); /* Paralel Ajanlar paneli varsayılan KAPALI — railBtn ile açılır */
|
|
4078
4055
|
|
|
4079
4056
|
state = await beast.getState();
|
|
4080
4057
|
try {
|
|
@@ -4411,8 +4388,6 @@ async function init() {
|
|
|
4411
4388
|
|
|
4412
4389
|
/* terminal paneli — olay bağlama */
|
|
4413
4390
|
try { termSetWidth(parseInt(localStorage.getItem('beast.termW')) || 520); } catch {}
|
|
4414
|
-
if (els.termBtn) els.termBtn.addEventListener('click', () => termToggle('powershell'));
|
|
4415
|
-
if (els.termGBtn) els.termGBtn.addEventListener('click', () => termToggle('bash'));
|
|
4416
4391
|
if (els.termCBtn) els.termCBtn.addEventListener('click', () => termToggle('cmd'));
|
|
4417
4392
|
if (els.termClose) els.termClose.addEventListener('click', () => termSetOpen(false));
|
|
4418
4393
|
if (els.termClear) els.termClear.addEventListener('click', () => { els.termOut.innerHTML = ''; });
|
|
@@ -4485,18 +4460,6 @@ async function init() {
|
|
|
4485
4460
|
if ($('#botClose')) $('#botClose').addEventListener('click', () => botOverlaySetOpen(false));
|
|
4486
4461
|
if ($('#botOverviewBack')) $('#botOverviewBack').addEventListener('click', () => openBotPage(null));
|
|
4487
4462
|
if ($('#botChip')) $('#botChip').addEventListener('click', () => openBotPage(activeBotId));
|
|
4488
|
-
|
|
4489
|
-
/* BOT DAVET MENÜSÜ: butona tıkla → aç/kapa; dışarı tık → kapa */
|
|
4490
|
-
if ($('#guestBotBtn') && $('#guestBotMenu')) {
|
|
4491
|
-
$('#guestBotBtn').addEventListener('click', (e) => {
|
|
4492
|
-
e.stopPropagation();
|
|
4493
|
-
renderGuestBotMenu();
|
|
4494
|
-
$('#guestBotMenu').hidden = !$('#guestBotMenu').hidden;
|
|
4495
|
-
});
|
|
4496
|
-
document.addEventListener('click', (e) => {
|
|
4497
|
-
if (!$('#guestBotMenu').hidden && !$('#guestBotMenu').contains(e.target)) $('#guestBotMenu').hidden = true;
|
|
4498
|
-
});
|
|
4499
|
-
}
|
|
4500
4463
|
/* kalıcı aktif bot: restart sonrası aynı botun UI'ı açılır */
|
|
4501
4464
|
beast.botsActiveGet().then((r) => { activeBotId = (r && r.id) || 'beast'; updateBotChip(); renderBotCards(); }).catch(() => {});
|
|
4502
4465
|
document.querySelectorAll('.btab').forEach((b) =>
|
|
@@ -4899,31 +4862,276 @@ document.querySelectorAll('.stab').forEach((b) =>
|
|
|
4899
4862
|
renderStorePane();
|
|
4900
4863
|
})
|
|
4901
4864
|
);
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
/* =================
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
'
|
|
4915
|
-
|
|
4916
|
-
|
|
4865
|
+
|
|
4866
|
+
|
|
4867
|
+
/* ================= GITHUB TRENDING =================
|
|
4868
|
+
Skills Store'un sağındaki buton → %70 modal (store ile aynı tasarım).
|
|
4869
|
+
SOL: son 14 günün yıldız yükselenleri (GitHub Search API).
|
|
4870
|
+
SAĞ: favoriler (localStorage'da kalıcı). Her kartta:
|
|
4871
|
+
★ favori · Chate at (ajana araştırma mesajı) · Kopyala · repoya git. */
|
|
4872
|
+
|
|
4873
|
+
const ghState = { items: [], err: '', range: '2w', sort: 'desc', q: '', ghTab: 'trend', allQ: '', allSort: 'best' };
|
|
4874
|
+
const GH_FAV_KEY = 'beast.github.favs';
|
|
4875
|
+
const GH_RANGE_LABEL = {
|
|
4876
|
+
all: '— tüm zamanların en yıldızlıları',
|
|
4877
|
+
'6m': '— son 6 ayın yıldız yükselenleri',
|
|
4878
|
+
'1m': '— son 1 ayın yıldız yükselenleri',
|
|
4879
|
+
'2w': '— son 2 haftanın yıldız yükselenleri',
|
|
4880
|
+
'1w': '— son 1 haftanın yıldız yükselenleri',
|
|
4881
|
+
};
|
|
4882
|
+
const GH_ALL_SORT_LABEL = { best: '⭐ En İyi', desc: '↓ Yıldız', asc: '↑ Yıldız' };
|
|
4883
|
+
|
|
4884
|
+
function ghFavs() {
|
|
4885
|
+
try { return JSON.parse(localStorage.getItem(GH_FAV_KEY) || '[]'); } catch { return []; }
|
|
4886
|
+
}
|
|
4887
|
+
function ghSaveFavs(list) {
|
|
4888
|
+
try { localStorage.setItem(GH_FAV_KEY, JSON.stringify(list.slice(0, 100))); } catch {}
|
|
4889
|
+
}
|
|
4890
|
+
function ghIsFav(fullName) {
|
|
4891
|
+
return ghFavs().some((f) => f.full_name === fullName);
|
|
4892
|
+
}
|
|
4893
|
+
|
|
4894
|
+
async function openGit() {
|
|
4895
|
+
$('#ghOverlay').hidden = false;
|
|
4896
|
+
renderGhFavs();
|
|
4897
|
+
updateGhSortBtn();
|
|
4898
|
+
updateGhAllSortBtn();
|
|
4899
|
+
updateGhSub();
|
|
4900
|
+
loadGhTrend();
|
|
4901
|
+
}
|
|
4902
|
+
|
|
4903
|
+
async function loadGhTrend() {
|
|
4904
|
+
const box = $('#ghTrendList');
|
|
4905
|
+
/* tüm repolar sekmesinde boş arama = API'yi boşa yorma, ipucu göster */
|
|
4906
|
+
if (ghState.ghTab === 'all' && !ghState.allQ) {
|
|
4907
|
+
box.innerHTML = '<div class="gh-empty">Depo adı, konu veya anahtar kelime yazıp Enter\u2019a bas — yıldız sayısına bakılmaksızın tüm GitHub aranır.</div>';
|
|
4908
|
+
return;
|
|
4909
|
+
}
|
|
4910
|
+
box.innerHTML = '<div class="gh-empty">Yükleniyor…</div>';
|
|
4911
|
+
const params = ghState.ghTab === 'all'
|
|
4912
|
+
? { mode: 'all', q: ghState.allQ, allSort: ghState.allSort, order: ghState.allSort === 'desc' ? 'desc' : 'asc' }
|
|
4913
|
+
: { mode: 'trend', range: ghState.range, sort: ghState.sort, q: ghState.q };
|
|
4914
|
+
const r = await beast.githubTrending(params).catch(() => ({ ok: false, error: 'ipc' }));
|
|
4915
|
+
if (r && r.ok) {
|
|
4916
|
+
ghState.items = r.items || [];
|
|
4917
|
+
ghState.err = '';
|
|
4918
|
+
} else {
|
|
4919
|
+
ghState.items = [];
|
|
4920
|
+
ghState.err = (r && r.error) || 'GitHub\u2019a ulaşılamadı';
|
|
4921
|
+
}
|
|
4922
|
+
renderGhTrend();
|
|
4923
|
+
}
|
|
4924
|
+
|
|
4925
|
+
function updateGhSortBtn() {
|
|
4926
|
+
const btn = $('#ghSortBtn');
|
|
4927
|
+
if (btn) {
|
|
4928
|
+
btn.textContent = ghState.sort === 'desc' ? '↓ Yıldız' : '↑ Yıldız';
|
|
4929
|
+
btn.title = ghState.sort === 'desc' ? 'Yıldız sırası: azalan — artana çevir' : 'Yıldız sırası: artan — azalana çevir';
|
|
4930
|
+
}
|
|
4931
|
+
}
|
|
4932
|
+
|
|
4933
|
+
function updateGhSub() {
|
|
4934
|
+
const sub = $('#ghTrendSub');
|
|
4935
|
+
if (!sub) return;
|
|
4936
|
+
if (ghState.ghTab === 'all') {
|
|
4937
|
+
const sortTxt = ghState.allSort === 'best' ? 'en iyi eşleşme' : ghState.allSort === 'desc' ? 'yıldız azalan' : 'yıldız artan';
|
|
4938
|
+
sub.textContent = ghState.allQ ? `— "${ghState.allQ}" araması · ${sortTxt}` : '— tüm GitHub: ada, konuya, açıklamaya göre arama';
|
|
4939
|
+
} else {
|
|
4940
|
+
sub.textContent = ghState.q ? `— "${ghState.q}" araması · tüm zamanlar` : GH_RANGE_LABEL[ghState.range] || '';
|
|
4941
|
+
}
|
|
4942
|
+
}
|
|
4943
|
+
|
|
4944
|
+
function updateGhAllSortBtn() {
|
|
4945
|
+
const btn = $('#ghAllSortBtn');
|
|
4946
|
+
if (btn) btn.textContent = GH_ALL_SORT_LABEL[ghState.allSort] || '⭐ En İyi';
|
|
4947
|
+
}
|
|
4948
|
+
|
|
4949
|
+
function closeGit() {
|
|
4950
|
+
$('#ghOverlay').hidden = true;
|
|
4951
|
+
}
|
|
4952
|
+
|
|
4953
|
+
/* chate at: ajana araştırma komutu gider (oturum yoksa input'a bırakılır) */
|
|
4954
|
+
function ghSendToChat(url, name) {
|
|
4955
|
+
const msg = `GitHub\u2019da şu repoyu araştır: ${url}${name ? ' (' + name + ')' : ''} — ne işe yarıyor, öne çıkan özellikleri neler, aktif mi? Kısa özet ver.`;
|
|
4956
|
+
if (!activeId) {
|
|
4957
|
+
els.input.value = msg;
|
|
4958
|
+
toast('Aktif oturum yok — mesaj kutusuna bırakıldı');
|
|
4959
|
+
return;
|
|
4960
|
+
}
|
|
4961
|
+
els.input.value = msg;
|
|
4962
|
+
sendCurrent();
|
|
4963
|
+
}
|
|
4964
|
+
|
|
4965
|
+
function ghCard(repo, isFav) {
|
|
4966
|
+
const stars = repo.stars >= 1000 ? (repo.stars / 1000).toFixed(1).replace('.0', '') + 'k' : String(repo.stars);
|
|
4967
|
+
const lang = repo.language ? `<span class="gh-lang">${escapeHtml(repo.language)}</span>` : '';
|
|
4968
|
+
return `
|
|
4969
|
+
<div class="gh-card" data-repo="${escapeHtml(repo.full_name)}">
|
|
4970
|
+
<div class="gh-card-top">
|
|
4971
|
+
<span class="gh-name" data-url="${escapeHtml(repo.html_url)}" title="${escapeHtml(repo.html_url)}">${escapeHtml(repo.full_name)}</span>
|
|
4972
|
+
<span class="gh-stars">★ ${stars}</span>
|
|
4973
|
+
${lang}
|
|
4974
|
+
</div>
|
|
4975
|
+
${repo.description ? `<div class="gh-desc" title="${escapeHtml(repo.description)}">${escapeHtml(repo.description)}</div>` : ''}
|
|
4976
|
+
<div class="gh-actions">
|
|
4977
|
+
<button class="gh-fav ${isFav ? 'on' : ''}" data-act="fav">${isFav ? '★ Favoride' : '☆ Favorile'}</button>
|
|
4978
|
+
<button data-act="chat"><svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-1px;margin-right:4px"><path d="M22 2 11 13"/><path d="M22 2 15 22l-4-9-9-4z"/></svg>Chate at</button>
|
|
4979
|
+
<button data-act="copy">⧉ Kopyala</button>
|
|
4980
|
+
</div>
|
|
4981
|
+
</div>`;
|
|
4982
|
+
}
|
|
4983
|
+
|
|
4984
|
+
function wireGhCards(container, list, isFavPane) {
|
|
4985
|
+
container.querySelectorAll('.gh-card').forEach((card) => {
|
|
4986
|
+
const repo = list.find((x) => x.full_name === card.dataset.repo);
|
|
4987
|
+
if (!repo) return;
|
|
4988
|
+
card.querySelector('.gh-name').addEventListener('click', () => beast.openExternal(repo.html_url).catch(() => {}));
|
|
4989
|
+
card.querySelector('[data-act="chat"]').addEventListener('click', () => {
|
|
4990
|
+
ghSendToChat(repo.html_url, repo.full_name);
|
|
4991
|
+
/* mesaj chate gitti — cevap chatten geleceği için modal kapanır */
|
|
4992
|
+
closeGit();
|
|
4993
|
+
});
|
|
4994
|
+
card.querySelector('[data-act="copy"]').addEventListener('click', async () => {
|
|
4995
|
+
try { await navigator.clipboard.writeText(repo.html_url); toast('Link kopyalandı'); } catch {}
|
|
4996
|
+
});
|
|
4997
|
+
card.querySelector('[data-act="fav"]').addEventListener('click', () => {
|
|
4998
|
+
const favs = ghFavs();
|
|
4999
|
+
if (ghIsFav(repo.full_name)) {
|
|
5000
|
+
ghSaveFavs(favs.filter((f) => f.full_name !== repo.full_name));
|
|
5001
|
+
toast('Favoriden çıkarıldı: ' + repo.full_name);
|
|
5002
|
+
} else {
|
|
5003
|
+
favs.unshift({ ...repo, addedAt: new Date().toISOString() });
|
|
5004
|
+
ghSaveFavs(favs);
|
|
5005
|
+
toast('Favorilere eklendi: ' + repo.full_name);
|
|
5006
|
+
}
|
|
5007
|
+
renderGhTrend();
|
|
5008
|
+
renderGhFavs();
|
|
5009
|
+
});
|
|
5010
|
+
});
|
|
5011
|
+
}
|
|
5012
|
+
|
|
5013
|
+
function renderGhTrend() {
|
|
5014
|
+
const box = $('#ghTrendList');
|
|
5015
|
+
if (!box) return;
|
|
5016
|
+
if (ghState.err) {
|
|
5017
|
+
box.innerHTML = `<div class="gh-err">⚠ ${escapeHtml(ghState.err)}</div>`;
|
|
5018
|
+
return;
|
|
5019
|
+
}
|
|
5020
|
+
if (!ghState.items.length) {
|
|
5021
|
+
box.innerHTML = '<div class="gh-empty">Son 14 günde öne çıkan repo bulunamadı.</div>';
|
|
5022
|
+
return;
|
|
5023
|
+
}
|
|
5024
|
+
box.innerHTML = ghState.items.map((r) => ghCard(r, ghIsFav(r.full_name))).join('');
|
|
5025
|
+
wireGhCards(box, ghState.items, false);
|
|
5026
|
+
}
|
|
5027
|
+
|
|
5028
|
+
function renderGhFavs() {
|
|
5029
|
+
const box = $('#ghFavList');
|
|
5030
|
+
if (!box) return;
|
|
5031
|
+
const favs = ghFavs();
|
|
5032
|
+
if (!favs.length) {
|
|
5033
|
+
box.innerHTML = '<div class="gh-empty">Henüz favori yok — trendden ☆ ile ekle.</div>';
|
|
5034
|
+
return;
|
|
5035
|
+
}
|
|
5036
|
+
box.innerHTML = favs.map((r) => ghCard(r, true)).join('');
|
|
5037
|
+
wireGhCards(box, favs, true);
|
|
5038
|
+
}
|
|
5039
|
+
|
|
5040
|
+
$('#gitBtn').addEventListener('click', openGit);
|
|
5041
|
+
$('#ghClose').addEventListener('click', closeGit);
|
|
5042
|
+
$('#ghOverlay').addEventListener('click', (e) => {
|
|
5043
|
+
if (e.target === $('#ghOverlay')) closeGit();
|
|
5044
|
+
});
|
|
5045
|
+
/* aralık filtreleri: Tümü / 6 Ay / 1 Ay / 2 Hafta / 1 Hafta */
|
|
5046
|
+
document.querySelectorAll('#ghRanges button').forEach((b) =>
|
|
5047
|
+
b.addEventListener('click', () => {
|
|
5048
|
+
ghState.range = b.dataset.range;
|
|
5049
|
+
document.querySelectorAll('#ghRanges button').forEach((x) => x.classList.toggle('on', x === b));
|
|
5050
|
+
loadGhTrend();
|
|
5051
|
+
updateGhSub();
|
|
5052
|
+
})
|
|
5053
|
+
);
|
|
5054
|
+
/* yıldız sırası: azalan ⇄ artan */
|
|
5055
|
+
$('#ghSortBtn').addEventListener('click', () => {
|
|
5056
|
+
ghState.sort = ghState.sort === 'desc' ? 'asc' : 'desc';
|
|
5057
|
+
updateGhSortBtn();
|
|
5058
|
+
loadGhTrend();
|
|
5059
|
+
});
|
|
5060
|
+
/* repo arama: Enter ile; boş Enter → trend moduna döner */
|
|
5061
|
+
$('#ghSearch').addEventListener('keydown', (e) => {
|
|
5062
|
+
if (e.key !== 'Enter') return;
|
|
5063
|
+
ghState.q = $('#ghSearch').value.trim();
|
|
5064
|
+
updateGhSub();
|
|
5065
|
+
loadGhTrend();
|
|
5066
|
+
});
|
|
5067
|
+
/* sol sekme: Trend Depolar ⇄ Tüm Repolar (eşit bölünmüş, ortalanmış) */
|
|
5068
|
+
document.querySelectorAll('.gh-tab').forEach((b) =>
|
|
5069
|
+
b.addEventListener('click', () => {
|
|
5070
|
+
ghState.ghTab = b.dataset.ghtab;
|
|
5071
|
+
document.querySelectorAll('.gh-tab').forEach((x) => x.classList.toggle('on', x === b));
|
|
5072
|
+
$('#ghTrendTools').hidden = ghState.ghTab !== 'trend';
|
|
5073
|
+
$('#ghAllTools').hidden = ghState.ghTab !== 'all';
|
|
5074
|
+
updateGhSub();
|
|
5075
|
+
loadGhTrend();
|
|
5076
|
+
})
|
|
5077
|
+
);
|
|
5078
|
+
/* tüm repolar arama + üçlü sıralama: en iyi eşleşme → azalan → artan */
|
|
5079
|
+
$('#ghAllSearch').addEventListener('keydown', (e) => {
|
|
5080
|
+
if (e.key !== 'Enter') return;
|
|
5081
|
+
ghState.allQ = $('#ghAllSearch').value.trim();
|
|
5082
|
+
updateGhSub();
|
|
5083
|
+
loadGhTrend();
|
|
5084
|
+
});
|
|
5085
|
+
$('#ghAllSortBtn').addEventListener('click', () => {
|
|
5086
|
+
ghState.allSort = ghState.allSort === 'best' ? 'desc' : ghState.allSort === 'desc' ? 'asc' : 'best';
|
|
5087
|
+
updateGhAllSortBtn();
|
|
5088
|
+
updateGhSub();
|
|
5089
|
+
loadGhTrend();
|
|
5090
|
+
});
|
|
5091
|
+
/* ⟳ sıfırla + yenile: ilgili sekmenin filtrelerini başa alır, modal ilk açıldığı gibi yüklenir */
|
|
5092
|
+
$('#ghTrendRefresh').addEventListener('click', () => {
|
|
5093
|
+
ghState.range = '2w';
|
|
5094
|
+
ghState.sort = 'desc';
|
|
5095
|
+
ghState.q = '';
|
|
5096
|
+
$('#ghSearch').value = '';
|
|
5097
|
+
document.querySelectorAll('#ghRanges button').forEach((x) => x.classList.toggle('on', x.dataset.range === '2w'));
|
|
5098
|
+
updateGhSortBtn();
|
|
5099
|
+
updateGhSub();
|
|
5100
|
+
loadGhTrend();
|
|
5101
|
+
});
|
|
5102
|
+
$('#ghAllRefresh').addEventListener('click', () => {
|
|
5103
|
+
ghState.allQ = '';
|
|
5104
|
+
ghState.allSort = 'best';
|
|
5105
|
+
$('#ghAllSearch').value = '';
|
|
5106
|
+
updateGhAllSortBtn();
|
|
5107
|
+
updateGhSub();
|
|
5108
|
+
loadGhTrend();
|
|
5109
|
+
});
|
|
5110
|
+
|
|
5111
|
+
|
|
5112
|
+
/* ================= IDE MODU =================
|
|
5113
|
+
Tek tuş (#ideBtn): sol → dosya gezgini, orta → chat, sağ → dahili tarayıcı (preview).
|
|
5114
|
+
Preview: workspace kökündeki index.html (yoksa ilk *.html) sağdaki tarayıcıda açılır.
|
|
5115
|
+
Dosyaya tıkla → editör; klasöre tıkla → aç/kapa. */
|
|
5116
|
+
|
|
5117
|
+
const IDE_ICONS = {
|
|
5118
|
+
'.html': '🌐', '.htm': '🌐', '.css': '🎨', '.js': '📜', '.mjs': '📜', '.cjs': '📜',
|
|
5119
|
+
'.ts': '📜', '.jsx': '📜', '.tsx': '📜', '.json': '🧾', '.md': '📝', '.txt': '📄',
|
|
5120
|
+
'.py': '🐍', '.ps1': '⚙️', '.bat': '⚙️', '.cmd': '⚙️', '.sh': '⚙️', '.yaml': '🧾',
|
|
5121
|
+
'.yml': '🧾', '.png': '🖼️', '.jpg': '🖼️', '.jpeg': '🖼️', '.gif': '🖼️', '.svg': '🖼️',
|
|
5122
|
+
'.pdf': '📕',
|
|
5123
|
+
};
|
|
5124
|
+
|
|
4917
5125
|
const ideState = {
|
|
4918
5126
|
cache: new Map(), // rel -> entries[]
|
|
4919
5127
|
open: new Set(['']),
|
|
4920
5128
|
path: '',
|
|
4921
|
-
};
|
|
4922
|
-
|
|
4923
|
-
function ideModeOn() {
|
|
4924
|
-
return document.body.classList.contains('ide-mode');
|
|
4925
|
-
}
|
|
4926
|
-
|
|
5129
|
+
};
|
|
5130
|
+
|
|
5131
|
+
function ideModeOn() {
|
|
5132
|
+
return document.body.classList.contains('ide-mode');
|
|
5133
|
+
}
|
|
5134
|
+
|
|
4927
5135
|
async function setIdeMode(on) {
|
|
4928
5136
|
document.body.classList.toggle('ide-mode', !!on);
|
|
4929
5137
|
/* IDE modu oturumluk: uygulama HER AÇILIŞTA agent (chat) modunda başlar */
|
|
@@ -4995,52 +5203,52 @@ if (els.ideSplit) {
|
|
|
4995
5203
|
window.addEventListener('resize', () => {
|
|
4996
5204
|
if (ideModeOn()) ideSplitApplyFrac();
|
|
4997
5205
|
});
|
|
4998
|
-
}
|
|
4999
|
-
|
|
5000
|
-
async function loadIdeTree() {
|
|
5001
|
-
ideState.cache.clear();
|
|
5002
|
-
await renderFileTree();
|
|
5003
|
-
}
|
|
5004
|
-
|
|
5005
|
-
function fmtFileSize(n) {
|
|
5006
|
-
n = Number(n) || 0;
|
|
5007
|
-
if (n >= 1048576) return (n / 1048576).toFixed(1) + 'M';
|
|
5008
|
-
if (n >= 1024) return Math.round(n / 1024) + 'K';
|
|
5009
|
-
return n ? n + 'B' : '';
|
|
5010
|
-
}
|
|
5011
|
-
|
|
5012
|
-
async function renderFileTree() {
|
|
5013
|
-
const tree = $('#fileTree');
|
|
5014
|
-
if (!tree) return;
|
|
5015
|
-
tree.innerHTML = '';
|
|
5016
|
-
const wsLabel = $('#filePanelPath');
|
|
5017
|
-
const build = async (rel, depth, container) => {
|
|
5018
|
-
let entries = ideState.cache.get(rel);
|
|
5019
|
-
if (!entries) {
|
|
5020
|
-
const r = await beast.ideTree(rel).catch(() => null);
|
|
5021
|
-
if (!r || !r.ok) {
|
|
5022
|
-
if (!rel) container.innerHTML = `<div class="file-empty">${escapeHtml((r && r.error) || 'okunamadı')}</div>`;
|
|
5023
|
-
return;
|
|
5024
|
-
}
|
|
5025
|
-
entries = r.entries;
|
|
5026
|
-
ideState.cache.set(rel, entries);
|
|
5206
|
+
}
|
|
5207
|
+
|
|
5208
|
+
async function loadIdeTree() {
|
|
5209
|
+
ideState.cache.clear();
|
|
5210
|
+
await renderFileTree();
|
|
5211
|
+
}
|
|
5212
|
+
|
|
5213
|
+
function fmtFileSize(n) {
|
|
5214
|
+
n = Number(n) || 0;
|
|
5215
|
+
if (n >= 1048576) return (n / 1048576).toFixed(1) + 'M';
|
|
5216
|
+
if (n >= 1024) return Math.round(n / 1024) + 'K';
|
|
5217
|
+
return n ? n + 'B' : '';
|
|
5218
|
+
}
|
|
5219
|
+
|
|
5220
|
+
async function renderFileTree() {
|
|
5221
|
+
const tree = $('#fileTree');
|
|
5222
|
+
if (!tree) return;
|
|
5223
|
+
tree.innerHTML = '';
|
|
5224
|
+
const wsLabel = $('#filePanelPath');
|
|
5225
|
+
const build = async (rel, depth, container) => {
|
|
5226
|
+
let entries = ideState.cache.get(rel);
|
|
5227
|
+
if (!entries) {
|
|
5228
|
+
const r = await beast.ideTree(rel).catch(() => null);
|
|
5229
|
+
if (!r || !r.ok) {
|
|
5230
|
+
if (!rel) container.innerHTML = `<div class="file-empty">${escapeHtml((r && r.error) || 'okunamadı')}</div>`;
|
|
5231
|
+
return;
|
|
5232
|
+
}
|
|
5233
|
+
entries = r.entries;
|
|
5234
|
+
ideState.cache.set(rel, entries);
|
|
5027
5235
|
if (r.workspace) {
|
|
5028
5236
|
ideState.path = r.workspace;
|
|
5029
5237
|
if (wsLabel) { wsLabel.textContent = r.workspace; wsLabel.title = r.workspace; }
|
|
5030
5238
|
if (els.bcCwd) { els.bcCwd.textContent = r.workspace; els.bcCwd.title = r.workspace; }
|
|
5031
5239
|
bcOnFolderChanged(r.workspace);
|
|
5032
|
-
}
|
|
5033
|
-
}
|
|
5034
|
-
for (const e of entries) {
|
|
5035
|
-
const child = rel ? rel + '/' + e.name : e.name;
|
|
5036
|
-
const row = document.createElement('div');
|
|
5037
|
-
row.className = 'file-row';
|
|
5038
|
-
row.style.paddingLeft = 6 + depth * 14 + 'px';
|
|
5039
|
-
const ico = e.dir ? (ideState.open.has(child) ? '📂' : '📁') : IDE_ICONS[e.name.slice(e.name.lastIndexOf('.')).toLowerCase()] || '📄';
|
|
5040
|
-
row.innerHTML =
|
|
5041
|
-
`<span class="f-ico">${ico}</span>` +
|
|
5042
|
-
`<span class="f-nm" title="${escapeHtml(e.name)}">${escapeHtml(e.name)}</span>` +
|
|
5043
|
-
(e.dir ? '' : `<span class="f-sz">${fmtFileSize(e.size)}</span>`);
|
|
5240
|
+
}
|
|
5241
|
+
}
|
|
5242
|
+
for (const e of entries) {
|
|
5243
|
+
const child = rel ? rel + '/' + e.name : e.name;
|
|
5244
|
+
const row = document.createElement('div');
|
|
5245
|
+
row.className = 'file-row';
|
|
5246
|
+
row.style.paddingLeft = 6 + depth * 14 + 'px';
|
|
5247
|
+
const ico = e.dir ? (ideState.open.has(child) ? '📂' : '📁') : IDE_ICONS[e.name.slice(e.name.lastIndexOf('.')).toLowerCase()] || '📄';
|
|
5248
|
+
row.innerHTML =
|
|
5249
|
+
`<span class="f-ico">${ico}</span>` +
|
|
5250
|
+
`<span class="f-nm" title="${escapeHtml(e.name)}">${escapeHtml(e.name)}</span>` +
|
|
5251
|
+
(e.dir ? '' : `<span class="f-sz">${fmtFileSize(e.size)}</span>`);
|
|
5044
5252
|
row.addEventListener('click', () => {
|
|
5045
5253
|
if (e.dir) {
|
|
5046
5254
|
if (ideState.open.has(child)) ideState.open.delete(child);
|
|
@@ -5280,7 +5488,7 @@ $('#fileTree').addEventListener('contextmenu', (e) => {
|
|
|
5280
5488
|
return;
|
|
5281
5489
|
}
|
|
5282
5490
|
fileCtxShow(e, row.dataset.rel, row.dataset.dir === '1');
|
|
5283
|
-
});
|
|
5491
|
+
});
|
|
5284
5492
|
|
|
5285
5493
|
/* ---------- IDE modu ortası: BEAST CODE paneli ----------
|
|
5286
5494
|
Sohbet yerine Beast'in kendi ajanı (varsayılan model) çalışır;
|
|
@@ -5627,4 +5835,4 @@ if (els.bcNew) els.bcNew.addEventListener('click', async () => {
|
|
|
5627
5835
|
}
|
|
5628
5836
|
});
|
|
5629
5837
|
/* Uygulama her açılışta agent (chat) modunda başlar — IDE modu yalnız
|
|
5630
|
-
kullanıcı butona basınca girilir (oturumluk). */
|
|
5838
|
+
kullanıcı butona basınca girilir (oturumluk). */
|