beast-agent 1.8.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 -128
- 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 +85 -11
- 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 -0
- 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 -651
- 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 +385 -6
- package/src/preload.js +13 -0
- package/src/renderer/browserPreload.js +73 -73
- package/src/renderer/i18n.js +38 -0
- package/src/renderer/index.html +448 -407
- package/src/renderer/renderer.js +897 -42
- package/src/renderer/style.css +275 -11
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);
|
|
@@ -1013,6 +1060,7 @@ async function renderActiveSettingsTab() {
|
|
|
1013
1060
|
case 'email': await renderEmailPane(); break;
|
|
1014
1061
|
case 'integrations': await renderIntegrationsPane(); break;
|
|
1015
1062
|
case 'websearch': await renderWebSearchPane(); break;
|
|
1063
|
+
case 'mcp': await renderMcpPane(); break;
|
|
1016
1064
|
case 'events': await renderEventsPane(); break;
|
|
1017
1065
|
case 'cron': await openCron(); break;
|
|
1018
1066
|
case 'usage': await renderUsagePane(); break;
|
|
@@ -1024,12 +1072,82 @@ async function renderActiveSettingsTab() {
|
|
|
1024
1072
|
}
|
|
1025
1073
|
}
|
|
1026
1074
|
|
|
1075
|
+
async function renderMcpPane() {
|
|
1076
|
+
const pane = $('#tab-mcp');
|
|
1077
|
+
if (!pane) return;
|
|
1078
|
+
const st = await beast.mcpStatus().catch(() => ({ path: '', servers: [] }));
|
|
1079
|
+
const cfg = await beast.mcpConfigGet().catch(() => ({ path: '', raw: '' }));
|
|
1080
|
+
const stateT = (s) => _t('mcp_state_' + s) || String(s || '').toUpperCase();
|
|
1081
|
+
let rows = '';
|
|
1082
|
+
if (!(st.servers || []).length) {
|
|
1083
|
+
rows = '<div class="sub">' + _t('mcp_none') + '</div>';
|
|
1084
|
+
}
|
|
1085
|
+
for (const s of st.servers || []) {
|
|
1086
|
+
rows +=
|
|
1087
|
+
'<div style="display:flex;align-items:center;gap:8px;padding:8px;border:1px solid var(--border);border-radius:8px;margin-bottom:6px;flex-wrap:wrap">' +
|
|
1088
|
+
'<span style="font-weight:600">' + escapeHtml(s.name) + '</span>' +
|
|
1089
|
+
'<span class="sub" style="margin:0;max-width:40%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + escapeHtml(s.command + ' ' + (s.args || []).join(' ')) + '</span>' +
|
|
1090
|
+
'<span style="color:var(--muted);font-size:12px">' + stateT(s.state) + (s.enabled && s.toolCount ? ' · ' + s.toolCount + ' ' + _t('mcp_tool_count') : '') + '</span>' +
|
|
1091
|
+
(s.lastError && s.state === 'down' ? '<span class="sub" style="color:#e06c75;margin:0;max-width:30%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + escapeHtml(s.lastError.slice(0, 90)) + '</span>' : '') +
|
|
1092
|
+
'<span style="flex:1"></span>' +
|
|
1093
|
+
'<button class="btn mcp-tgl" data-n="' + escapeHtml(s.name) + '" style="width:auto;padding:2px 10px">' + (s.enabled ? '⏸' : '▶') + '</button>' +
|
|
1094
|
+
'<button class="btn ghost mcp-ref" data-n="' + escapeHtml(s.name) + '" style="width:auto;padding:2px 10px">' + _t('mcp_refresh') + '</button>' +
|
|
1095
|
+
'</div>';
|
|
1096
|
+
}
|
|
1097
|
+
pane.innerHTML =
|
|
1098
|
+
'<h2>' + _t('mcp_h2') + '</h2>' +
|
|
1099
|
+
'<div class="sub">' + _t('mcp_sub') + '</div>' +
|
|
1100
|
+
'<div id="mcpList" style="margin-top:10px">' + rows + '</div>' +
|
|
1101
|
+
'<div class="divider"></div>' +
|
|
1102
|
+
'<h2>' + _t('mcp_json_h2') + '</h2>' +
|
|
1103
|
+
'<div class="sub">' + _t('mcp_json_sub') + '</div>' +
|
|
1104
|
+
'<textarea id="mcpJson" class="inp" rows="10" spellcheck="false" style="margin-top:8px;font-family:monospace;font-size:12px"></textarea>' +
|
|
1105
|
+
'<div style="display:flex;gap:8px;margin-top:8px">' +
|
|
1106
|
+
'<button id="mcpSave" class="btn">' + _t('mcp_save') + '</button>' +
|
|
1107
|
+
'<span id="mcpMsg" class="sub" style="margin:0;align-self:center"></span></div>';
|
|
1108
|
+
const box = $('#mcpJson');
|
|
1109
|
+
box.value = cfg.raw || JSON.stringify({ servers: {} }, null, 2);
|
|
1110
|
+
$('#mcpSave').addEventListener('click', async () => {
|
|
1111
|
+
const msg = $('#mcpMsg');
|
|
1112
|
+
const r = await beast.mcpConfigSet(box.value).catch(() => ({ ok: false, error: 'IPC' }));
|
|
1113
|
+
if (r && r.ok) {
|
|
1114
|
+
msg.textContent = _t('mcp_saved');
|
|
1115
|
+
msg.style.color = '';
|
|
1116
|
+
renderMcpPane();
|
|
1117
|
+
} else {
|
|
1118
|
+
msg.textContent = _t('mcp_save_err') + ((r && r.error) || '?');
|
|
1119
|
+
msg.style.color = '#e06c75';
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
1122
|
+
pane.querySelectorAll('.mcp-ref').forEach((b) =>
|
|
1123
|
+
b.addEventListener('click', async () => {
|
|
1124
|
+
b.disabled = true;
|
|
1125
|
+
await beast.mcpRefresh(b.dataset.n).catch(() => {});
|
|
1126
|
+
renderMcpPane();
|
|
1127
|
+
})
|
|
1128
|
+
);
|
|
1129
|
+
pane.querySelectorAll('.mcp-tgl').forEach((b) =>
|
|
1130
|
+
b.addEventListener('click', async () => {
|
|
1131
|
+
b.disabled = true;
|
|
1132
|
+
try {
|
|
1133
|
+
const obj = JSON.parse(box.value || '{}');
|
|
1134
|
+
const name = b.dataset.n;
|
|
1135
|
+
if (obj.servers && obj.servers[name]) {
|
|
1136
|
+
obj.servers[name].enabled = obj.servers[name].enabled === false;
|
|
1137
|
+
await beast.mcpConfigSet(JSON.stringify(obj));
|
|
1138
|
+
}
|
|
1139
|
+
} catch {}
|
|
1140
|
+
renderMcpPane();
|
|
1141
|
+
})
|
|
1142
|
+
);
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1027
1145
|
function switchTab(name) {
|
|
1028
1146
|
setTab = name;
|
|
1029
1147
|
document.querySelectorAll('#setTabs .tab').forEach((b) =>
|
|
1030
1148
|
b.classList.toggle('active', b.dataset.tab === name)
|
|
1031
1149
|
);
|
|
1032
|
-
for (const p of ['lang', 'provider', 'fallout', 'skills', 'agents', 'tts', 'email', 'integrations', 'websearch', 'events', 'cron', 'usage', 'logs', 'dash', 'sec', 'update']) {
|
|
1150
|
+
for (const p of ['lang', 'provider', 'fallout', 'skills', 'agents', 'tts', 'email', 'integrations', 'websearch', 'mcp', 'events', 'cron', 'usage', 'logs', 'dash', 'sec', 'update']) {
|
|
1033
1151
|
const el = $('#tab-' + p);
|
|
1034
1152
|
if (el) el.hidden = p !== name; // guard: eksik pane tüm sekmeleri kilitlemesin
|
|
1035
1153
|
}
|
|
@@ -1043,6 +1161,7 @@ function switchTab(name) {
|
|
|
1043
1161
|
if (name === 'update') renderUpdatePane(true);
|
|
1044
1162
|
if (name === 'agents') refreshAgentsPane();
|
|
1045
1163
|
if (name === 'websearch') renderWebSearchPane();
|
|
1164
|
+
if (name === 'mcp') renderMcpPane();
|
|
1046
1165
|
/* Fallout: her açılışta güncel provider zincirini çek */
|
|
1047
1166
|
if (name === 'fallout') refreshFalloutPane();
|
|
1048
1167
|
}
|
|
@@ -4173,6 +4292,12 @@ function renderAgentsPane() {
|
|
|
4173
4292
|
function onEvent(ev) {
|
|
4174
4293
|
if (ev.type === 'sessions') { refreshSessions(); return; }
|
|
4175
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
|
+
}
|
|
4176
4301
|
/* Beast Code oturumunun onayı: panelde ipucu + kart sohbete düşer */
|
|
4177
4302
|
if (bcSessionId && ev.sessionId === bcSessionId) {
|
|
4178
4303
|
showApprovalCard(ev);
|
|
@@ -4198,6 +4323,12 @@ function onEvent(ev) {
|
|
|
4198
4323
|
}
|
|
4199
4324
|
/* OFFLINE MESAJ KUYRUĞU: bağlantı + kuyruk olayları (sessionId filtresinden önce) */
|
|
4200
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
|
+
}
|
|
4201
4332
|
/* Beast Code oturumu (IDE modu ortasındaki panel): olayları panele akıt,
|
|
4202
4333
|
ana sohbeti kirletme */
|
|
4203
4334
|
if (bcSessionId && ev.sessionId === bcSessionId) {
|
|
@@ -5137,12 +5268,15 @@ async function init() {
|
|
|
5137
5268
|
document.addEventListener('langchange', syncSttLang);
|
|
5138
5269
|
}
|
|
5139
5270
|
|
|
5140
|
-
/* + butonu
|
|
5271
|
+
/* + butonu üç hedefe hizmet eder: chat composer, Beast Code VE Beast Studio */
|
|
5141
5272
|
let fileSink = 'chat';
|
|
5142
5273
|
els.attachBtn.addEventListener('click', () => { fileSink = 'chat'; els.fileInput.click(); });
|
|
5143
5274
|
if (els.bcAttach) {
|
|
5144
5275
|
els.bcAttach.addEventListener('click', () => { fileSink = 'bc'; els.fileInput.click(); });
|
|
5145
5276
|
}
|
|
5277
|
+
if (els.stAttach) {
|
|
5278
|
+
els.stAttach.addEventListener('click', () => { fileSink = 'st'; els.fileInput.click(); });
|
|
5279
|
+
}
|
|
5146
5280
|
els.fileInput.addEventListener('change', () => {
|
|
5147
5281
|
addFiles([...els.fileInput.files], fileSink);
|
|
5148
5282
|
els.fileInput.value = '';
|
|
@@ -5204,6 +5338,12 @@ async function init() {
|
|
|
5204
5338
|
els.bcInput.focus();
|
|
5205
5339
|
bcInputResize();
|
|
5206
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
|
+
});
|
|
5207
5347
|
|
|
5208
5348
|
beast.onWaEvent(onWaEvent);
|
|
5209
5349
|
beast.onTgEvent(onTgEvent);
|
|
@@ -6072,13 +6212,27 @@ $('#ghAllRefresh').addEventListener('click', () => {
|
|
|
6072
6212
|
Dosyaya tıkla → editör; klasöre tıkla → aç/kapa. */
|
|
6073
6213
|
|
|
6074
6214
|
const IDE_ICONS = {
|
|
6075
|
-
'.html': '🌐', '.htm': '🌐', '.css': '🎨', '.
|
|
6076
|
-
'.
|
|
6077
|
-
'.
|
|
6078
|
-
'.
|
|
6079
|
-
'.
|
|
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': '💬',
|
|
6080
6231
|
};
|
|
6081
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
|
+
|
|
6082
6236
|
const ideState = {
|
|
6083
6237
|
cache: new Map(), // rel -> entries[]
|
|
6084
6238
|
open: new Set(['']),
|
|
@@ -6090,8 +6244,10 @@ function ideModeOn() {
|
|
|
6090
6244
|
}
|
|
6091
6245
|
|
|
6092
6246
|
async function setIdeMode(on) {
|
|
6247
|
+
if (on && studioModeOn()) await setStudioMode(false); /* Studio açıkken IDE'ye geçiş — Studio kapanır */
|
|
6093
6248
|
document.body.classList.toggle('ide-mode', !!on);
|
|
6094
|
-
|
|
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 */
|
|
6095
6251
|
const brandSub = document.querySelector('#brand .brand-sub');
|
|
6096
6252
|
if (brandSub) brandSub.textContent = on ? 'Code' : 'Agent';
|
|
6097
6253
|
/* rail her iki modda da DEFAULT KAPALI — çalışan paralel ajan varsa
|
|
@@ -6116,6 +6272,166 @@ async function setIdeMode(on) {
|
|
|
6116
6272
|
}
|
|
6117
6273
|
}
|
|
6118
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
|
+
|
|
6119
6435
|
/* ---------- editör panelini kapat/göster ----------
|
|
6120
6436
|
Kapatınca kod bölmesi gider, Beast Code tam genişlik alır; tercih
|
|
6121
6437
|
localStorage'da kalıcıdır. Dosya ağacından dosya açınca geri açılır. */
|
|
@@ -6207,21 +6523,31 @@ async function renderFileTree() {
|
|
|
6207
6523
|
if (!tree) return;
|
|
6208
6524
|
tree.innerHTML = '';
|
|
6209
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;
|
|
6210
6531
|
const build = async (rel, depth, container) => {
|
|
6211
|
-
let entries =
|
|
6532
|
+
let entries = st.cache.get(rel);
|
|
6212
6533
|
if (!entries) {
|
|
6213
|
-
const r = await
|
|
6534
|
+
const r = await treeApi(rel).catch(() => null);
|
|
6214
6535
|
if (!r || !r.ok) {
|
|
6215
6536
|
if (!rel) container.innerHTML = `<div class="file-empty">${escapeHtml((r && r.error) || 'okunamadı')}</div>`;
|
|
6216
6537
|
return;
|
|
6217
6538
|
}
|
|
6218
6539
|
entries = r.entries;
|
|
6219
|
-
|
|
6540
|
+
st.cache.set(rel, entries);
|
|
6220
6541
|
if (r.workspace) {
|
|
6221
|
-
|
|
6542
|
+
st.path = r.workspace;
|
|
6222
6543
|
if (wsLabel) { wsLabel.textContent = r.workspace; wsLabel.title = r.workspace; }
|
|
6223
|
-
if (
|
|
6224
|
-
|
|
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
|
+
}
|
|
6225
6551
|
}
|
|
6226
6552
|
}
|
|
6227
6553
|
for (const e of entries) {
|
|
@@ -6229,16 +6555,21 @@ async function renderFileTree() {
|
|
|
6229
6555
|
const row = document.createElement('div');
|
|
6230
6556
|
row.className = 'file-row';
|
|
6231
6557
|
row.style.paddingLeft = 6 + depth * 14 + 'px';
|
|
6232
|
-
const
|
|
6558
|
+
const ext = e.name.slice(e.name.lastIndexOf('.')).toLowerCase();
|
|
6559
|
+
const ico = e.dir ? (st.open.has(child) ? '📂' : '📁') : IDE_ICONS[ext] || '📄';
|
|
6233
6560
|
row.innerHTML =
|
|
6234
6561
|
`<span class="f-ico">${ico}</span>` +
|
|
6235
6562
|
`<span class="f-nm" title="${escapeHtml(e.name)}">${escapeHtml(e.name)}</span>` +
|
|
6236
6563
|
(e.dir ? '' : `<span class="f-sz">${fmtFileSize(e.size)}</span>`);
|
|
6237
6564
|
row.addEventListener('click', () => {
|
|
6238
6565
|
if (e.dir) {
|
|
6239
|
-
if (
|
|
6240
|
-
else
|
|
6566
|
+
if (st.open.has(child)) st.open.delete(child);
|
|
6567
|
+
else st.open.add(child);
|
|
6241
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');
|
|
6242
6573
|
} else {
|
|
6243
6574
|
codeOpen(child);
|
|
6244
6575
|
}
|
|
@@ -6246,7 +6577,7 @@ async function renderFileTree() {
|
|
|
6246
6577
|
row.dataset.rel = child;
|
|
6247
6578
|
row.dataset.dir = e.dir ? '1' : '0';
|
|
6248
6579
|
container.appendChild(row);
|
|
6249
|
-
if (e.dir &&
|
|
6580
|
+
if (e.dir && st.open.has(child)) {
|
|
6250
6581
|
const box = document.createElement('div');
|
|
6251
6582
|
container.appendChild(box);
|
|
6252
6583
|
await build(child, depth + 1, box);
|
|
@@ -6265,7 +6596,9 @@ function ideRefreshTree() {
|
|
|
6265
6596
|
ideTreeTimer = setTimeout(() => {
|
|
6266
6597
|
ideTreeTimer = null;
|
|
6267
6598
|
try {
|
|
6268
|
-
|
|
6599
|
+
/* hangi moddaysak o ağacın önbelleği tazelenir */
|
|
6600
|
+
if (studioModeOn()) studioState.cache.clear();
|
|
6601
|
+
else ideState.cache.clear();
|
|
6269
6602
|
renderFileTree().catch(() => {});
|
|
6270
6603
|
} catch {}
|
|
6271
6604
|
}, 600);
|
|
@@ -6658,16 +6991,29 @@ async function codeReloadIfOpen(p) {
|
|
|
6658
6991
|
}
|
|
6659
6992
|
|
|
6660
6993
|
$('#ideBtn').addEventListener('click', () => setIdeMode(!ideModeOn()));
|
|
6994
|
+
if (els.studioBtn) els.studioBtn.addEventListener('click', () => setStudioMode(!studioModeOn()));
|
|
6661
6995
|
$('#filePick').addEventListener('click', async () => {
|
|
6662
|
-
|
|
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);
|
|
6663
7001
|
if (r && r.ok) {
|
|
6664
|
-
|
|
6665
|
-
|
|
7002
|
+
if (studioModeOn()) {
|
|
7003
|
+
studioState.open = new Set(['']);
|
|
7004
|
+
await loadStudioTree();
|
|
7005
|
+
} else {
|
|
7006
|
+
ideState.open = new Set(['']);
|
|
7007
|
+
await loadIdeTree();
|
|
7008
|
+
}
|
|
6666
7009
|
} else if (r && !r.canceled && r.error) {
|
|
6667
7010
|
toast(r.error);
|
|
6668
7011
|
}
|
|
6669
7012
|
});
|
|
6670
|
-
$('#fileRefresh').addEventListener('click', () =>
|
|
7013
|
+
$('#fileRefresh').addEventListener('click', () => {
|
|
7014
|
+
if (studioModeOn()) loadStudioTree();
|
|
7015
|
+
else loadIdeTree();
|
|
7016
|
+
});
|
|
6671
7017
|
|
|
6672
7018
|
/* ---------- görev listesi + TEK TUŞ GERİ ALMA (dosya paneli) ---------- */
|
|
6673
7019
|
let tasksPanelOpen = false;
|
|
@@ -6682,11 +7028,14 @@ function toggleTasksPanel(force) {
|
|
|
6682
7028
|
async function renderTasksPanel() {
|
|
6683
7029
|
const box = els.tasksPanel;
|
|
6684
7030
|
if (!box) return;
|
|
6685
|
-
|
|
6686
|
-
|
|
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>';
|
|
6687
7036
|
return;
|
|
6688
7037
|
}
|
|
6689
|
-
const r = await beast.bcTodos(
|
|
7038
|
+
const r = await beast.bcTodos(sid).catch(() => null);
|
|
6690
7039
|
if (!r || !r.ok) {
|
|
6691
7040
|
box.innerHTML = '<div class="tsk-empty">' + escapeHtml((r && r.error) || 'okunamad\u0131') + '</div>';
|
|
6692
7041
|
return;
|
|
@@ -6722,9 +7071,10 @@ async function renderTasksPanel() {
|
|
|
6722
7071
|
}
|
|
6723
7072
|
|
|
6724
7073
|
async function undoTask(id) {
|
|
6725
|
-
|
|
7074
|
+
const sid = studioModeOn() ? stSessionId : bcSessionId;
|
|
7075
|
+
if (!sid) return;
|
|
6726
7076
|
if (busy) { toast('Ajan \u00E7al\u0131\u015F\u0131yor — \u25A0 ile durdurup \u00F6yle geri al'); return; }
|
|
6727
|
-
const r = await beast.bcUndo(
|
|
7077
|
+
const r = await beast.bcUndo(sid, id).catch(() => null);
|
|
6728
7078
|
if (r && r.ok) {
|
|
6729
7079
|
toast('\u21B6 Geri al\u0131nd\u0131 — ' + (r.reverted || 0) + ' dosya \u00F6nceki h\u00E2line d\u00F6nd\u00FC');
|
|
6730
7080
|
ideRefreshTree();
|
|
@@ -6823,17 +7173,23 @@ function fileCtxShow(e, rel, isDir) {
|
|
|
6823
7173
|
const menu = els.fileCtxMenu;
|
|
6824
7174
|
if (!menu || !rel) return;
|
|
6825
7175
|
e.preventDefault();
|
|
6826
|
-
const
|
|
7176
|
+
const studio = studioModeOn();
|
|
7177
|
+
const st = studio ? studioState : ideState;
|
|
7178
|
+
const isMedia = MEDIA_FILE_RE.test(rel.split('/').pop() || '');
|
|
6827
7179
|
const items = [];
|
|
6828
7180
|
if (isDir) {
|
|
6829
7181
|
items.push({
|
|
6830
|
-
label:
|
|
7182
|
+
label: st.open.has(rel) ? 'Kapat' : 'Aç',
|
|
6831
7183
|
fn: () => {
|
|
6832
|
-
if (
|
|
6833
|
-
else
|
|
7184
|
+
if (st.open.has(rel)) st.open.delete(rel);
|
|
7185
|
+
else st.open.add(rel);
|
|
6834
7186
|
renderFileTree();
|
|
6835
7187
|
},
|
|
6836
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(() => {}) });
|
|
6837
7193
|
} else {
|
|
6838
7194
|
items.push({ label: 'Aç', fn: () => codeOpen(rel) });
|
|
6839
7195
|
if (isHtml) {
|
|
@@ -6850,13 +7206,17 @@ function fileCtxShow(e, rel, isDir) {
|
|
|
6850
7206
|
label: 'Sil',
|
|
6851
7207
|
danger: true,
|
|
6852
7208
|
fn: async () => {
|
|
6853
|
-
const r =
|
|
7209
|
+
const r = studio
|
|
7210
|
+
? await beast.studioDelete(rel).catch(() => null)
|
|
7211
|
+
: await beast.ideDelete(rel).catch(() => null);
|
|
6854
7212
|
if (r && r.ok) {
|
|
6855
|
-
|
|
6856
|
-
|
|
6857
|
-
|
|
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
|
+
}
|
|
6858
7218
|
}
|
|
6859
|
-
await
|
|
7219
|
+
await renderFileTree();
|
|
6860
7220
|
} else if (r && !r.canceled && r.error) {
|
|
6861
7221
|
toast(r.error);
|
|
6862
7222
|
}
|
|
@@ -6890,12 +7250,113 @@ if (els.fileCtxMenu) {
|
|
|
6890
7250
|
$('#fileTree').addEventListener('contextmenu', (e) => {
|
|
6891
7251
|
const row = e.target.closest('.file-row');
|
|
6892
7252
|
if (!row || !row.dataset.rel) {
|
|
7253
|
+
/* boş ağaç alanı: hızlı işlemler (mod-farkında) */
|
|
7254
|
+
e.preventDefault();
|
|
6893
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';
|
|
6894
7267
|
return;
|
|
6895
7268
|
}
|
|
6896
7269
|
fileCtxShow(e, row.dataset.rel, row.dataset.dir === '1');
|
|
6897
7270
|
});
|
|
6898
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
|
+
|
|
6899
7360
|
/* ---------- IDE modu ortası: BEAST CODE paneli ----------
|
|
6900
7361
|
Sohbet yerine Beast'in kendi ajanı (varsayılan model) çalışır;
|
|
6901
7362
|
soldaki dosya panelindeki klasörü workspace olarak kullanır.
|
|
@@ -7385,5 +7846,399 @@ if (els.bcNew) els.bcNew.addEventListener('click', async () => {
|
|
|
7385
7846
|
bcLine('t-sys', 'yeni oturum — sonraki mesaj taze başlar');
|
|
7386
7847
|
}
|
|
7387
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
|
+
});
|
|
7388
8243
|
/* Uygulama her açılışta agent (chat) modunda başlar — IDE modu yalnız
|
|
7389
8244
|
kullanıcı butona basınca girilir (oturumluk). */
|