beast-agent 2.11.0 → 2.12.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 +24 -0
- package/src/agent/tools.js +15 -0
- package/src/main.js +461 -7
- package/src/preload.js +13 -0
- package/src/renderer/i18n.js +2 -0
- package/src/renderer/index.html +50 -3
- package/src/renderer/renderer.js +551 -9
- package/src/renderer/style.css +269 -0
package/src/renderer/renderer.js
CHANGED
|
@@ -84,6 +84,29 @@ const els = {
|
|
|
84
84
|
bcMic: $('#bcMic'),
|
|
85
85
|
bcChips: $('#bcChips'),
|
|
86
86
|
studioBtn: $('#studioBtn'),
|
|
87
|
+
sbBtn: $('#sbBtn'),
|
|
88
|
+
sandboxRow: $('#sandboxRow'),
|
|
89
|
+
sbRepo: $('#sbRepo'),
|
|
90
|
+
sbReveal: $('#sbReveal'),
|
|
91
|
+
sbRemove: $('#sbRemove'),
|
|
92
|
+
sbNew: $('#sbNew'),
|
|
93
|
+
sbCloneInput: $('#sbCloneInput'),
|
|
94
|
+
sbCloneBtn: $('#sbCloneBtn'),
|
|
95
|
+
sbGhBtn: $('#sbGhBtn'),
|
|
96
|
+
sbOut: $('#sbOut'),
|
|
97
|
+
sbStatus: $('#sbStatus'),
|
|
98
|
+
sbInput: $('#sbInput'),
|
|
99
|
+
sbStop: $('#sbStop'),
|
|
100
|
+
sbRunCwd: $('#sbRunCwd'),
|
|
101
|
+
sbRunInstall: $('#sbRunInstall'),
|
|
102
|
+
sbRunStart: $('#sbRunStart'),
|
|
103
|
+
sbRunDev: $('#sbRunDev'),
|
|
104
|
+
sbRunStop: $('#sbRunStop'),
|
|
105
|
+
sbRunCmd: $('#sbRunCmd'),
|
|
106
|
+
sbRunGo: $('#sbRunGo'),
|
|
107
|
+
sbRunOut: $('#sbRunOut'),
|
|
108
|
+
sbRunOpen: $('#sbRunOpen'),
|
|
109
|
+
sbRunUrl: $('#sbRunUrl'),
|
|
87
110
|
stPanel: $('#stPanel'),
|
|
88
111
|
stTitle: $('#stTitle'),
|
|
89
112
|
stCwd: $('#stCwd'),
|
|
@@ -4984,6 +5007,19 @@ function onEvent(ev) {
|
|
|
4984
5007
|
}
|
|
4985
5008
|
/* OFFLINE MESAJ KUYRUĞU: bağlantı + kuyruk olayları (sessionId filtresinden önce) */
|
|
4986
5009
|
if (ev.type === 'net' || ev.type === 'netQueue') { onNetEvent(ev); return; }
|
|
5010
|
+
/* Sandbox klonlama progress'i (sessionId'siz global olay) */
|
|
5011
|
+
if (ev.type === 'sb-clone') { sbCloneProgress(ev.pct, ev.text, !!ev.done); return; }
|
|
5012
|
+
/* Sandbox ÇALIŞTIRICI süreç akışı: sessionId'siz global olaylar */
|
|
5013
|
+
if (ev.type === 'sb-run' || ev.type === 'sb-run-url' || ev.type === 'sb-run-end') {
|
|
5014
|
+
sbRunIngest(ev);
|
|
5015
|
+
return;
|
|
5016
|
+
}
|
|
5017
|
+
/* Beast Sandbox oturumu: olaylar SADECE Sandbox paneline akar — ana sohbeti
|
|
5018
|
+
ve Code/Studio panellerini kirletmez (dünyalar ayrı) */
|
|
5019
|
+
if (sbSessionId && ev.sessionId === sbSessionId) {
|
|
5020
|
+
sbIngest(ev);
|
|
5021
|
+
return;
|
|
5022
|
+
}
|
|
4987
5023
|
/* Beast Studio oturumu: olaylar SADECE Studio paneline akar — ana sohbeti
|
|
4988
5024
|
ve Beast Code panelini kirletmez (dünyalar ayrı) */
|
|
4989
5025
|
if (stSessionId && ev.sessionId === stSessionId) {
|
|
@@ -6896,6 +6932,7 @@ function ghCard(repo, isFav) {
|
|
|
6896
6932
|
<div class="gh-actions">
|
|
6897
6933
|
<button class="gh-fav ${isFav ? 'on' : ''}" data-act="fav">${isFav ? '★ Favori' : '☆ Favorile'}</button>
|
|
6898
6934
|
<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>
|
|
6935
|
+
<button data-act="dl" title="Sandbox'a indir (git clone)">⬇ İndir</button>
|
|
6899
6936
|
<button data-act="copy">⧉ Kopyala</button>
|
|
6900
6937
|
</div>
|
|
6901
6938
|
</div>`;
|
|
@@ -6911,6 +6948,12 @@ function wireGhCards(container, list, isFavPane) {
|
|
|
6911
6948
|
/* mesaj chate gitti — cevap chatten geleceği için modal kapanır */
|
|
6912
6949
|
closeGit();
|
|
6913
6950
|
});
|
|
6951
|
+
/* Sandbox'a indir: klonlama Sandbox panelinde görünür, panel açılır */
|
|
6952
|
+
card.querySelector('[data-act="dl"]').addEventListener('click', async () => {
|
|
6953
|
+
closeGit();
|
|
6954
|
+
setSandboxMode(true);
|
|
6955
|
+
sbClone(repo.full_name);
|
|
6956
|
+
});
|
|
6914
6957
|
card.querySelector('[data-act="copy"]').addEventListener('click', async () => {
|
|
6915
6958
|
try { await navigator.clipboard.writeText(repo.html_url); toast('Link kopyalandı'); } catch {}
|
|
6916
6959
|
});
|
|
@@ -7068,6 +7111,7 @@ function ideModeOn() {
|
|
|
7068
7111
|
|
|
7069
7112
|
async function setIdeMode(on) {
|
|
7070
7113
|
if (on && studioModeOn()) await setStudioMode(false); /* Studio açıkken IDE'ye geçiş — Studio kapanır */
|
|
7114
|
+
if (on && sbModeOn()) setSandboxMode(false); /* Sandbox açıkken IDE'ye geçiş — Sandbox kapanır */
|
|
7071
7115
|
document.body.classList.toggle('ide-mode', !!on);
|
|
7072
7116
|
if (els.ideBtn) els.ideBtn.classList.toggle('on', !!on);
|
|
7073
7117
|
/* soldaki marka: chat modunda BEAST Agent, IDE modunda BEAST Code, Studio modunda BEAST Studio */
|
|
@@ -7137,6 +7181,7 @@ function studioModeOn() {
|
|
|
7137
7181
|
|
|
7138
7182
|
async function setStudioMode(on) {
|
|
7139
7183
|
if (on && ideModeOn()) await setIdeMode(false); /* IDE açıkken Studio'ya geçiş — IDE kapanır */
|
|
7184
|
+
if (on && sbModeOn()) setSandboxMode(false); /* Sandbox açıkken Studio'ya geçiş — Sandbox kapanır */
|
|
7140
7185
|
document.body.classList.toggle('studio-mode', !!on);
|
|
7141
7186
|
if (els.studioBtn) els.studioBtn.classList.toggle('on', !!on);
|
|
7142
7187
|
/* ALT TERMINAL: yalnız Beast Code'a özgü — Studio'ya geçişte kapanır */
|
|
@@ -7359,7 +7404,8 @@ if (els.ideSplit) {
|
|
|
7359
7404
|
}
|
|
7360
7405
|
|
|
7361
7406
|
async function loadIdeTree() {
|
|
7362
|
-
|
|
7407
|
+
/* hangi moddaysak o ağacın önbelleği tazelenir (Sandbox → repo ağacı) */
|
|
7408
|
+
(sbModeOn() ? sbTreeState : studioModeOn() ? studioState : ideState).cache.clear();
|
|
7363
7409
|
await renderFileTree();
|
|
7364
7410
|
}
|
|
7365
7411
|
|
|
@@ -7375,17 +7421,26 @@ async function renderFileTree() {
|
|
|
7375
7421
|
if (!tree) return;
|
|
7376
7422
|
tree.innerHTML = '';
|
|
7377
7423
|
const wsLabel = $('#filePanelPath');
|
|
7378
|
-
/* Studio modunda ağaç studioRoot'tan,
|
|
7379
|
-
|
|
7424
|
+
/* Studio modunda ağaç studioRoot'tan, Sandbox modunda seçili reponun
|
|
7425
|
+
klasöründen, IDE modunda ideRoot'tan okunur — aynı panel, aynı çizim */
|
|
7426
|
+
const sbx = sbModeOn();
|
|
7380
7427
|
const studio = studioModeOn();
|
|
7381
|
-
const st = studio ? studioState : ideState;
|
|
7382
|
-
const treeApi =
|
|
7428
|
+
const st = sbx ? sbTreeState : studio ? studioState : ideState;
|
|
7429
|
+
const treeApi = sbx
|
|
7430
|
+
? (rel) => beast.sandboxTree({ folder: sbFolder, rel })
|
|
7431
|
+
: studio
|
|
7432
|
+
? beast.studioTree
|
|
7433
|
+
: beast.ideTree;
|
|
7383
7434
|
const build = async (rel, depth, container) => {
|
|
7384
7435
|
let entries = st.cache.get(rel);
|
|
7385
7436
|
if (!entries) {
|
|
7386
7437
|
const r = await treeApi(rel).catch(() => null);
|
|
7387
7438
|
if (!r || !r.ok) {
|
|
7388
|
-
if (!rel)
|
|
7439
|
+
if (!rel) {
|
|
7440
|
+
container.innerHTML = sbx
|
|
7441
|
+
? '<div class="file-empty">Repo seçili değil — yukarıdan indir ya da seç</div>'
|
|
7442
|
+
: `<div class="file-empty">${escapeHtml((r && r.error) || 'okunamadı')}</div>`;
|
|
7443
|
+
}
|
|
7389
7444
|
return;
|
|
7390
7445
|
}
|
|
7391
7446
|
entries = r.entries;
|
|
@@ -7393,7 +7448,9 @@ async function renderFileTree() {
|
|
|
7393
7448
|
if (r.workspace) {
|
|
7394
7449
|
st.path = r.workspace;
|
|
7395
7450
|
if (wsLabel) { wsLabel.textContent = r.workspace; wsLabel.title = r.workspace; }
|
|
7396
|
-
if (
|
|
7451
|
+
if (sbx) {
|
|
7452
|
+
if (els.sbRunCwd) { els.sbRunCwd.textContent = r.workspace; els.sbRunCwd.title = r.workspace; }
|
|
7453
|
+
} else if (studio) {
|
|
7397
7454
|
if (els.stCwd) { els.stCwd.textContent = r.workspace; els.stCwd.title = r.workspace; }
|
|
7398
7455
|
stOnFolderChanged(r.workspace);
|
|
7399
7456
|
} else {
|
|
@@ -7418,6 +7475,13 @@ async function renderFileTree() {
|
|
|
7418
7475
|
if (st.open.has(child)) st.open.delete(child);
|
|
7419
7476
|
else st.open.add(child);
|
|
7420
7477
|
renderFileTree();
|
|
7478
|
+
} else if (sbx) {
|
|
7479
|
+
/* Sandbox: dosyayı chat'e bağlam olarak bırak — ajan incelesin */
|
|
7480
|
+
if (els.sbInput) {
|
|
7481
|
+
els.sbInput.value = 'Şu dosyayı incele: ' + child;
|
|
7482
|
+
els.sbInput.focus();
|
|
7483
|
+
sbInputResize();
|
|
7484
|
+
}
|
|
7421
7485
|
} else if (studio && MEDIA_FILE_RE.test(e.name)) {
|
|
7422
7486
|
stVideoPlay(child); /* video/ses → sağdaki video bölümünde oynat */
|
|
7423
7487
|
} else if (studio) {
|
|
@@ -7449,7 +7513,8 @@ function ideRefreshTree() {
|
|
|
7449
7513
|
ideTreeTimer = null;
|
|
7450
7514
|
try {
|
|
7451
7515
|
/* hangi moddaysak o ağacın önbelleği tazelenir */
|
|
7452
|
-
if (
|
|
7516
|
+
if (sbModeOn()) sbTreeState.cache.clear();
|
|
7517
|
+
else if (studioModeOn()) studioState.cache.clear();
|
|
7453
7518
|
else ideState.cache.clear();
|
|
7454
7519
|
renderFileTree().catch(() => {});
|
|
7455
7520
|
} catch {}
|
|
@@ -8028,8 +8093,9 @@ function fileCtxShow(e, rel, isDir) {
|
|
|
8028
8093
|
const menu = els.fileCtxMenu;
|
|
8029
8094
|
if (!menu || !rel) return;
|
|
8030
8095
|
e.preventDefault();
|
|
8096
|
+
const sbx = sbModeOn();
|
|
8031
8097
|
const studio = studioModeOn();
|
|
8032
|
-
const st = studio ? studioState : ideState;
|
|
8098
|
+
const st = sbx ? sbTreeState : studio ? studioState : ideState;
|
|
8033
8099
|
const isMedia = MEDIA_FILE_RE.test(rel.split('/').pop() || '');
|
|
8034
8100
|
const items = [];
|
|
8035
8101
|
if (isDir) {
|
|
@@ -8041,6 +8107,22 @@ function fileCtxShow(e, rel, isDir) {
|
|
|
8041
8107
|
renderFileTree();
|
|
8042
8108
|
},
|
|
8043
8109
|
});
|
|
8110
|
+
} else if (sbx) {
|
|
8111
|
+
/* Sandbox: dosya düzenleme Code moduna aittir — chate bağlam bırak/aç */
|
|
8112
|
+
items.push({
|
|
8113
|
+
label: 'Chate ekle (şu dosyaya bak)',
|
|
8114
|
+
fn: () => {
|
|
8115
|
+
if (els.sbInput) {
|
|
8116
|
+
els.sbInput.value = 'Şu dosyayı incele: ' + rel;
|
|
8117
|
+
els.sbInput.focus();
|
|
8118
|
+
sbInputResize();
|
|
8119
|
+
}
|
|
8120
|
+
},
|
|
8121
|
+
});
|
|
8122
|
+
items.push({
|
|
8123
|
+
label: 'Dış uygulamada aç',
|
|
8124
|
+
fn: () => beast.openPath((sbTreeState.path || '') + '\\' + rel.replace(/\//g, '\\')).catch(() => {}),
|
|
8125
|
+
});
|
|
8044
8126
|
} else if (studio && isMedia) {
|
|
8045
8127
|
items.push({ label: 'Oynat', fn: () => stVideoPlay(rel) });
|
|
8046
8128
|
} else if (studio) {
|
|
@@ -9247,3 +9329,463 @@ if (els.stNew) els.stNew.addEventListener('click', async () => {
|
|
|
9247
9329
|
});
|
|
9248
9330
|
/* Uygulama her açılışta agent (chat) modunda başlar — IDE modu yalnız
|
|
9249
9331
|
kullanıcı butona basınca girilir (oturumluk). */
|
|
9332
|
+
|
|
9333
|
+
/* ================= BEAST SANDBOX =================
|
|
9334
|
+
GitHub reposu indir (git clone) + repo klasöründe ajanla çalış.
|
|
9335
|
+
Sağ dock — ana chat solda yerinde kalır; Code/Studio'dan tamamen ayrı. */
|
|
9336
|
+
|
|
9337
|
+
let sbSessionId = '';
|
|
9338
|
+
let sbFolder = '';
|
|
9339
|
+
let sbBusy = false;
|
|
9340
|
+
let sbItems = [];
|
|
9341
|
+
let sbStreamEl = null;
|
|
9342
|
+
let sbStreamRaw = '';
|
|
9343
|
+
let sbCloning = false;
|
|
9344
|
+
/* sol dosya konsolu (repo ağacı) + sağ çalıştırıcı durumu */
|
|
9345
|
+
const sbTreeState = { cache: new Map(), open: new Set(['']), path: '' };
|
|
9346
|
+
let sbRunUrl = '';
|
|
9347
|
+
let sbRunRunning = false;
|
|
9348
|
+
|
|
9349
|
+
function sbModeOn() {
|
|
9350
|
+
return document.body.classList.contains('sandbox-mode');
|
|
9351
|
+
}
|
|
9352
|
+
|
|
9353
|
+
function sbLine(cls, text) {
|
|
9354
|
+
if (!els.sbOut) return null;
|
|
9355
|
+
const div = document.createElement('div');
|
|
9356
|
+
div.className = cls || 't-out';
|
|
9357
|
+
div.textContent = String(text || '');
|
|
9358
|
+
els.sbOut.appendChild(div);
|
|
9359
|
+
els.sbOut.scrollTop = els.sbOut.scrollHeight;
|
|
9360
|
+
return div;
|
|
9361
|
+
}
|
|
9362
|
+
|
|
9363
|
+
function sbStreamDelta(delta) {
|
|
9364
|
+
if (!els.sbOut) return;
|
|
9365
|
+
if (!sbStreamEl) {
|
|
9366
|
+
sbStreamEl = sbLine('t-out', '');
|
|
9367
|
+
}
|
|
9368
|
+
sbStreamRaw += String(delta || '');
|
|
9369
|
+
sbStreamEl.textContent = sbStreamRaw;
|
|
9370
|
+
els.sbOut.scrollTop = els.sbOut.scrollHeight;
|
|
9371
|
+
}
|
|
9372
|
+
|
|
9373
|
+
function sbFlushStream() {
|
|
9374
|
+
sbStreamEl = null;
|
|
9375
|
+
sbStreamRaw = '';
|
|
9376
|
+
}
|
|
9377
|
+
|
|
9378
|
+
function sbMsgText(content) {
|
|
9379
|
+
const t = Array.isArray(content)
|
|
9380
|
+
? content.filter((p) => p && p.type === 'text').map((p) => String(p.text || '')).join('\n')
|
|
9381
|
+
: String(content || '');
|
|
9382
|
+
return t.replace(/\s+/g, ' ').trim();
|
|
9383
|
+
}
|
|
9384
|
+
|
|
9385
|
+
function sbArgsSummary(args) {
|
|
9386
|
+
try {
|
|
9387
|
+
const j = typeof args === 'string' ? JSON.parse(args) : args || {};
|
|
9388
|
+
return String(j.command || j.path || j.url || j.query || j.pattern || '').replace(/\s+/g, ' ').slice(0, 90);
|
|
9389
|
+
} catch {
|
|
9390
|
+
return '';
|
|
9391
|
+
}
|
|
9392
|
+
}
|
|
9393
|
+
|
|
9394
|
+
function sbSetBusy(b) {
|
|
9395
|
+
sbBusy = !!b;
|
|
9396
|
+
if (els.sbStop) els.sbStop.hidden = !sbBusy;
|
|
9397
|
+
}
|
|
9398
|
+
|
|
9399
|
+
function sbStatusShow(text) {
|
|
9400
|
+
if (els.sbStatus) {
|
|
9401
|
+
els.sbStatus.hidden = false;
|
|
9402
|
+
els.sbStatus.textContent = text;
|
|
9403
|
+
}
|
|
9404
|
+
}
|
|
9405
|
+
function sbStatusHide() {
|
|
9406
|
+
if (els.sbStatus) els.sbStatus.hidden = true;
|
|
9407
|
+
}
|
|
9408
|
+
|
|
9409
|
+
/* Sandbox oturumunun engine olayları → panel (bcIngest'in minimal karşılığı) */
|
|
9410
|
+
function sbIngest(ev) {
|
|
9411
|
+
if (!sbSessionId || ev.sessionId !== sbSessionId) return;
|
|
9412
|
+
switch (ev.type) {
|
|
9413
|
+
case 'token':
|
|
9414
|
+
sbStreamDelta(ev.delta);
|
|
9415
|
+
break;
|
|
9416
|
+
case 'message': {
|
|
9417
|
+
const m = ev.message;
|
|
9418
|
+
if (!m) break;
|
|
9419
|
+
/* KULLANICI ECHO BASILMAZ — gönderirken zaten 'sen>' satırı düştü
|
|
9420
|
+
(Beast Code paneliyle aynı disiplin; yoksa mesaj ÇİFT görünür) */
|
|
9421
|
+
if (m.role === 'assistant') {
|
|
9422
|
+
sbFlushStream();
|
|
9423
|
+
const hasTools = Array.isArray(m.tool_calls) && m.tool_calls.length > 0;
|
|
9424
|
+
const txt = typeof m.content === 'string' ? m.content.trim() : '';
|
|
9425
|
+
if (txt && !hasTools) sbLine('t-out', txt);
|
|
9426
|
+
}
|
|
9427
|
+
break;
|
|
9428
|
+
}
|
|
9429
|
+
case 'tool-start':
|
|
9430
|
+
sbSetBusy(true);
|
|
9431
|
+
sbLine('t-dim', '\u2692 ' + (ev.name || '?') + (sbArgsSummary(ev.args) ? ' \u00B7 ' + sbArgsSummary(ev.args) : ''));
|
|
9432
|
+
break;
|
|
9433
|
+
case 'tool-end': {
|
|
9434
|
+
const ok = ev.ok !== false;
|
|
9435
|
+
sbLine(ok ? 't-dim' : 't-err', (ok ? ' \u2713 ' : ' \u2717 ') + String(ev.result || '').replace(/\s+/g, ' ').slice(0, 160));
|
|
9436
|
+
/* ajan dosya yazarsa/editlerse soldaki repo ağacı canlı tazelenir */
|
|
9437
|
+
if (ev.name === 'write_file' || ev.name === 'edit_file' || ev.name === 'run_command') ideRefreshTree();
|
|
9438
|
+
break;
|
|
9439
|
+
}
|
|
9440
|
+
case 'status':
|
|
9441
|
+
if (ev.status === 'idle') {
|
|
9442
|
+
sbSetBusy(false);
|
|
9443
|
+
sbStatusHide();
|
|
9444
|
+
} else {
|
|
9445
|
+
sbSetBusy(true);
|
|
9446
|
+
sbStatusShow(ev.status === 'thinking' ? 'düşünüyor…' : String(ev.status || ''));
|
|
9447
|
+
}
|
|
9448
|
+
break;
|
|
9449
|
+
case 'done':
|
|
9450
|
+
sbFlushStream();
|
|
9451
|
+
sbSetBusy(false);
|
|
9452
|
+
sbStatusHide();
|
|
9453
|
+
sbLine('t-dim', ev.aborted ? '[durduruldu' + (ev.reason ? ' — ' + ev.reason : '') + ']' : '(tamamlandı)');
|
|
9454
|
+
break;
|
|
9455
|
+
case 'error':
|
|
9456
|
+
sbFlushStream();
|
|
9457
|
+
sbSetBusy(false);
|
|
9458
|
+
sbStatusHide();
|
|
9459
|
+
sbLine('t-err', '[hata] ' + (ev.error || ''));
|
|
9460
|
+
break;
|
|
9461
|
+
}
|
|
9462
|
+
}
|
|
9463
|
+
|
|
9464
|
+
async function loadSandboxList() {
|
|
9465
|
+
const r = await beast.sandboxList().catch(() => ({ ok: false }));
|
|
9466
|
+
sbItems = (r && r.items) || [];
|
|
9467
|
+
const sel = els.sbRepo;
|
|
9468
|
+
if (!sel) return;
|
|
9469
|
+
sel.innerHTML = '';
|
|
9470
|
+
if (!sbItems.length) {
|
|
9471
|
+
const o = document.createElement('option');
|
|
9472
|
+
o.value = '';
|
|
9473
|
+
o.textContent = 'Repo yok, indir';
|
|
9474
|
+
sel.appendChild(o);
|
|
9475
|
+
}
|
|
9476
|
+
for (const it of sbItems) {
|
|
9477
|
+
const o = document.createElement('option');
|
|
9478
|
+
o.value = it.folder;
|
|
9479
|
+
o.textContent = it.name + (it.busy ? ' ●' : '');
|
|
9480
|
+
sel.appendChild(o);
|
|
9481
|
+
}
|
|
9482
|
+
if (sbFolder && sbItems.some((x) => x.folder === sbFolder)) sel.value = sbFolder;
|
|
9483
|
+
else if (sbItems.length) {
|
|
9484
|
+
sel.value = sbItems[0].folder;
|
|
9485
|
+
sbFolder = sel.value;
|
|
9486
|
+
} else {
|
|
9487
|
+
sbFolder = '';
|
|
9488
|
+
}
|
|
9489
|
+
await sbSelectCurrent();
|
|
9490
|
+
}
|
|
9491
|
+
|
|
9492
|
+
async function sbSelectCurrent() {
|
|
9493
|
+
sbFolder = els.sbRepo ? String(els.sbRepo.value || '') : '';
|
|
9494
|
+
if (els.sbOut) els.sbOut.innerHTML = '';
|
|
9495
|
+
sbSessionId = '';
|
|
9496
|
+
sbStreamEl = null;
|
|
9497
|
+
sbStreamRaw = '';
|
|
9498
|
+
sbSetBusy(false);
|
|
9499
|
+
sbStatusHide();
|
|
9500
|
+
/* çalıştırıcı + ağaç yeni repoya döner */
|
|
9501
|
+
sbRunUrl = '';
|
|
9502
|
+
sbRunRunning = false;
|
|
9503
|
+
if (els.sbRunOpen) els.sbRunOpen.disabled = true;
|
|
9504
|
+
if (els.sbRunUrl) els.sbRunUrl.textContent = '';
|
|
9505
|
+
if (els.sbRunOut) els.sbRunOut.innerHTML = '';
|
|
9506
|
+
sbTreeState.cache.clear();
|
|
9507
|
+
sbTreeState.open = new Set(['']);
|
|
9508
|
+
if (sbModeOn()) renderFileTree().catch(() => {});
|
|
9509
|
+
if (!sbFolder) {
|
|
9510
|
+
sbLine('t-dim', 'Repo indir: kutuya github.com/owner/repo yaz → İndir. Ya da 🔍 ile GitHub\u2019da ara.');
|
|
9511
|
+
return;
|
|
9512
|
+
}
|
|
9513
|
+
const r = await beast.sandboxOpen({ folder: sbFolder }).catch(() => null);
|
|
9514
|
+
if (r && r.ok) {
|
|
9515
|
+
sbSessionId = r.sessionId;
|
|
9516
|
+
for (const m of r.messages || []) {
|
|
9517
|
+
sbLine(m.role === 'assistant' ? 't-out' : 't-cmd', (m.role === 'assistant' ? '' : 'sen> ') + m.text);
|
|
9518
|
+
}
|
|
9519
|
+
sbLine('t-dim', 'Oturum yüklendi');
|
|
9520
|
+
} else {
|
|
9521
|
+
sbLine('t-err', (r && r.error) || 'oturum açılamadı');
|
|
9522
|
+
}
|
|
9523
|
+
sbSetBusy(!!(r && r.busy));
|
|
9524
|
+
/* sol konsol: seçilen reponun klasörü — oturum açıldıktan sonra da garanti tazele */
|
|
9525
|
+
sbTreeState.cache.clear();
|
|
9526
|
+
if (sbModeOn()) renderFileTree().catch(() => {});
|
|
9527
|
+
}
|
|
9528
|
+
|
|
9529
|
+
function sbInputResize() {
|
|
9530
|
+
const ta = els.sbInput;
|
|
9531
|
+
if (!ta) return;
|
|
9532
|
+
ta.style.height = 'auto';
|
|
9533
|
+
ta.style.height = Math.min(ta.scrollHeight, 140) + 'px';
|
|
9534
|
+
ta.classList.toggle('expand', ta.scrollHeight > 140);
|
|
9535
|
+
}
|
|
9536
|
+
|
|
9537
|
+
function sbRunCurrent() {
|
|
9538
|
+
const msg = els.sbInput.value.trim();
|
|
9539
|
+
if (!msg || !sbFolder || sbCloning) return;
|
|
9540
|
+
els.sbInput.value = '';
|
|
9541
|
+
sbInputResize();
|
|
9542
|
+
sbLine('t-cmd', 'sen> ' + msg);
|
|
9543
|
+
sbSetBusy(true);
|
|
9544
|
+
beast.sandboxSend({ folder: sbFolder, msg }).then((r) => {
|
|
9545
|
+
if (r && r.ok) {
|
|
9546
|
+
if (r.sessionId) sbSessionId = r.sessionId;
|
|
9547
|
+
if (r.queued) sbLine('t-dim', '⏳ kuyrukta (' + r.count + ') — iş bitince gönderilir');
|
|
9548
|
+
} else {
|
|
9549
|
+
sbSetBusy(false);
|
|
9550
|
+
sbLine('t-err', (r && r.error) || 'gönderilemedi');
|
|
9551
|
+
}
|
|
9552
|
+
}).catch((e) => {
|
|
9553
|
+
sbSetBusy(false);
|
|
9554
|
+
sbLine('t-err', String((e && e.message) || e));
|
|
9555
|
+
});
|
|
9556
|
+
}
|
|
9557
|
+
|
|
9558
|
+
let sbCloneLine = null;
|
|
9559
|
+
function sbCloneProgress(pct, text, done) {
|
|
9560
|
+
/* buton etiketi: %34 · İndir */
|
|
9561
|
+
const label = document.getElementById('sbCloneLabel');
|
|
9562
|
+
if (label) label.textContent = pct != null ? '%' + pct : 'İndir';
|
|
9563
|
+
if (!els.sbOut) return;
|
|
9564
|
+
if (done) {
|
|
9565
|
+
if (sbCloneLine && sbCloneLine.isConnected) sbCloneLine.remove();
|
|
9566
|
+
sbCloneLine = null;
|
|
9567
|
+
return;
|
|
9568
|
+
}
|
|
9569
|
+
if (!sbCloneLine || !sbCloneLine.isConnected) {
|
|
9570
|
+
sbCloneLine = sbLine('t-dim', '');
|
|
9571
|
+
}
|
|
9572
|
+
if (sbCloneLine) {
|
|
9573
|
+
sbCloneLine.textContent = (pct != null ? '⬇ %' + pct : '⬇ klonlanıyor') + (text ? ' · ' + text : '');
|
|
9574
|
+
els.sbOut.scrollTop = els.sbOut.scrollHeight;
|
|
9575
|
+
}
|
|
9576
|
+
}
|
|
9577
|
+
|
|
9578
|
+
async function sbClone(input) {
|
|
9579
|
+
if (sbCloning) return;
|
|
9580
|
+
const src = String(input || '').trim();
|
|
9581
|
+
if (!src) {
|
|
9582
|
+
toast('Repo adresi gir: github.com/owner/repo');
|
|
9583
|
+
return;
|
|
9584
|
+
}
|
|
9585
|
+
sbCloning = true;
|
|
9586
|
+
if (els.sbCloneBtn) els.sbCloneBtn.disabled = true;
|
|
9587
|
+
sbCloneLine = null;
|
|
9588
|
+
sbLine('t-dim', '⬇ klonlanıyor: ' + src + ' — (büyük repolar sürebilir…)');
|
|
9589
|
+
const r = await beast.sandboxClone(src).catch((e) => ({ ok: false, error: String((e && e.message) || e) }));
|
|
9590
|
+
sbCloning = false;
|
|
9591
|
+
if (els.sbCloneBtn) els.sbCloneBtn.disabled = false;
|
|
9592
|
+
sbCloneProgress(null, '', true); /* progress satırını temizle + etiketi geri koy */
|
|
9593
|
+
if (r && r.ok) {
|
|
9594
|
+
sbLine('t-dim', '✓ indirildi: ' + r.name);
|
|
9595
|
+
if (els.sbCloneInput) els.sbCloneInput.value = '';
|
|
9596
|
+
sbFolder = r.folder;
|
|
9597
|
+
await loadSandboxList();
|
|
9598
|
+
if (els.sbInput) els.sbInput.focus();
|
|
9599
|
+
} else {
|
|
9600
|
+
sbLine('t-err', '[klonlama] ' + ((r && r.error) || 'başarısız'));
|
|
9601
|
+
}
|
|
9602
|
+
}
|
|
9603
|
+
|
|
9604
|
+
function setSandboxMode(on) {
|
|
9605
|
+
if (on && ideModeOn()) { setIdeMode(false); }
|
|
9606
|
+
if (on && studioModeOn()) { setStudioMode(false); }
|
|
9607
|
+
document.body.classList.toggle('sandbox-mode', !!on);
|
|
9608
|
+
if (els.sbBtn) els.sbBtn.classList.toggle('on', !!on);
|
|
9609
|
+
/* marka + sol konsol başlığı: moduna göre BEAST Agent/Code/Studio/Sandbox */
|
|
9610
|
+
const brandSub = document.querySelector('#brand .brand-sub');
|
|
9611
|
+
if (brandSub) brandSub.textContent = on ? 'Sandbox' : 'Agent';
|
|
9612
|
+
const ftp = document.getElementById('filePanelTitle');
|
|
9613
|
+
if (ftp && on) ftp.textContent = 'REPO DOSYALARI';
|
|
9614
|
+
if (on) {
|
|
9615
|
+
loadSandboxList();
|
|
9616
|
+
sbTreeState.cache.clear();
|
|
9617
|
+
renderFileTree().catch(() => {});
|
|
9618
|
+
} else if (!ideModeOn() && !studioModeOn()) {
|
|
9619
|
+
/* agent moduna dönüş: ağaç eski köküne döner */
|
|
9620
|
+
ideState.cache.clear();
|
|
9621
|
+
renderFileTree().catch(() => {});
|
|
9622
|
+
}
|
|
9623
|
+
}
|
|
9624
|
+
|
|
9625
|
+
/* ---------- ÇALIŞTIRICI: butonlar KOMUT DEĞİL AJANA TALİMATTIR ----------
|
|
9626
|
+
Her proje farklı çalışır; komutu kullanıcı bilemez, AJAN bilir:
|
|
9627
|
+
paket bildirim dosyasına + README'ye bakıp doğru komutu bulur, uzun süreli
|
|
9628
|
+
süreci panel_run aracıyla ÇALIŞTIR panelinde (turu kilitlemeden) başlatır. */
|
|
9629
|
+
function sbInstruct(text) {
|
|
9630
|
+
if (!sbFolder) { toast('Önce repo indir ya da seç'); return; }
|
|
9631
|
+
sbLine('t-cmd', 'sen> ' + text);
|
|
9632
|
+
sbSetBusy(true);
|
|
9633
|
+
beast.sandboxSend({ folder: sbFolder, msg: text }).then((r) => {
|
|
9634
|
+
if (r && r.ok) {
|
|
9635
|
+
if (r.sessionId) sbSessionId = r.sessionId;
|
|
9636
|
+
if (r.queued) sbLine('t-dim', '⏳ kuyrukta (' + r.count + ') — iş bitince gönderilir');
|
|
9637
|
+
} else {
|
|
9638
|
+
sbSetBusy(false);
|
|
9639
|
+
sbLine('t-err', (r && r.error) || 'gönderilemedi');
|
|
9640
|
+
}
|
|
9641
|
+
}).catch((e) => {
|
|
9642
|
+
sbSetBusy(false);
|
|
9643
|
+
sbLine('t-err', String((e && e.message) || e));
|
|
9644
|
+
});
|
|
9645
|
+
}
|
|
9646
|
+
|
|
9647
|
+
function sbRunLine(text, cls) {
|
|
9648
|
+
if (!els.sbRunOut) return null;
|
|
9649
|
+
const div = document.createElement('div');
|
|
9650
|
+
div.className = cls || 't-out';
|
|
9651
|
+
div.textContent = String(text || '');
|
|
9652
|
+
els.sbRunOut.appendChild(div);
|
|
9653
|
+
els.sbRunOut.scrollTop = els.sbRunOut.scrollHeight;
|
|
9654
|
+
return div;
|
|
9655
|
+
}
|
|
9656
|
+
|
|
9657
|
+
/* süreç çıktısı akışı: sessionId'siz global olaylar — en üstte yönlendirilir */
|
|
9658
|
+
function sbRunIngest(ev) {
|
|
9659
|
+
if (ev.type === 'sb-run') {
|
|
9660
|
+
sbRunLine(ev.data);
|
|
9661
|
+
return;
|
|
9662
|
+
}
|
|
9663
|
+
if (ev.type === 'sb-run-url') {
|
|
9664
|
+
sbRunUrl = String(ev.url || '');
|
|
9665
|
+
sbRunLine('🌐 dev server: ' + sbRunUrl, 't-dim');
|
|
9666
|
+
if (els.sbRunOpen) els.sbRunOpen.disabled = !sbRunUrl;
|
|
9667
|
+
if (els.sbRunUrl) els.sbRunUrl.textContent = sbRunUrl;
|
|
9668
|
+
return;
|
|
9669
|
+
}
|
|
9670
|
+
if (ev.type === 'sb-run-end') {
|
|
9671
|
+
sbRunRunning = false;
|
|
9672
|
+
if (els.sbRunStop) els.sbRunStop.hidden = true;
|
|
9673
|
+
}
|
|
9674
|
+
}
|
|
9675
|
+
|
|
9676
|
+
function sbRunExec(cmd) {
|
|
9677
|
+
if (!sbFolder) { toast('Önce repo indir ya da seç'); return; }
|
|
9678
|
+
if (sbRunRunning) { toast('Zaten çalışıyor — önce ■ ile durdur'); return; }
|
|
9679
|
+
sbRunRunning = true;
|
|
9680
|
+
if (els.sbRunStop) els.sbRunStop.hidden = false;
|
|
9681
|
+
beast.sandboxRun({ folder: sbFolder, cmd }).then((r) => {
|
|
9682
|
+
if (!r || !r.ok) {
|
|
9683
|
+
sbRunRunning = false;
|
|
9684
|
+
if (els.sbRunStop) els.sbRunStop.hidden = true;
|
|
9685
|
+
sbRunLine('[hata] ' + ((r && r.error) || 'çalıştırılamadı'), 't-err');
|
|
9686
|
+
}
|
|
9687
|
+
}).catch((e) => {
|
|
9688
|
+
sbRunRunning = false;
|
|
9689
|
+
if (els.sbRunStop) els.sbRunStop.hidden = true;
|
|
9690
|
+
sbRunLine('[hata] ' + String((e && e.message) || e), 't-err');
|
|
9691
|
+
});
|
|
9692
|
+
}
|
|
9693
|
+
|
|
9694
|
+
/* topbar + dock olay bağlama */
|
|
9695
|
+
if (els.sbBtn) els.sbBtn.addEventListener('click', () => setSandboxMode(!sbModeOn()));
|
|
9696
|
+
if (els.sbRepo) els.sbRepo.addEventListener('change', sbSelectCurrent);
|
|
9697
|
+
if (els.sbCloneBtn) els.sbCloneBtn.addEventListener('click', () => sbClone(els.sbCloneInput.value));
|
|
9698
|
+
if (els.sbCloneInput) {
|
|
9699
|
+
els.sbCloneInput.addEventListener('keydown', (e) => {
|
|
9700
|
+
if (e.key === 'Enter') {
|
|
9701
|
+
e.preventDefault();
|
|
9702
|
+
sbClone(els.sbCloneInput.value);
|
|
9703
|
+
}
|
|
9704
|
+
});
|
|
9705
|
+
}
|
|
9706
|
+
if (els.sbGhBtn) els.sbGhBtn.addEventListener('click', () => openGit());
|
|
9707
|
+
if (els.sbNew) els.sbNew.addEventListener('click', async () => {
|
|
9708
|
+
if (sbBusy) { toast('Mesaj sürüyor — önce ■ ile durdur'); return; }
|
|
9709
|
+
if (!sbFolder) return;
|
|
9710
|
+
const r = await beast.sandboxNew({ folder: sbFolder }).catch(() => null);
|
|
9711
|
+
if (r && r.ok) {
|
|
9712
|
+
sbSessionId = '';
|
|
9713
|
+
await sbSelectCurrent();
|
|
9714
|
+
sbLine('t-sys', 'yeni oturum — taze başlar');
|
|
9715
|
+
}
|
|
9716
|
+
});
|
|
9717
|
+
if (els.sbRemove) els.sbRemove.addEventListener('click', async () => {
|
|
9718
|
+
if (!sbFolder) { toast('Önce repo seç'); return; }
|
|
9719
|
+
const name = (sbItems.find((x) => x.folder === sbFolder) || {}).name || 'repo';
|
|
9720
|
+
const ok = await uiConfirm('"' + name + '" reposunu diskten silmek istiyor musun? (klasör + sohbet)', 'Sil');
|
|
9721
|
+
if (!ok) return;
|
|
9722
|
+
const r = await beast.sandboxRemove({ folder: sbFolder }).catch(() => null);
|
|
9723
|
+
if (r && r.ok) {
|
|
9724
|
+
sbFolder = '';
|
|
9725
|
+
sbSessionId = '';
|
|
9726
|
+
await loadSandboxList();
|
|
9727
|
+
} else {
|
|
9728
|
+
toast((r && r.error) || 'silinemedi');
|
|
9729
|
+
}
|
|
9730
|
+
});
|
|
9731
|
+
if (els.sbReveal) els.sbReveal.addEventListener('click', () => {
|
|
9732
|
+
if (sbFolder) beast.sandboxReveal({ folder: sbFolder }).catch(() => {});
|
|
9733
|
+
});
|
|
9734
|
+
if (els.sbInput) {
|
|
9735
|
+
els.sbInput.addEventListener('input', sbInputResize);
|
|
9736
|
+
els.sbInput.addEventListener('keydown', (e) => {
|
|
9737
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
9738
|
+
e.preventDefault();
|
|
9739
|
+
sbRunCurrent();
|
|
9740
|
+
}
|
|
9741
|
+
});
|
|
9742
|
+
}
|
|
9743
|
+
if (els.sbStop) {
|
|
9744
|
+
els.sbStop.addEventListener('click', () => {
|
|
9745
|
+
beast.sandboxStop({ folder: sbFolder }).then((r) => {
|
|
9746
|
+
if (r && r.ok && r.wasBusy === false) {
|
|
9747
|
+
sbSetBusy(false);
|
|
9748
|
+
sbStatusHide();
|
|
9749
|
+
}
|
|
9750
|
+
}).catch(() => {});
|
|
9751
|
+
});
|
|
9752
|
+
}
|
|
9753
|
+
/* ÇALIŞTIRICI butonları — KOMUT DEĞİL AJANA TALİMAT (komutu ajan bulur):
|
|
9754
|
+
uzun süreli süreci panel_run ile ÇALIŞTIR paneline bırakır, tur kilitlenmez */
|
|
9755
|
+
if (els.sbRunInstall) els.sbRunInstall.addEventListener('click', () =>
|
|
9756
|
+
sbInstruct('Bu projeyi KUR — paket bildirim dosyasına (package.json, requirements.txt, Cargo.toml, go.mod, pom.xml vb.) göre doğru kurulum komutunu bul ve çalıştır (run_command); sonucu 1-2 satırla raporla.')
|
|
9757
|
+
);
|
|
9758
|
+
if (els.sbRunStart) els.sbRunStart.addEventListener('click', () =>
|
|
9759
|
+
sbInstruct('Bu projeyi ÇALIŞTIR — README/package.json scripts\u2019e göre doğru başlatma komutunu bul; uzun süreli sunucu/süreçse panel_run ile ÇALIŞTIR panelinde başlat (tur kilitleme), adresini/çalıştığını kullanıcıya bildir.')
|
|
9760
|
+
);
|
|
9761
|
+
if (els.sbRunDev) els.sbRunDev.addEventListener('click', () =>
|
|
9762
|
+
sbInstruct('Bu projeyi GELİŞTİRME modunda başlat — package.json scripts\u2019e bak (npm run dev, vite, expo start, ng serve vb. hangisi varsa) ve panel_run ile ÇALIŞTIR panelinde başlat; adresini kullanıcıya bildir.')
|
|
9763
|
+
);
|
|
9764
|
+
if (els.sbRunGo) els.sbRunGo.addEventListener('click', () => {
|
|
9765
|
+
const c = els.sbRunCmd.value.trim();
|
|
9766
|
+
if (!c) { toast('Komut yaz'); return; }
|
|
9767
|
+
sbRunExec(c);
|
|
9768
|
+
});
|
|
9769
|
+
if (els.sbRunCmd) {
|
|
9770
|
+
els.sbRunCmd.addEventListener('keydown', (e) => {
|
|
9771
|
+
if (e.key === 'Enter') {
|
|
9772
|
+
e.preventDefault();
|
|
9773
|
+
const c = els.sbRunCmd.value.trim();
|
|
9774
|
+
if (c) sbRunExec(c);
|
|
9775
|
+
}
|
|
9776
|
+
});
|
|
9777
|
+
}
|
|
9778
|
+
if (els.sbRunStop) {
|
|
9779
|
+
els.sbRunStop.addEventListener('click', () => {
|
|
9780
|
+
beast.sandboxRunStop().then((r) => {
|
|
9781
|
+
if (r && r.ok) sbRunLine('⏹ durduruldu', 't-dim');
|
|
9782
|
+
}).catch(() => {});
|
|
9783
|
+
});
|
|
9784
|
+
}
|
|
9785
|
+
if (els.sbRunOpen) {
|
|
9786
|
+
els.sbRunOpen.addEventListener('click', () => {
|
|
9787
|
+
/* Tarayıcıda aç da AJANA TALİMAT: ajan çalışma adresini bulup kendi
|
|
9788
|
+
browser_open aracıyla dahili tarayıcıda açar */
|
|
9789
|
+
sbInstruct('Bu projenin web arayüzü çalışıyorsa adresini tespit et (çıktılar/README/port taraması) ve browser_open aracıyla DAHİLİ TARAYICIDA aç.')
|
|
9790
|
+
});
|
|
9791
|
+
}
|