beast-agent 2.4.5 → 2.5.1

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.
@@ -59,8 +59,6 @@ const els = {
59
59
  bbClose: $('#bbClose'),
60
60
  bbResize: $('#bbResize'),
61
61
  bbPhone: $('#bbPhone'),
62
- bbMobile: $('#bbMobile'),
63
- bbDevice: $('#bbDevice'),
64
62
  termCBtn: $('#termCBtn'),
65
63
  termPanel: $('#termPanel'),
66
64
  termCwd: $('#termCwd'),
@@ -77,6 +75,9 @@ const els = {
77
75
  bcStop: $('#bcStop'),
78
76
  bcClear: $('#bcClear'),
79
77
  bcNew: $('#bcNew'),
78
+ bcHistList: $('#bcHistList'),
79
+ bcHistRefresh: $('#bcHistRefresh'),
80
+ bcHistClear: $('#bcHistClear'),
80
81
  bcTodoWrap: $('#bcTodoWrap'),
81
82
  bcStatus: $('#bcStatus'),
82
83
  bcAttach: $('#bcAttach'),
@@ -3076,6 +3077,7 @@ async function renderEmpatiPane() {
3076
3077
  '<div style="font-size:12px">' + escapeHtml(e.title || '') + '</div>' +
3077
3078
  '<div class="ur-meta">' + escapeHtml(e.source || '') + ' · ' + when(e.ts) + ' · %' + (e.priority || 0) +
3078
3079
  (e.reason ? ' · ' + escapeHtml(e.reason) : '') + '</div>' +
3080
+ (e.url ? '<div class="ur-meta"><span class="em-evlink" style="color:var(--accent);cursor:pointer;text-decoration:underline" data-u="' + escapeHtml(e.url) + '">🔗 kaynağı aç</span></div>' : '') +
3079
3081
  (e.text ? '<div class="sub" style="font-size:11px">' + escapeHtml(e.text) + '</div>' : '') +
3080
3082
  '</div>' +
3081
3083
  '<span style="flex:none;font-size:11px;color:var(--muted)">' + (statusT[e.status] || e.status) + lvBadge(e) + '</span>' +
@@ -3109,51 +3111,42 @@ async function renderEmpatiPane() {
3109
3111
  <label class="sub">${_t('em_interests')}</label>
3110
3112
  <textarea id="emInterests" class="inp" rows="2" placeholder="${_t('em_interests_ph')}">${escapeHtml(cfg.interests || '')}</textarea>
3111
3113
  <div class="sub">${_t('em_interests_auto')}</div>
3114
+ ${(() => {
3115
+ const learned = (mem && Array.isArray(mem.learned)) ? mem.learned : [];
3116
+ if (!learned.length) return '<div class="sub" style="margin-top:4px;opacity:.8">' + _t('em_mem_no_learned') + '</div>';
3117
+ return '<div style="display:flex;flex-wrap:wrap;gap:4px;margin-top:6px">' +
3118
+ learned.map((x) =>
3119
+ '<span style="font-size:11px;padding:2px 8px;border:1px solid var(--border);border-radius:10px">' +
3120
+ escapeHtml(x.w) + '</span>'
3121
+ ).join('') + '</div>';
3122
+ })()}
3112
3123
  </div>
3113
- <label class="lock-row" style="margin-top:8px"><input type="checkbox" id="emNews" ${cfg.newsTopics ? 'checked' : ''}/><span>${_t('em_news')}</span></label>
3114
- <input id="emTopics" class="inp" style="${cfg.newsTopics ? '' : 'opacity:.5'}" placeholder="${_t('em_news_topics_ph')}" value="${escapeHtml(cfg.newsTopics || '')}" spellcheck="false"/>
3115
- <div style="display:flex;gap:8px;margin-top:10px;align-items:center">
3124
+ <div style="margin-top:8px">
3125
+ <label class="sub">${_t('em_behavior')}</label>
3126
+ <textarea id="emBehavior" class="inp" rows="2" placeholder="${_t('em_behavior_ph')}">${escapeHtml(cfg.behavior || '')}</textarea>
3127
+ </div>
3128
+ <div style="display:flex;gap:8px;margin-top:12px;align-items:center;justify-content:center">
3116
3129
  <button id="emSave" class="btn">${_t('mcp_save')}</button>
3117
3130
  <button id="emScan" class="btn ghost">${_t('em_scan')}</button>
3118
3131
  <span id="emMsg" class="sub" style="margin:0"></span>
3119
3132
  </div>
3120
- <div class="sub" style="margin-top:6px">${_t('em_note')}</div>
3121
- </div>
3122
- <h3 style="margin-top:16px;color:var(--muted)">${_t('em_mem_h2')}</h3>
3123
- <div class="sub">${_t('em_mem_sub')}</div>
3124
- <div style="margin-top:6px"><label class="sub">${_t('em_mem_learned')}</label>${(() => {
3125
- const learned = (mem && Array.isArray(mem.learned)) ? mem.learned : [];
3126
- if (!learned.length) return '<div class="sub" style="margin-top:2px">' + _t('em_mem_no_learned') + '</div>';
3127
- return '<div style="display:flex;flex-wrap:wrap;gap:4px;margin-top:4px">' +
3128
- learned.map((x) =>
3129
- '<span style="font-size:11px;padding:2px 8px;border:1px solid var(--border);border-radius:10px">' +
3130
- escapeHtml(x.w) + ' <span style="color:var(--muted)">×' + (x.c || 0) + '</span></span>'
3131
- ).join('') + '</div>';
3132
- })()}</div>
3133
- <div style="margin-top:8px"><label class="sub">${_t('em_mem_recent')}</label>${(() => {
3134
- const chats = (mem && Array.isArray(mem.chats)) ? mem.chats : [];
3135
- if (!chats.length) return '<div class="sub" style="margin-top:2px">' + _t('em_mem_no_recent') + '</div>';
3136
- return '<div style="margin-top:4px">' + chats.map((c) =>
3137
- '<div class="usage-row" style="align-items:flex-start">' +
3138
- '<div style="min-width:0;flex:1">' +
3139
- '<div style="font-size:12px">' + escapeHtml(c.t || '') + '</div>' +
3140
- '<div class="ur-meta">' + escapeHtml(c.ch || '') + ' · ' + when(c.ts) + '</div>' +
3141
- '</div></div>').join('') + '</div>';
3142
- })()}
3143
- <button id="emMemClear" class="btn ghost" style="margin-top:8px;font-size:12px">${_t('em_mem_clear')}</button>
3144
3133
  </div>
3145
3134
  <h3 style="margin-top:16px;color:var(--muted)">${_t('em_events')}</h3>`;
3146
3135
  const wrap = document.createElement('div');
3147
3136
  if (!rows) wrap.innerHTML = '<p class="sub">' + _t('em_no_events') + '</p>';
3148
3137
  else wrap.innerHTML = rows;
3149
3138
  pane.appendChild(wrap);
3139
+ /* olay linkleri: tıklayınca harici tarayıcıda açılır */
3140
+ wrap.querySelectorAll('.em-evlink').forEach((el) => {
3141
+ el.addEventListener('click', () => {
3142
+ const u = el.dataset.u;
3143
+ if (u && /^https?:\/\//i.test(u)) beast.openExternal(u);
3144
+ });
3145
+ });
3150
3146
 
3151
3147
  const emOn = q('#emOn');
3152
3148
  const emDetail = q('#emDetail');
3153
- const emNews = q('#emNews');
3154
- const emTopics = q('#emTopics');
3155
3149
  if (emOn && emDetail) emOn.addEventListener('change', () => { emDetail.style.opacity = emOn.checked ? '' : '.5'; });
3156
- if (emNews && emTopics) emNews.addEventListener('change', () => { emTopics.style.opacity = emNews.checked ? '' : '.5'; });
3157
3150
  const emSaveBtn = q('#emSave');
3158
3151
  if (emSaveBtn) emSaveBtn.addEventListener('click', async () => {
3159
3152
  const patch = {
@@ -3163,8 +3156,8 @@ async function renderEmpatiPane() {
3163
3156
  cooldownMin: Number(q('#emCd').value),
3164
3157
  notifyTarget: q('#emTarget') ? q('#emTarget').value : '',
3165
3158
  filterModel: q('#emModel') ? q('#emModel').value : '',
3159
+ behavior: q('#emBehavior') ? q('#emBehavior').value.trim() : '',
3166
3160
  interests: q('#emInterests').value.trim(),
3167
- newsTopics: emNews.checked ? emTopics.value.trim() : '',
3168
3161
  };
3169
3162
  const r = await beast.empatiSet(patch).catch(() => null);
3170
3163
  toast(r ? _t('em_saved') : 'Hata');
@@ -3193,12 +3186,6 @@ async function renderEmpatiPane() {
3193
3186
  const b2 = q('#emScan');
3194
3187
  if (b2) b2.disabled = false;
3195
3188
  });
3196
- const emMemClearBtn = q('#emMemClear');
3197
- if (emMemClearBtn) emMemClearBtn.addEventListener('click', async () => {
3198
- const r = await beast.empatiMemClear().catch(() => null);
3199
- toast(r && r.ok ? _t('em_mem_cleared') : 'Hata');
3200
- if (r && r.ok) renderEmpatiPane();
3201
- });
3202
3189
  }
3203
3190
 
3204
3191
  async function renderWaAllow() {
@@ -5006,14 +4993,6 @@ function onEvent(ev) {
5006
4993
  if (shown && ev.width) document.body.style.setProperty('--bw', ev.width + 'px');
5007
4994
  document.body.classList.toggle('phone-mode', !!ev.phone);
5008
4995
  if (els.bbPhone) els.bbPhone.classList.toggle('on', !!ev.phone);
5009
- /* MOBİL ÖNİZLEME: telefon silueti çerçevesi + düğme durumu + cihaz seçimi */
5010
- document.body.classList.toggle('mobile-preview', !!ev.mobile);
5011
- if (els.bbMobile) els.bbMobile.classList.toggle('on', !!ev.mobile);
5012
- if (ev.device) {
5013
- document.body.dataset.pfDevice = ev.device;
5014
- if (els.bbDevice) els.bbDevice.value = ev.device;
5015
- }
5016
- renderPhoneFrame(ev.phoneRect || null);
5017
4996
  els.browserBar.hidden = !shown;
5018
4997
  els.bbResize.hidden = !shown;
5019
4998
  /* terminal artık ALT dock — tarayıcıyla birlikte yaşar, kapatılmaz */
@@ -5167,22 +5146,28 @@ function termSetHeight(h) {
5167
5146
  const v = Math.max(120, Math.min(Math.round(h), Math.round(window.innerHeight * 0.7)));
5168
5147
  document.body.style.setProperty('--th', v + 'px');
5169
5148
  try { localStorage.setItem('beast.termH', String(v)); } catch {}
5170
- /* native tarayıcı view'ına alt payı bildir — view yüksekliğini kısar */
5171
- beast.browserSetBottomInset(termOpen ? v : 0).catch(() => {});
5149
+ /* native tarayıcı view'ına alt payı bildir — IDE modunda terminal bölme içindedir,
5150
+ tarayıcıya dokunmaz; yalnız ajan modundaki alt dock paylaşımı bildirilir */
5151
+ if (!ideModeOn()) beast.browserSetBottomInset(termOpen ? v : 0).catch(() => {});
5172
5152
  }
5173
5153
 
5174
5154
  function termSetOpen(v) {
5175
- /* BEAST CODE modunda terminal HEP AÇIK: kapatma denemeleri IDE modunda yok sayılır */
5176
- if (!v && ideModeOn()) {
5177
- toast('Beast Code modunda terminal açık kalır');
5178
- return;
5179
- }
5180
5155
  termOpen = !!v;
5181
5156
  els.termPanel.hidden = !v;
5182
- els.termResize.hidden = !v;
5157
+ els.termResize.hidden = !v || ideModeOn(); /* IDE'de terminal bölme içi — boyutlandırma yok */
5183
5158
  document.body.classList.toggle('term-open', v);
5184
5159
  termSetShell(termShell);
5185
- /* alt dock: tarayıcı view'ı terminal payını boşaltır */
5160
+ if (ideModeOn()) {
5161
+ /* IDE modunda terminal soldaki KOD BÖLMÜNDE yaşar: açılınca editörü kapatır,
5162
+ kapanınca editör geri gelir — tarayıcıyla HİÇbir ilişkisi yok */
5163
+ document.body.classList.toggle('term-pane', v);
5164
+ if (v) {
5165
+ els.termInput.focus();
5166
+ termScroll(true);
5167
+ }
5168
+ return;
5169
+ }
5170
+ /* alt dock (ajan modu): tarayıcı view'ı terminal payını boşaltır */
5186
5171
  const th = parseInt(getComputedStyle(document.body).getPropertyValue('--th')) || 180;
5187
5172
  beast.browserSetBottomInset(v ? th : 0).catch(() => {});
5188
5173
  if (v) {
@@ -5226,55 +5211,9 @@ function termShortTool(name, args) {
5226
5211
  } catch { return ''; }
5227
5212
  }
5228
5213
 
5229
- /* ---------------- MOBİL ÖNİZLEME: telefon silueti ----------------
5230
- main, WebContentsView'ı cihaz EKRANI boyutuna küçültür (phoneRect olayıyla
5231
- gelir); çerçeve TEK YUVARLAK HALKA (border 12px, radius 42 — üst/alt köşeler
5232
- birebir aynı) DOM'da çizilir; home çubuğu alt kenar içindedir. */
5233
- const PF_BEZEL = 12;
5234
-
5235
- function renderPhoneFrame(rect) {
5236
- const pk = document.getElementById('bbDevice');
5237
- let f = document.getElementById('phoneFrame');
5238
- if (!rect) {
5239
- if (f) f.style.display = 'none';
5240
- if (pk) pk.style.display = 'none';
5241
- return;
5242
- }
5243
- if (!f) {
5244
- f = document.createElement('div');
5245
- f.id = 'phoneFrame';
5246
- f.innerHTML = '<div class="pf-home"></div>';
5247
- document.body.appendChild(f);
5248
- }
5249
- f.style.display = 'block';
5250
- f.style.left = (rect.x - PF_BEZEL) + 'px';
5251
- f.style.top = (rect.y - PF_BEZEL) + 'px';
5252
- f.style.width = (rect.width + PF_BEZEL * 2) + 'px';
5253
- f.style.height = (rect.height + PF_BEZEL * 2) + 'px';
5254
- /* cihaz seçici: çerçevenin altında ortalanmış */
5255
- if (pk) {
5256
- const frameBottom = rect.y + rect.height + PF_BEZEL;
5257
- pk.hidden = false;
5258
- pk.style.display = 'block';
5259
- pk.style.top = (frameBottom + 12) + 'px';
5260
- pk.style.left = Math.max(8, rect.x + rect.width / 2 - pk.offsetWidth / 2) + 'px';
5261
- }
5262
- }
5263
-
5264
- /* ajan dev sunucu başlattı mı? (expo/metro/vite/next) — mobil önizleme
5265
- açıksa oraya otomatik gidilir, kapatılsa da son URL hatırlanır */
5266
- let devSeenUrl = '';
5267
- const DEV_URL_RE_R = /https?:\/\/(?:localhost|127\.0\.0\.1|\[::1\]|(?:192\.168|10\.\d+|172\.(?:1[6-9]|2\d|3[01]))\.\d+\.\d+):(\d{2,5})/;
5268
- function devServerSeen(text) {
5269
- const m = DEV_URL_RE_R.exec(String(text || ''));
5270
- if (!m) return;
5271
- const port = Number(m[1]);
5272
- if (port === 19000 || port === 19001 || port === 19002) return; // expo native/log portları
5273
- const url = m[0].replace(/\/+$/, '') + '/';
5274
- if (devSeenUrl === url) return;
5275
- devSeenUrl = url;
5276
- if (document.body.classList.contains('mobile-preview')) beast.browserNavigate(url).catch(() => {});
5277
- }
5214
+ /* ---------------- MOBİL ÖNİZLEME kaldırıldı ----------------
5215
+ Telefon silueti (Expo/Metro canlı önizleme) şimdilik devre dışı —
5216
+ önizleme her projede normal tarayıcı dock'unda açılır. */
5278
5217
 
5279
5218
  /* ajan araç etkinliğini terminale akıt (tüm oturumlar: ana sohbet + paralel ajanlar + cron) */
5280
5219
  function termAgentEvent(ev) {
@@ -5283,8 +5222,6 @@ function termAgentEvent(ev) {
5283
5222
  const args = termShortTool(ev.name, ev.args);
5284
5223
  termLine('t-agent', sid + '▸ ' + ev.name + (args ? ': ' + args : ''));
5285
5224
  } else if (ev.type === 'tool-end') {
5286
- /* mobil önizleme: dev sunucu çıktısı yakala ("Local: http://localhost:8081" vb.) */
5287
- devServerSeen(ev.result);
5288
5225
  const shellish = /bash|shell|powershell|cmd|command|script|terminal/i.test(String(ev.name || ''));
5289
5226
  const out = String(ev.result || '').replace(/\s+$/, '');
5290
5227
  const cap = shellish ? 1600 : 240;
@@ -6091,25 +6028,8 @@ async function init() {
6091
6028
  beast.browserPhone(on).catch(() => {});
6092
6029
  });
6093
6030
  }
6094
- if (els.bbMobile) {
6095
- els.bbMobile.addEventListener('click', () => {
6096
- /* MOBİL ÖNİZLEME: telefon silueti içinde canlı dev-server önizlemesi */
6097
- const on = !document.body.classList.contains('mobile-preview');
6098
- beast.browserMobileSet(on).catch(() => {});
6099
- });
6100
- }
6101
- if (els.bbDevice) {
6102
- els.bbDevice.addEventListener('change', () => {
6103
- beast.browserDeviceSet(els.bbDevice.value).catch(() => {});
6104
- });
6105
- }
6106
6031
  els.bbClose.addEventListener('click', () => {
6107
6032
  document.body.classList.remove('browser-open');
6108
- /* mobil önizleme KESİN kapansın: main tarafı zaten kapatıyor, DOM tarafı da
6109
- beklemeden temizlenir (siluet + cihaz seçici + mod düğmesi) */
6110
- document.body.classList.remove('mobile-preview');
6111
- if (els.bbMobile) els.bbMobile.classList.remove('on');
6112
- renderPhoneFrame(null);
6113
6033
  els.browserBar.hidden = true;
6114
6034
  els.bbResize.hidden = true;
6115
6035
  els.browserBtn.classList.remove('on');
@@ -6967,17 +6887,25 @@ async function setIdeMode(on) {
6967
6887
  if (!on && document.body.classList.contains('browser-open')) {
6968
6888
  try { beast.toggleBrowser(); } catch {}
6969
6889
  }
6970
- /* ALT TERMINAL: yalnız Beast Code'a özgü — Agent/Studio moduna dönüşte kapanır */
6971
- if (!on && termOpen) termSetOpen(false);
6972
6890
  if (on) {
6891
+ /* terminal ALT DOCK'tan KOD BÖLMÜNE taşınır: soldaki yer editör + terminal ortak alanı */
6892
+ ideTermPlace(true);
6973
6893
  ideSplitRestore();
6974
6894
  setEditorHidden(localStorage.getItem('beast.editorHidden') === '1');
6975
- /* BEAST CODE modunda terminal HEP AÇIK mod girilirken otomatik açılır */
6976
- if (!termOpen) termSetOpen(true);
6895
+ /* mod geçişinde bir kez: ajan modundan kalabilecek alt dock payını sıfırla */
6896
+ beast.browserSetBottomInset(0).catch(() => {});
6897
+ /* terminal açıksa bölmeyi o alır; kapalıysa editör pref'ine göre başlar —
6898
+ editör görünürse terminal ⌘ butonuyla (veya editör kapatılınca) açılır */
6899
+ termSetOpen(termOpen ? true : editorHiddenOn());
6977
6900
  await loadIdeTree();
6978
6901
  bcBanner();
6902
+ renderBcHistory(); /* soldaki geçmiş listesi: IDE'ye girişte tazelenir */
6979
6903
  codeGutterRender(); /* dosya açık olmasa bile rakamlar görünür */
6980
6904
  } else {
6905
+ /* terminal bölmeye alınmadan önce kapatılır, sonra ALT DOCK'a geri taşınır */
6906
+ if (termOpen) termSetOpen(false);
6907
+ document.body.classList.remove('term-pane');
6908
+ ideTermPlace(false);
6981
6909
  /* agent moduna dönüş: koşan paralel ajan varsa rail otomatik açılır
6982
6910
  (autoOpened sıfırlanır — Code modundayken başlayan iş için de tetiklensin) */
6983
6911
  agentState.autoOpened = false;
@@ -6985,6 +6913,19 @@ async function setIdeMode(on) {
6985
6913
  }
6986
6914
  }
6987
6915
 
6916
+ /* terminal panelini mode'a göre yerleştir: IDE'de #codePane içine, ajan modunda body altına */
6917
+ function ideTermPlace(inside) {
6918
+ const pane = document.getElementById('codePane');
6919
+ if (!pane || !els.termPanel) return;
6920
+ if (inside && els.termPanel.parentElement !== pane) {
6921
+ pane.appendChild(els.termPanel);
6922
+ if (els.termResize) pane.appendChild(els.termResize);
6923
+ } else if (!inside && els.termPanel.parentElement === pane) {
6924
+ document.body.appendChild(els.termResize);
6925
+ document.body.appendChild(els.termPanel);
6926
+ }
6927
+ }
6928
+
6988
6929
  /* ================= BEAST STUDIO MODU =================
6989
6930
  Beast Code ile AYRI dünya: sol klasör konsolu (başlık: BEAST STUDIO),
6990
6931
  sağ → chat + video bölümü. Oturumlar main tarafında studioRoot bazlı ve
@@ -7155,6 +7096,8 @@ function editorHiddenOn() {
7155
7096
  }
7156
7097
 
7157
7098
  function setEditorHidden(h) {
7099
+ /* paylaşılan bölme: editör açılınca terminal kapanır (IDE modu) */
7100
+ if (!h && ideModeOn() && termOpen) termSetOpen(false);
7158
7101
  document.body.classList.toggle('editor-hidden', !!h);
7159
7102
  if (els.codeShow) els.codeShow.hidden = !h;
7160
7103
  try { localStorage.setItem('beast.editorHidden', h ? '1' : '0'); } catch {}
@@ -7611,6 +7554,8 @@ function codeActivate(i) {
7611
7554
  }
7612
7555
 
7613
7556
  async function codeOpen(rel) {
7557
+ /* dosya açılımı = editör açılır → terminal bölmeyi bırakır (paylaşılan bölme) */
7558
+ if (ideModeOn() && termOpen) termSetOpen(false);
7614
7559
  if (editorHiddenOn()) setEditorHidden(false); /* dosya açılınca editör geri gelir */
7615
7560
  const idx = codeTabs.findIndex((t) => t.rel === rel);
7616
7561
  if (idx >= 0) {
@@ -7806,8 +7751,6 @@ $('#filePreview').addEventListener('click', async () => {
7806
7751
  const r = await beast.idePreview().catch(() => null);
7807
7752
  if (r && r.ok) {
7808
7753
  if (ideModeOn() === false) setIdeMode(true);
7809
- /* mobil proje: npm run web + telefon silueti — kullanıcıya net geri bildirim */
7810
- if (r.mobile) toast('Mobil önizleme: dev sunucu başlatıldı — telefon siluetine bak');
7811
7754
  } else {
7812
7755
  toast((r && r.error) || 'preview açılamadı');
7813
7756
  }
@@ -8137,9 +8080,130 @@ function bcOnFolderChanged(p) {
8137
8080
  bcStreamEl = null;
8138
8081
  bcStreamRaw = '';
8139
8082
  bcBannerDone = false;
8083
+
8140
8084
  bcBanner();
8085
+ renderBcHistory();
8086
+ }
8087
+
8088
+ /* ---------- Beast Code SOHBET GEÇMİŞİ (dosya panelinin alt yarısı) ----------
8089
+ Eski Beast Code oturumları listelenir; tıklanınca panelde açılır ve
8090
+ kaldığı yerden devam edilir. Ana sohbet listesiyle ilgisi yoktur. */
8091
+ let bcHistBusy = false;
8092
+
8093
+ function histWhen(iso) {
8094
+ try {
8095
+ return new Date(iso).toLocaleString('tr-TR', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });
8096
+ } catch { return ''; }
8141
8097
  }
8142
8098
 
8099
+ async function renderBcHistory() {
8100
+ const list = els.bcHistList;
8101
+ if (!list || !ideModeOn() || bcHistBusy) return;
8102
+ bcHistBusy = true;
8103
+ try {
8104
+ const r = await beast.bcHistory().catch(() => null);
8105
+ if (!r || !r.ok) return;
8106
+ const items = r.items || [];
8107
+ list.innerHTML = '';
8108
+ if (!items.length) {
8109
+ list.innerHTML = '<div class="bc-hist-empty">Henüz Beast Code oturumu yok — mesaj yazınca burada birikir.</div>';
8110
+ return;
8111
+ }
8112
+ for (const it of items) {
8113
+ const row = document.createElement('div');
8114
+ row.className = 'bc-hist-item' + (it.id === bcSessionId ? ' active' : '');
8115
+ const wsShort = it.ws ? String(it.ws).split(/[\\/]/).filter(Boolean).pop() : '';
8116
+ row.innerHTML =
8117
+ '<span class="bh-dot"></span>' +
8118
+ '<div class="bh-main">' +
8119
+ '<span class="bh-title">' + escapeHtml(it.title || 'Beast Code oturumu') + '</span>' +
8120
+ '<span class="bh-meta">' + escapeHtml((wsShort ? wsShort + ' · ' : '') + histWhen(it.updatedAt) + ' · ' + (it.count || 0) + ' msj') + '</span>' +
8121
+ '</div>' +
8122
+ '<button class="bh-del" title="Bu oturumu sil">&#x00D7;</button>';
8123
+ row.title = (it.ws ? it.ws + '\n' : '') + (it.title || '');
8124
+ row.addEventListener('click', () => { bcOpenHistory(it.id); });
8125
+ const del = row.querySelector('.bh-del');
8126
+ if (del) del.addEventListener('click', (e) => {
8127
+ e.stopPropagation();
8128
+ bcDeleteHistory(it.id, it.title);
8129
+ });
8130
+ list.appendChild(row);
8131
+ }
8132
+ } finally {
8133
+ bcHistBusy = false;
8134
+ }
8135
+ }
8136
+
8137
+ async function bcOpenHistory(id) {
8138
+ if (!id) return;
8139
+ if (bcRunning) { toast('Mesaj sürüyor — önce ■ ile durdur'); return; }
8140
+ const r = await beast.bcOpen(id).catch(() => null);
8141
+ if (!r || !r.ok) { toast((r && r.error) || 'oturum açılamadı'); return; }
8142
+ bcSessionId = r.sessionId;
8143
+ if (els.bcOut) els.bcOut.innerHTML = '';
8144
+ bcTools.clear();
8145
+ bcCloseToolGroup();
8146
+ bcHideTodos();
8147
+ bcFlushStream();
8148
+ bcLine('t-sys', '[eski oturum açıldı · ' + (r.messages ? r.messages.length : 0) + ' mesaj — kaldığın yerden devam edebilirsin]');
8149
+ for (const m of r.messages || []) {
8150
+ if (m.role === 'user') bcLine('t-cmd', 'code> ' + m.text);
8151
+ else bcLine('t-out', m.text);
8152
+ }
8153
+ bcSetBusy(!!r.busy);
8154
+ if (r.busy) bcStatusShow('çalışıyor…');
8155
+ else bcStatusHide();
8156
+ renderBcHistory();
8157
+ }
8158
+
8159
+ /* aktif Beast Code panelini taze başlangıca döndür (oturum silinince) */
8160
+ function bcResetPanel() {
8161
+ bcSessionId = null;
8162
+ bcPending = [];
8163
+ renderBcChips();
8164
+ bcTools.clear();
8165
+ bcCloseToolGroup();
8166
+ bcHideTodos();
8167
+ bcFlushStream();
8168
+ if (els.bcOut) els.bcOut.innerHTML = '';
8169
+ bcSetBusy(false);
8170
+ bcStatusHide();
8171
+ }
8172
+
8173
+ /* TEK oturum silme — onay sorulur */
8174
+ async function bcDeleteHistory(id, title) {
8175
+ if (!id) return;
8176
+ if (!confirm('"' + (title || 'Beast Code oturumu') + '" silinsin mi?\n\nBu işlem geri alınamaz.')) return;
8177
+ const r = await beast.bcDelete(id).catch(() => null);
8178
+ if (!r || !r.ok) { toast((r && r.error) || 'silinemedi'); return; }
8179
+ if (bcSessionId === id) {
8180
+ bcResetPanel();
8181
+ bcLine('t-sys', '[oturum silindi — sonraki mesaj taze oturumda başlar]');
8182
+ }
8183
+ toast('Oturum silindi');
8184
+ renderBcHistory();
8185
+ }
8186
+
8187
+ /* TÜM oturumları sil — onay sorulur; çalışan oturumlar atlanır */
8188
+ if (els.bcHistClear) els.bcHistClear.addEventListener('click', async () => {
8189
+ if (bcHistBusy) return;
8190
+ const r0 = await beast.bcHistory().catch(() => null);
8191
+ const n = r0 && r0.ok ? (r0.items || []).length : 0;
8192
+ if (!n) { toast('Silinecek oturum yok'); return; }
8193
+ if (!confirm(n + ' Beast Code oturumunun TÜMÜ silinsin mi?\n\nBu işlem geri alınamaz.')) return;
8194
+ const r = await beast.bcDeleteAll().catch(() => null);
8195
+ if (!r || !r.ok) { toast((r && r.error) || 'silinemedi'); return; }
8196
+ /* aktif oturum da silindiyse panel tazelensin */
8197
+ const r2 = await beast.bcHistory().catch(() => null);
8198
+ const still = r2 && r2.ok ? (r2.items || []).some((x) => x.id === bcSessionId) : true;
8199
+ if (!still) {
8200
+ bcResetPanel();
8201
+ bcLine('t-sys', '[tüm geçmiş silindi — sonraki mesaj taze oturumda başlar]');
8202
+ }
8203
+ toast(r.deleted + ' oturum silindi' + (r.skipped ? ' · ' + r.skipped + ' çalışıyor (atlandı)' : ''));
8204
+ renderBcHistory();
8205
+ });
8206
+
8143
8207
  function bcSetBusy(v) {
8144
8208
  bcRunning = !!v;
8145
8209
  if (els.bcStop) els.bcStop.hidden = !v;
@@ -8493,6 +8557,7 @@ function bcRunCurrent() {
8493
8557
  bcLine('t-cmd', 'code> ' + (msg || (atts.length ? '[' + atts.length + ' ek]' : '')));
8494
8558
  bcHideTodos(); /* yeni sorgu = eski todo list temizlenir; agent yeniden basacak */
8495
8559
  bcSetBusy(true);
8560
+ const prevSid = bcSessionId;
8496
8561
  /* sürüyor/serbest kararını main'deki gerçek engine.isBusy verir —
8497
8562
  panel bayat kilitli kaldıysa ilk mesajla kendini düzeltir */
8498
8563
  beast.beastcodeSend(msg || '[dosya ekleri]', atts).then((r) => {
@@ -8517,6 +8582,8 @@ function bcRunCurrent() {
8517
8582
  bcSetBusy(false);
8518
8583
  bcLine('t-err', (r && r.error) || 'gönderilemedi');
8519
8584
  }
8585
+ /* yeni oturum açıldıysa soldaki geçmiş listesi tazelensin */
8586
+ if (bcSessionId && bcSessionId !== prevSid) renderBcHistory();
8520
8587
  }).catch((e) => {
8521
8588
  bcSetBusy(false);
8522
8589
  bcLine('t-err', String((e && e.message) || e));
@@ -8561,8 +8628,10 @@ if (els.bcNew) els.bcNew.addEventListener('click', async () => {
8561
8628
  bcFlushStream();
8562
8629
  if (els.bcTitle) els.bcTitle.textContent = 'BEAST CODE';
8563
8630
  bcLine('t-sys', 'yeni oturum — sonraki mesaj taze başlar');
8631
+ renderBcHistory(); /* silinen oturum listeden düşsün */
8564
8632
  }
8565
8633
  });
8634
+ if (els.bcHistRefresh) els.bcHistRefresh.addEventListener('click', () => renderBcHistory());
8566
8635
 
8567
8636
  /* ---------- BEAST STUDIO paneli ----------
8568
8637
  Beast Code panelinin birebir karşılığı — AMA ayrı oturum, ayrı kuyruk,
@@ -362,57 +362,6 @@ body.rail-hidden #rail { display: none; }
362
362
  /* telefon modu: aktif buton vurgulu + dar dockta mobil çerçeve hissi */
363
363
  #bbPhone.on { color: var(--accent); background: var(--panel2); box-shadow: inset 0 -2px 0 var(--accent); }
364
364
  body.phone-mode #bbPhone { color: var(--accent); }
365
- /* mobil önizleme: telefon silueti çerçevesi */
366
- #bbMobile.on { color: var(--accent); background: var(--panel2); box-shadow: inset 0 -2px 0 var(--accent); }
367
- body.mobile-preview #bbMobile { color: var(--accent); }
368
- /* cihaz seçici: telefonun ALTINDA yüzen modern pill picker (konumu renderPhoneFrame) */
369
- #bbDevice {
370
- position: fixed;
371
- display: none;
372
- z-index: 10000;
373
- height: 34px;
374
- padding: 0 34px 0 16px;
375
- border-radius: 17px;
376
- border: 1px solid var(--border);
377
- background-color: var(--panel2);
378
- color: var(--text);
379
- font-size: 12px;
380
- font-weight: 600;
381
- letter-spacing: .2px;
382
- outline: none;
383
- appearance: none;
384
- -webkit-appearance: none;
385
- background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23888890' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
386
- background-repeat: no-repeat;
387
- background-position: right 14px center;
388
- box-shadow: 0 6px 18px rgba(0, 0, 0, .3);
389
- }
390
- #bbDevice:hover { border-color: var(--accent); }
391
- #bbDevice:focus { border-color: var(--accent); }
392
-
393
- /* ---------- MOBİL ÖNİZLEME: telefon silueti çerçevesi ----------
394
- WebContentsView ekranın kendisidir (main'deki PHONE_* sabitleriyle birebir);
395
- çerçeve/çentik/durum çubuğu/home bar DOM'da çizilir — pointer-events yok,
396
- native view'a asla dokunmaz (kenar şeritleri view sınırlarının dışındadır) */
397
- #phoneFrame {
398
- position: fixed;
399
- display: none;
400
- pointer-events: none;
401
- z-index: 9999;
402
- box-sizing: border-box; /* border rect sınırlarının İÇİNDE kalır — view ile birebir hizalı */
403
- border: 12px solid #0a0a0e;
404
- border-radius: 42px;
405
- filter: drop-shadow(0 12px 32px rgba(0, 0, 0, .55));
406
- }
407
- #phoneFrame .pf-home {
408
- /* alt kenar çerçeve bandının İÇİNDE — native view'ın dışında, görünür */
409
- position: absolute;
410
- bottom: -9px; left: 50%;
411
- transform: translateX(-50%);
412
- width: 38%; height: 4px;
413
- border-radius: 3px;
414
- background: rgba(255, 255, 255, .8);
415
- }
416
365
 
417
366
  /* sürükle-boyutlandır tutamacı (görünmez) */
418
367
  /* Beast Code chat ↔ tarayıcı arası ayırıcı: ideSplit ile BİREBİR aynı çizgi
@@ -2621,6 +2570,83 @@ body.ide-mode #bcPanel { display: flex; }
2621
2570
  text-overflow: ellipsis;
2622
2571
  }
2623
2572
  #fileTree { flex: 1; overflow-y: auto; padding: 6px 4px; }
2573
+
2574
+ /* ---------- Beast Code sohbet geçmişi (dosya panelinin ALT YARISI) ----------
2575
+ Yalnız IDE (Beast Code) modunda görünür; ana sohbet listesinden ayrıdır.
2576
+ Üst yarı klasör ağacı, alt yarı eski Beast Code oturumları. */
2577
+ #bcHistWrap {
2578
+ display: none;
2579
+ flex-direction: column;
2580
+ height: 50%;
2581
+ min-height: 140px;
2582
+ border-top: 1px solid var(--border);
2583
+ background: var(--panel);
2584
+ }
2585
+ body.ide-mode #bcHistWrap { display: flex; }
2586
+ #bcHistHead {
2587
+ flex: none;
2588
+ display: flex;
2589
+ align-items: center;
2590
+ gap: 6px;
2591
+ padding: 7px 10px;
2592
+ border-bottom: 1px solid var(--border);
2593
+ }
2594
+ #bcHistTitle { font-size: 10.5px; letter-spacing: 2px; color: var(--muted); font-weight: 800; }
2595
+ #bcHistHead button {
2596
+ margin-left: auto;
2597
+ background: none;
2598
+ border: 1px solid var(--border);
2599
+ border-radius: 7px;
2600
+ color: var(--muted);
2601
+ cursor: pointer;
2602
+ font-size: 11px;
2603
+ padding: 2px 7px;
2604
+ line-height: 1.4;
2605
+ }
2606
+ /* ikinci buton (çöp) yenile butonunun sağına BİTİŞİK — segmented görünüm */
2607
+ #bcHistHead #bcHistClear {
2608
+ margin-left: -6px; /* flex gap'i iptal et — iki buton yan yana yapışık */
2609
+ border-top-left-radius: 0;
2610
+ border-bottom-left-radius: 0;
2611
+ }
2612
+ #bcHistHead #bcHistRefresh { border-top-right-radius: 0; border-bottom-right-radius: 0; }
2613
+ #bcHistHead button:hover { color: var(--text); background: var(--panel2); }
2614
+ #bcHistList { flex: 1; overflow-y: auto; padding: 4px; }
2615
+ .bc-hist-item {
2616
+ display: flex;
2617
+ align-items: flex-start;
2618
+ gap: 8px;
2619
+ padding: 7px 8px;
2620
+ border-radius: 8px;
2621
+ cursor: pointer;
2622
+ }
2623
+ .bc-hist-item:hover { background: var(--panel2); }
2624
+ .bc-hist-item.active { background: var(--accent-dim); }
2625
+ .bh-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--muted); margin-top: 5px; }
2626
+ .bc-hist-item.active .bh-dot { background: var(--accent); }
2627
+ .bh-main { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 1px; }
2628
+ .bh-title { font-size: 12px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
2629
+ .bh-meta { font-size: 10.5px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
2630
+ /* satır silme: hover'da belirir */
2631
+ .bh-del {
2632
+ flex: none;
2633
+ width: 20px;
2634
+ height: 20px;
2635
+ border: none;
2636
+ background: none;
2637
+ color: var(--muted);
2638
+ font-size: 13px;
2639
+ line-height: 1;
2640
+ padding: 0;
2641
+ border-radius: 6px;
2642
+ cursor: pointer;
2643
+ opacity: 0;
2644
+ margin-top: 2px;
2645
+ }
2646
+ .bc-hist-item:hover .bh-del,
2647
+ .bc-hist-item.active .bh-del { opacity: 1; }
2648
+ .bh-del:hover { color: var(--err); background: var(--panel2); }
2649
+ .bc-hist-empty { padding: 10px 8px; font-size: 11.5px; color: var(--muted); }
2624
2650
  /* görev listesi + geri alma paneli (dosya paneli başlığından açılır) */
2625
2651
  #tasksPanel {
2626
2652
  position: absolute;
@@ -2747,6 +2773,27 @@ body.ide-mode #codePane { display: flex; }
2747
2773
  body.ide-mode.editor-hidden #codePane,
2748
2774
  body.ide-mode.editor-hidden #ideSplit { display: none; }
2749
2775
  body.ide-mode.editor-hidden #ideRow #bcPanel { flex: 1 1 auto; min-width: 0; }
2776
+
2777
+ /* ---------- paylaşılan kod bölmesi: editör ↔ terminal ----------
2778
+ IDE modunda terminal ALT DOCK'ta değil; #codePane İÇİNDE yaşar.
2779
+ Terminal açılınca editör kapanır (term-pane), editör açılınca terminal kapanır. */
2780
+ body.ide-mode #termPanel {
2781
+ flex: 1 1 auto;
2782
+ height: auto;
2783
+ min-height: 0;
2784
+ border-top: none;
2785
+ z-index: auto;
2786
+ }
2787
+ body.ide-mode #termResize { display: none; }
2788
+ body.ide-mode.term-pane #codeTabsBar,
2789
+ body.ide-mode.term-pane #codeBody { display: none; }
2790
+ /* terminal açıkken bölme editör pref'inden bağımsız GÖRÜNÜR kalır */
2791
+ body.ide-mode.term-pane #codePane { display: flex; }
2792
+ /* terminal açıkken bölme düzeni geçerli kalır (editör pref'i ne olursa olsun) */
2793
+ body.ide-mode.term-pane #ideSplit { display: block; }
2794
+ body.ide-mode.term-pane #ideRow #bcPanel { flex: 0 0 var(--ideSplit, 420px); min-width: 280px; }
2795
+ /* IDE'de terminal altta değil — tarayıcı tutamacı tam boy kalır */
2796
+ body.ide-mode.term-open #bbResize { height: calc(100vh - 46px); }
2750
2797
  #codeHide {
2751
2798
  flex: none;
2752
2799
  width: 24px;