beast-agent 0.24.4 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/agent/engine.js +34 -59
- package/src/agent/tools.js +1 -1
- package/src/main.js +211 -45
- 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 +346 -138
- package/src/renderer/style.css +195 -29
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 || []);
|
|
@@ -1820,7 +1822,7 @@ async function renderUpdatePane(autoCheck) {
|
|
|
1820
1822
|
if (st.npm) {
|
|
1821
1823
|
actions = `<div class="form-grid" style="grid-template-columns:auto auto;gap:8px;margin-top:12px">
|
|
1822
1824
|
<button id="upCheck" class="btn ghost">${_t('up_check_now')}</button>
|
|
1823
|
-
<button id="upInstall" class="btn"
|
|
1825
|
+
<button id="upInstall" class="btn"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px"><path d="M21 12a9 9 0 1 1-2.64-6.36"/><path d="M21 3v6h-6"/></svg>${_t('up_install_now')}</button>
|
|
1824
1826
|
</div>
|
|
1825
1827
|
<div class="sub" style="margin-top:8px">${_t('up_npm_only')}</div>`;
|
|
1826
1828
|
} else if (isDev) {
|
|
@@ -2462,41 +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
|
-
menu.innerHTML = '<div class="dd-item" style="pointer-events:none">Davet edilebilir bot yok</div>';
|
|
2482
|
-
return;
|
|
2483
|
-
}
|
|
2484
|
-
for (const b of candidates) {
|
|
2485
|
-
const invited = activeGuests.some((g) => g.id === b.id);
|
|
2486
|
-
const item = document.createElement('div');
|
|
2487
|
-
item.className = 'dd-item';
|
|
2488
|
-
item.innerHTML = `${b.icon} ${escapeHtml(b.name)} <span style="float:right;color:var(--muted)">${invited ? '✓ davetli' : '+ davet et'}</span>`;
|
|
2489
|
-
item.addEventListener('click', async () => {
|
|
2490
|
-
const next = invited ? activeGuests.filter((g) => g.id !== b.id) : [...activeGuests, { id: b.id, code: b.code || '', name: b.name }];
|
|
2491
|
-
activeGuests = next;
|
|
2492
|
-
await beast.sessionSetGuests(activeId, next).catch(() => {});
|
|
2493
|
-
renderGuestBotMenu();
|
|
2494
|
-
toast(invited ? `${b.name} davetten çıkarıldı` : `${b.name} sohbete davet edildi — ajan gerektiğinde ona danışacak`);
|
|
2495
|
-
menu.hidden = true;
|
|
2496
|
-
});
|
|
2497
|
-
menu.appendChild(item);
|
|
2498
|
-
}
|
|
2499
|
-
}
|
|
2500
2467
|
|
|
2501
2468
|
async function refreshBots() {
|
|
2502
2469
|
try {
|
|
@@ -2827,9 +2794,6 @@ function renderBotSettings(pane, b) {
|
|
|
2827
2794
|
<div class="bot-checks" style="margin-bottom:6px">
|
|
2828
2795
|
<label><input type="checkbox" id="bExtBrowser" ${b.extBrowser ? 'checked' : ''}/> ${_t('bot_ext_browser')}</label>
|
|
2829
2796
|
</div>
|
|
2830
|
-
<div class="bot-checks" style="margin-bottom:6px">
|
|
2831
|
-
<label><input type="checkbox" id="bVis" ${b.vis !== false ? 'checked' : ''}/> ${_t('bot_vis')}</label>
|
|
2832
|
-
</div>
|
|
2833
2797
|
<div class="form-grid">
|
|
2834
2798
|
<div>
|
|
2835
2799
|
<label class="mem-label" style="margin-top:0">${_t('bot_def_browser')}</label>
|
|
@@ -2890,7 +2854,6 @@ function renderBotSettings(pane, b) {
|
|
|
2890
2854
|
prompt: $('#bPrompt').value,
|
|
2891
2855
|
seeBots: [...f.querySelectorAll('#bSee input:checked')].map((c) => c.dataset.see),
|
|
2892
2856
|
extBrowser: $('#bExtBrowser').checked,
|
|
2893
|
-
vis: f.querySelector('#bVis') ? f.querySelector('#bVis').checked : true,
|
|
2894
2857
|
browserDefault: $('#bBrDef').value,
|
|
2895
2858
|
extCommand: $('#bBrCmd').value.trim(),
|
|
2896
2859
|
numbers: (b.numbers || []).map((n) => n.num),
|
|
@@ -3049,6 +3012,7 @@ function renderBotAdd(pane) {
|
|
|
3049
3012
|
|
|
3050
3013
|
const agentState = {
|
|
3051
3014
|
jobs: [],
|
|
3015
|
+
autoOpened: false, // konsol bu turda otomatik açıldı mı (boştan-çalışıyor geçişi)
|
|
3052
3016
|
last: new Map(), // bgSessionId -> son aktivite metni
|
|
3053
3017
|
runningIds: new Set(),
|
|
3054
3018
|
expanded: new Set(), // detayı açık kartlar
|
|
@@ -3076,11 +3040,26 @@ function scheduleAgentsRender() {
|
|
|
3076
3040
|
|
|
3077
3041
|
async function refreshAgentsPane() {
|
|
3078
3042
|
try { agentState.jobs = (await beast.agentsList()) || []; } catch {}
|
|
3043
|
+
/* açılışta ajanlar zaten çalışıyorsa konsolu otomatik aç */
|
|
3044
|
+
maybeAutoOpenRail();
|
|
3079
3045
|
updateAgentIds();
|
|
3080
3046
|
renderAgentsPane();
|
|
3081
3047
|
renderAgentRail();
|
|
3082
3048
|
}
|
|
3083
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
|
+
|
|
3084
3063
|
function ingestAgentActivity(ev) {
|
|
3085
3064
|
const id = ev.sessionId;
|
|
3086
3065
|
let label = agentState.last.get(id) || '';
|
|
@@ -3341,6 +3320,7 @@ function onEvent(ev) {
|
|
|
3341
3320
|
}
|
|
3342
3321
|
if (ev.type === 'agents') {
|
|
3343
3322
|
agentState.jobs = ev.jobs || [];
|
|
3323
|
+
maybeAutoOpenRail();
|
|
3344
3324
|
updateAgentIds();
|
|
3345
3325
|
scheduleAgentsRender();
|
|
3346
3326
|
return;
|
|
@@ -3506,23 +3486,19 @@ let termBannerDone = false;
|
|
|
3506
3486
|
let termRunning = false;
|
|
3507
3487
|
let termHist = [];
|
|
3508
3488
|
let termHistIdx = -1;
|
|
3509
|
-
let termShell = '
|
|
3489
|
+
let termShell = 'cmd';
|
|
3510
3490
|
const TERM_MAX_LINES = 800;
|
|
3511
3491
|
|
|
3512
|
-
/* terminal
|
|
3492
|
+
/* terminal kabuğu: yalnız CMD (PowerShell/Git Bash kaldırıldı) */
|
|
3513
3493
|
const TERM_SHELLS = {
|
|
3514
|
-
|
|
3515
|
-
bash: { label: 'Git Bash', prompt: 'bash $' },
|
|
3516
|
-
cmd: { label: 'CMD', prompt: 'C>' },
|
|
3494
|
+
cmd: { label: 'CMD', prompt: 'CMD>' },
|
|
3517
3495
|
};
|
|
3518
3496
|
|
|
3519
3497
|
function termSetShell(s) {
|
|
3520
|
-
if (!TERM_SHELLS[s]) s = '
|
|
3498
|
+
if (!TERM_SHELLS[s]) s = 'cmd';
|
|
3521
3499
|
const changed = termShell !== s;
|
|
3522
3500
|
termShell = s;
|
|
3523
3501
|
if (els.termPrompt) els.termPrompt.textContent = TERM_SHELLS[s].prompt;
|
|
3524
|
-
if (els.termBtn) els.termBtn.classList.toggle('on', termOpen && s === 'powershell');
|
|
3525
|
-
if (els.termGBtn) els.termGBtn.classList.toggle('on', termOpen && s === 'bash');
|
|
3526
3502
|
if (els.termCBtn) els.termCBtn.classList.toggle('on', termOpen && s === 'cmd');
|
|
3527
3503
|
if (changed && termOpen && termBannerDone) termLine('t-sys', 'Kabuk: ' + TERM_SHELLS[s].label);
|
|
3528
3504
|
}
|
|
@@ -3567,7 +3543,7 @@ function termBanner(cwd) {
|
|
|
3567
3543
|
els.termCwd.title = cwd || '';
|
|
3568
3544
|
termLine('t-sys', 'Beast Terminal — çalışma klasörü: ' + (cwd || '?'));
|
|
3569
3545
|
termLine('t-sys', 'Kabuk: ' + TERM_SHELLS[termShell].label + ' · Ajanlar çalışırken araç çağrıları ve çıktıları burada canlı akar.', false);
|
|
3570
|
-
termLine('t-dim', 'Komut yaz, Enter\'a bas — her komut workspace\'te ayrı süreçle çalışır.
|
|
3546
|
+
termLine('t-dim', 'Komut yaz, Enter\'a bas — her komut workspace\'te ayrı süreçle çalışır. Kabuk: CMD.', false);
|
|
3571
3547
|
}
|
|
3572
3548
|
|
|
3573
3549
|
function termShortTool(name, args) {
|
|
@@ -3602,7 +3578,7 @@ function termCmdDone(ev) {
|
|
|
3602
3578
|
}
|
|
3603
3579
|
|
|
3604
3580
|
async function termToggle(shell) {
|
|
3605
|
-
const want = TERM_SHELLS[shell] ? shell : '
|
|
3581
|
+
const want = TERM_SHELLS[shell] ? shell : 'cmd';
|
|
3606
3582
|
/* aynı kabuk butonuna tekrar basıldıysa paneli kapat */
|
|
3607
3583
|
if (termOpen && termShell === want) {
|
|
3608
3584
|
termSetOpen(false);
|
|
@@ -3629,7 +3605,7 @@ function termRunCurrent() {
|
|
|
3629
3605
|
termHist.push(cmd);
|
|
3630
3606
|
if (termHist.length > 100) termHist.shift();
|
|
3631
3607
|
termHistIdx = termHist.length;
|
|
3632
|
-
termLine('t-cmd', '
|
|
3608
|
+
termLine('t-cmd', TERM_SHELLS[termShell].prompt + ' ' + cmd);
|
|
3633
3609
|
termRunning = true;
|
|
3634
3610
|
els.termStop.hidden = false;
|
|
3635
3611
|
beast.terminalRun(cmd, termShell).then((r) => {
|
|
@@ -4069,6 +4045,7 @@ function openCron() { refreshCron(); }
|
|
|
4069
4045
|
|
|
4070
4046
|
async function init() {
|
|
4071
4047
|
beast.onEvent(onEvent);
|
|
4048
|
+
toggleRail(true); /* Paralel Ajanlar paneli varsayılan KAPALI — railBtn ile açılır */
|
|
4072
4049
|
|
|
4073
4050
|
state = await beast.getState();
|
|
4074
4051
|
try {
|
|
@@ -4405,8 +4382,6 @@ async function init() {
|
|
|
4405
4382
|
|
|
4406
4383
|
/* terminal paneli — olay bağlama */
|
|
4407
4384
|
try { termSetWidth(parseInt(localStorage.getItem('beast.termW')) || 520); } catch {}
|
|
4408
|
-
if (els.termBtn) els.termBtn.addEventListener('click', () => termToggle('powershell'));
|
|
4409
|
-
if (els.termGBtn) els.termGBtn.addEventListener('click', () => termToggle('bash'));
|
|
4410
4385
|
if (els.termCBtn) els.termCBtn.addEventListener('click', () => termToggle('cmd'));
|
|
4411
4386
|
if (els.termClose) els.termClose.addEventListener('click', () => termSetOpen(false));
|
|
4412
4387
|
if (els.termClear) els.termClear.addEventListener('click', () => { els.termOut.innerHTML = ''; });
|
|
@@ -4479,18 +4454,6 @@ async function init() {
|
|
|
4479
4454
|
if ($('#botClose')) $('#botClose').addEventListener('click', () => botOverlaySetOpen(false));
|
|
4480
4455
|
if ($('#botOverviewBack')) $('#botOverviewBack').addEventListener('click', () => openBotPage(null));
|
|
4481
4456
|
if ($('#botChip')) $('#botChip').addEventListener('click', () => openBotPage(activeBotId));
|
|
4482
|
-
|
|
4483
|
-
/* BOT DAVET MENÜSÜ: butona tıkla → aç/kapa; dışarı tık → kapa */
|
|
4484
|
-
if ($('#guestBotBtn') && $('#guestBotMenu')) {
|
|
4485
|
-
$('#guestBotBtn').addEventListener('click', (e) => {
|
|
4486
|
-
e.stopPropagation();
|
|
4487
|
-
renderGuestBotMenu();
|
|
4488
|
-
$('#guestBotMenu').hidden = !$('#guestBotMenu').hidden;
|
|
4489
|
-
});
|
|
4490
|
-
document.addEventListener('click', (e) => {
|
|
4491
|
-
if (!$('#guestBotMenu').hidden && !$('#guestBotMenu').contains(e.target)) $('#guestBotMenu').hidden = true;
|
|
4492
|
-
});
|
|
4493
|
-
}
|
|
4494
4457
|
/* kalıcı aktif bot: restart sonrası aynı botun UI'ı açılır */
|
|
4495
4458
|
beast.botsActiveGet().then((r) => { activeBotId = (r && r.id) || 'beast'; updateBotChip(); renderBotCards(); }).catch(() => {});
|
|
4496
4459
|
document.querySelectorAll('.btab').forEach((b) =>
|
|
@@ -4893,31 +4856,276 @@ document.querySelectorAll('.stab').forEach((b) =>
|
|
|
4893
4856
|
renderStorePane();
|
|
4894
4857
|
})
|
|
4895
4858
|
);
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
/* =================
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
'
|
|
4909
|
-
|
|
4910
|
-
|
|
4859
|
+
|
|
4860
|
+
|
|
4861
|
+
/* ================= GITHUB TRENDING =================
|
|
4862
|
+
Skills Store'un sağındaki buton → %70 modal (store ile aynı tasarım).
|
|
4863
|
+
SOL: son 14 günün yıldız yükselenleri (GitHub Search API).
|
|
4864
|
+
SAĞ: favoriler (localStorage'da kalıcı). Her kartta:
|
|
4865
|
+
★ favori · Chate at (ajana araştırma mesajı) · Kopyala · repoya git. */
|
|
4866
|
+
|
|
4867
|
+
const ghState = { items: [], err: '', range: '2w', sort: 'desc', q: '', ghTab: 'trend', allQ: '', allSort: 'best' };
|
|
4868
|
+
const GH_FAV_KEY = 'beast.github.favs';
|
|
4869
|
+
const GH_RANGE_LABEL = {
|
|
4870
|
+
all: '— tüm zamanların en yıldızlıları',
|
|
4871
|
+
'6m': '— son 6 ayın yıldız yükselenleri',
|
|
4872
|
+
'1m': '— son 1 ayın yıldız yükselenleri',
|
|
4873
|
+
'2w': '— son 2 haftanın yıldız yükselenleri',
|
|
4874
|
+
'1w': '— son 1 haftanın yıldız yükselenleri',
|
|
4875
|
+
};
|
|
4876
|
+
const GH_ALL_SORT_LABEL = { best: '⭐ En İyi', desc: '↓ Yıldız', asc: '↑ Yıldız' };
|
|
4877
|
+
|
|
4878
|
+
function ghFavs() {
|
|
4879
|
+
try { return JSON.parse(localStorage.getItem(GH_FAV_KEY) || '[]'); } catch { return []; }
|
|
4880
|
+
}
|
|
4881
|
+
function ghSaveFavs(list) {
|
|
4882
|
+
try { localStorage.setItem(GH_FAV_KEY, JSON.stringify(list.slice(0, 100))); } catch {}
|
|
4883
|
+
}
|
|
4884
|
+
function ghIsFav(fullName) {
|
|
4885
|
+
return ghFavs().some((f) => f.full_name === fullName);
|
|
4886
|
+
}
|
|
4887
|
+
|
|
4888
|
+
async function openGit() {
|
|
4889
|
+
$('#ghOverlay').hidden = false;
|
|
4890
|
+
renderGhFavs();
|
|
4891
|
+
updateGhSortBtn();
|
|
4892
|
+
updateGhAllSortBtn();
|
|
4893
|
+
updateGhSub();
|
|
4894
|
+
loadGhTrend();
|
|
4895
|
+
}
|
|
4896
|
+
|
|
4897
|
+
async function loadGhTrend() {
|
|
4898
|
+
const box = $('#ghTrendList');
|
|
4899
|
+
/* tüm repolar sekmesinde boş arama = API'yi boşa yorma, ipucu göster */
|
|
4900
|
+
if (ghState.ghTab === 'all' && !ghState.allQ) {
|
|
4901
|
+
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>';
|
|
4902
|
+
return;
|
|
4903
|
+
}
|
|
4904
|
+
box.innerHTML = '<div class="gh-empty">Yükleniyor…</div>';
|
|
4905
|
+
const params = ghState.ghTab === 'all'
|
|
4906
|
+
? { mode: 'all', q: ghState.allQ, allSort: ghState.allSort, order: ghState.allSort === 'desc' ? 'desc' : 'asc' }
|
|
4907
|
+
: { mode: 'trend', range: ghState.range, sort: ghState.sort, q: ghState.q };
|
|
4908
|
+
const r = await beast.githubTrending(params).catch(() => ({ ok: false, error: 'ipc' }));
|
|
4909
|
+
if (r && r.ok) {
|
|
4910
|
+
ghState.items = r.items || [];
|
|
4911
|
+
ghState.err = '';
|
|
4912
|
+
} else {
|
|
4913
|
+
ghState.items = [];
|
|
4914
|
+
ghState.err = (r && r.error) || 'GitHub\u2019a ulaşılamadı';
|
|
4915
|
+
}
|
|
4916
|
+
renderGhTrend();
|
|
4917
|
+
}
|
|
4918
|
+
|
|
4919
|
+
function updateGhSortBtn() {
|
|
4920
|
+
const btn = $('#ghSortBtn');
|
|
4921
|
+
if (btn) {
|
|
4922
|
+
btn.textContent = ghState.sort === 'desc' ? '↓ Yıldız' : '↑ Yıldız';
|
|
4923
|
+
btn.title = ghState.sort === 'desc' ? 'Yıldız sırası: azalan — artana çevir' : 'Yıldız sırası: artan — azalana çevir';
|
|
4924
|
+
}
|
|
4925
|
+
}
|
|
4926
|
+
|
|
4927
|
+
function updateGhSub() {
|
|
4928
|
+
const sub = $('#ghTrendSub');
|
|
4929
|
+
if (!sub) return;
|
|
4930
|
+
if (ghState.ghTab === 'all') {
|
|
4931
|
+
const sortTxt = ghState.allSort === 'best' ? 'en iyi eşleşme' : ghState.allSort === 'desc' ? 'yıldız azalan' : 'yıldız artan';
|
|
4932
|
+
sub.textContent = ghState.allQ ? `— "${ghState.allQ}" araması · ${sortTxt}` : '— tüm GitHub: ada, konuya, açıklamaya göre arama';
|
|
4933
|
+
} else {
|
|
4934
|
+
sub.textContent = ghState.q ? `— "${ghState.q}" araması · tüm zamanlar` : GH_RANGE_LABEL[ghState.range] || '';
|
|
4935
|
+
}
|
|
4936
|
+
}
|
|
4937
|
+
|
|
4938
|
+
function updateGhAllSortBtn() {
|
|
4939
|
+
const btn = $('#ghAllSortBtn');
|
|
4940
|
+
if (btn) btn.textContent = GH_ALL_SORT_LABEL[ghState.allSort] || '⭐ En İyi';
|
|
4941
|
+
}
|
|
4942
|
+
|
|
4943
|
+
function closeGit() {
|
|
4944
|
+
$('#ghOverlay').hidden = true;
|
|
4945
|
+
}
|
|
4946
|
+
|
|
4947
|
+
/* chate at: ajana araştırma komutu gider (oturum yoksa input'a bırakılır) */
|
|
4948
|
+
function ghSendToChat(url, name) {
|
|
4949
|
+
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.`;
|
|
4950
|
+
if (!activeId) {
|
|
4951
|
+
els.input.value = msg;
|
|
4952
|
+
toast('Aktif oturum yok — mesaj kutusuna bırakıldı');
|
|
4953
|
+
return;
|
|
4954
|
+
}
|
|
4955
|
+
els.input.value = msg;
|
|
4956
|
+
sendCurrent();
|
|
4957
|
+
}
|
|
4958
|
+
|
|
4959
|
+
function ghCard(repo, isFav) {
|
|
4960
|
+
const stars = repo.stars >= 1000 ? (repo.stars / 1000).toFixed(1).replace('.0', '') + 'k' : String(repo.stars);
|
|
4961
|
+
const lang = repo.language ? `<span class="gh-lang">${escapeHtml(repo.language)}</span>` : '';
|
|
4962
|
+
return `
|
|
4963
|
+
<div class="gh-card" data-repo="${escapeHtml(repo.full_name)}">
|
|
4964
|
+
<div class="gh-card-top">
|
|
4965
|
+
<span class="gh-name" data-url="${escapeHtml(repo.html_url)}" title="${escapeHtml(repo.html_url)}">${escapeHtml(repo.full_name)}</span>
|
|
4966
|
+
<span class="gh-stars">★ ${stars}</span>
|
|
4967
|
+
${lang}
|
|
4968
|
+
</div>
|
|
4969
|
+
${repo.description ? `<div class="gh-desc" title="${escapeHtml(repo.description)}">${escapeHtml(repo.description)}</div>` : ''}
|
|
4970
|
+
<div class="gh-actions">
|
|
4971
|
+
<button class="gh-fav ${isFav ? 'on' : ''}" data-act="fav">${isFav ? '★ Favoride' : '☆ Favorile'}</button>
|
|
4972
|
+
<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>
|
|
4973
|
+
<button data-act="copy">⧉ Kopyala</button>
|
|
4974
|
+
</div>
|
|
4975
|
+
</div>`;
|
|
4976
|
+
}
|
|
4977
|
+
|
|
4978
|
+
function wireGhCards(container, list, isFavPane) {
|
|
4979
|
+
container.querySelectorAll('.gh-card').forEach((card) => {
|
|
4980
|
+
const repo = list.find((x) => x.full_name === card.dataset.repo);
|
|
4981
|
+
if (!repo) return;
|
|
4982
|
+
card.querySelector('.gh-name').addEventListener('click', () => beast.openExternal(repo.html_url).catch(() => {}));
|
|
4983
|
+
card.querySelector('[data-act="chat"]').addEventListener('click', () => {
|
|
4984
|
+
ghSendToChat(repo.html_url, repo.full_name);
|
|
4985
|
+
/* mesaj chate gitti — cevap chatten geleceği için modal kapanır */
|
|
4986
|
+
closeGit();
|
|
4987
|
+
});
|
|
4988
|
+
card.querySelector('[data-act="copy"]').addEventListener('click', async () => {
|
|
4989
|
+
try { await navigator.clipboard.writeText(repo.html_url); toast('Link kopyalandı'); } catch {}
|
|
4990
|
+
});
|
|
4991
|
+
card.querySelector('[data-act="fav"]').addEventListener('click', () => {
|
|
4992
|
+
const favs = ghFavs();
|
|
4993
|
+
if (ghIsFav(repo.full_name)) {
|
|
4994
|
+
ghSaveFavs(favs.filter((f) => f.full_name !== repo.full_name));
|
|
4995
|
+
toast('Favoriden çıkarıldı: ' + repo.full_name);
|
|
4996
|
+
} else {
|
|
4997
|
+
favs.unshift({ ...repo, addedAt: new Date().toISOString() });
|
|
4998
|
+
ghSaveFavs(favs);
|
|
4999
|
+
toast('Favorilere eklendi: ' + repo.full_name);
|
|
5000
|
+
}
|
|
5001
|
+
renderGhTrend();
|
|
5002
|
+
renderGhFavs();
|
|
5003
|
+
});
|
|
5004
|
+
});
|
|
5005
|
+
}
|
|
5006
|
+
|
|
5007
|
+
function renderGhTrend() {
|
|
5008
|
+
const box = $('#ghTrendList');
|
|
5009
|
+
if (!box) return;
|
|
5010
|
+
if (ghState.err) {
|
|
5011
|
+
box.innerHTML = `<div class="gh-err">⚠ ${escapeHtml(ghState.err)}</div>`;
|
|
5012
|
+
return;
|
|
5013
|
+
}
|
|
5014
|
+
if (!ghState.items.length) {
|
|
5015
|
+
box.innerHTML = '<div class="gh-empty">Son 14 günde öne çıkan repo bulunamadı.</div>';
|
|
5016
|
+
return;
|
|
5017
|
+
}
|
|
5018
|
+
box.innerHTML = ghState.items.map((r) => ghCard(r, ghIsFav(r.full_name))).join('');
|
|
5019
|
+
wireGhCards(box, ghState.items, false);
|
|
5020
|
+
}
|
|
5021
|
+
|
|
5022
|
+
function renderGhFavs() {
|
|
5023
|
+
const box = $('#ghFavList');
|
|
5024
|
+
if (!box) return;
|
|
5025
|
+
const favs = ghFavs();
|
|
5026
|
+
if (!favs.length) {
|
|
5027
|
+
box.innerHTML = '<div class="gh-empty">Henüz favori yok — trendden ☆ ile ekle.</div>';
|
|
5028
|
+
return;
|
|
5029
|
+
}
|
|
5030
|
+
box.innerHTML = favs.map((r) => ghCard(r, true)).join('');
|
|
5031
|
+
wireGhCards(box, favs, true);
|
|
5032
|
+
}
|
|
5033
|
+
|
|
5034
|
+
$('#gitBtn').addEventListener('click', openGit);
|
|
5035
|
+
$('#ghClose').addEventListener('click', closeGit);
|
|
5036
|
+
$('#ghOverlay').addEventListener('click', (e) => {
|
|
5037
|
+
if (e.target === $('#ghOverlay')) closeGit();
|
|
5038
|
+
});
|
|
5039
|
+
/* aralık filtreleri: Tümü / 6 Ay / 1 Ay / 2 Hafta / 1 Hafta */
|
|
5040
|
+
document.querySelectorAll('#ghRanges button').forEach((b) =>
|
|
5041
|
+
b.addEventListener('click', () => {
|
|
5042
|
+
ghState.range = b.dataset.range;
|
|
5043
|
+
document.querySelectorAll('#ghRanges button').forEach((x) => x.classList.toggle('on', x === b));
|
|
5044
|
+
loadGhTrend();
|
|
5045
|
+
updateGhSub();
|
|
5046
|
+
})
|
|
5047
|
+
);
|
|
5048
|
+
/* yıldız sırası: azalan ⇄ artan */
|
|
5049
|
+
$('#ghSortBtn').addEventListener('click', () => {
|
|
5050
|
+
ghState.sort = ghState.sort === 'desc' ? 'asc' : 'desc';
|
|
5051
|
+
updateGhSortBtn();
|
|
5052
|
+
loadGhTrend();
|
|
5053
|
+
});
|
|
5054
|
+
/* repo arama: Enter ile; boş Enter → trend moduna döner */
|
|
5055
|
+
$('#ghSearch').addEventListener('keydown', (e) => {
|
|
5056
|
+
if (e.key !== 'Enter') return;
|
|
5057
|
+
ghState.q = $('#ghSearch').value.trim();
|
|
5058
|
+
updateGhSub();
|
|
5059
|
+
loadGhTrend();
|
|
5060
|
+
});
|
|
5061
|
+
/* sol sekme: Trend Depolar ⇄ Tüm Repolar (eşit bölünmüş, ortalanmış) */
|
|
5062
|
+
document.querySelectorAll('.gh-tab').forEach((b) =>
|
|
5063
|
+
b.addEventListener('click', () => {
|
|
5064
|
+
ghState.ghTab = b.dataset.ghtab;
|
|
5065
|
+
document.querySelectorAll('.gh-tab').forEach((x) => x.classList.toggle('on', x === b));
|
|
5066
|
+
$('#ghTrendTools').hidden = ghState.ghTab !== 'trend';
|
|
5067
|
+
$('#ghAllTools').hidden = ghState.ghTab !== 'all';
|
|
5068
|
+
updateGhSub();
|
|
5069
|
+
loadGhTrend();
|
|
5070
|
+
})
|
|
5071
|
+
);
|
|
5072
|
+
/* tüm repolar arama + üçlü sıralama: en iyi eşleşme → azalan → artan */
|
|
5073
|
+
$('#ghAllSearch').addEventListener('keydown', (e) => {
|
|
5074
|
+
if (e.key !== 'Enter') return;
|
|
5075
|
+
ghState.allQ = $('#ghAllSearch').value.trim();
|
|
5076
|
+
updateGhSub();
|
|
5077
|
+
loadGhTrend();
|
|
5078
|
+
});
|
|
5079
|
+
$('#ghAllSortBtn').addEventListener('click', () => {
|
|
5080
|
+
ghState.allSort = ghState.allSort === 'best' ? 'desc' : ghState.allSort === 'desc' ? 'asc' : 'best';
|
|
5081
|
+
updateGhAllSortBtn();
|
|
5082
|
+
updateGhSub();
|
|
5083
|
+
loadGhTrend();
|
|
5084
|
+
});
|
|
5085
|
+
/* ⟳ sıfırla + yenile: ilgili sekmenin filtrelerini başa alır, modal ilk açıldığı gibi yüklenir */
|
|
5086
|
+
$('#ghTrendRefresh').addEventListener('click', () => {
|
|
5087
|
+
ghState.range = '2w';
|
|
5088
|
+
ghState.sort = 'desc';
|
|
5089
|
+
ghState.q = '';
|
|
5090
|
+
$('#ghSearch').value = '';
|
|
5091
|
+
document.querySelectorAll('#ghRanges button').forEach((x) => x.classList.toggle('on', x.dataset.range === '2w'));
|
|
5092
|
+
updateGhSortBtn();
|
|
5093
|
+
updateGhSub();
|
|
5094
|
+
loadGhTrend();
|
|
5095
|
+
});
|
|
5096
|
+
$('#ghAllRefresh').addEventListener('click', () => {
|
|
5097
|
+
ghState.allQ = '';
|
|
5098
|
+
ghState.allSort = 'best';
|
|
5099
|
+
$('#ghAllSearch').value = '';
|
|
5100
|
+
updateGhAllSortBtn();
|
|
5101
|
+
updateGhSub();
|
|
5102
|
+
loadGhTrend();
|
|
5103
|
+
});
|
|
5104
|
+
|
|
5105
|
+
|
|
5106
|
+
/* ================= IDE MODU =================
|
|
5107
|
+
Tek tuş (#ideBtn): sol → dosya gezgini, orta → chat, sağ → dahili tarayıcı (preview).
|
|
5108
|
+
Preview: workspace kökündeki index.html (yoksa ilk *.html) sağdaki tarayıcıda açılır.
|
|
5109
|
+
Dosyaya tıkla → editör; klasöre tıkla → aç/kapa. */
|
|
5110
|
+
|
|
5111
|
+
const IDE_ICONS = {
|
|
5112
|
+
'.html': '🌐', '.htm': '🌐', '.css': '🎨', '.js': '📜', '.mjs': '📜', '.cjs': '📜',
|
|
5113
|
+
'.ts': '📜', '.jsx': '📜', '.tsx': '📜', '.json': '🧾', '.md': '📝', '.txt': '📄',
|
|
5114
|
+
'.py': '🐍', '.ps1': '⚙️', '.bat': '⚙️', '.cmd': '⚙️', '.sh': '⚙️', '.yaml': '🧾',
|
|
5115
|
+
'.yml': '🧾', '.png': '🖼️', '.jpg': '🖼️', '.jpeg': '🖼️', '.gif': '🖼️', '.svg': '🖼️',
|
|
5116
|
+
'.pdf': '📕',
|
|
5117
|
+
};
|
|
5118
|
+
|
|
4911
5119
|
const ideState = {
|
|
4912
5120
|
cache: new Map(), // rel -> entries[]
|
|
4913
5121
|
open: new Set(['']),
|
|
4914
5122
|
path: '',
|
|
4915
|
-
};
|
|
4916
|
-
|
|
4917
|
-
function ideModeOn() {
|
|
4918
|
-
return document.body.classList.contains('ide-mode');
|
|
4919
|
-
}
|
|
4920
|
-
|
|
5123
|
+
};
|
|
5124
|
+
|
|
5125
|
+
function ideModeOn() {
|
|
5126
|
+
return document.body.classList.contains('ide-mode');
|
|
5127
|
+
}
|
|
5128
|
+
|
|
4921
5129
|
async function setIdeMode(on) {
|
|
4922
5130
|
document.body.classList.toggle('ide-mode', !!on);
|
|
4923
5131
|
/* IDE modu oturumluk: uygulama HER AÇILIŞTA agent (chat) modunda başlar */
|
|
@@ -4989,52 +5197,52 @@ if (els.ideSplit) {
|
|
|
4989
5197
|
window.addEventListener('resize', () => {
|
|
4990
5198
|
if (ideModeOn()) ideSplitApplyFrac();
|
|
4991
5199
|
});
|
|
4992
|
-
}
|
|
4993
|
-
|
|
4994
|
-
async function loadIdeTree() {
|
|
4995
|
-
ideState.cache.clear();
|
|
4996
|
-
await renderFileTree();
|
|
4997
|
-
}
|
|
4998
|
-
|
|
4999
|
-
function fmtFileSize(n) {
|
|
5000
|
-
n = Number(n) || 0;
|
|
5001
|
-
if (n >= 1048576) return (n / 1048576).toFixed(1) + 'M';
|
|
5002
|
-
if (n >= 1024) return Math.round(n / 1024) + 'K';
|
|
5003
|
-
return n ? n + 'B' : '';
|
|
5004
|
-
}
|
|
5005
|
-
|
|
5006
|
-
async function renderFileTree() {
|
|
5007
|
-
const tree = $('#fileTree');
|
|
5008
|
-
if (!tree) return;
|
|
5009
|
-
tree.innerHTML = '';
|
|
5010
|
-
const wsLabel = $('#filePanelPath');
|
|
5011
|
-
const build = async (rel, depth, container) => {
|
|
5012
|
-
let entries = ideState.cache.get(rel);
|
|
5013
|
-
if (!entries) {
|
|
5014
|
-
const r = await beast.ideTree(rel).catch(() => null);
|
|
5015
|
-
if (!r || !r.ok) {
|
|
5016
|
-
if (!rel) container.innerHTML = `<div class="file-empty">${escapeHtml((r && r.error) || 'okunamadı')}</div>`;
|
|
5017
|
-
return;
|
|
5018
|
-
}
|
|
5019
|
-
entries = r.entries;
|
|
5020
|
-
ideState.cache.set(rel, entries);
|
|
5200
|
+
}
|
|
5201
|
+
|
|
5202
|
+
async function loadIdeTree() {
|
|
5203
|
+
ideState.cache.clear();
|
|
5204
|
+
await renderFileTree();
|
|
5205
|
+
}
|
|
5206
|
+
|
|
5207
|
+
function fmtFileSize(n) {
|
|
5208
|
+
n = Number(n) || 0;
|
|
5209
|
+
if (n >= 1048576) return (n / 1048576).toFixed(1) + 'M';
|
|
5210
|
+
if (n >= 1024) return Math.round(n / 1024) + 'K';
|
|
5211
|
+
return n ? n + 'B' : '';
|
|
5212
|
+
}
|
|
5213
|
+
|
|
5214
|
+
async function renderFileTree() {
|
|
5215
|
+
const tree = $('#fileTree');
|
|
5216
|
+
if (!tree) return;
|
|
5217
|
+
tree.innerHTML = '';
|
|
5218
|
+
const wsLabel = $('#filePanelPath');
|
|
5219
|
+
const build = async (rel, depth, container) => {
|
|
5220
|
+
let entries = ideState.cache.get(rel);
|
|
5221
|
+
if (!entries) {
|
|
5222
|
+
const r = await beast.ideTree(rel).catch(() => null);
|
|
5223
|
+
if (!r || !r.ok) {
|
|
5224
|
+
if (!rel) container.innerHTML = `<div class="file-empty">${escapeHtml((r && r.error) || 'okunamadı')}</div>`;
|
|
5225
|
+
return;
|
|
5226
|
+
}
|
|
5227
|
+
entries = r.entries;
|
|
5228
|
+
ideState.cache.set(rel, entries);
|
|
5021
5229
|
if (r.workspace) {
|
|
5022
5230
|
ideState.path = r.workspace;
|
|
5023
5231
|
if (wsLabel) { wsLabel.textContent = r.workspace; wsLabel.title = r.workspace; }
|
|
5024
5232
|
if (els.bcCwd) { els.bcCwd.textContent = r.workspace; els.bcCwd.title = r.workspace; }
|
|
5025
5233
|
bcOnFolderChanged(r.workspace);
|
|
5026
|
-
}
|
|
5027
|
-
}
|
|
5028
|
-
for (const e of entries) {
|
|
5029
|
-
const child = rel ? rel + '/' + e.name : e.name;
|
|
5030
|
-
const row = document.createElement('div');
|
|
5031
|
-
row.className = 'file-row';
|
|
5032
|
-
row.style.paddingLeft = 6 + depth * 14 + 'px';
|
|
5033
|
-
const ico = e.dir ? (ideState.open.has(child) ? '📂' : '📁') : IDE_ICONS[e.name.slice(e.name.lastIndexOf('.')).toLowerCase()] || '📄';
|
|
5034
|
-
row.innerHTML =
|
|
5035
|
-
`<span class="f-ico">${ico}</span>` +
|
|
5036
|
-
`<span class="f-nm" title="${escapeHtml(e.name)}">${escapeHtml(e.name)}</span>` +
|
|
5037
|
-
(e.dir ? '' : `<span class="f-sz">${fmtFileSize(e.size)}</span>`);
|
|
5234
|
+
}
|
|
5235
|
+
}
|
|
5236
|
+
for (const e of entries) {
|
|
5237
|
+
const child = rel ? rel + '/' + e.name : e.name;
|
|
5238
|
+
const row = document.createElement('div');
|
|
5239
|
+
row.className = 'file-row';
|
|
5240
|
+
row.style.paddingLeft = 6 + depth * 14 + 'px';
|
|
5241
|
+
const ico = e.dir ? (ideState.open.has(child) ? '📂' : '📁') : IDE_ICONS[e.name.slice(e.name.lastIndexOf('.')).toLowerCase()] || '📄';
|
|
5242
|
+
row.innerHTML =
|
|
5243
|
+
`<span class="f-ico">${ico}</span>` +
|
|
5244
|
+
`<span class="f-nm" title="${escapeHtml(e.name)}">${escapeHtml(e.name)}</span>` +
|
|
5245
|
+
(e.dir ? '' : `<span class="f-sz">${fmtFileSize(e.size)}</span>`);
|
|
5038
5246
|
row.addEventListener('click', () => {
|
|
5039
5247
|
if (e.dir) {
|
|
5040
5248
|
if (ideState.open.has(child)) ideState.open.delete(child);
|
|
@@ -5274,7 +5482,7 @@ $('#fileTree').addEventListener('contextmenu', (e) => {
|
|
|
5274
5482
|
return;
|
|
5275
5483
|
}
|
|
5276
5484
|
fileCtxShow(e, row.dataset.rel, row.dataset.dir === '1');
|
|
5277
|
-
});
|
|
5485
|
+
});
|
|
5278
5486
|
|
|
5279
5487
|
/* ---------- IDE modu ortası: BEAST CODE paneli ----------
|
|
5280
5488
|
Sohbet yerine Beast'in kendi ajanı (varsayılan model) çalışır;
|
|
@@ -5621,4 +5829,4 @@ if (els.bcNew) els.bcNew.addEventListener('click', async () => {
|
|
|
5621
5829
|
}
|
|
5622
5830
|
});
|
|
5623
5831
|
/* Uygulama her açılışta agent (chat) modunda başlar — IDE modu yalnız
|
|
5624
|
-
kullanıcı butona basınca girilir (oturumluk). */
|
|
5832
|
+
kullanıcı butona basınca girilir (oturumluk). */
|