beast-agent 1.9.0 → 2.0.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/LICENSE +21 -21
- package/README.md +130 -130
- package/bin/beast-agent.js +137 -137
- package/package.json +1 -1
- package/scripts/fix-electron.js +138 -138
- package/scripts/release.js +137 -131
- package/scripts/swap-electron.js +40 -40
- package/src/agent/agentdefs.js +122 -122
- package/src/agent/bots.js +580 -580
- package/src/agent/bus.js +389 -389
- package/src/agent/computeruse.js +200 -200
- package/src/agent/config.js +284 -284
- package/src/agent/discord.js +332 -332
- package/src/agent/engine.js +75 -10
- package/src/agent/kb.js +123 -123
- package/src/agent/llm.js +430 -430
- package/src/agent/logger.js +90 -90
- package/src/agent/mcp.js +427 -427
- package/src/agent/mem0.js +605 -605
- package/src/agent/memory.js +427 -427
- package/src/agent/mqueue.js +124 -124
- package/src/agent/pdf.js +20 -20
- package/src/agent/research.js +133 -133
- package/src/agent/scripts/news.py +113 -113
- package/src/agent/scripts/stealthsearch.py +30 -30
- package/src/agent/scripts/websearch.py +225 -225
- package/src/agent/searxng.js +325 -325
- package/src/agent/seeds/brainstorming/SKILL.md +90 -90
- package/src/agent/seeds/dispatching-parallel-agents/SKILL.md +120 -120
- package/src/agent/seeds/executing-plans/SKILL.md +60 -60
- package/src/agent/seeds/subagent-driven-development/SKILL.md +167 -167
- package/src/agent/seeds/systematic-debugging/SKILL.md +131 -131
- package/src/agent/seeds/test-driven-development/SKILL.md +152 -152
- package/src/agent/seeds/verification-before-completion/SKILL.md +63 -63
- package/src/agent/seeds/writing-plans/SKILL.md +162 -162
- package/src/agent/seeds/writing-skills/SKILL.md +229 -229
- package/src/agent/skills.js +652 -652
- package/src/agent/store.js +378 -378
- package/src/agent/telegram.js +155 -155
- package/src/agent/tokens.js +39 -39
- package/src/agent/usage.js +125 -125
- package/src/agent/watchers.js +312 -312
- package/src/agent/watext.js +80 -80
- package/src/agent/whatsapp.js +555 -555
- package/src/cron.js +255 -255
- package/src/main.js +348 -6
- package/src/preload.js +9 -0
- package/src/renderer/browserPreload.js +73 -73
- package/src/renderer/i18n.js +4 -0
- package/src/renderer/index.html +448 -409
- package/src/renderer/renderer.js +824 -41
- package/src/renderer/style.css +264 -5
package/src/renderer/renderer.js
CHANGED
|
@@ -80,6 +80,28 @@ const els = {
|
|
|
80
80
|
bcAttach: $('#bcAttach'),
|
|
81
81
|
bcMic: $('#bcMic'),
|
|
82
82
|
bcChips: $('#bcChips'),
|
|
83
|
+
studioBtn: $('#studioBtn'),
|
|
84
|
+
stPanel: $('#stPanel'),
|
|
85
|
+
stTitle: $('#stTitle'),
|
|
86
|
+
stCwd: $('#stCwd'),
|
|
87
|
+
stOut: $('#stOut'),
|
|
88
|
+
stTodoWrap: $('#stTodoWrap'),
|
|
89
|
+
stStatus: $('#stStatus'),
|
|
90
|
+
stChips: $('#stChips'),
|
|
91
|
+
stInput: $('#stInput'),
|
|
92
|
+
stStop: $('#stStop'),
|
|
93
|
+
stClear: $('#stClear'),
|
|
94
|
+
stNew: $('#stNew'),
|
|
95
|
+
stAttach: $('#stAttach'),
|
|
96
|
+
stMic: $('#stMic'),
|
|
97
|
+
studioRow: $('#studioRow'),
|
|
98
|
+
stSplit: $('#stSplit'),
|
|
99
|
+
stVideoEl: $('#stVideoEl'),
|
|
100
|
+
stVideoName: $('#stVideoName'),
|
|
101
|
+
stVideoOpen: $('#stVideoOpen'),
|
|
102
|
+
stVideoExt: $('#stVideoExt'),
|
|
103
|
+
stVideoBody: $('#stVideoBody'),
|
|
104
|
+
stVideoEmpty: $('#stVideoEmpty'),
|
|
83
105
|
codeTabs: $('#codeTabs'),
|
|
84
106
|
codeTa: $('#codeTa'),
|
|
85
107
|
codeGutter: $('#codeGutter'),
|
|
@@ -881,8 +903,9 @@ async function openSession(id) {
|
|
|
881
903
|
|
|
882
904
|
const TEXT_EXT = /\.(txt|md|json|csv|log|js|ts|py|ps1|bat|cmd|html|css|yaml|yml|xml|ini)$/i;
|
|
883
905
|
|
|
884
|
-
/* ek hedefleri: chat + Beast Code
|
|
906
|
+
/* ek hedefleri: chat + Beast Code + Beast Studio ayrı kuyruklar */
|
|
885
907
|
let bcPending = [];
|
|
908
|
+
let stPending = [];
|
|
886
909
|
|
|
887
910
|
function renderChips() {
|
|
888
911
|
els.chips.innerHTML = '';
|
|
@@ -925,25 +948,49 @@ function renderBcChips() {
|
|
|
925
948
|
});
|
|
926
949
|
}
|
|
927
950
|
|
|
951
|
+
function renderStChips() {
|
|
952
|
+
if (!els.stChips) return;
|
|
953
|
+
els.stChips.innerHTML = '';
|
|
954
|
+
els.stChips.hidden = stPending.length === 0;
|
|
955
|
+
stPending.forEach((a, i) => {
|
|
956
|
+
const c = document.createElement('span');
|
|
957
|
+
c.className = 'chip';
|
|
958
|
+
const label = a.type === 'image' ? `\u25A3 ${a.name}` : `\u2261 ${a.name}`;
|
|
959
|
+
c.appendChild(document.createTextNode(label));
|
|
960
|
+
const x = document.createElement('span');
|
|
961
|
+
x.className = 'x';
|
|
962
|
+
x.textContent = '×';
|
|
963
|
+
x.addEventListener('click', () => {
|
|
964
|
+
stPending.splice(i, 1);
|
|
965
|
+
renderStChips();
|
|
966
|
+
});
|
|
967
|
+
c.appendChild(x);
|
|
968
|
+
els.stChips.appendChild(c);
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
|
|
928
972
|
function addFiles(files, mode) {
|
|
929
973
|
const isBc = mode === 'bc';
|
|
974
|
+
const isSt = mode === 'st';
|
|
975
|
+
const getList = () => (isBc ? bcPending : isSt ? stPending : pending);
|
|
976
|
+
const paint = () => (isBc ? renderBcChips() : isSt ? renderStChips() : renderChips());
|
|
930
977
|
for (const f of files) {
|
|
931
978
|
if (f.size > 8 * 1024 * 1024) { toast('Çok büyük (max 8MB): ' + f.name); continue; }
|
|
932
979
|
if (f.type.startsWith('image/')) {
|
|
933
980
|
const r = new FileReader();
|
|
934
981
|
r.onload = () => {
|
|
935
|
-
const list =
|
|
982
|
+
const list = getList();
|
|
936
983
|
if (list.length >= 6) { toast('En fazla 6 ek'); return; }
|
|
937
984
|
list.push({ type: 'image', name: f.name, dataUrl: String(r.result) });
|
|
938
|
-
|
|
985
|
+
paint();
|
|
939
986
|
};
|
|
940
987
|
r.readAsDataURL(f);
|
|
941
988
|
} else if (TEXT_EXT.test(f.name)) {
|
|
942
989
|
f.text().then((t) => {
|
|
943
|
-
const list =
|
|
990
|
+
const list = getList();
|
|
944
991
|
if (list.length >= 6) { toast('En fazla 6 ek'); return; }
|
|
945
992
|
list.push({ type: 'file', name: f.name, content: t.slice(0, 200000) });
|
|
946
|
-
|
|
993
|
+
paint();
|
|
947
994
|
});
|
|
948
995
|
} else {
|
|
949
996
|
toast('Desteklenmeyen tür: ' + f.name);
|
|
@@ -4245,6 +4292,12 @@ function renderAgentsPane() {
|
|
|
4245
4292
|
function onEvent(ev) {
|
|
4246
4293
|
if (ev.type === 'sessions') { refreshSessions(); return; }
|
|
4247
4294
|
if (ev.type === 'approval') {
|
|
4295
|
+
/* Beast Studio oturumunun onayı: panelde ipucu + kart sohbete düşer */
|
|
4296
|
+
if (stSessionId && ev.sessionId === stSessionId) {
|
|
4297
|
+
showApprovalCard(ev);
|
|
4298
|
+
stLine('t-dim', '⏳ onay bekleniyor: ' + (ev.tool || '?') + ' — chat moduna geçip kartı onayla');
|
|
4299
|
+
return;
|
|
4300
|
+
}
|
|
4248
4301
|
/* Beast Code oturumunun onayı: panelde ipucu + kart sohbete düşer */
|
|
4249
4302
|
if (bcSessionId && ev.sessionId === bcSessionId) {
|
|
4250
4303
|
showApprovalCard(ev);
|
|
@@ -4270,6 +4323,12 @@ function onEvent(ev) {
|
|
|
4270
4323
|
}
|
|
4271
4324
|
/* OFFLINE MESAJ KUYRUĞU: bağlantı + kuyruk olayları (sessionId filtresinden önce) */
|
|
4272
4325
|
if (ev.type === 'net' || ev.type === 'netQueue') { onNetEvent(ev); return; }
|
|
4326
|
+
/* Beast Studio oturumu: olaylar SADECE Studio paneline akar — ana sohbeti
|
|
4327
|
+
ve Beast Code panelini kirletmez (dünyalar ayrı) */
|
|
4328
|
+
if (stSessionId && ev.sessionId === stSessionId) {
|
|
4329
|
+
stIngest(ev);
|
|
4330
|
+
return;
|
|
4331
|
+
}
|
|
4273
4332
|
/* Beast Code oturumu (IDE modu ortasındaki panel): olayları panele akıt,
|
|
4274
4333
|
ana sohbeti kirletme */
|
|
4275
4334
|
if (bcSessionId && ev.sessionId === bcSessionId) {
|
|
@@ -5209,12 +5268,15 @@ async function init() {
|
|
|
5209
5268
|
document.addEventListener('langchange', syncSttLang);
|
|
5210
5269
|
}
|
|
5211
5270
|
|
|
5212
|
-
/* + butonu
|
|
5271
|
+
/* + butonu üç hedefe hizmet eder: chat composer, Beast Code VE Beast Studio */
|
|
5213
5272
|
let fileSink = 'chat';
|
|
5214
5273
|
els.attachBtn.addEventListener('click', () => { fileSink = 'chat'; els.fileInput.click(); });
|
|
5215
5274
|
if (els.bcAttach) {
|
|
5216
5275
|
els.bcAttach.addEventListener('click', () => { fileSink = 'bc'; els.fileInput.click(); });
|
|
5217
5276
|
}
|
|
5277
|
+
if (els.stAttach) {
|
|
5278
|
+
els.stAttach.addEventListener('click', () => { fileSink = 'st'; els.fileInput.click(); });
|
|
5279
|
+
}
|
|
5218
5280
|
els.fileInput.addEventListener('change', () => {
|
|
5219
5281
|
addFiles([...els.fileInput.files], fileSink);
|
|
5220
5282
|
els.fileInput.value = '';
|
|
@@ -5276,6 +5338,12 @@ async function init() {
|
|
|
5276
5338
|
els.bcInput.focus();
|
|
5277
5339
|
bcInputResize();
|
|
5278
5340
|
});
|
|
5341
|
+
setupMicButton(els.stMic, (t) => {
|
|
5342
|
+
if (!els.stInput) return;
|
|
5343
|
+
els.stInput.value = (els.stInput.value ? els.stInput.value.replace(/\s+$/, '') + ' ' : '') + t;
|
|
5344
|
+
els.stInput.focus();
|
|
5345
|
+
stInputResize();
|
|
5346
|
+
});
|
|
5279
5347
|
|
|
5280
5348
|
beast.onWaEvent(onWaEvent);
|
|
5281
5349
|
beast.onTgEvent(onTgEvent);
|
|
@@ -6144,13 +6212,27 @@ $('#ghAllRefresh').addEventListener('click', () => {
|
|
|
6144
6212
|
Dosyaya tıkla → editör; klasöre tıkla → aç/kapa. */
|
|
6145
6213
|
|
|
6146
6214
|
const IDE_ICONS = {
|
|
6147
|
-
'.html': '🌐', '.htm': '🌐', '.css': '🎨', '.
|
|
6148
|
-
'.
|
|
6149
|
-
'.
|
|
6150
|
-
'.
|
|
6151
|
-
'.
|
|
6215
|
+
'.html': '🌐', '.htm': '🌐', '.css': '🎨', '.scss': '🎨', '.sass': '🎨', '.less': '🎨',
|
|
6216
|
+
'.js': '📜', '.mjs': '📜', '.cjs': '📜', '.ts': '📜', '.mts': '📜', '.cts': '📜',
|
|
6217
|
+
'.jsx': '📜', '.tsx': '📜', '.vue': '📜', '.svelte': '📜', '.astro': '📜',
|
|
6218
|
+
'.json': '🧾', '.jsonc': '🧾', '.yaml': '🧾', '.yml': '🧾', '.toml': '🧾', '.xml': '🧾',
|
|
6219
|
+
'.md': '📝', '.mdx': '📝', '.txt': '📄', '.log': '📄', '.csv': '📊', '.tsv': '📊',
|
|
6220
|
+
'.py': '🐍', '.go': '🐹', '.rs': '🦀', '.java': '☕', '.kt': '🧩', '.swift': '🕊️',
|
|
6221
|
+
'.rb': '💎', '.php': '🐘', '.cs': '🎯', '.c': '🔧', '.h': '🔧', '.cpp': '🔧',
|
|
6222
|
+
'.hpp': '🔧', '.sql': '🗄️', '.sh': '⚙️', '.ps1': '⚙️', '.bat': '⚙️', '.cmd': '⚙️',
|
|
6223
|
+
'.lua': '🌙', '.r': '📈', '.dart': '🎯', '.graphql': '◈', '.proto': '◈',
|
|
6224
|
+
'.png': '🖼️', '.jpg': '🖼️', '.jpeg': '🖼️', '.gif': '🖼️', '.svg': '🖼️', '.webp': '🖼️',
|
|
6225
|
+
'.pdf': '📕', '.env': '🔑',
|
|
6226
|
+
/* Studio medya ikonları — IDE ağacında da doğru simge */
|
|
6227
|
+
'.mp4': '🎬', '.mkv': '🎬', '.mov': '🎬', '.avi': '🎬', '.webm': '🎬', '.m4v': '🎬',
|
|
6228
|
+
'.mpg': '🎬', '.mpeg': '🎬', '.wmv': '🎬', '.flv': '🎬', '.3gp': '🎬', '.ogv': '🎬',
|
|
6229
|
+
'.mp3': '🎵', '.wav': '🎵', '.ogg': '🎵', '.m4a': '🎵', '.flac': '🎵', '.aac': '🎵', '.opus': '🎵',
|
|
6230
|
+
'.srt': '💬', '.vtt': '💬', '.ass': '💬', '.ssa': '💬',
|
|
6152
6231
|
};
|
|
6153
6232
|
|
|
6233
|
+
/* Studio modunda ağaçta TIKLANAN medya dosyaları video bölümünde oynatılır */
|
|
6234
|
+
const MEDIA_FILE_RE = /\.(mp4|mkv|mov|avi|webm|m4v|mpg|mpeg|wmv|flv|3gp|ogv|mp3|wav|ogg|m4a|flac|aac|opus)$/i;
|
|
6235
|
+
|
|
6154
6236
|
const ideState = {
|
|
6155
6237
|
cache: new Map(), // rel -> entries[]
|
|
6156
6238
|
open: new Set(['']),
|
|
@@ -6162,8 +6244,10 @@ function ideModeOn() {
|
|
|
6162
6244
|
}
|
|
6163
6245
|
|
|
6164
6246
|
async function setIdeMode(on) {
|
|
6247
|
+
if (on && studioModeOn()) await setStudioMode(false); /* Studio açıkken IDE'ye geçiş — Studio kapanır */
|
|
6165
6248
|
document.body.classList.toggle('ide-mode', !!on);
|
|
6166
|
-
|
|
6249
|
+
if (els.ideBtn) els.ideBtn.classList.toggle('on', !!on);
|
|
6250
|
+
/* soldaki marka: chat modunda BEAST Agent, IDE modunda BEAST Code, Studio modunda BEAST Studio */
|
|
6167
6251
|
const brandSub = document.querySelector('#brand .brand-sub');
|
|
6168
6252
|
if (brandSub) brandSub.textContent = on ? 'Code' : 'Agent';
|
|
6169
6253
|
/* rail her iki modda da DEFAULT KAPALI — çalışan paralel ajan varsa
|
|
@@ -6188,6 +6272,166 @@ async function setIdeMode(on) {
|
|
|
6188
6272
|
}
|
|
6189
6273
|
}
|
|
6190
6274
|
|
|
6275
|
+
/* ================= BEAST STUDIO MODU =================
|
|
6276
|
+
Beast Code ile AYRI dünya: sol klasör konsolu (başlık: BEAST STUDIO),
|
|
6277
|
+
sağ → chat + video bölümü. Oturumlar main tarafında studioRoot bazlı ve
|
|
6278
|
+
ÖZELDİR — chat geçmişi listesine VE Beast Code paneline karışmaz. */
|
|
6279
|
+
|
|
6280
|
+
const studioState = {
|
|
6281
|
+
cache: new Map(),
|
|
6282
|
+
open: new Set(['']),
|
|
6283
|
+
path: '',
|
|
6284
|
+
};
|
|
6285
|
+
|
|
6286
|
+
function studioModeOn() {
|
|
6287
|
+
return document.body.classList.contains('studio-mode');
|
|
6288
|
+
}
|
|
6289
|
+
|
|
6290
|
+
async function setStudioMode(on) {
|
|
6291
|
+
if (on && ideModeOn()) await setIdeMode(false); /* IDE açıkken Studio'ya geçiş — IDE kapanır */
|
|
6292
|
+
document.body.classList.toggle('studio-mode', !!on);
|
|
6293
|
+
if (els.studioBtn) els.studioBtn.classList.toggle('on', !!on);
|
|
6294
|
+
const brandSub = document.querySelector('#brand .brand-sub');
|
|
6295
|
+
if (brandSub) brandSub.textContent = on ? 'Studio' : 'Agent';
|
|
6296
|
+
/* klasör konsolunun en üstü: Studio modunda "BEAST STUDIO" yazar */
|
|
6297
|
+
const ftp = document.getElementById('filePanelTitle');
|
|
6298
|
+
if (ftp) {
|
|
6299
|
+
if (on) {
|
|
6300
|
+
ftp.textContent = 'BEAST STUDIO';
|
|
6301
|
+
ftp.removeAttribute('data-i18n');
|
|
6302
|
+
} else {
|
|
6303
|
+
ftp.setAttribute('data-i18n', 'ide_files');
|
|
6304
|
+
ftp.textContent = (window.I18N && window.I18N.t('ide_files')) || 'DOSYALAR';
|
|
6305
|
+
}
|
|
6306
|
+
}
|
|
6307
|
+
toggleRail(true);
|
|
6308
|
+
railManualOpen = false;
|
|
6309
|
+
/* Studio'da web önizleme yok — açık tarayıcıyı her iki yönde de kapat */
|
|
6310
|
+
if (document.body.classList.contains('browser-open')) {
|
|
6311
|
+
try { beast.toggleBrowser(); } catch {}
|
|
6312
|
+
}
|
|
6313
|
+
if (on) {
|
|
6314
|
+
stSplitApply();
|
|
6315
|
+
await loadStudioTree();
|
|
6316
|
+
stBanner();
|
|
6317
|
+
} else {
|
|
6318
|
+
stVideoStop();
|
|
6319
|
+
}
|
|
6320
|
+
}
|
|
6321
|
+
|
|
6322
|
+
async function loadStudioTree() {
|
|
6323
|
+
studioState.cache.clear();
|
|
6324
|
+
await renderFileTree();
|
|
6325
|
+
}
|
|
6326
|
+
|
|
6327
|
+
/* ---------- chat/video ayırıcı (IDE split ile aynı model) ---------- */
|
|
6328
|
+
let stSplitFrac = 0;
|
|
6329
|
+
|
|
6330
|
+
function stSplitApply() {
|
|
6331
|
+
if (!stSplitFrac) {
|
|
6332
|
+
let saved = 0;
|
|
6333
|
+
try { saved = parseFloat(localStorage.getItem('beast.studioSplit')) || 0; } catch {}
|
|
6334
|
+
stSplitFrac = saved > 0.05 && saved < 0.95 ? saved : 0.48;
|
|
6335
|
+
}
|
|
6336
|
+
stSplitFrac = Math.max(0.2, Math.min(stSplitFrac, 0.8));
|
|
6337
|
+
const rowW = els.studioRow && els.studioRow.clientWidth ? els.studioRow.clientWidth : window.innerWidth - 250;
|
|
6338
|
+
const w = Math.max(300, Math.min(Math.round(rowW * stSplitFrac), Math.max(340, rowW - 260)));
|
|
6339
|
+
document.body.style.setProperty('--stSplit', w + 'px');
|
|
6340
|
+
}
|
|
6341
|
+
|
|
6342
|
+
if (els.stSplit) {
|
|
6343
|
+
els.stSplit.addEventListener('mousedown', (e) => {
|
|
6344
|
+
e.preventDefault();
|
|
6345
|
+
els.stSplit.classList.add('dragging');
|
|
6346
|
+
const rowLeft = els.stPanel ? els.stPanel.getBoundingClientRect().left : 250;
|
|
6347
|
+
const rowW = Math.max(600, els.studioRow && els.studioRow.clientWidth ? els.studioRow.clientWidth : window.innerWidth - 250);
|
|
6348
|
+
const move = (ev) => {
|
|
6349
|
+
const w = Math.max(300, Math.min(ev.clientX - rowLeft, rowW - 260));
|
|
6350
|
+
stSplitFrac = Math.max(0.2, Math.min(w / rowW, 0.8));
|
|
6351
|
+
document.body.style.setProperty('--stSplit', Math.round(w) + 'px');
|
|
6352
|
+
};
|
|
6353
|
+
const up = () => {
|
|
6354
|
+
document.removeEventListener('mousemove', move);
|
|
6355
|
+
document.removeEventListener('mouseup', up);
|
|
6356
|
+
els.stSplit.classList.remove('dragging');
|
|
6357
|
+
try { localStorage.setItem('beast.studioSplit', String(stSplitFrac)); } catch {}
|
|
6358
|
+
};
|
|
6359
|
+
document.addEventListener('mousemove', move);
|
|
6360
|
+
document.addEventListener('mouseup', up);
|
|
6361
|
+
});
|
|
6362
|
+
window.addEventListener('resize', () => {
|
|
6363
|
+
if (studioModeOn()) stSplitApply();
|
|
6364
|
+
});
|
|
6365
|
+
}
|
|
6366
|
+
|
|
6367
|
+
/* ---------- video bölümü ----------
|
|
6368
|
+
Sol ağaçtan video/ses seçilir veya "Aç" ile dosya seçilir; ajanın ffmpeg
|
|
6369
|
+
çıktıları (output/ klasörü) ağaçta belirdiği an burada oynatılabilir. */
|
|
6370
|
+
let stVideoPath = '';
|
|
6371
|
+
|
|
6372
|
+
function stVideoFileUrl(abs) {
|
|
6373
|
+
let p = String(abs || '').replace(/\\/g, '/');
|
|
6374
|
+
if (!p.startsWith('/')) p = '/' + p;
|
|
6375
|
+
return 'file://' + p.split('/').map((seg) => encodeURIComponent(seg)).join('/');
|
|
6376
|
+
}
|
|
6377
|
+
|
|
6378
|
+
function stVideoPlayPath(abs) {
|
|
6379
|
+
if (!els.stVideoEl) return;
|
|
6380
|
+
stVideoPath = String(abs || '');
|
|
6381
|
+
els.stVideoEl.src = stVideoFileUrl(stVideoPath);
|
|
6382
|
+
els.stVideoEl.hidden = false;
|
|
6383
|
+
if (els.stVideoEmpty) els.stVideoEmpty.hidden = true;
|
|
6384
|
+
const nm = stVideoPath.split(/[\\/]/).pop() || '—';
|
|
6385
|
+
if (els.stVideoName) { els.stVideoName.textContent = nm; els.stVideoName.title = stVideoPath; }
|
|
6386
|
+
els.stVideoEl.play().catch(() => {});
|
|
6387
|
+
}
|
|
6388
|
+
|
|
6389
|
+
function stVideoPlay(rel) {
|
|
6390
|
+
const root = studioState.path;
|
|
6391
|
+
if (!root || !rel) return;
|
|
6392
|
+
stVideoPlayPath(root + '\\' + String(rel).replace(/\//g, '\\'));
|
|
6393
|
+
}
|
|
6394
|
+
|
|
6395
|
+
function stVideoStop() {
|
|
6396
|
+
if (!els.stVideoEl) return;
|
|
6397
|
+
try { els.stVideoEl.pause(); } catch {}
|
|
6398
|
+
els.stVideoEl.removeAttribute('src');
|
|
6399
|
+
try { els.stVideoEl.load(); } catch {}
|
|
6400
|
+
els.stVideoEl.hidden = true;
|
|
6401
|
+
if (els.stVideoEmpty) els.stVideoEmpty.hidden = false;
|
|
6402
|
+
if (els.stVideoName) els.stVideoName.textContent = '—';
|
|
6403
|
+
stVideoPath = '';
|
|
6404
|
+
}
|
|
6405
|
+
|
|
6406
|
+
if (els.stVideoOpen) {
|
|
6407
|
+
els.stVideoOpen.addEventListener('click', async () => {
|
|
6408
|
+
const r = await beast.studioPickVideo().catch(() => null);
|
|
6409
|
+
if (r && r.ok && r.path) stVideoPlayPath(r.path);
|
|
6410
|
+
else if (r && !r.canceled && r.error) toast(r.error);
|
|
6411
|
+
});
|
|
6412
|
+
}
|
|
6413
|
+
if (els.stVideoExt) {
|
|
6414
|
+
els.stVideoExt.addEventListener('click', () => {
|
|
6415
|
+
if (!stVideoPath) { toast('Açık video yok'); return; }
|
|
6416
|
+
beast.openPath(stVideoPath).catch(() => {});
|
|
6417
|
+
});
|
|
6418
|
+
}
|
|
6419
|
+
/* sürükle-bırak: video dosyası doğrudan video bölümüne bırakılabilir */
|
|
6420
|
+
if (els.stVideoBody) {
|
|
6421
|
+
els.stVideoBody.addEventListener('dragover', (e) => {
|
|
6422
|
+
e.preventDefault();
|
|
6423
|
+
els.stVideoBody.classList.add('dragover');
|
|
6424
|
+
});
|
|
6425
|
+
els.stVideoBody.addEventListener('dragleave', () => els.stVideoBody.classList.remove('dragover'));
|
|
6426
|
+
els.stVideoBody.addEventListener('drop', (e) => {
|
|
6427
|
+
e.preventDefault();
|
|
6428
|
+
els.stVideoBody.classList.remove('dragover');
|
|
6429
|
+
const f = e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files[0];
|
|
6430
|
+
if (f && f.path && MEDIA_FILE_RE.test(f.name)) stVideoPlayPath(f.path);
|
|
6431
|
+
else if (f) toast('Medya dosyası değil: ' + f.name);
|
|
6432
|
+
});
|
|
6433
|
+
}
|
|
6434
|
+
|
|
6191
6435
|
/* ---------- editör panelini kapat/göster ----------
|
|
6192
6436
|
Kapatınca kod bölmesi gider, Beast Code tam genişlik alır; tercih
|
|
6193
6437
|
localStorage'da kalıcıdır. Dosya ağacından dosya açınca geri açılır. */
|
|
@@ -6279,21 +6523,31 @@ async function renderFileTree() {
|
|
|
6279
6523
|
if (!tree) return;
|
|
6280
6524
|
tree.innerHTML = '';
|
|
6281
6525
|
const wsLabel = $('#filePanelPath');
|
|
6526
|
+
/* Studio modunda ağaç studioRoot'tan, IDE modunda ideRoot'tan okunur —
|
|
6527
|
+
aynı panel, aynı çizim; yalnız kaynak ve davranış moduna göre değişir */
|
|
6528
|
+
const studio = studioModeOn();
|
|
6529
|
+
const st = studio ? studioState : ideState;
|
|
6530
|
+
const treeApi = studio ? beast.studioTree : beast.ideTree;
|
|
6282
6531
|
const build = async (rel, depth, container) => {
|
|
6283
|
-
let entries =
|
|
6532
|
+
let entries = st.cache.get(rel);
|
|
6284
6533
|
if (!entries) {
|
|
6285
|
-
const r = await
|
|
6534
|
+
const r = await treeApi(rel).catch(() => null);
|
|
6286
6535
|
if (!r || !r.ok) {
|
|
6287
6536
|
if (!rel) container.innerHTML = `<div class="file-empty">${escapeHtml((r && r.error) || 'okunamadı')}</div>`;
|
|
6288
6537
|
return;
|
|
6289
6538
|
}
|
|
6290
6539
|
entries = r.entries;
|
|
6291
|
-
|
|
6540
|
+
st.cache.set(rel, entries);
|
|
6292
6541
|
if (r.workspace) {
|
|
6293
|
-
|
|
6542
|
+
st.path = r.workspace;
|
|
6294
6543
|
if (wsLabel) { wsLabel.textContent = r.workspace; wsLabel.title = r.workspace; }
|
|
6295
|
-
if (
|
|
6296
|
-
|
|
6544
|
+
if (studio) {
|
|
6545
|
+
if (els.stCwd) { els.stCwd.textContent = r.workspace; els.stCwd.title = r.workspace; }
|
|
6546
|
+
stOnFolderChanged(r.workspace);
|
|
6547
|
+
} else {
|
|
6548
|
+
if (els.bcCwd) { els.bcCwd.textContent = r.workspace; els.bcCwd.title = r.workspace; }
|
|
6549
|
+
bcOnFolderChanged(r.workspace);
|
|
6550
|
+
}
|
|
6297
6551
|
}
|
|
6298
6552
|
}
|
|
6299
6553
|
for (const e of entries) {
|
|
@@ -6301,16 +6555,21 @@ async function renderFileTree() {
|
|
|
6301
6555
|
const row = document.createElement('div');
|
|
6302
6556
|
row.className = 'file-row';
|
|
6303
6557
|
row.style.paddingLeft = 6 + depth * 14 + 'px';
|
|
6304
|
-
const
|
|
6558
|
+
const ext = e.name.slice(e.name.lastIndexOf('.')).toLowerCase();
|
|
6559
|
+
const ico = e.dir ? (st.open.has(child) ? '📂' : '📁') : IDE_ICONS[ext] || '📄';
|
|
6305
6560
|
row.innerHTML =
|
|
6306
6561
|
`<span class="f-ico">${ico}</span>` +
|
|
6307
6562
|
`<span class="f-nm" title="${escapeHtml(e.name)}">${escapeHtml(e.name)}</span>` +
|
|
6308
6563
|
(e.dir ? '' : `<span class="f-sz">${fmtFileSize(e.size)}</span>`);
|
|
6309
6564
|
row.addEventListener('click', () => {
|
|
6310
6565
|
if (e.dir) {
|
|
6311
|
-
if (
|
|
6312
|
-
else
|
|
6566
|
+
if (st.open.has(child)) st.open.delete(child);
|
|
6567
|
+
else st.open.add(child);
|
|
6313
6568
|
renderFileTree();
|
|
6569
|
+
} else if (studio && MEDIA_FILE_RE.test(e.name)) {
|
|
6570
|
+
stVideoPlay(child); /* video/ses → sağdaki video bölümünde oynat */
|
|
6571
|
+
} else if (studio) {
|
|
6572
|
+
toast('Studio modunda medya dosyaları oynatılır — dosya düzenleme Beast Code modunda');
|
|
6314
6573
|
} else {
|
|
6315
6574
|
codeOpen(child);
|
|
6316
6575
|
}
|
|
@@ -6318,7 +6577,7 @@ async function renderFileTree() {
|
|
|
6318
6577
|
row.dataset.rel = child;
|
|
6319
6578
|
row.dataset.dir = e.dir ? '1' : '0';
|
|
6320
6579
|
container.appendChild(row);
|
|
6321
|
-
if (e.dir &&
|
|
6580
|
+
if (e.dir && st.open.has(child)) {
|
|
6322
6581
|
const box = document.createElement('div');
|
|
6323
6582
|
container.appendChild(box);
|
|
6324
6583
|
await build(child, depth + 1, box);
|
|
@@ -6337,7 +6596,9 @@ function ideRefreshTree() {
|
|
|
6337
6596
|
ideTreeTimer = setTimeout(() => {
|
|
6338
6597
|
ideTreeTimer = null;
|
|
6339
6598
|
try {
|
|
6340
|
-
|
|
6599
|
+
/* hangi moddaysak o ağacın önbelleği tazelenir */
|
|
6600
|
+
if (studioModeOn()) studioState.cache.clear();
|
|
6601
|
+
else ideState.cache.clear();
|
|
6341
6602
|
renderFileTree().catch(() => {});
|
|
6342
6603
|
} catch {}
|
|
6343
6604
|
}, 600);
|
|
@@ -6730,16 +6991,29 @@ async function codeReloadIfOpen(p) {
|
|
|
6730
6991
|
}
|
|
6731
6992
|
|
|
6732
6993
|
$('#ideBtn').addEventListener('click', () => setIdeMode(!ideModeOn()));
|
|
6994
|
+
if (els.studioBtn) els.studioBtn.addEventListener('click', () => setStudioMode(!studioModeOn()));
|
|
6733
6995
|
$('#filePick').addEventListener('click', async () => {
|
|
6734
|
-
|
|
6996
|
+
/* Studio modunda klasör seçimi Studio'nun KENDİ kökünü değiştirir —
|
|
6997
|
+
IDE köküne dokunmaz (dünyalar ayrıdır) */
|
|
6998
|
+
const r = studioModeOn()
|
|
6999
|
+
? await beast.studioSetRoot().catch(() => null)
|
|
7000
|
+
: await beast.ideSetRoot().catch(() => null);
|
|
6735
7001
|
if (r && r.ok) {
|
|
6736
|
-
|
|
6737
|
-
|
|
7002
|
+
if (studioModeOn()) {
|
|
7003
|
+
studioState.open = new Set(['']);
|
|
7004
|
+
await loadStudioTree();
|
|
7005
|
+
} else {
|
|
7006
|
+
ideState.open = new Set(['']);
|
|
7007
|
+
await loadIdeTree();
|
|
7008
|
+
}
|
|
6738
7009
|
} else if (r && !r.canceled && r.error) {
|
|
6739
7010
|
toast(r.error);
|
|
6740
7011
|
}
|
|
6741
7012
|
});
|
|
6742
|
-
$('#fileRefresh').addEventListener('click', () =>
|
|
7013
|
+
$('#fileRefresh').addEventListener('click', () => {
|
|
7014
|
+
if (studioModeOn()) loadStudioTree();
|
|
7015
|
+
else loadIdeTree();
|
|
7016
|
+
});
|
|
6743
7017
|
|
|
6744
7018
|
/* ---------- görev listesi + TEK TUŞ GERİ ALMA (dosya paneli) ---------- */
|
|
6745
7019
|
let tasksPanelOpen = false;
|
|
@@ -6754,11 +7028,14 @@ function toggleTasksPanel(force) {
|
|
|
6754
7028
|
async function renderTasksPanel() {
|
|
6755
7029
|
const box = els.tasksPanel;
|
|
6756
7030
|
if (!box) return;
|
|
6757
|
-
|
|
6758
|
-
|
|
7031
|
+
const sid = studioModeOn() ? stSessionId : bcSessionId;
|
|
7032
|
+
if (!sid) {
|
|
7033
|
+
box.innerHTML = '<div class="tsk-empty">' + (studioModeOn()
|
|
7034
|
+
? '\u00D6nce Beast Studio\u2019da bir mesaj yaz — g\u00F6rev listesi i\u00E7in oturum gerekli.'
|
|
7035
|
+
: '\u00D6nce Beast Code\u2019da bir mesaj yaz — g\u00F6rev listesi i\u00E7in oturum gerekli.') + '</div>';
|
|
6759
7036
|
return;
|
|
6760
7037
|
}
|
|
6761
|
-
const r = await beast.bcTodos(
|
|
7038
|
+
const r = await beast.bcTodos(sid).catch(() => null);
|
|
6762
7039
|
if (!r || !r.ok) {
|
|
6763
7040
|
box.innerHTML = '<div class="tsk-empty">' + escapeHtml((r && r.error) || 'okunamad\u0131') + '</div>';
|
|
6764
7041
|
return;
|
|
@@ -6794,9 +7071,10 @@ async function renderTasksPanel() {
|
|
|
6794
7071
|
}
|
|
6795
7072
|
|
|
6796
7073
|
async function undoTask(id) {
|
|
6797
|
-
|
|
7074
|
+
const sid = studioModeOn() ? stSessionId : bcSessionId;
|
|
7075
|
+
if (!sid) return;
|
|
6798
7076
|
if (busy) { toast('Ajan \u00E7al\u0131\u015F\u0131yor — \u25A0 ile durdurup \u00F6yle geri al'); return; }
|
|
6799
|
-
const r = await beast.bcUndo(
|
|
7077
|
+
const r = await beast.bcUndo(sid, id).catch(() => null);
|
|
6800
7078
|
if (r && r.ok) {
|
|
6801
7079
|
toast('\u21B6 Geri al\u0131nd\u0131 — ' + (r.reverted || 0) + ' dosya \u00F6nceki h\u00E2line d\u00F6nd\u00FC');
|
|
6802
7080
|
ideRefreshTree();
|
|
@@ -6895,17 +7173,23 @@ function fileCtxShow(e, rel, isDir) {
|
|
|
6895
7173
|
const menu = els.fileCtxMenu;
|
|
6896
7174
|
if (!menu || !rel) return;
|
|
6897
7175
|
e.preventDefault();
|
|
6898
|
-
const
|
|
7176
|
+
const studio = studioModeOn();
|
|
7177
|
+
const st = studio ? studioState : ideState;
|
|
7178
|
+
const isMedia = MEDIA_FILE_RE.test(rel.split('/').pop() || '');
|
|
6899
7179
|
const items = [];
|
|
6900
7180
|
if (isDir) {
|
|
6901
7181
|
items.push({
|
|
6902
|
-
label:
|
|
7182
|
+
label: st.open.has(rel) ? 'Kapat' : 'Aç',
|
|
6903
7183
|
fn: () => {
|
|
6904
|
-
if (
|
|
6905
|
-
else
|
|
7184
|
+
if (st.open.has(rel)) st.open.delete(rel);
|
|
7185
|
+
else st.open.add(rel);
|
|
6906
7186
|
renderFileTree();
|
|
6907
7187
|
},
|
|
6908
7188
|
});
|
|
7189
|
+
} else if (studio && isMedia) {
|
|
7190
|
+
items.push({ label: 'Oynat', fn: () => stVideoPlay(rel) });
|
|
7191
|
+
} else if (studio) {
|
|
7192
|
+
items.push({ label: 'Dış uygulamada aç', fn: () => beast.openPath((studioState.path || '') + '\\' + rel.replace(/\//g, '\\')).catch(() => {}) });
|
|
6909
7193
|
} else {
|
|
6910
7194
|
items.push({ label: 'Aç', fn: () => codeOpen(rel) });
|
|
6911
7195
|
if (isHtml) {
|
|
@@ -6922,13 +7206,17 @@ function fileCtxShow(e, rel, isDir) {
|
|
|
6922
7206
|
label: 'Sil',
|
|
6923
7207
|
danger: true,
|
|
6924
7208
|
fn: async () => {
|
|
6925
|
-
const r =
|
|
7209
|
+
const r = studio
|
|
7210
|
+
? await beast.studioDelete(rel).catch(() => null)
|
|
7211
|
+
: await beast.ideDelete(rel).catch(() => null);
|
|
6926
7212
|
if (r && r.ok) {
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
7213
|
+
if (!studio) {
|
|
7214
|
+
/* silinen dosya/klasörün açık sekmelerini kapat */
|
|
7215
|
+
for (let i = codeTabs.length - 1; i >= 0; i--) {
|
|
7216
|
+
if (codeTabs[i].rel === rel || codeTabs[i].rel.startsWith(rel + '/')) codeClose(i);
|
|
7217
|
+
}
|
|
6930
7218
|
}
|
|
6931
|
-
await
|
|
7219
|
+
await renderFileTree();
|
|
6932
7220
|
} else if (r && !r.canceled && r.error) {
|
|
6933
7221
|
toast(r.error);
|
|
6934
7222
|
}
|
|
@@ -6962,12 +7250,113 @@ if (els.fileCtxMenu) {
|
|
|
6962
7250
|
$('#fileTree').addEventListener('contextmenu', (e) => {
|
|
6963
7251
|
const row = e.target.closest('.file-row');
|
|
6964
7252
|
if (!row || !row.dataset.rel) {
|
|
7253
|
+
/* boş ağaç alanı: hızlı işlemler (mod-farkında) */
|
|
7254
|
+
e.preventDefault();
|
|
6965
7255
|
fileCtxHide();
|
|
7256
|
+
const menu = els.fileCtxMenu;
|
|
7257
|
+
if (!menu) return;
|
|
7258
|
+
const items = [{ label: 'Yenile', fn: () => (studioModeOn() ? loadStudioTree() : loadIdeTree()) }];
|
|
7259
|
+
const pick = document.getElementById('filePick');
|
|
7260
|
+
if (pick) items.push({ label: 'Klasör seç…', fn: () => pick.click() });
|
|
7261
|
+
menu.innerHTML = '';
|
|
7262
|
+
for (const it of items) ctxMenuAppend(menu, it);
|
|
7263
|
+
menu.hidden = false;
|
|
7264
|
+
const mh = items.length * 33 + 8;
|
|
7265
|
+
menu.style.left = Math.max(4, Math.min(e.clientX, window.innerWidth - 170)) + 'px';
|
|
7266
|
+
menu.style.top = Math.max(4, Math.min(e.clientY, window.innerHeight - mh)) + 'px';
|
|
6966
7267
|
return;
|
|
6967
7268
|
}
|
|
6968
7269
|
fileCtxShow(e, row.dataset.rel, row.dataset.dir === '1');
|
|
6969
7270
|
});
|
|
6970
7271
|
|
|
7272
|
+
/* ---------- UYGULAMA GENELİ SAĞ TIK ----------
|
|
7273
|
+
Metin alanlarında (input/textarea): Kes / Kopyala / Yapıştır / Tümünü seç;
|
|
7274
|
+
seçili metinde (sohbet çıktısı vs.): Kopyala. Pano işlemleri pano
|
|
7275
|
+
köprüsüyle (clip:read / clip:write) MANUEL yapılır — Chromium'un
|
|
7276
|
+
execCommand('paste') kısıtı Electron'da da güvenilir değil; imleç
|
|
7277
|
+
konumuna elle eklenir, 'input' olayı tetiklenir (oto-büyüme vs. çalışır).
|
|
7278
|
+
Dosya ağacı kendi menüsünü gösterir (yukarıda). */
|
|
7279
|
+
function isEditableEl(t) {
|
|
7280
|
+
if (!t || !t.tagName) return false;
|
|
7281
|
+
const tag = String(t.tagName).toLowerCase();
|
|
7282
|
+
if (tag === 'input' || tag === 'textarea') return !(t.disabled || t.readOnly);
|
|
7283
|
+
return false;
|
|
7284
|
+
}
|
|
7285
|
+
|
|
7286
|
+
function ctxMenuAppend(menu, it) {
|
|
7287
|
+
const el = document.createElement('div');
|
|
7288
|
+
el.className = 'ctx-item' + (it.danger ? ' danger' : '') + (it.disabled ? ' disabled' : '');
|
|
7289
|
+
el.textContent = it.label;
|
|
7290
|
+
if (!it.disabled) el.addEventListener('click', () => { fileCtxHide(); it.fn(); });
|
|
7291
|
+
menu.appendChild(el);
|
|
7292
|
+
}
|
|
7293
|
+
|
|
7294
|
+
function ctxFieldInputEvent(el) {
|
|
7295
|
+
try { el.dispatchEvent(new Event('input', { bubbles: true })); } catch {}
|
|
7296
|
+
}
|
|
7297
|
+
|
|
7298
|
+
async function ctxFieldOp(el, op) {
|
|
7299
|
+
if (!el) return;
|
|
7300
|
+
el.focus();
|
|
7301
|
+
if (op === 'all') {
|
|
7302
|
+
if (typeof el.select === 'function') el.select();
|
|
7303
|
+
return;
|
|
7304
|
+
}
|
|
7305
|
+
const v = typeof el.value === 'string' ? el.value : '';
|
|
7306
|
+
const start = typeof el.selectionStart === 'number' ? el.selectionStart : v.length;
|
|
7307
|
+
const end = typeof el.selectionEnd === 'number' ? el.selectionEnd : v.length;
|
|
7308
|
+
if (op === 'paste') {
|
|
7309
|
+
const text = String((await beast.clipRead().catch(() => '')) || '');
|
|
7310
|
+
if (!text) return;
|
|
7311
|
+
el.value = v.slice(0, start) + text + v.slice(end);
|
|
7312
|
+
el.setSelectionRange(start + text.length, start + text.length);
|
|
7313
|
+
ctxFieldInputEvent(el);
|
|
7314
|
+
return;
|
|
7315
|
+
}
|
|
7316
|
+
if (op === 'copy' || op === 'cut') {
|
|
7317
|
+
const sel = v.slice(start, end);
|
|
7318
|
+
if (!sel) return;
|
|
7319
|
+
await beast.clipWrite(sel).catch(() => {});
|
|
7320
|
+
if (op === 'cut') {
|
|
7321
|
+
el.value = v.slice(0, start) + v.slice(end);
|
|
7322
|
+
el.setSelectionRange(start, start);
|
|
7323
|
+
ctxFieldInputEvent(el);
|
|
7324
|
+
}
|
|
7325
|
+
}
|
|
7326
|
+
}
|
|
7327
|
+
|
|
7328
|
+
document.addEventListener('contextmenu', (e) => {
|
|
7329
|
+
/* dosya ağacı kendi menüsünü kendisi açar */
|
|
7330
|
+
if (e.target && e.target.closest && e.target.closest('#fileTree')) return;
|
|
7331
|
+
fileCtxHide();
|
|
7332
|
+
const field = isEditableEl(e.target) ? e.target : (isEditableEl(document.activeElement) ? document.activeElement : null);
|
|
7333
|
+
const selText = String((window.getSelection && window.getSelection()) || '');
|
|
7334
|
+
const hasSel = field && typeof field.selectionStart === 'number'
|
|
7335
|
+
? field.selectionEnd > field.selectionStart
|
|
7336
|
+
: !!selText.trim();
|
|
7337
|
+
if (!field && !hasSel) return; /* boş alan — menü yok */
|
|
7338
|
+
e.preventDefault();
|
|
7339
|
+
const menu = els.fileCtxMenu;
|
|
7340
|
+
if (!menu) return;
|
|
7341
|
+
const items = [];
|
|
7342
|
+
if (field) items.push({ label: 'Kes', disabled: !hasSel, fn: () => ctxFieldOp(field, 'cut') });
|
|
7343
|
+
items.push({
|
|
7344
|
+
label: 'Kopyala',
|
|
7345
|
+
disabled: !hasSel,
|
|
7346
|
+
fn: () => (field ? ctxFieldOp(field, 'copy') : beast.clipWrite(selText).catch(() => {})),
|
|
7347
|
+
});
|
|
7348
|
+
if (field) {
|
|
7349
|
+
items.push({ label: 'Yapıştır', fn: () => ctxFieldOp(field, 'paste') });
|
|
7350
|
+
items.push({ label: 'Tümünü seç', fn: () => ctxFieldOp(field, 'all') });
|
|
7351
|
+
}
|
|
7352
|
+
menu.innerHTML = '';
|
|
7353
|
+
for (const it of items) ctxMenuAppend(menu, it);
|
|
7354
|
+
menu.hidden = false;
|
|
7355
|
+
const mh = items.length * 33 + 8;
|
|
7356
|
+
menu.style.left = Math.max(4, Math.min(e.clientX, window.innerWidth - 170)) + 'px';
|
|
7357
|
+
menu.style.top = Math.max(4, Math.min(e.clientY, window.innerHeight - mh)) + 'px';
|
|
7358
|
+
});
|
|
7359
|
+
|
|
6971
7360
|
/* ---------- IDE modu ortası: BEAST CODE paneli ----------
|
|
6972
7361
|
Sohbet yerine Beast'in kendi ajanı (varsayılan model) çalışır;
|
|
6973
7362
|
soldaki dosya panelindeki klasörü workspace olarak kullanır.
|
|
@@ -7457,5 +7846,399 @@ if (els.bcNew) els.bcNew.addEventListener('click', async () => {
|
|
|
7457
7846
|
bcLine('t-sys', 'yeni oturum — sonraki mesaj taze başlar');
|
|
7458
7847
|
}
|
|
7459
7848
|
});
|
|
7849
|
+
|
|
7850
|
+
/* ---------- BEAST STUDIO paneli ----------
|
|
7851
|
+
Beast Code panelinin birebir karşılığı — AMA ayrı oturum, ayrı kuyruk,
|
|
7852
|
+
ayrı çıktı. Olaylar stSessionId ile eşlenir; Beast Code sohbetine ve ana
|
|
7853
|
+
chate ASLA sızmaz. Ajan buildStudioSystem ile açılır: video yapma/düzenleme. */
|
|
7854
|
+
|
|
7855
|
+
const ST_MAX_LINES = 1200;
|
|
7856
|
+
let stSessionId = null;
|
|
7857
|
+
let stRunning = false;
|
|
7858
|
+
let stBannerDone = false;
|
|
7859
|
+
let stStreamEl = null;
|
|
7860
|
+
let stStreamRaw = '';
|
|
7861
|
+
let stWsPath = '';
|
|
7862
|
+
const stTools = new Map(); /* callId → { box, sec } */
|
|
7863
|
+
let stCurBox = null;
|
|
7864
|
+
let stNoteEl = null;
|
|
7865
|
+
let stNoteRaw = '';
|
|
7866
|
+
|
|
7867
|
+
function stScroll() {
|
|
7868
|
+
const b = els.stOut;
|
|
7869
|
+
if (!b) return;
|
|
7870
|
+
b.scrollTop = b.scrollHeight;
|
|
7871
|
+
}
|
|
7872
|
+
|
|
7873
|
+
function stBodyScroll(el) {
|
|
7874
|
+
const b = el && el.closest ? el.closest('.bc-toolbody') : null;
|
|
7875
|
+
if (b) b.scrollTop = b.scrollHeight;
|
|
7876
|
+
}
|
|
7877
|
+
|
|
7878
|
+
function stLine(cls, text, time = false) {
|
|
7879
|
+
if (!els.stOut) return;
|
|
7880
|
+
const el = document.createElement('div');
|
|
7881
|
+
el.className = 't-line ' + (cls || '');
|
|
7882
|
+
const ts = time ? '<span class="t-time">' + new Date().toTimeString().slice(0, 8) + '</span> ' : '';
|
|
7883
|
+
el.innerHTML = ts + escapeHtml(String(text ?? ''));
|
|
7884
|
+
els.stOut.appendChild(el);
|
|
7885
|
+
while (els.stOut.childElementCount > ST_MAX_LINES) els.stOut.removeChild(els.stOut.firstChild);
|
|
7886
|
+
stScroll();
|
|
7887
|
+
}
|
|
7888
|
+
|
|
7889
|
+
function stBanner() {
|
|
7890
|
+
if (stBannerDone) return;
|
|
7891
|
+
stBannerDone = true;
|
|
7892
|
+
const cwd = studioState.path || '';
|
|
7893
|
+
if (els.stCwd && cwd) { els.stCwd.textContent = cwd; els.stCwd.title = cwd; }
|
|
7894
|
+
stLine('t-sys', 'BEAST STUDIO — stüdyo klasörü: ' + (cwd || '?'));
|
|
7895
|
+
stLine('t-dim', 'Video yapma/düzenleme ajanı: montaj, kesme, altyazı, ses, format — ffmpeg ile üretir, çıktılar "output" klasörüne düşer. + yeni oturum · Temizle çıktıyı siler.', false);
|
|
7896
|
+
}
|
|
7897
|
+
|
|
7898
|
+
/* Klasör değişimi → panel taze başlar (oturum main'de klasör bazlı saklanır) */
|
|
7899
|
+
function stOnFolderChanged(p) {
|
|
7900
|
+
if (!p || stWsPath === p) return;
|
|
7901
|
+
const first = !stWsPath;
|
|
7902
|
+
stWsPath = p;
|
|
7903
|
+
if (first) return; /* ilk yükleme — panel zaten boş, banner setStudioMode'da basılır */
|
|
7904
|
+
if (els.stOut) els.stOut.innerHTML = '';
|
|
7905
|
+
stTools.clear();
|
|
7906
|
+
stCloseToolGroup();
|
|
7907
|
+
stHideTodos();
|
|
7908
|
+
stStreamEl = null;
|
|
7909
|
+
stStreamRaw = '';
|
|
7910
|
+
stBannerDone = false;
|
|
7911
|
+
stBanner();
|
|
7912
|
+
}
|
|
7913
|
+
|
|
7914
|
+
function stSetBusy(v) {
|
|
7915
|
+
stRunning = !!v;
|
|
7916
|
+
if (els.stStop) els.stStop.hidden = !v;
|
|
7917
|
+
}
|
|
7918
|
+
|
|
7919
|
+
function stFlushStream() {
|
|
7920
|
+
stStreamEl = null;
|
|
7921
|
+
stStreamRaw = '';
|
|
7922
|
+
}
|
|
7923
|
+
|
|
7924
|
+
function stStreamDelta(delta) {
|
|
7925
|
+
if (!els.stOut) return;
|
|
7926
|
+
if (!stStreamEl) {
|
|
7927
|
+
stStreamEl = document.createElement('div');
|
|
7928
|
+
stStreamEl.className = 't-line t-out';
|
|
7929
|
+
els.stOut.appendChild(stStreamEl);
|
|
7930
|
+
}
|
|
7931
|
+
stStreamRaw += String(delta || '');
|
|
7932
|
+
stStreamEl.textContent = stStreamRaw.slice(-4000);
|
|
7933
|
+
stScroll(true);
|
|
7934
|
+
}
|
|
7935
|
+
|
|
7936
|
+
function stStatusShow(text) {
|
|
7937
|
+
if (!els.stStatus) return;
|
|
7938
|
+
const t = String(text || '').trim();
|
|
7939
|
+
if (!t) return;
|
|
7940
|
+
els.stStatus.textContent = t;
|
|
7941
|
+
els.stStatus.hidden = false;
|
|
7942
|
+
}
|
|
7943
|
+
|
|
7944
|
+
function stStatusHide() {
|
|
7945
|
+
if (els.stStatus) els.stStatus.hidden = true;
|
|
7946
|
+
}
|
|
7947
|
+
|
|
7948
|
+
function stNoteDetach() {
|
|
7949
|
+
stNoteEl = null;
|
|
7950
|
+
stNoteRaw = '';
|
|
7951
|
+
}
|
|
7952
|
+
|
|
7953
|
+
function stCloseToolGroup() {
|
|
7954
|
+
if (stCurBox) stCurBox.classList.remove('running');
|
|
7955
|
+
stCurBox = null;
|
|
7956
|
+
stNoteDetach();
|
|
7957
|
+
}
|
|
7958
|
+
|
|
7959
|
+
function stToolGroupNew() {
|
|
7960
|
+
const box = document.createElement('div');
|
|
7961
|
+
box.className = 'bc-toolbox';
|
|
7962
|
+
const body = document.createElement('div');
|
|
7963
|
+
body.className = 'bc-toolbody';
|
|
7964
|
+
box.appendChild(body);
|
|
7965
|
+
els.stOut.appendChild(box);
|
|
7966
|
+
while (els.stOut.childElementCount > ST_MAX_LINES) els.stOut.removeChild(els.stOut.firstChild);
|
|
7967
|
+
return box;
|
|
7968
|
+
}
|
|
7969
|
+
|
|
7970
|
+
function stToolBoxStart(callId, name, args) {
|
|
7971
|
+
stFlushStream();
|
|
7972
|
+
if (!stCurBox) stCurBox = stToolGroupNew();
|
|
7973
|
+
const sec = document.createElement('div');
|
|
7974
|
+
sec.className = 'bc-toolsection';
|
|
7975
|
+
const short = termShortTool(name, args);
|
|
7976
|
+
sec.innerHTML =
|
|
7977
|
+
'<div class="bc-toolhead">' +
|
|
7978
|
+
'<span class="bc-toolspin"></span>' +
|
|
7979
|
+
'<span class="bc-toolname">▸ ' + escapeHtml(String(name || 'araç')) + '</span>' +
|
|
7980
|
+
(short ? '<span class="bc-toolar" title="' + escapeHtml(short) + '">' + escapeHtml(short) + '</span>' : '') +
|
|
7981
|
+
'</div>' +
|
|
7982
|
+
'<div class="bc-toolout" hidden></div>';
|
|
7983
|
+
stCurBox.classList.add('running');
|
|
7984
|
+
const body = stCurBox.querySelector('.bc-toolbody') || stCurBox;
|
|
7985
|
+
body.appendChild(sec);
|
|
7986
|
+
if (callId) stTools.set(callId, { box: stCurBox, sec });
|
|
7987
|
+
stScroll();
|
|
7988
|
+
stBodyScroll(body);
|
|
7989
|
+
}
|
|
7990
|
+
|
|
7991
|
+
function stToolBoxEnd(callId, ok, result, diff) {
|
|
7992
|
+
stFlushStream();
|
|
7993
|
+
const t = (callId && stTools.get(callId)) || null;
|
|
7994
|
+
if (callId) stTools.delete(callId);
|
|
7995
|
+
const out = String(result || '').replace(/\s+$/, '');
|
|
7996
|
+
if (t) {
|
|
7997
|
+
const { sec } = t;
|
|
7998
|
+
sec.classList.add('done');
|
|
7999
|
+
if (!ok) sec.classList.add('failed');
|
|
8000
|
+
if (!t.box.querySelector('.bc-toolsection:not(.done)')) {
|
|
8001
|
+
t.box.classList.remove('running');
|
|
8002
|
+
}
|
|
8003
|
+
const pre = sec.querySelector('.bc-toolout');
|
|
8004
|
+
if (diff && diff.path) {
|
|
8005
|
+
const headEl = sec.querySelector('.bc-toolhead');
|
|
8006
|
+
if (headEl && !headEl.querySelector('.diff-badge')) {
|
|
8007
|
+
const badge = document.createElement('span');
|
|
8008
|
+
badge.className = 'diff-badge';
|
|
8009
|
+
const a = document.createElement('span');
|
|
8010
|
+
a.className = 'diff-badge-add';
|
|
8011
|
+
a.textContent = '+' + (diff.additions || 0);
|
|
8012
|
+
const d = document.createElement('span');
|
|
8013
|
+
d.className = 'diff-badge-del';
|
|
8014
|
+
d.textContent = '−' + (diff.deletions || 0);
|
|
8015
|
+
badge.appendChild(a);
|
|
8016
|
+
badge.appendChild(d);
|
|
8017
|
+
headEl.appendChild(badge);
|
|
8018
|
+
}
|
|
8019
|
+
pre.hidden = false;
|
|
8020
|
+
pre.textContent = '';
|
|
8021
|
+
pre.classList.add('bc-diffview');
|
|
8022
|
+
pre.appendChild(buildDiffEl(diff, pre.clientWidth || 480));
|
|
8023
|
+
} else if (out) {
|
|
8024
|
+
pre.hidden = false;
|
|
8025
|
+
pre.textContent = out.length > 4000 ? out.slice(0, 4000) + '\n… (kesildi)' : out;
|
|
8026
|
+
} else {
|
|
8027
|
+
pre.remove();
|
|
8028
|
+
}
|
|
8029
|
+
stBodyScroll(sec);
|
|
8030
|
+
} else if (out || !ok) {
|
|
8031
|
+
stLine(ok ? 't-out' : 't-err', out ? (out.length > 400 ? out.slice(0, 400) + ' …(kesildi)' : out) : '(hata)');
|
|
8032
|
+
}
|
|
8033
|
+
stScroll();
|
|
8034
|
+
}
|
|
8035
|
+
|
|
8036
|
+
/* Ara yazı → açık grup varsa kutu İÇİNE not olarak akar */
|
|
8037
|
+
function stNoteStream(delta) {
|
|
8038
|
+
if (!stCurBox) return false;
|
|
8039
|
+
if (!stNoteEl) {
|
|
8040
|
+
stNoteEl = document.createElement('div');
|
|
8041
|
+
stNoteEl.className = 'bc-toolnote';
|
|
8042
|
+
const body = stCurBox.querySelector('.bc-toolbody') || stCurBox;
|
|
8043
|
+
body.appendChild(stNoteEl);
|
|
8044
|
+
}
|
|
8045
|
+
stNoteRaw += String(delta || '');
|
|
8046
|
+
stNoteEl.textContent = stNoteRaw.slice(-2000);
|
|
8047
|
+
stScroll(true);
|
|
8048
|
+
stBodyScroll(stNoteEl);
|
|
8049
|
+
return true;
|
|
8050
|
+
}
|
|
8051
|
+
|
|
8052
|
+
function stRenderTodos(todos) {
|
|
8053
|
+
const list = Array.isArray(todos) ? todos : [];
|
|
8054
|
+
if (!els.stTodoWrap) return;
|
|
8055
|
+
stFlushStream();
|
|
8056
|
+
if (!list.length) {
|
|
8057
|
+
stHideTodos();
|
|
8058
|
+
return;
|
|
8059
|
+
}
|
|
8060
|
+
els.stTodoWrap.hidden = false;
|
|
8061
|
+
els.stTodoWrap.innerHTML =
|
|
8062
|
+
'<div class="bc-todobox">' +
|
|
8063
|
+
'<div class="bc-todotitle"><span>GÖREVLER</span><span class="bc-todocount"></span></div>' +
|
|
8064
|
+
'<div class="bc-todoitems"></div>';
|
|
8065
|
+
const done = list.filter((t) => t.status === 'done').length;
|
|
8066
|
+
els.stTodoWrap.querySelector('.bc-todocount').textContent = done + '/' + list.length;
|
|
8067
|
+
const wrap = els.stTodoWrap.querySelector('.bc-todoitems');
|
|
8068
|
+
wrap.innerHTML = '';
|
|
8069
|
+
for (const t of list) {
|
|
8070
|
+
const st = TODO_GLYPH[t.status] ? t.status : 'pending';
|
|
8071
|
+
const row = document.createElement('div');
|
|
8072
|
+
row.className = 'bc-todoitem ' + st;
|
|
8073
|
+
row.innerHTML =
|
|
8074
|
+
'<span class="bc-todocheck">' + TODO_GLYPH[st] + '</span>' +
|
|
8075
|
+
'<span class="bc-todotext"></span>';
|
|
8076
|
+
row.querySelector('.bc-todotext').textContent = String(t.title || '');
|
|
8077
|
+
wrap.appendChild(row);
|
|
8078
|
+
}
|
|
8079
|
+
}
|
|
8080
|
+
|
|
8081
|
+
function stHideTodos() {
|
|
8082
|
+
if (els.stTodoWrap) {
|
|
8083
|
+
els.stTodoWrap.hidden = true;
|
|
8084
|
+
els.stTodoWrap.innerHTML = '';
|
|
8085
|
+
}
|
|
8086
|
+
}
|
|
8087
|
+
|
|
8088
|
+
/* Studio oturumunun engine olayları → panel çıktısı (bcIngest'in karşılığı) */
|
|
8089
|
+
function stIngest(ev) {
|
|
8090
|
+
switch (ev.type) {
|
|
8091
|
+
case 'token':
|
|
8092
|
+
if (stNoteStream(ev.delta)) break;
|
|
8093
|
+
stStreamDelta(ev.delta);
|
|
8094
|
+
break;
|
|
8095
|
+
case 'message':
|
|
8096
|
+
if (ev.message && ev.message.role === 'assistant') {
|
|
8097
|
+
const content = typeof ev.message.content === 'string' ? ev.message.content : '';
|
|
8098
|
+
const hasTools = Array.isArray(ev.message.tool_calls) && ev.message.tool_calls.length > 0;
|
|
8099
|
+
if (hasTools) {
|
|
8100
|
+
stNoteDetach();
|
|
8101
|
+
stFlushStream();
|
|
8102
|
+
break;
|
|
8103
|
+
}
|
|
8104
|
+
if (stNoteEl) { stNoteEl.remove(); stNoteDetach(); }
|
|
8105
|
+
if (content && !stStreamRaw.trim()) stLine('t-out', content);
|
|
8106
|
+
stCloseToolGroup();
|
|
8107
|
+
stFlushStream();
|
|
8108
|
+
}
|
|
8109
|
+
break;
|
|
8110
|
+
case 'todos':
|
|
8111
|
+
stRenderTodos(ev.todos);
|
|
8112
|
+
break;
|
|
8113
|
+
case 'tool-start':
|
|
8114
|
+
stSetBusy(true);
|
|
8115
|
+
stToolBoxStart(ev.callId, ev.name, ev.args);
|
|
8116
|
+
break;
|
|
8117
|
+
case 'tool-end':
|
|
8118
|
+
stToolBoxEnd(ev.callId, ev.ok, ev.result, ev.diff);
|
|
8119
|
+
if (ev.name === 'write_file' || ev.name === 'edit_file' || ev.name === 'run_command' || ev.name === 'python_run') {
|
|
8120
|
+
ideRefreshTree(); /* ffmpeg çıktısı anında ağaca düşer */
|
|
8121
|
+
}
|
|
8122
|
+
break;
|
|
8123
|
+
case 'st-mode':
|
|
8124
|
+
if (els.stTitle) {
|
|
8125
|
+
els.stTitle.textContent =
|
|
8126
|
+
ev.mode === 'plan' ? 'BEAST STUDIO · PLAN' :
|
|
8127
|
+
ev.mode === 'build' ? 'BEAST STUDIO · BUILD' : 'BEAST STUDIO';
|
|
8128
|
+
}
|
|
8129
|
+
stLine('t-dim', '[' + (ev.body || ev.mode || 'mod değişti') + ']');
|
|
8130
|
+
break;
|
|
8131
|
+
case 'done':
|
|
8132
|
+
stFlushStream();
|
|
8133
|
+
stCloseToolGroup();
|
|
8134
|
+
stSetBusy(false);
|
|
8135
|
+
stStatusHide();
|
|
8136
|
+
stLine(ev.aborted ? 't-err' : 't-dim', ev.aborted ? '[durduruldu — sebep: ' + (ev.reason || 'sebep belirtilmedi') + ']' : '(tamamlandı)');
|
|
8137
|
+
ideRefreshTree();
|
|
8138
|
+
if (studioModeOn() && els.stInput) els.stInput.focus();
|
|
8139
|
+
break;
|
|
8140
|
+
case 'error':
|
|
8141
|
+
stFlushStream();
|
|
8142
|
+
stCloseToolGroup();
|
|
8143
|
+
stSetBusy(false);
|
|
8144
|
+
stStatusHide();
|
|
8145
|
+
stLine('t-err', '[hata] ' + (ev.error || ''));
|
|
8146
|
+
break;
|
|
8147
|
+
case 'status':
|
|
8148
|
+
if (ev.status === 'idle') {
|
|
8149
|
+
stCloseToolGroup();
|
|
8150
|
+
stSetBusy(false);
|
|
8151
|
+
stStatusHide();
|
|
8152
|
+
} else {
|
|
8153
|
+
stSetBusy(true);
|
|
8154
|
+
stStatusShow(ev.status === 'thinking' ? 'düşünüyor…' : String(ev.status || ''));
|
|
8155
|
+
}
|
|
8156
|
+
break;
|
|
8157
|
+
}
|
|
8158
|
+
}
|
|
8159
|
+
|
|
8160
|
+
function stInputResize() {
|
|
8161
|
+
const ta = els.stInput;
|
|
8162
|
+
if (!ta) return;
|
|
8163
|
+
ta.style.height = 'auto';
|
|
8164
|
+
const max = 140;
|
|
8165
|
+
const h = Math.min(ta.scrollHeight, max);
|
|
8166
|
+
ta.style.height = h + 'px';
|
|
8167
|
+
ta.classList.toggle('expand', ta.scrollHeight > max);
|
|
8168
|
+
}
|
|
8169
|
+
|
|
8170
|
+
function stRunCurrent() {
|
|
8171
|
+
const msg = els.stInput.value.trim();
|
|
8172
|
+
if (!msg && !stPending.length) return;
|
|
8173
|
+
const atts = stPending.slice();
|
|
8174
|
+
stPending = [];
|
|
8175
|
+
renderStChips();
|
|
8176
|
+
els.stInput.value = '';
|
|
8177
|
+
stInputResize();
|
|
8178
|
+
els.stInput.focus();
|
|
8179
|
+
stLine('t-cmd', 'studio> ' + (msg || (atts.length ? '[' + atts.length + ' ek]' : '')));
|
|
8180
|
+
stHideTodos();
|
|
8181
|
+
stSetBusy(true);
|
|
8182
|
+
beast.studioSend(msg || '[dosya ekleri]', atts).then((r) => {
|
|
8183
|
+
if (r && r.ok && r.mode) {
|
|
8184
|
+
if (r.sessionId) stSessionId = r.sessionId;
|
|
8185
|
+
stSetBusy(false);
|
|
8186
|
+
} else if (r && r.ok && r.queued) {
|
|
8187
|
+
if (r.sessionId) stSessionId = r.sessionId;
|
|
8188
|
+
stLine('t-dim', '⏳ kuyrukta (' + r.count + ') — iş bitince gönderilir');
|
|
8189
|
+
} else if (r && r.ok && r.pending) {
|
|
8190
|
+
if (r.sessionId) stSessionId = r.sessionId;
|
|
8191
|
+
} else if (r && r.ok) {
|
|
8192
|
+
if (r.sessionId) stSessionId = r.sessionId;
|
|
8193
|
+
} else if (r && r.busy) {
|
|
8194
|
+
stLine('t-dim', (r && r.error) || 'mesaj sürüyor');
|
|
8195
|
+
} else {
|
|
8196
|
+
stSetBusy(false);
|
|
8197
|
+
stLine('t-err', (r && r.error) || 'gönderilemedi');
|
|
8198
|
+
}
|
|
8199
|
+
}).catch((e) => {
|
|
8200
|
+
stSetBusy(false);
|
|
8201
|
+
stLine('t-err', String((e && e.message) || e));
|
|
8202
|
+
});
|
|
8203
|
+
}
|
|
8204
|
+
|
|
8205
|
+
if (els.stInput) {
|
|
8206
|
+
els.stInput.addEventListener('input', stInputResize);
|
|
8207
|
+
els.stInput.addEventListener('keydown', (e) => {
|
|
8208
|
+
if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); stRunCurrent(); }
|
|
8209
|
+
});
|
|
8210
|
+
}
|
|
8211
|
+
if (els.stStop) els.stStop.addEventListener('click', () => {
|
|
8212
|
+
stPending = [];
|
|
8213
|
+
renderStChips();
|
|
8214
|
+
beast.studioStop().then((r) => {
|
|
8215
|
+
if (r && r.ok && r.wasBusy === false) {
|
|
8216
|
+
stSetBusy(false);
|
|
8217
|
+
stStatusHide();
|
|
8218
|
+
}
|
|
8219
|
+
}).catch(() => {});
|
|
8220
|
+
});
|
|
8221
|
+
if (els.stClear) els.stClear.addEventListener('click', () => {
|
|
8222
|
+
els.stOut.innerHTML = '';
|
|
8223
|
+
stTools.clear();
|
|
8224
|
+
stCloseToolGroup();
|
|
8225
|
+
stHideTodos();
|
|
8226
|
+
stFlushStream();
|
|
8227
|
+
});
|
|
8228
|
+
if (els.stNew) els.stNew.addEventListener('click', async () => {
|
|
8229
|
+
if (stRunning) { toast('Mesaj sürüyor — önce ■ ile durdur'); return; }
|
|
8230
|
+
const r = await beast.studioNew().catch(() => null);
|
|
8231
|
+
if (r && r.ok) {
|
|
8232
|
+
stSessionId = null;
|
|
8233
|
+
stPending = [];
|
|
8234
|
+
renderStChips();
|
|
8235
|
+
stTools.clear();
|
|
8236
|
+
stCloseToolGroup();
|
|
8237
|
+
stHideTodos();
|
|
8238
|
+
stFlushStream();
|
|
8239
|
+
if (els.stTitle) els.stTitle.textContent = 'BEAST STUDIO';
|
|
8240
|
+
stLine('t-sys', 'yeni oturum — sonraki mesaj taze başlar');
|
|
8241
|
+
}
|
|
8242
|
+
});
|
|
7460
8243
|
/* Uygulama her açılışta agent (chat) modunda başlar — IDE modu yalnız
|
|
7461
8244
|
kullanıcı butona basınca girilir (oturumluk). */
|