beast-agent 1.4.2 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/agent/engine.js +239 -15
- package/src/agent/llm.js +62 -39
- package/src/main.js +478 -75
- package/src/preload.js +5 -1
- package/src/renderer/i18n.js +12 -2
- package/src/renderer/index.html +30 -7
- package/src/renderer/renderer.js +477 -60
- package/src/renderer/style.css +288 -20
package/src/renderer/renderer.js
CHANGED
|
@@ -28,7 +28,6 @@ const els = {
|
|
|
28
28
|
cfgNone: $('#cfgNone'),
|
|
29
29
|
cfgList: $('#cfgList'),
|
|
30
30
|
themeBtn: $('#themeBtn'),
|
|
31
|
-
langBtn: $('#langBtn'),
|
|
32
31
|
chatScroll: $('#chatScroll'),
|
|
33
32
|
msgs: $('#msgs'),
|
|
34
33
|
empty: $('#empty'),
|
|
@@ -60,6 +59,7 @@ const els = {
|
|
|
60
59
|
bbShot: $('#bbShot'),
|
|
61
60
|
bbClose: $('#bbClose'),
|
|
62
61
|
bbResize: $('#bbResize'),
|
|
62
|
+
bbPhone: $('#bbPhone'),
|
|
63
63
|
termCBtn: $('#termCBtn'),
|
|
64
64
|
termPanel: $('#termPanel'),
|
|
65
65
|
termCwd: $('#termCwd'),
|
|
@@ -78,9 +78,25 @@ const els = {
|
|
|
78
78
|
bcNew: $('#bcNew'),
|
|
79
79
|
bcTodoWrap: $('#bcTodoWrap'),
|
|
80
80
|
bcStatus: $('#bcStatus'),
|
|
81
|
+
bcAttach: $('#bcAttach'),
|
|
82
|
+
bcMic: $('#bcMic'),
|
|
83
|
+
bcChips: $('#bcChips'),
|
|
81
84
|
codeTabs: $('#codeTabs'),
|
|
82
85
|
codeTa: $('#codeTa'),
|
|
83
86
|
codeGutter: $('#codeGutter'),
|
|
87
|
+
codeLayer: $('#codeLayer'),
|
|
88
|
+
codeDiffBtn: $('#codeDiffBtn'),
|
|
89
|
+
codeDiffView: $('#codeDiffView'),
|
|
90
|
+
codeDiffTitle: $('#codeDiffTitle'),
|
|
91
|
+
codeDiffStats: $('#codeDiffStats'),
|
|
92
|
+
codeDiffRows: $('#codeDiffRows'),
|
|
93
|
+
codeDiffClose: $('#codeDiffClose'),
|
|
94
|
+
codeFind: $('#codeFind'),
|
|
95
|
+
codeFindInp: $('#codeFindInp'),
|
|
96
|
+
codeFindCount: $('#codeFindCount'),
|
|
97
|
+
codeFindPrev: $('#codeFindPrev'),
|
|
98
|
+
codeFindNext: $('#codeFindNext'),
|
|
99
|
+
codeFindClose: $('#codeFindClose'),
|
|
84
100
|
codePath: $('#codePath'),
|
|
85
101
|
codeSave: $('#codeSave'),
|
|
86
102
|
codeHide: $('#codeHide'),
|
|
@@ -98,11 +114,14 @@ const els = {
|
|
|
98
114
|
gearBtn: $('#gearBtn'),
|
|
99
115
|
settingsOverlay: $('#settingsOverlay'),
|
|
100
116
|
setClose: $('#setClose'),
|
|
117
|
+
setVersion: $('#setVersion'),
|
|
101
118
|
beastCode: $('#beastCode'),
|
|
102
119
|
bcCopy: $('#bcCopy'),
|
|
103
120
|
attachBtn: $('#attachBtn'),
|
|
104
121
|
micBtn: $('#micBtn'),
|
|
105
122
|
fileInput: $('#fileInput'),
|
|
123
|
+
fileTasks: $('#fileTasks'),
|
|
124
|
+
tasksPanel: $('#tasksPanel'),
|
|
106
125
|
chips: $('#chips'),
|
|
107
126
|
toast: $('#toast'),
|
|
108
127
|
railList: $('#railList'),
|
|
@@ -320,7 +339,7 @@ function toast(msg) {
|
|
|
320
339
|
|
|
321
340
|
/* ---------------- messages ---------------- */
|
|
322
341
|
|
|
323
|
-
function addUserBubble(content) {
|
|
342
|
+
function addUserBubble(content, atts) {
|
|
324
343
|
showEmpty(false);
|
|
325
344
|
const div = document.createElement('div');
|
|
326
345
|
div.className = 'msg msg-user';
|
|
@@ -339,11 +358,27 @@ function addUserBubble(content) {
|
|
|
339
358
|
text = String(content);
|
|
340
359
|
}
|
|
341
360
|
div.appendChild(document.createTextNode(text));
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
361
|
+
/* ekler İÇERİK AÇILMADAN kompakt kart olarak görünür: ≡ dosya · ▣ resim */
|
|
362
|
+
const list = Array.isArray(atts) ? atts : [];
|
|
363
|
+
if (nImg || list.length) {
|
|
364
|
+
const wrap = document.createElement('div');
|
|
365
|
+
wrap.className = 'att-row';
|
|
366
|
+
let named = 0;
|
|
367
|
+
for (const a of list) {
|
|
368
|
+
const isImg = a && a.type === 'image';
|
|
369
|
+
const chip = document.createElement('span');
|
|
370
|
+
chip.className = 'att-chip' + (isImg ? ' att-img' : '');
|
|
371
|
+
chip.textContent = (isImg ? '\u25A3 ' : '\u2261 ') + String((a && a.name) || (isImg ? 'resim' : 'dosya'));
|
|
372
|
+
wrap.appendChild(chip);
|
|
373
|
+
if (isImg) named++;
|
|
374
|
+
}
|
|
375
|
+
for (let k = named; k < nImg; k++) {
|
|
376
|
+
const chip = document.createElement('span');
|
|
377
|
+
chip.className = 'att-chip att-img';
|
|
378
|
+
chip.textContent = '\u25A3 resim';
|
|
379
|
+
wrap.appendChild(chip);
|
|
380
|
+
}
|
|
381
|
+
div.appendChild(wrap);
|
|
347
382
|
}
|
|
348
383
|
els.msgs.appendChild(div);
|
|
349
384
|
scrollDown(true);
|
|
@@ -812,7 +847,7 @@ async function openSession(id) {
|
|
|
812
847
|
|
|
813
848
|
for (let i = 0; i < s.messages.length; i++) {
|
|
814
849
|
const m = s.messages[i];
|
|
815
|
-
if (m.role === 'user') addUserBubble(m.content);
|
|
850
|
+
if (m.role === 'user') addUserBubble(m.content, m.attachments);
|
|
816
851
|
else if (m.role === 'assistant') {
|
|
817
852
|
if (m.tool_calls && m.tool_calls.length) {
|
|
818
853
|
for (const tc of m.tool_calls) {
|
|
@@ -840,6 +875,9 @@ async function openSession(id) {
|
|
|
840
875
|
|
|
841
876
|
const TEXT_EXT = /\.(txt|md|json|csv|log|js|ts|py|ps1|bat|cmd|html|css|yaml|yml|xml|ini)$/i;
|
|
842
877
|
|
|
878
|
+
/* ek hedefleri: chat + Beast Code panosu ayrı kuyruklar */
|
|
879
|
+
let bcPending = [];
|
|
880
|
+
|
|
843
881
|
function renderChips() {
|
|
844
882
|
els.chips.innerHTML = '';
|
|
845
883
|
els.chips.hidden = pending.length === 0;
|
|
@@ -860,22 +898,46 @@ function renderChips() {
|
|
|
860
898
|
});
|
|
861
899
|
}
|
|
862
900
|
|
|
863
|
-
function
|
|
901
|
+
function renderBcChips() {
|
|
902
|
+
if (!els.bcChips) return;
|
|
903
|
+
els.bcChips.innerHTML = '';
|
|
904
|
+
els.bcChips.hidden = bcPending.length === 0;
|
|
905
|
+
bcPending.forEach((a, i) => {
|
|
906
|
+
const c = document.createElement('span');
|
|
907
|
+
c.className = 'chip';
|
|
908
|
+
const label = a.type === 'image' ? `\u25A3 ${a.name}` : `\u2261 ${a.name}`;
|
|
909
|
+
c.appendChild(document.createTextNode(label));
|
|
910
|
+
const x = document.createElement('span');
|
|
911
|
+
x.className = 'x';
|
|
912
|
+
x.textContent = '×';
|
|
913
|
+
x.addEventListener('click', () => {
|
|
914
|
+
bcPending.splice(i, 1);
|
|
915
|
+
renderBcChips();
|
|
916
|
+
});
|
|
917
|
+
c.appendChild(x);
|
|
918
|
+
els.bcChips.appendChild(c);
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
function addFiles(files, mode) {
|
|
923
|
+
const isBc = mode === 'bc';
|
|
864
924
|
for (const f of files) {
|
|
865
925
|
if (f.size > 8 * 1024 * 1024) { toast('Çok büyük (max 8MB): ' + f.name); continue; }
|
|
866
926
|
if (f.type.startsWith('image/')) {
|
|
867
927
|
const r = new FileReader();
|
|
868
928
|
r.onload = () => {
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
929
|
+
const list = isBc ? bcPending : pending;
|
|
930
|
+
if (list.length >= 6) { toast('En fazla 6 ek'); return; }
|
|
931
|
+
list.push({ type: 'image', name: f.name, dataUrl: String(r.result) });
|
|
932
|
+
isBc ? renderBcChips() : renderChips();
|
|
872
933
|
};
|
|
873
934
|
r.readAsDataURL(f);
|
|
874
935
|
} else if (TEXT_EXT.test(f.name)) {
|
|
875
936
|
f.text().then((t) => {
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
937
|
+
const list = isBc ? bcPending : pending;
|
|
938
|
+
if (list.length >= 6) { toast('En fazla 6 ek'); return; }
|
|
939
|
+
list.push({ type: 'file', name: f.name, content: t.slice(0, 200000) });
|
|
940
|
+
isBc ? renderBcChips() : renderChips();
|
|
879
941
|
});
|
|
880
942
|
} else {
|
|
881
943
|
toast('Desteklenmeyen tür: ' + f.name);
|
|
@@ -885,10 +947,42 @@ function addFiles(files) {
|
|
|
885
947
|
|
|
886
948
|
/* ---------------- settings ---------------- */
|
|
887
949
|
|
|
888
|
-
let setTab = '
|
|
950
|
+
let setTab = 'lang'; /* ayarlar artık DİL sekmesiyle açılır */
|
|
951
|
+
|
|
952
|
+
/* DİL sekmesi: arayüz dili seçimi (eski sağ-alt dil ikonunun yerine) */
|
|
953
|
+
function renderLangPane() {
|
|
954
|
+
const pane = $('#tab-lang');
|
|
955
|
+
if (!pane) return;
|
|
956
|
+
const cur = (window.I18N && window.I18N.lang) || 'tr';
|
|
957
|
+
/* iki büyük kart YAN YANA — aynı boyda (seçili dil vurgusu çerçeveyle verilir, tick yok) */
|
|
958
|
+
const item = (code, label, sub) =>
|
|
959
|
+
`<button class="prov-row lang-row${cur === code ? ' active' : ''}" data-lang="${code}" ` +
|
|
960
|
+
`style="flex:1;flex-direction:column;align-items:center;justify-content:center;gap:5px;min-height:88px;margin:0">` +
|
|
961
|
+
`<span style="font-size:16px;font-weight:800">${escapeHtml(label)}</span>` +
|
|
962
|
+
`<span class="sub" style="margin:0;text-align:center;font-size:11.5px">${escapeHtml(sub)}</span>` +
|
|
963
|
+
`</button>`;
|
|
964
|
+
pane.innerHTML =
|
|
965
|
+
`<h2 data-i18n="tab_lang">${_t('tab_lang')}</h2>` +
|
|
966
|
+
`<div class="sub">${_t('lang_sub')}</div>` +
|
|
967
|
+
`<div style="display:flex;gap:12px;max-width:460px;width:100%">` +
|
|
968
|
+
item('tr', 'T\u00FCrk\u00E7e', 'T\u00FCrk\u00E7e aray\u00FCz') +
|
|
969
|
+
item('en', 'English', 'English UI') +
|
|
970
|
+
`</div>`;
|
|
971
|
+
pane.querySelectorAll('.lang-row').forEach((b) => {
|
|
972
|
+
b.addEventListener('click', () => {
|
|
973
|
+
const l = b.dataset.lang;
|
|
974
|
+
if (window.I18N && window.I18N.lang !== l) {
|
|
975
|
+
window.I18N.setLang(l); /* langchange → paneler otomatik yeniden çizilir */
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
});
|
|
979
|
+
}
|
|
889
980
|
|
|
890
981
|
async function openSettings() {
|
|
891
982
|
els.settingsOverlay.hidden = false;
|
|
983
|
+
if (els.setVersion) {
|
|
984
|
+
beast.appVersion().then((v) => { els.setVersion.textContent = 'v' + String(v || '?'); }).catch(() => {});
|
|
985
|
+
}
|
|
892
986
|
try {
|
|
893
987
|
const s = await beast.getSettings();
|
|
894
988
|
if (els.beastCode) els.beastCode.textContent = s.beastCode || '—';
|
|
@@ -909,6 +1003,7 @@ function closeSettings() {
|
|
|
909
1003
|
async function renderActiveSettingsTab() {
|
|
910
1004
|
if (els.settingsOverlay.hidden) return;
|
|
911
1005
|
switch (setTab) {
|
|
1006
|
+
case 'lang': renderLangPane(); break;
|
|
912
1007
|
case 'provider': await renderProviderPane(); break;
|
|
913
1008
|
case 'fallout': await refreshFalloutPane(); break;
|
|
914
1009
|
case 'skills': await renderSkillsPane(); break;
|
|
@@ -922,7 +1017,6 @@ async function renderActiveSettingsTab() {
|
|
|
922
1017
|
case 'agents': await refreshAgentsPane(); break;
|
|
923
1018
|
case 'logs': await renderLogPane(); break;
|
|
924
1019
|
case 'dash': await renderDashboardPane(); break;
|
|
925
|
-
case 'limits': await renderLimitsPane(); break;
|
|
926
1020
|
case 'sec': await renderSecurityPane(); break;
|
|
927
1021
|
case 'update': await renderUpdatePane(); break;
|
|
928
1022
|
}
|
|
@@ -933,16 +1027,16 @@ function switchTab(name) {
|
|
|
933
1027
|
document.querySelectorAll('#setTabs .tab').forEach((b) =>
|
|
934
1028
|
b.classList.toggle('active', b.dataset.tab === name)
|
|
935
1029
|
);
|
|
936
|
-
for (const p of ['provider', 'fallout', 'skills', 'agents', 'tts', 'email', 'integrations', 'websearch', 'events', 'cron', 'usage', 'logs', 'dash', '
|
|
1030
|
+
for (const p of ['lang', 'provider', 'fallout', 'skills', 'agents', 'tts', 'email', 'integrations', 'websearch', 'events', 'cron', 'usage', 'logs', 'dash', 'sec', 'update']) {
|
|
937
1031
|
const el = $('#tab-' + p);
|
|
938
1032
|
if (el) el.hidden = p !== name; // guard: eksik pane tüm sekmeleri kilitlemesin
|
|
939
1033
|
}
|
|
1034
|
+
if (name === 'lang') renderLangPane();
|
|
940
1035
|
if (name === 'cron') openCron();
|
|
941
1036
|
if (name === 'usage') renderUsagePane();
|
|
942
1037
|
if (name === 'events') renderEventsPane();
|
|
943
1038
|
if (name === 'logs') renderLogPane();
|
|
944
1039
|
if (name === 'dash') renderDashboardPane();
|
|
945
|
-
if (name === 'limits') renderLimitsPane();
|
|
946
1040
|
if (name === 'sec') renderSecurityPane();
|
|
947
1041
|
if (name === 'update') renderUpdatePane(true);
|
|
948
1042
|
if (name === 'agents') refreshAgentsPane();
|
|
@@ -1027,6 +1121,11 @@ async function renderUsagePane() {
|
|
|
1027
1121
|
await beast.whereWasISet({ enabled: e.target.checked });
|
|
1028
1122
|
toast(e.target.checked ? _t('us_where_on_toast') : _t('us_where_off_toast'));
|
|
1029
1123
|
});
|
|
1124
|
+
/* LİMİT ayarları aynı sekmenin alt bölümünde (Maliyet · Limit birleşik) */
|
|
1125
|
+
const limBox = document.createElement('div');
|
|
1126
|
+
limBox.id = 'limBox';
|
|
1127
|
+
pane.appendChild(limBox);
|
|
1128
|
+
await renderLimitsPane();
|
|
1030
1129
|
}
|
|
1031
1130
|
|
|
1032
1131
|
async function refreshFalloutPane() {
|
|
@@ -2194,7 +2293,8 @@ async function renderDashboardPane() {
|
|
|
2194
2293
|
/* ---------------- Limit: provider bazlı girdi limiti ---------------- */
|
|
2195
2294
|
|
|
2196
2295
|
async function renderLimitsPane() {
|
|
2197
|
-
|
|
2296
|
+
/* Maliyet sekmesine GÖMÜLÜ çalışır (ayrı sekme kaldırıldı) */
|
|
2297
|
+
const pane = $('#tab-limits') || $('#limBox');
|
|
2198
2298
|
if (!pane) return;
|
|
2199
2299
|
const cur = await beast.getLimits().catch(() => ({ enabled: false, compress: true, default: 0, perProvider: {} }));
|
|
2200
2300
|
const provs = [...new Set((state.models || []).map((m) => m.providerName))].sort((a, b) => a.localeCompare(b));
|
|
@@ -4197,7 +4297,7 @@ function onEvent(ev) {
|
|
|
4197
4297
|
beast.getState().then((s) => { state = s; applyState(); }).catch(() => {});
|
|
4198
4298
|
break;
|
|
4199
4299
|
case 'message':
|
|
4200
|
-
if (ev.message.role === 'user') addUserBubble(ev.message.content);
|
|
4300
|
+
if (ev.message.role === 'user') addUserBubble(ev.message.content, ev.message.attachments);
|
|
4201
4301
|
else if (ev.message.role === 'assistant') {
|
|
4202
4302
|
finalizeAssistant(ev.message.content);
|
|
4203
4303
|
/* tool_calls'lı iş turu grupları açık tutar; saf metin (normal cevap) kapatır */
|
|
@@ -4237,12 +4337,19 @@ function onEvent(ev) {
|
|
|
4237
4337
|
case 'file':
|
|
4238
4338
|
addFileCard(ev);
|
|
4239
4339
|
break;
|
|
4340
|
+
case 'ide-tree-changed':
|
|
4341
|
+
/* dosya sistemi değişti (ajan, kullanıcı kaydı, git, harici program) —
|
|
4342
|
+
soldaki klasör paneli ELLE yenilemeden canlı tazelenir */
|
|
4343
|
+
ideRefreshTree();
|
|
4344
|
+
break;
|
|
4240
4345
|
case 'browser': {
|
|
4241
4346
|
/* visible=false → ajan tarayıcıyı GİZLİ kullanıyor: UI yer açmaz */
|
|
4242
4347
|
const shown = !!ev.open && ev.visible !== false;
|
|
4243
4348
|
const wasShown = document.body.classList.contains('browser-open');
|
|
4244
4349
|
document.body.classList.toggle('browser-open', shown);
|
|
4245
4350
|
if (shown && ev.width) document.body.style.setProperty('--bw', ev.width + 'px');
|
|
4351
|
+
document.body.classList.toggle('phone-mode', !!ev.phone);
|
|
4352
|
+
if (els.bbPhone) els.bbPhone.classList.toggle('on', !!ev.phone);
|
|
4246
4353
|
els.browserBar.hidden = !shown;
|
|
4247
4354
|
els.bbResize.hidden = !shown;
|
|
4248
4355
|
/* terminal de sağ dock'u kullanır — tarayıcı açılınca yerini bırak */
|
|
@@ -4276,9 +4383,29 @@ function onEvent(ev) {
|
|
|
4276
4383
|
if (!busy) break;
|
|
4277
4384
|
setStatus(ev.status === 'idle' ? (busy ? 'düşünüyor…' : '') : ev.status === 'thinking' ? 'düşünüyor…' : ev.status + '…');
|
|
4278
4385
|
break;
|
|
4279
|
-
case 'term-out':
|
|
4280
|
-
|
|
4386
|
+
case 'term-out': {
|
|
4387
|
+
/* KALICI CMD: her komutun sonunda marker satırı gelir —
|
|
4388
|
+
__BEAST_EOF__<yol>__BEAST_EOF__ → yazdırılmaz, cwd güncellenir, kilit açılır */
|
|
4389
|
+
const chunk = String(ev.chunk || '');
|
|
4390
|
+
if (ev.stream === 'err') { termLine('t-err', chunk, false); break; }
|
|
4391
|
+
termPendBuf += chunk;
|
|
4392
|
+
const parts = termPendBuf.split(/\r?\n/);
|
|
4393
|
+
termPendBuf = parts.pop(); /* son yarım satır bekler */
|
|
4394
|
+
for (const line of parts) {
|
|
4395
|
+
const m = /__BEAST_EOF__(.*)__BEAST_EOF__/.exec(line.trim());
|
|
4396
|
+
if (m) {
|
|
4397
|
+
const cwd2 = m[1].trim();
|
|
4398
|
+
if (cwd2) {
|
|
4399
|
+
els.termCwd.textContent = cwd2;
|
|
4400
|
+
els.termCwd.title = cwd2;
|
|
4401
|
+
}
|
|
4402
|
+
termCmdDone({ code: 0, silent: true });
|
|
4403
|
+
continue;
|
|
4404
|
+
}
|
|
4405
|
+
if (line.trim()) termLine('t-out', line, false);
|
|
4406
|
+
}
|
|
4281
4407
|
break;
|
|
4408
|
+
}
|
|
4282
4409
|
case 'term-end':
|
|
4283
4410
|
termCmdDone(ev);
|
|
4284
4411
|
break;
|
|
@@ -4342,6 +4469,7 @@ function addFileCard(ev) {
|
|
|
4342
4469
|
let termOpen = false;
|
|
4343
4470
|
let termBannerDone = false;
|
|
4344
4471
|
let termRunning = false;
|
|
4472
|
+
let termPendBuf = ''; /* kalıcı CMD: yarım satır tamponu (marker tespiti için) */
|
|
4345
4473
|
let termHist = [];
|
|
4346
4474
|
let termHistIdx = -1;
|
|
4347
4475
|
let termShell = 'cmd';
|
|
@@ -4401,7 +4529,7 @@ function termBanner(cwd) {
|
|
|
4401
4529
|
els.termCwd.title = cwd || '';
|
|
4402
4530
|
termLine('t-sys', 'Beast Terminal — çalışma klasörü: ' + (cwd || '?'));
|
|
4403
4531
|
termLine('t-sys', 'Kabuk: ' + TERM_SHELLS[termShell].label + ' · Ajanlar çalışırken araç çağrıları ve çıktıları burada canlı akar.', false);
|
|
4404
|
-
termLine('t-dim', '
|
|
4532
|
+
termLine('t-dim', 'KALICI CMD oturumu — cd ile geçtiğin klasör komutlar arasında KORUNUR; set ile tanımladığın değişkenler de öyle.', false);
|
|
4405
4533
|
}
|
|
4406
4534
|
|
|
4407
4535
|
function termShortTool(name, args) {
|
|
@@ -4431,8 +4559,9 @@ function termAgentEvent(ev) {
|
|
|
4431
4559
|
function termCmdDone(ev) {
|
|
4432
4560
|
termRunning = false;
|
|
4433
4561
|
els.termStop.hidden = true;
|
|
4434
|
-
if (ev.
|
|
4435
|
-
|
|
4562
|
+
if (ev && ev.silent) return; /* kalıcı CMD marker bitişi — çıkış satırı yazma */
|
|
4563
|
+
if (ev && ev.error) termLine('t-err', '[hata] ' + ev.error, false);
|
|
4564
|
+
else termLine('t-dim', '(çıkış kodu: ' + (ev ? ev.code : 0) + ')' + (ev && ev.code ? ' — başarısız' : ''), false);
|
|
4436
4565
|
}
|
|
4437
4566
|
|
|
4438
4567
|
async function termToggle(shell) {
|
|
@@ -4953,12 +5082,6 @@ async function init() {
|
|
|
4953
5082
|
}
|
|
4954
5083
|
};
|
|
4955
5084
|
|
|
4956
|
-
const syncLangBtn = () => {
|
|
4957
|
-
if (!els.langBtn) return;
|
|
4958
|
-
els.langBtn.innerHTML =
|
|
4959
|
-
'<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="9"/><path d="M3 12h18"/><path d="M12 3c2.6 2.6 2.6 15.4 0 18M12 3c-2.6 2.6-2.6 15.4 0 18"/></svg>';
|
|
4960
|
-
};
|
|
4961
|
-
|
|
4962
5085
|
refreshAgentsPane();
|
|
4963
5086
|
|
|
4964
5087
|
els.sendBtn.addEventListener('click', sendCurrent);
|
|
@@ -5052,29 +5175,29 @@ async function init() {
|
|
|
5052
5175
|
await beast.setTheme(dark ? 'dark' : 'light');
|
|
5053
5176
|
});
|
|
5054
5177
|
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
const next = (window.I18N && window.I18N.lang) === 'en' ? 'tr' : 'en';
|
|
5059
|
-
window.I18N.setLang(next);
|
|
5060
|
-
syncLangBtn();
|
|
5061
|
-
});
|
|
5062
|
-
document.addEventListener('langchange', syncLangBtn);
|
|
5063
|
-
document.addEventListener('langchange', renderActiveSettingsTab);
|
|
5064
|
-
/* Whisper STT dili arayüz dilini izler (WA sesli notları da) */
|
|
5178
|
+
/* dil seçimi artık Ayarlar → DİL sekmesinde; STT dili arayüz dilini izler */
|
|
5179
|
+
document.addEventListener('langchange', renderActiveSettingsTab);
|
|
5180
|
+
{
|
|
5065
5181
|
const syncSttLang = () => { try { beast.sttLangSet((window.I18N && window.I18N.lang) || 'tr'); } catch {} };
|
|
5066
5182
|
syncSttLang();
|
|
5067
5183
|
document.addEventListener('langchange', syncSttLang);
|
|
5068
5184
|
}
|
|
5069
5185
|
|
|
5070
|
-
|
|
5186
|
+
/* + butonu iki hedefe hizmet eder: chat composer VE Beast Code paneli */
|
|
5187
|
+
let fileSink = 'chat';
|
|
5188
|
+
els.attachBtn.addEventListener('click', () => { fileSink = 'chat'; els.fileInput.click(); });
|
|
5189
|
+
if (els.bcAttach) {
|
|
5190
|
+
els.bcAttach.addEventListener('click', () => { fileSink = 'bc'; els.fileInput.click(); });
|
|
5191
|
+
}
|
|
5071
5192
|
els.fileInput.addEventListener('change', () => {
|
|
5072
|
-
addFiles([...els.fileInput.files]);
|
|
5193
|
+
addFiles([...els.fileInput.files], fileSink);
|
|
5073
5194
|
els.fileInput.value = '';
|
|
5074
5195
|
});
|
|
5075
5196
|
|
|
5076
|
-
/* ---- Sesli komut (yerel Whisper): kayıt → yazıya çevir → input'a koy ----
|
|
5077
|
-
|
|
5197
|
+
/* ---- Sesli komut (yerel Whisper): kayıt → yazıya çevir → hedef input'a koy ----
|
|
5198
|
+
Aynı düzenek chat composer VE Beast Code girişinde çalışır. */
|
|
5199
|
+
const setupMicButton = (btn, apply) => {
|
|
5200
|
+
if (!btn) return;
|
|
5078
5201
|
let micRec = null;
|
|
5079
5202
|
let micChunks = [];
|
|
5080
5203
|
let micStream = null;
|
|
@@ -5084,7 +5207,7 @@ async function init() {
|
|
|
5084
5207
|
fr.onload = () => res(fr.result);
|
|
5085
5208
|
fr.readAsDataURL(b);
|
|
5086
5209
|
});
|
|
5087
|
-
|
|
5210
|
+
btn.addEventListener('click', async () => {
|
|
5088
5211
|
if (micRec && micRec.state === 'recording') {
|
|
5089
5212
|
micRec.stop();
|
|
5090
5213
|
return;
|
|
@@ -5100,7 +5223,7 @@ async function init() {
|
|
|
5100
5223
|
micRec.ondataavailable = (e) => { if (e.data && e.data.size) micChunks.push(e.data); };
|
|
5101
5224
|
micRec.onstop = async () => {
|
|
5102
5225
|
try { micStream.getTracks().forEach((t) => t.stop()); } catch {}
|
|
5103
|
-
|
|
5226
|
+
btn.classList.remove('rec');
|
|
5104
5227
|
const blob = new Blob(micChunks, { type: micRec.mimeType || 'audio/webm' });
|
|
5105
5228
|
if (!blob.size) return;
|
|
5106
5229
|
toast(_t('mic_transcribing'));
|
|
@@ -5108,19 +5231,25 @@ async function init() {
|
|
|
5108
5231
|
/* arayüz dili = Whisper dili: TR ise Türkçe, EN ise İngilizce algılar */
|
|
5109
5232
|
const uiLang = (window.I18N && window.I18N.lang) || 'tr';
|
|
5110
5233
|
const r = await beast.sttTranscribe(b64, uiLang).catch(() => ({ ok: false, error: 'ipc' }));
|
|
5111
|
-
if (r && r.ok && r.text)
|
|
5112
|
-
|
|
5113
|
-
els.input.focus();
|
|
5114
|
-
els.input.dispatchEvent(new Event('input'));
|
|
5115
|
-
} else {
|
|
5116
|
-
toast(_t('mic_fail'));
|
|
5117
|
-
}
|
|
5234
|
+
if (r && r.ok && r.text) apply(r.text);
|
|
5235
|
+
else toast(_t('mic_fail'));
|
|
5118
5236
|
};
|
|
5119
5237
|
micRec.start();
|
|
5120
|
-
|
|
5238
|
+
btn.classList.add('rec');
|
|
5121
5239
|
toast(_t('mic_listening'));
|
|
5122
5240
|
});
|
|
5123
|
-
}
|
|
5241
|
+
};
|
|
5242
|
+
setupMicButton(els.micBtn, (t) => {
|
|
5243
|
+
els.input.value = (els.input.value ? els.input.value.replace(/\s+$/, '') + ' ' : '') + t;
|
|
5244
|
+
els.input.focus();
|
|
5245
|
+
els.input.dispatchEvent(new Event('input'));
|
|
5246
|
+
});
|
|
5247
|
+
setupMicButton(els.bcMic, (t) => {
|
|
5248
|
+
if (!els.bcInput) return;
|
|
5249
|
+
els.bcInput.value = (els.bcInput.value ? els.bcInput.value.replace(/\s+$/, '') + ' ' : '') + t;
|
|
5250
|
+
els.bcInput.focus();
|
|
5251
|
+
bcInputResize();
|
|
5252
|
+
});
|
|
5124
5253
|
|
|
5125
5254
|
beast.onWaEvent(onWaEvent);
|
|
5126
5255
|
beast.onTgEvent(onTgEvent);
|
|
@@ -5179,6 +5308,13 @@ async function init() {
|
|
|
5179
5308
|
els.bbBack.addEventListener('click', () => beast.browserCtrl('back'));
|
|
5180
5309
|
els.bbFwd.addEventListener('click', () => beast.browserCtrl('forward'));
|
|
5181
5310
|
els.bbReload.addEventListener('click', () => beast.browserCtrl('reload'));
|
|
5311
|
+
if (els.bbPhone) {
|
|
5312
|
+
els.bbPhone.addEventListener('click', () => {
|
|
5313
|
+
/* web ↔ mobil: aynı sitenin iki versiyonu arasındaki anahtar */
|
|
5314
|
+
const on = !document.body.classList.contains('phone-mode');
|
|
5315
|
+
beast.browserPhone(on).catch(() => {});
|
|
5316
|
+
});
|
|
5317
|
+
}
|
|
5182
5318
|
els.bbClose.addEventListener('click', () => {
|
|
5183
5319
|
document.body.classList.remove('browser-open');
|
|
5184
5320
|
els.browserBar.hidden = true;
|
|
@@ -6020,6 +6156,9 @@ function ideModeOn() {
|
|
|
6020
6156
|
|
|
6021
6157
|
async function setIdeMode(on) {
|
|
6022
6158
|
document.body.classList.toggle('ide-mode', !!on);
|
|
6159
|
+
/* soldaki marka: chat modunda BEAST Agent, IDE modunda BEAST Code */
|
|
6160
|
+
const brandSub = document.querySelector('#brand .brand-sub');
|
|
6161
|
+
if (brandSub) brandSub.textContent = on ? 'Code' : 'Agent';
|
|
6023
6162
|
/* IDE modu oturumluk: uygulama HER AÇILIŞTA agent (chat) modunda başlar */
|
|
6024
6163
|
toggleRail(!!on);
|
|
6025
6164
|
/* IDE'den çıkış: açık tarayıcı da kapansın — her şey default haline dönsün */
|
|
@@ -6287,6 +6426,148 @@ function codeGutterRender() {
|
|
|
6287
6426
|
}
|
|
6288
6427
|
g.innerHTML = html;
|
|
6289
6428
|
g.scrollTop = ta.scrollTop;
|
|
6429
|
+
codeLayerRender();
|
|
6430
|
+
}
|
|
6431
|
+
|
|
6432
|
+
/* canlı satır boyama: base ile güncel içeriğin diff'ine göre textarea'nın
|
|
6433
|
+
ARKASINDAKİ katmana boya basılır — eklenen satırlar YEŞİL, silinme olan
|
|
6434
|
+
konumlar KIRMIZı çizgili; metin birebir aynı yazıldığı için satırlar
|
|
6435
|
+
birebir üst üste gelir (silinen metnin tamamı Diff görünümünde okunur) */
|
|
6436
|
+
function codeLayerRender() {
|
|
6437
|
+
const layer = els.codeLayer;
|
|
6438
|
+
const ta = els.codeTa;
|
|
6439
|
+
if (!layer || !ta) return;
|
|
6440
|
+
const hasFile = codeActive >= 0 && codeTabs[codeActive];
|
|
6441
|
+
if (!hasFile) {
|
|
6442
|
+
layer.textContent = '';
|
|
6443
|
+
return;
|
|
6444
|
+
}
|
|
6445
|
+
const t = codeTabs[codeActive];
|
|
6446
|
+
const diff = codeDiffLines(t.base, ta.value);
|
|
6447
|
+
const lines = ta.value.split('\n');
|
|
6448
|
+
let html = '';
|
|
6449
|
+
for (let i = 1; i <= lines.length; i++) {
|
|
6450
|
+
const isAdd = diff.added.has(i);
|
|
6451
|
+
const delN = diff.dels.get(i) || 0;
|
|
6452
|
+
const isFind = findLineSet.has(i);
|
|
6453
|
+
const cls = (isAdd ? ' add' : delN ? ' mod' : '') + (isFind ? ' find' : '');
|
|
6454
|
+
html += `<span class="row${cls}">${escapeHtml(lines[i - 1])}</span>`;
|
|
6455
|
+
}
|
|
6456
|
+
layer.innerHTML = html;
|
|
6457
|
+
layer.scrollTop = ta.scrollTop;
|
|
6458
|
+
}
|
|
6459
|
+
|
|
6460
|
+
/* ---------- kod içi arama (Shift+F) ----------
|
|
6461
|
+
VS Code find widget'ı: kutucuk editörün sağ üstünde yüzer; eşleşen satırlar
|
|
6462
|
+
katmanda sarı boyanır, güncel eşleşme textarea seçimiyle işaretlenir. */
|
|
6463
|
+
let findMatches = [];
|
|
6464
|
+
let findIdx = -1;
|
|
6465
|
+
let findTimer = null;
|
|
6466
|
+
const findLineSet = new Set();
|
|
6467
|
+
|
|
6468
|
+
function findOpen() {
|
|
6469
|
+
if (!els.codeFind) return;
|
|
6470
|
+
els.codeFind.hidden = false;
|
|
6471
|
+
els.codeFindInp.focus();
|
|
6472
|
+
els.codeFindInp.select();
|
|
6473
|
+
findCompute();
|
|
6474
|
+
}
|
|
6475
|
+
|
|
6476
|
+
function findClose() {
|
|
6477
|
+
if (!els.codeFind || els.codeFind.hidden) return;
|
|
6478
|
+
els.codeFind.hidden = true;
|
|
6479
|
+
findMatches = [];
|
|
6480
|
+
findIdx = -1;
|
|
6481
|
+
findLineSet.clear();
|
|
6482
|
+
codeGutterRender(); /* katmandaki sarı tint'i temizle */
|
|
6483
|
+
els.codeTa.focus();
|
|
6484
|
+
}
|
|
6485
|
+
|
|
6486
|
+
function findCompute() {
|
|
6487
|
+
const ta = els.codeTa;
|
|
6488
|
+
if (!ta) return;
|
|
6489
|
+
const q = els.codeFindInp.value;
|
|
6490
|
+
findMatches = [];
|
|
6491
|
+
findIdx = -1;
|
|
6492
|
+
findLineSet.clear();
|
|
6493
|
+
if (q) {
|
|
6494
|
+
const hay = ta.value.toLowerCase();
|
|
6495
|
+
const needle = q.toLowerCase();
|
|
6496
|
+
let i = hay.indexOf(needle);
|
|
6497
|
+
while (i !== -1 && findMatches.length < 2000) {
|
|
6498
|
+
findMatches.push({ s: i, e: i + needle.length });
|
|
6499
|
+
i = hay.indexOf(needle, i + Math.max(1, needle.length));
|
|
6500
|
+
}
|
|
6501
|
+
for (const m of findMatches) {
|
|
6502
|
+
findLineSet.add(ta.value.slice(0, m.s).split('\n').length);
|
|
6503
|
+
}
|
|
6504
|
+
}
|
|
6505
|
+
codeGutterRender(); /* satır tintlerini yeniden boya */
|
|
6506
|
+
if (findMatches.length) findGoto(0, { focus: false });
|
|
6507
|
+
else findCount();
|
|
6508
|
+
}
|
|
6509
|
+
|
|
6510
|
+
function findCount() {
|
|
6511
|
+
if (els.codeFindCount) {
|
|
6512
|
+
els.codeFindCount.textContent = findMatches.length
|
|
6513
|
+
? (findIdx + 1) + '/' + findMatches.length
|
|
6514
|
+
: '0/0';
|
|
6515
|
+
}
|
|
6516
|
+
}
|
|
6517
|
+
|
|
6518
|
+
function findGoto(i, opts = {}) {
|
|
6519
|
+
if (!findMatches.length) return;
|
|
6520
|
+
findIdx = ((i % findMatches.length) + findMatches.length) % findMatches.length;
|
|
6521
|
+
const m = findMatches[findIdx];
|
|
6522
|
+
const ta = els.codeTa;
|
|
6523
|
+
/* YAZARKEN ODAK ÇALINMAZ: arama kutusuna yazıyorsa focus editöre geçmez —
|
|
6524
|
+
sadece seçim + kaydırma güncellenir (yoksa harfler koda düşer) */
|
|
6525
|
+
const keepBox = opts.focus === false || document.activeElement === els.codeFindInp;
|
|
6526
|
+
ta.setSelectionRange(m.s, m.e);
|
|
6527
|
+
if (!keepBox) ta.focus();
|
|
6528
|
+
const line = ta.value.slice(0, m.s).split('\n').length - 1;
|
|
6529
|
+
ta.scrollTop = Math.max(0, line * 20 - ta.clientHeight / 3);
|
|
6530
|
+
if (els.codeLayer) els.codeLayer.scrollTop = ta.scrollTop;
|
|
6531
|
+
findCount();
|
|
6532
|
+
}
|
|
6533
|
+
|
|
6534
|
+
function findNext() { findGoto(findIdx + 1); }
|
|
6535
|
+
function findPrev() { findGoto(findIdx - 1); }
|
|
6536
|
+
|
|
6537
|
+
/* okunur diff görünümü: silinen satırlar KIRMIZI, eklenenler YEŞİL —
|
|
6538
|
+
ajan dosyayı değiştirdiğinde OTOMATİK açılır; Diff butonuyla elle de açılır */
|
|
6539
|
+
function codeDiffHide() {
|
|
6540
|
+
if (els.codeDiffView) els.codeDiffView.hidden = true;
|
|
6541
|
+
}
|
|
6542
|
+
|
|
6543
|
+
function codeDiffShow() {
|
|
6544
|
+
const t = codeActive >= 0 ? codeTabs[codeActive] : null;
|
|
6545
|
+
if (!t || !els.codeDiffView) return;
|
|
6546
|
+
findClose(); /* diff görünümü editörü kapatır — arama widget'ı da kapanır */
|
|
6547
|
+
const ops = diffOps(t.base, els.codeTa.value);
|
|
6548
|
+
let adds = 0;
|
|
6549
|
+
let dels = 0;
|
|
6550
|
+
let o = 0;
|
|
6551
|
+
let n = 0;
|
|
6552
|
+
let html = '';
|
|
6553
|
+
for (const op of ops) {
|
|
6554
|
+
if (op.t === 'ctx') {
|
|
6555
|
+
o++; n++;
|
|
6556
|
+
html += `<div class="dr ctx"><span class="sign"> </span><span class="num">${o}</span><span class="tx">${escapeHtml(op.a || '')}</span></div>`;
|
|
6557
|
+
} else if (op.t === 'del') {
|
|
6558
|
+
o++; dels++;
|
|
6559
|
+
html += `<div class="dr del"><span class="sign">−</span><span class="num">${o}</span><span class="tx">${escapeHtml(op.a || '')}</span></div>`;
|
|
6560
|
+
} else {
|
|
6561
|
+
n++; adds++;
|
|
6562
|
+
html += `<div class="dr add"><span class="sign">+</span><span class="num">${n}</span><span class="tx">${escapeHtml(op.b || '')}</span></div>`;
|
|
6563
|
+
}
|
|
6564
|
+
}
|
|
6565
|
+
els.codeDiffRows.innerHTML =
|
|
6566
|
+
html || '<div class="dr ctx"><span class="tx"> (de\u011Fi\u015Fiklik yok)</span></div>';
|
|
6567
|
+
els.codeDiffTitle.textContent = t.rel;
|
|
6568
|
+
els.codeDiffStats.innerHTML =
|
|
6569
|
+
`<span class="plus">+${adds}</span> <span class="minus">\u2212${dels}</span>`;
|
|
6570
|
+
els.codeDiffView.hidden = false;
|
|
6290
6571
|
}
|
|
6291
6572
|
|
|
6292
6573
|
let codeGutterTimer = null;
|
|
@@ -6320,6 +6601,8 @@ function codeFlushActive() {
|
|
|
6320
6601
|
|
|
6321
6602
|
function codeActivate(i) {
|
|
6322
6603
|
codeFlushActive();
|
|
6604
|
+
codeDiffHide(); /* sekme değişince diff incelemesi kapanır */
|
|
6605
|
+
findClose(); /* arama eşleşmeleri sekmeye özeldir — yeni sekmede temiz başla */
|
|
6323
6606
|
if (i < 0 || i >= codeTabs.length) {
|
|
6324
6607
|
codeActive = -1;
|
|
6325
6608
|
els.codeTa.value = '';
|
|
@@ -6356,6 +6639,16 @@ async function codeOpen(rel) {
|
|
|
6356
6639
|
|
|
6357
6640
|
function codeClose(i) {
|
|
6358
6641
|
if (i < 0 || i >= codeTabs.length) return;
|
|
6642
|
+
/* KAYIT DİSİPLİNİ: düzenlemeler yalnız Kaydet/Ctrl+S ile diske yazılır.
|
|
6643
|
+
Kaydedilmemiş sekme kapatılırken kullanıcıya sorulur — sessiz kayıp yok. */
|
|
6644
|
+
if (codeTabs[i].dirty) {
|
|
6645
|
+
const ok = confirm(
|
|
6646
|
+
'"' + codeTabs[i].rel + '" kaydedilmedi.\n\n' +
|
|
6647
|
+
'Tamam = kaydetmeden kapat\n' +
|
|
6648
|
+
'İptal = editörde kal (kaydetmek için Ctrl+S)'
|
|
6649
|
+
);
|
|
6650
|
+
if (!ok) return;
|
|
6651
|
+
}
|
|
6359
6652
|
codeFlushActive();
|
|
6360
6653
|
const oldActive = codeActive;
|
|
6361
6654
|
const wasActive = i === oldActive;
|
|
@@ -6384,6 +6677,7 @@ async function codeSave() {
|
|
|
6384
6677
|
t.base = t.content; /* kaydedildi → diff sıfırlanır (VS Code davranışı) */
|
|
6385
6678
|
codeRenderTabs();
|
|
6386
6679
|
codeGutterRender();
|
|
6680
|
+
codeDiffHide(); /* kaydedildi — incelenecek diff kalmadı */
|
|
6387
6681
|
toast(_t('ide_saved'));
|
|
6388
6682
|
} else {
|
|
6389
6683
|
toast((r && r.error) || 'kaydedilemedi');
|
|
@@ -6415,6 +6709,8 @@ async function codeReloadIfOpen(p) {
|
|
|
6415
6709
|
t.content = r.content || ''; /* ajanın yazdığı yeni içerik */
|
|
6416
6710
|
if (i === codeActive) {
|
|
6417
6711
|
els.codeTa.value = t.content;
|
|
6712
|
+
/* ajan aktif dosyayı değiştirdi → chat diffView gibi KIRMIZI/YEŞİL inceleme otomatik açılır */
|
|
6713
|
+
if (!editorHiddenOn()) codeDiffShow();
|
|
6418
6714
|
}
|
|
6419
6715
|
codeGutterRender();
|
|
6420
6716
|
}
|
|
@@ -6430,6 +6726,74 @@ $('#filePick').addEventListener('click', async () => {
|
|
|
6430
6726
|
}
|
|
6431
6727
|
});
|
|
6432
6728
|
$('#fileRefresh').addEventListener('click', () => loadIdeTree());
|
|
6729
|
+
|
|
6730
|
+
/* ---------- görev listesi + TEK TUŞ GERİ ALMA (dosya paneli) ---------- */
|
|
6731
|
+
let tasksPanelOpen = false;
|
|
6732
|
+
|
|
6733
|
+
function toggleTasksPanel(force) {
|
|
6734
|
+
tasksPanelOpen = typeof force === 'boolean' ? force : !tasksPanelOpen;
|
|
6735
|
+
if (els.tasksPanel) els.tasksPanel.hidden = !tasksPanelOpen;
|
|
6736
|
+
if (els.fileTasks) els.fileTasks.classList.toggle('on', tasksPanelOpen);
|
|
6737
|
+
if (tasksPanelOpen) renderTasksPanel();
|
|
6738
|
+
}
|
|
6739
|
+
|
|
6740
|
+
async function renderTasksPanel() {
|
|
6741
|
+
const box = els.tasksPanel;
|
|
6742
|
+
if (!box) return;
|
|
6743
|
+
if (!bcSessionId) {
|
|
6744
|
+
box.innerHTML = '<div class="tsk-empty">\u00D6nce Beast Code\u2019da bir mesaj yaz — g\u00F6rev listesi i\u00E7in oturum gerekli.</div>';
|
|
6745
|
+
return;
|
|
6746
|
+
}
|
|
6747
|
+
const r = await beast.bcTodos(bcSessionId).catch(() => null);
|
|
6748
|
+
if (!r || !r.ok) {
|
|
6749
|
+
box.innerHTML = '<div class="tsk-empty">' + escapeHtml((r && r.error) || 'okunamad\u0131') + '</div>';
|
|
6750
|
+
return;
|
|
6751
|
+
}
|
|
6752
|
+
const GLYPH = { pending: '\u25CB', active: '\u25D0', done: '\u25CF' };
|
|
6753
|
+
const undoMap = new Map((r.undo || []).map((u) => [u.id, u.files]));
|
|
6754
|
+
let html =
|
|
6755
|
+
'<div class="tsk-head"><span>G\u00D6REVLER</span>' +
|
|
6756
|
+
'<button id="tskUndoLast" ' + (r.lastTodoId ? '' : 'disabled') + ' title="Kay\u0131tl\u0131 son g\u00F6revi geri al">\u21B6 Son G\u00F6revi Geri Al</button>' +
|
|
6757
|
+
'<button id="tskClose" title="Kapat">\u00D7</button></div>';
|
|
6758
|
+
if (!(r.todos || []).length) {
|
|
6759
|
+
html += '<div class="tsk-empty">g\u00F6rev listesi yok</div>';
|
|
6760
|
+
}
|
|
6761
|
+
for (const t of r.todos || []) {
|
|
6762
|
+
const files = undoMap.get(t.id) || 0;
|
|
6763
|
+
html +=
|
|
6764
|
+
'<div class="tsk-row">' +
|
|
6765
|
+
'<span class="tsk-id">' + escapeHtml(t.id || '?') + '</span>' +
|
|
6766
|
+
'<span class="tsk-title" title="' + escapeHtml(t.title) + '">' + escapeHtml(t.title) + '</span>' +
|
|
6767
|
+
'<span class="tsk-st ' + escapeHtml(t.status || 'pending') + '">' + (GLYPH[t.status] || '\u25CB') + '</span>' +
|
|
6768
|
+
'<button class="tsk-undo" data-id="' + escapeHtml(t.id || '') + '" ' + (files ? '' : 'disabled') +
|
|
6769
|
+
' title="' + files + ' dosya \u00F6nceki haline d\u00F6ner">\u21B6</button></div>';
|
|
6770
|
+
}
|
|
6771
|
+
box.innerHTML = html;
|
|
6772
|
+
const close = box.querySelector('#tskClose');
|
|
6773
|
+
if (close) close.addEventListener('click', () => toggleTasksPanel(false));
|
|
6774
|
+
const ul = box.querySelector('#tskUndoLast');
|
|
6775
|
+
if (ul) ul.addEventListener('click', () => undoTask('last'));
|
|
6776
|
+
box.querySelectorAll('.tsk-undo[data-id]').forEach((b) => {
|
|
6777
|
+
b.addEventListener('click', () => undoTask(b.dataset.id));
|
|
6778
|
+
});
|
|
6779
|
+
}
|
|
6780
|
+
|
|
6781
|
+
async function undoTask(id) {
|
|
6782
|
+
if (!bcSessionId) return;
|
|
6783
|
+
if (busy) { toast('Ajan \u00E7al\u0131\u015F\u0131yor — \u25A0 ile durdurup \u00F6yle geri al'); return; }
|
|
6784
|
+
const r = await beast.bcUndo(bcSessionId, id).catch(() => null);
|
|
6785
|
+
if (r && r.ok) {
|
|
6786
|
+
toast('\u21B6 Geri al\u0131nd\u0131 — ' + (r.reverted || 0) + ' dosya \u00F6nceki h\u00E2line d\u00F6nd\u00FC');
|
|
6787
|
+
ideRefreshTree();
|
|
6788
|
+
for (const p of r.paths || []) codeReloadIfOpen(p);
|
|
6789
|
+
renderTasksPanel();
|
|
6790
|
+
} else {
|
|
6791
|
+
toast((r && r.error) || 'geri al\u0131namad\u0131');
|
|
6792
|
+
}
|
|
6793
|
+
}
|
|
6794
|
+
|
|
6795
|
+
if (els.fileTasks) els.fileTasks.addEventListener('click', () => toggleTasksPanel());
|
|
6796
|
+
|
|
6433
6797
|
$('#filePreview').addEventListener('click', async () => {
|
|
6434
6798
|
const r = await beast.idePreview().catch(() => null);
|
|
6435
6799
|
if (r && r.ok) {
|
|
@@ -6439,6 +6803,24 @@ $('#filePreview').addEventListener('click', async () => {
|
|
|
6439
6803
|
}
|
|
6440
6804
|
});
|
|
6441
6805
|
if (els.codeSave) els.codeSave.addEventListener('click', codeSave);
|
|
6806
|
+
if (els.codeDiffBtn) {
|
|
6807
|
+
els.codeDiffBtn.addEventListener('click', () => {
|
|
6808
|
+
if (els.codeDiffView && !els.codeDiffView.hidden) {
|
|
6809
|
+
codeDiffHide();
|
|
6810
|
+
return;
|
|
6811
|
+
}
|
|
6812
|
+
if (codeActive < 0 || !codeTabs[codeActive]) {
|
|
6813
|
+
toast('Dosya a\u00E7\u0131k de\u011Fil');
|
|
6814
|
+
return;
|
|
6815
|
+
}
|
|
6816
|
+
if (els.codeTa.value === codeTabs[codeActive].base) {
|
|
6817
|
+
toast('De\u011Fi\u015Fiklik yok');
|
|
6818
|
+
return;
|
|
6819
|
+
}
|
|
6820
|
+
codeDiffShow();
|
|
6821
|
+
});
|
|
6822
|
+
}
|
|
6823
|
+
if (els.codeDiffClose) els.codeDiffClose.addEventListener('click', codeDiffHide);
|
|
6442
6824
|
if (els.codeTa) {
|
|
6443
6825
|
els.codeTa.addEventListener('input', () => {
|
|
6444
6826
|
if (codeActive < 0) return;
|
|
@@ -6448,16 +6830,44 @@ if (els.codeTa) {
|
|
|
6448
6830
|
/* gutter diff'i hafif gecikmeli — her tuşta LCS koşmasın */
|
|
6449
6831
|
clearTimeout(codeGutterTimer);
|
|
6450
6832
|
codeGutterTimer = setTimeout(codeGutterRender, 120);
|
|
6833
|
+
/* arama açıkken içerik değişti → eşleşmeler tazelensin */
|
|
6834
|
+
if (els.codeFind && !els.codeFind.hidden) {
|
|
6835
|
+
clearTimeout(findTimer);
|
|
6836
|
+
findTimer = setTimeout(findCompute, 220);
|
|
6837
|
+
}
|
|
6451
6838
|
});
|
|
6452
6839
|
els.codeTa.addEventListener('scroll', () => {
|
|
6453
6840
|
if (els.codeGutter) els.codeGutter.scrollTop = els.codeTa.scrollTop;
|
|
6841
|
+
if (els.codeLayer) els.codeLayer.scrollTop = els.codeTa.scrollTop;
|
|
6454
6842
|
});
|
|
6455
6843
|
els.codeTa.addEventListener('keydown', (e) => {
|
|
6456
6844
|
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 's') {
|
|
6457
6845
|
e.preventDefault();
|
|
6458
6846
|
codeSave();
|
|
6847
|
+
return;
|
|
6848
|
+
}
|
|
6849
|
+
/* Shift+F: kod içinde arama (VS Code tarzı find widget'ı) */
|
|
6850
|
+
if (e.shiftKey && !e.ctrlKey && !e.altKey && (e.key === 'F' || e.key === 'f')) {
|
|
6851
|
+
e.preventDefault();
|
|
6852
|
+
findOpen();
|
|
6459
6853
|
}
|
|
6460
6854
|
});
|
|
6855
|
+
/* arama widget'ı bağlantıları */
|
|
6856
|
+
if (els.codeFindInp) {
|
|
6857
|
+
els.codeFindInp.addEventListener('keydown', (e) => {
|
|
6858
|
+
/* Enter/Shift+Enter: eşleşmeye GEÇ ve odağı editöre ver (yazma bitti) */
|
|
6859
|
+
if (e.key === 'Enter' && e.shiftKey) { e.preventDefault(); findGoto(findIdx - 1, { focus: true }); }
|
|
6860
|
+
else if (e.key === 'Enter') { e.preventDefault(); findGoto(findIdx + 1, { focus: true }); }
|
|
6861
|
+
else if (e.key === 'Escape') { e.preventDefault(); findClose(); }
|
|
6862
|
+
});
|
|
6863
|
+
els.codeFindInp.addEventListener('input', () => {
|
|
6864
|
+
clearTimeout(findTimer);
|
|
6865
|
+
findTimer = setTimeout(findCompute, 200);
|
|
6866
|
+
});
|
|
6867
|
+
}
|
|
6868
|
+
if (els.codeFindNext) els.codeFindNext.addEventListener('click', findNext);
|
|
6869
|
+
if (els.codeFindPrev) els.codeFindPrev.addEventListener('click', findPrev);
|
|
6870
|
+
if (els.codeFindClose) els.codeFindClose.addEventListener('click', findClose);
|
|
6461
6871
|
}
|
|
6462
6872
|
|
|
6463
6873
|
/* ---------- dosya ağacı sağ tık menüsü (Sil / Aç / Preview) ---------- */
|
|
@@ -6948,16 +7358,19 @@ function bcInputResize() {
|
|
|
6948
7358
|
|
|
6949
7359
|
function bcRunCurrent() {
|
|
6950
7360
|
const msg = els.bcInput.value.trim();
|
|
6951
|
-
if (!msg) return;
|
|
7361
|
+
if (!msg && !bcPending.length) return;
|
|
7362
|
+
const atts = bcPending.slice();
|
|
7363
|
+
bcPending = [];
|
|
7364
|
+
renderBcChips();
|
|
6952
7365
|
els.bcInput.value = '';
|
|
6953
7366
|
bcInputResize();
|
|
6954
7367
|
els.bcInput.focus();
|
|
6955
|
-
bcLine('t-cmd', 'code> ' + msg);
|
|
7368
|
+
bcLine('t-cmd', 'code> ' + (msg || (atts.length ? '[' + atts.length + ' ek]' : '')));
|
|
6956
7369
|
bcHideTodos(); /* yeni sorgu = eski todo list temizlenir; agent yeniden basacak */
|
|
6957
7370
|
bcSetBusy(true);
|
|
6958
7371
|
/* sürüyor/serbest kararını main'deki gerçek engine.isBusy verir —
|
|
6959
7372
|
panel bayat kilitli kaldıysa ilk mesajla kendini düzeltir */
|
|
6960
|
-
beast.beastcodeSend(msg).then((r) => {
|
|
7373
|
+
beast.beastcodeSend(msg || '[dosya ekleri]', atts).then((r) => {
|
|
6961
7374
|
if (r && r.ok && r.mode) {
|
|
6962
7375
|
/* /plan · /build · /auto: mod değişimi — tur AÇILMAZ, kilit anında açılır
|
|
6963
7376
|
(bilgi satırı bc-mode olayıyla düşer, başlık rozeti güncellenir) */
|
|
@@ -6993,6 +7406,8 @@ if (els.bcInput) {
|
|
|
6993
7406
|
});
|
|
6994
7407
|
}
|
|
6995
7408
|
if (els.bcStop) els.bcStop.addEventListener('click', () => {
|
|
7409
|
+
bcPending = [];
|
|
7410
|
+
renderBcChips();
|
|
6996
7411
|
beast.beastcodeStop().then((r) => {
|
|
6997
7412
|
/* kuyrukta bekleyen mesajlar da silindi; engine boştaysa kilidi aç */
|
|
6998
7413
|
if (r && r.ok && r.wasBusy === false) {
|
|
@@ -7013,6 +7428,8 @@ if (els.bcNew) els.bcNew.addEventListener('click', async () => {
|
|
|
7013
7428
|
const r = await beast.beastcodeNew().catch(() => null);
|
|
7014
7429
|
if (r && r.ok) {
|
|
7015
7430
|
bcSessionId = null;
|
|
7431
|
+
bcPending = [];
|
|
7432
|
+
renderBcChips();
|
|
7016
7433
|
bcTools.clear();
|
|
7017
7434
|
bcCloseToolGroup();
|
|
7018
7435
|
bcHideTodos();
|