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.
Files changed (52) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +130 -128
  3. package/bin/beast-agent.js +137 -137
  4. package/package.json +1 -1
  5. package/scripts/fix-electron.js +138 -138
  6. package/scripts/release.js +137 -131
  7. package/scripts/swap-electron.js +40 -40
  8. package/src/agent/agentdefs.js +122 -122
  9. package/src/agent/bots.js +580 -580
  10. package/src/agent/bus.js +389 -389
  11. package/src/agent/computeruse.js +200 -200
  12. package/src/agent/config.js +284 -284
  13. package/src/agent/discord.js +332 -332
  14. package/src/agent/engine.js +85 -11
  15. package/src/agent/kb.js +123 -123
  16. package/src/agent/llm.js +430 -430
  17. package/src/agent/logger.js +90 -90
  18. package/src/agent/mcp.js +427 -0
  19. package/src/agent/mem0.js +605 -605
  20. package/src/agent/memory.js +427 -427
  21. package/src/agent/mqueue.js +124 -124
  22. package/src/agent/pdf.js +20 -20
  23. package/src/agent/research.js +133 -133
  24. package/src/agent/scripts/news.py +113 -113
  25. package/src/agent/scripts/stealthsearch.py +30 -30
  26. package/src/agent/scripts/websearch.py +225 -225
  27. package/src/agent/searxng.js +325 -325
  28. package/src/agent/seeds/brainstorming/SKILL.md +90 -90
  29. package/src/agent/seeds/dispatching-parallel-agents/SKILL.md +120 -120
  30. package/src/agent/seeds/executing-plans/SKILL.md +60 -60
  31. package/src/agent/seeds/subagent-driven-development/SKILL.md +167 -167
  32. package/src/agent/seeds/systematic-debugging/SKILL.md +131 -131
  33. package/src/agent/seeds/test-driven-development/SKILL.md +152 -152
  34. package/src/agent/seeds/verification-before-completion/SKILL.md +63 -63
  35. package/src/agent/seeds/writing-plans/SKILL.md +162 -162
  36. package/src/agent/seeds/writing-skills/SKILL.md +229 -229
  37. package/src/agent/skills.js +652 -651
  38. package/src/agent/store.js +378 -378
  39. package/src/agent/telegram.js +155 -155
  40. package/src/agent/tokens.js +39 -39
  41. package/src/agent/usage.js +125 -125
  42. package/src/agent/watchers.js +312 -312
  43. package/src/agent/watext.js +80 -80
  44. package/src/agent/whatsapp.js +555 -555
  45. package/src/cron.js +255 -255
  46. package/src/main.js +385 -6
  47. package/src/preload.js +13 -0
  48. package/src/renderer/browserPreload.js +73 -73
  49. package/src/renderer/i18n.js +38 -0
  50. package/src/renderer/index.html +448 -407
  51. package/src/renderer/renderer.js +897 -42
  52. package/src/renderer/style.css +275 -11
package/src/main.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { app, BrowserWindow, WebContentsView, ipcMain, shell, dialog, Tray, Menu, nativeImage, desktopCapturer, session, net: electronNet } = require('electron');
3
+ const { app, BrowserWindow, WebContentsView, ipcMain, shell, dialog, Tray, Menu, nativeImage, desktopCapturer, session, net: electronNet, clipboard } = require('electron');
4
4
  const path = require('path');
5
5
  const fs = require('fs');
6
6
  const http = require('http');
@@ -151,6 +151,7 @@ function startNpmUpdateWatch() {
151
151
  setInterval(check, 6 * 60 * 60 * 1000);
152
152
  }
153
153
  const toolsMod = require('./agent/tools');
154
+ const mcpMod = require('./agent/mcp');
154
155
  const { htmlToText, setSearchChain, setTinyfishKey } = toolsMod;
155
156
  /* OpenCode köprüsü KALDIRILDI: Beast Code artık tamamen BEAST motoruyla
156
157
  çalışır — opencode'in döngü mantığı (compaction, prune, cache disiplini,
@@ -2616,6 +2617,7 @@ function reloadBackend() {
2616
2617
  if (win && !win.isDestroyed()) win.webContents.send('agent:event', ev);
2617
2618
  flushDesktopOnDone(ev); /* biriken desktop mesajlarını sıraya bas */
2618
2619
  bcFlushOnDone(ev); /* Beast Code kuyruğunu iş bitiminde boşalt */
2620
+ stFlushOnDone(ev); /* Beast Studio kuyruğunu iş bitiminde boşalt */
2619
2621
  /* BC canlı önizleme: ajan bir dev server başlattıysa adresi yakala —
2620
2622
  preview butonu ve otomatik açılış DAİMA bu sunucuyu öncelikli kullanır */
2621
2623
  if (ev.type === 'bc-preview' && /^https?:\/\/(?:localhost|127\.0\.0\.1)(?::\d{2,5})?/i.test(String(ev.url || ''))) {
@@ -2931,6 +2933,7 @@ app.whenReady().then(() => {
2931
2933
  watchers.start({ onTrigger: watcherFire });
2932
2934
  startEventBus();
2933
2935
  ideWatchStart(); // soldaki dosya ağacı canlı izlemede
2936
+ studioWatchStart(); // Beast Studio klasörü canlı izlemede
2934
2937
  maybeRunWhereWasI();
2935
2938
  falloutResume();
2936
2939
  startAutoUpdater(); // #3 sessiz güncelleme
@@ -2972,6 +2975,7 @@ app.whenReady().then(() => {
2972
2975
  app.isQuitting = true;
2973
2976
  flushBrowserStorage(); // x.com/google oturumları (cookies) diske yazılsın
2974
2977
  try { toolsMod.disposeShellSessions(); } catch {} // kalıcı shell oturumlarını kapat
2978
+ try { require('./agent/mcp').stopAll(); } catch {} // MCP server süreçlerini kapat
2975
2979
  });
2976
2980
 
2977
2981
  if (process.argv.includes('--smoke')) {
@@ -4977,6 +4981,41 @@ ipcMain.handle('settings:get', () => {
4977
4981
  return out;
4978
4982
  });
4979
4983
 
4984
+ /* ---------------- MCP IPC ---------------- */
4985
+
4986
+ ipcMain.handle('mcp:status', () => {
4987
+ try { return mcpMod.status(); } catch { return { path: '', servers: [] }; }
4988
+ });
4989
+
4990
+ ipcMain.handle('mcp:config:get', () => {
4991
+ try {
4992
+ const p = mcpMod.configPath();
4993
+ let raw = '';
4994
+ try { raw = require('fs').readFileSync(p, 'utf8'); } catch {}
4995
+ return { path: p, raw };
4996
+ } catch { return { path: '', raw: '' }; }
4997
+ });
4998
+
4999
+ ipcMain.handle('mcp:config:set', (_e, raw) => {
5000
+ try {
5001
+ const text = String(raw || '');
5002
+ if (text.trim()) JSON.parse(text); /* bozuk JSON diske yazılmaz */
5003
+ mcpMod.saveConfig(text.trim() ? JSON.parse(text) : { servers: {} });
5004
+ return { ok: true };
5005
+ } catch (e) {
5006
+ return { ok: false, error: String((e && e.message) || e) };
5007
+ }
5008
+ });
5009
+
5010
+ ipcMain.handle('mcp:refresh', async (_e, name) => {
5011
+ try {
5012
+ const ok = await mcpMod.refresh(String(name || ''));
5013
+ return { ok, status: mcpMod.status() };
5014
+ } catch (e) {
5015
+ return { ok: false, error: String((e && e.message) || e) };
5016
+ }
5017
+ });
5018
+
4980
5019
  /* ---------------- FALLOUT IPC ---------------- */
4981
5020
 
4982
5021
  function defaultFallout() {
@@ -5820,12 +5859,304 @@ ipcMain.handle('beastcode:new', async () => {
5820
5859
  return { ok: true };
5821
5860
  });
5822
5861
 
5862
+ /* ---------------- Beast Studio paneli (video yapma/düzenleme modu) ----------------
5863
+ Beast Code ile AYRI ve ÖZEL dünya: kendi çalışma klasörü (studioRoot), kendi
5864
+ gizli engine oturumları (klasör bazlı), kendi sohbet kuyruğu. Studio
5865
+ oturumları chat geçmişinde VE Beast Code panelinde ASLA görünmez; Beast Code
5866
+ oturumları da Studio'ya sızmaz. Ajan studio=true ile açılır → buildStudioSystem:
5867
+ klasör içeriğini video proje malzemesi olarak görür (ffmpeg/ffprobe farkında). */
5868
+ const studioSessions = new Map(); /* klasör yolu → sessionId */
5869
+
5870
+ function studioRoot() {
5871
+ /* Studio'nun KENDİ klasörü — IDE'nin ideRoot'undan bağımsız.
5872
+ Ayar yoksa videolar klasörü (Windows Videos) makul başlangıçtır. */
5873
+ if (settings.studioRoot) return path.resolve(settings.studioRoot);
5874
+ let v = '';
5875
+ try { v = app.getPath('videos'); } catch {}
5876
+ return path.resolve(v || settings.workspace || app.getPath('home'));
5877
+ }
5878
+
5879
+ function studioSafe(rel) {
5880
+ const root = studioRoot();
5881
+ const p = path.resolve(root, String(rel || ''));
5882
+ if (p !== root && !p.startsWith(root + path.sep)) return null;
5883
+ return p;
5884
+ }
5885
+
5886
+ function studioGetSession(folder) {
5887
+ let sid = studioSessions.get(folder);
5888
+ if (sid) {
5889
+ try {
5890
+ const s = engine.cache.get(sid);
5891
+ if (s) return s;
5892
+ } catch {}
5893
+ studioSessions.delete(folder);
5894
+ }
5895
+ const s = engine._load(engine.createSession().id);
5896
+ s.messages = s.messages || [];
5897
+ s.bgTitle = 'Beast Studio'; /* _view.isBg → sohbet geçmişi listesinde gizli */
5898
+ s.bcCode = true; /* todo disiplini + hızlı iş kapanışı (engine) */
5899
+ s.studio = true; /* engine: buildStudioSystem — video yapma/düzenleme ajanı */
5900
+ try {
5901
+ fs.appendFileSync(
5902
+ engine._file(s.id),
5903
+ JSON.stringify({ t: 'meta2', bgOf: '', title: 'Beast Studio', at: new Date().toISOString() }) + '\n'
5904
+ );
5905
+ } catch {}
5906
+ engine.cache.set(s.id, s);
5907
+ studioSessions.set(folder, s.id);
5908
+ return s;
5909
+ }
5910
+
5911
+ /* Studio mesaj kuyruğu: Beast Code kuyruğunun birebir karşılığı —
5912
+ ajan çalışırken mesajlar birikir, iş bitince TEK pakette gönderilir */
5913
+ const ST_DEBOUNCE_MS = 900;
5914
+ const stQueue = new Map(); /* klasör yolu → { timer, msgs[] } */
5915
+
5916
+ function stQueuePush(ws, text, attachments) {
5917
+ let q = stQueue.get(ws);
5918
+ if (!q) {
5919
+ q = { timer: null, msgs: [] };
5920
+ stQueue.set(ws, q);
5921
+ }
5922
+ q.msgs.push({
5923
+ text,
5924
+ attachments: Array.isArray(attachments) && attachments.length ? attachments : undefined,
5925
+ });
5926
+ return q;
5927
+ }
5928
+
5929
+ function stFlush(folder) {
5930
+ const q = stQueue.get(folder);
5931
+ if (!q || !q.msgs.length) return;
5932
+ const s = studioGetSession(folder);
5933
+ if (engine.isBusy(s.id)) return;
5934
+ let merged = '';
5935
+ let mergedAtts = null;
5936
+ for (const m of q.msgs) {
5937
+ if (m.text) merged += (merged ? '\n' : '') + m.text;
5938
+ if (!mergedAtts && Array.isArray(m.attachments) && m.attachments.length) mergedAtts = m.attachments;
5939
+ }
5940
+ if (!merged.trim() && !mergedAtts) {
5941
+ stQueue.delete(folder);
5942
+ clearTimeout(q.timer);
5943
+ return;
5944
+ }
5945
+ s.workspace = folder;
5946
+ s.bcCode = true;
5947
+ s.studio = true;
5948
+ engine.cache.set(s.id, s);
5949
+ const payload = mergedAtts ? { text: merged, attachments: mergedAtts } : merged;
5950
+ if (engine.send(s.id, payload, { userAction: true })) {
5951
+ stQueue.delete(folder);
5952
+ clearTimeout(q.timer);
5953
+ } else {
5954
+ q.retries = (q.retries || 0) + 1;
5955
+ if (q.retries > 5) {
5956
+ stQueue.delete(folder);
5957
+ clearTimeout(q.timer);
5958
+ try {
5959
+ if (win && !win.isDestroyed()) {
5960
+ win.webContents.send('agent:event', { sessionId: s.id, type: 'error', error: 'Beast Studio mesajı gönderilemedi — panele tekrar yaz' });
5961
+ }
5962
+ } catch {}
5963
+ return;
5964
+ }
5965
+ setTimeout(() => { try { stFlush(folder); } catch {} }, 800);
5966
+ }
5967
+ }
5968
+
5969
+ function stFlushOnDone(ev) {
5970
+ if (!ev || (ev.type !== 'done' && ev.type !== 'error') || !ev.sessionId) return;
5971
+ for (const [folder, sid] of studioSessions) {
5972
+ if (String(sid) === String(ev.sessionId) && stQueue.has(folder)) {
5973
+ setTimeout(() => { try { stFlush(folder); } catch {} }, 150);
5974
+ }
5975
+ }
5976
+ }
5977
+
5978
+ ipcMain.handle('studio:send', async (_e, payload) => {
5979
+ const text = String((payload && payload.msg) || '').trim();
5980
+ const attachments = Array.isArray(payload && payload.attachments) ? payload.attachments : [];
5981
+ if (!text && !attachments.length) return { ok: false, error: 'boş mesaj' };
5982
+ if (!engine) return { ok: false, error: 'ajan hazır değil' };
5983
+ const ws = studioRoot();
5984
+ const modeM = /^\/(plan|build|auto)\b/i.exec(text);
5985
+
5986
+ if (!engine.publicState().hasModel) return { ok: false, error: 'model yok — Ayarlar → Provider sekmesinden ekle' };
5987
+ const s = studioGetSession(ws);
5988
+ s.workspace = ws;
5989
+ s.bcCode = true;
5990
+ s.studio = true;
5991
+ engine.cache.set(s.id, s);
5992
+ const busy = engine.isBusy(s.id);
5993
+ if (modeM) {
5994
+ s.bcMode = modeM[1].toLowerCase();
5995
+ if (win && !win.isDestroyed()) {
5996
+ const body = modeM[1].toLowerCase() === 'plan'
5997
+ ? 'PLAN MODU — malzemeyi inceler (list_dir/ffprobe), KOMUT ÇALIŞTIRMAZ; adım adım montaj planı verir.'
5998
+ : modeM[1].toLowerCase() === 'build'
5999
+ ? 'BUILD MODU — son montaj planını UYGULAR: ffmpeg işlerini çalıştırır, çıktıları doğrular.'
6000
+ : 'OTOMATİK MOD — önce kısa plan, sonra uygulama + doğrulama.';
6001
+ win.webContents.send('agent:event', { sessionId: s.id, type: 'st-mode', mode: s.bcMode, body });
6002
+ }
6003
+ return { ok: true, sessionId: s.id, mode: s.bcMode };
6004
+ }
6005
+ if (busy) {
6006
+ const q = stQueuePush(ws, text, attachments);
6007
+ return { ok: true, queued: true, count: q.msgs.length, sessionId: s.id };
6008
+ }
6009
+ const q = stQueuePush(ws, text, attachments);
6010
+ clearTimeout(q.timer);
6011
+ q.timer = setTimeout(() => { try { stFlush(ws); } catch {} }, ST_DEBOUNCE_MS);
6012
+ return { ok: true, sessionId: s.id, pending: true };
6013
+ });
6014
+
6015
+ ipcMain.handle('studio:stop', async () => {
6016
+ const ws = studioRoot();
6017
+ const sid = studioSessions.get(ws);
6018
+ const q = stQueue.get(ws);
6019
+ if (q) {
6020
+ clearTimeout(q.timer);
6021
+ stQueue.delete(ws);
6022
+ }
6023
+ const wasBusy = sid ? engine.isBusy(sid) : false;
6024
+ let r = false;
6025
+ if (wasBusy) {
6026
+ try { r = engine.interrupt(sid, 'kullanıcı Beast Studio panelinden ■ ile durdurdu'); } catch {}
6027
+ }
6028
+ return { ok: true, wasBusy, interrupted: r };
6029
+ });
6030
+
6031
+ ipcMain.handle('studio:new', async () => {
6032
+ const ws = studioRoot();
6033
+ const sid = studioSessions.get(ws);
6034
+ if (sid && engine.isBusy(sid)) return { ok: false, error: 'mesaj sürüyor — önce ■ ile durdur' };
6035
+ const q = stQueue.get(ws);
6036
+ if (q) {
6037
+ clearTimeout(q.timer);
6038
+ stQueue.delete(ws);
6039
+ }
6040
+ if (sid) {
6041
+ try { engine.deleteSession(sid); } catch {}
6042
+ studioSessions.delete(ws);
6043
+ }
6044
+ return { ok: true };
6045
+ });
6046
+
6047
+ ipcMain.handle('studio:setroot', async () => {
6048
+ try {
6049
+ const r = await dialog.showOpenDialog({
6050
+ title: 'Beast Studio klasörü seç — videolar ve malzemeler bu klasörde',
6051
+ defaultPath: studioRoot(),
6052
+ properties: ['openDirectory'],
6053
+ });
6054
+ if (r.canceled || !r.filePaths || !r.filePaths[0]) return { ok: false, canceled: true };
6055
+ settings.studioRoot = r.filePaths[0];
6056
+ saveSettings();
6057
+ studioWatchStart();
6058
+ return { ok: true, root: settings.studioRoot };
6059
+ } catch (e) {
6060
+ return { ok: false, error: String((e && e.message) || e) };
6061
+ }
6062
+ });
6063
+
6064
+ ipcMain.handle('studio:tree', (_e, rel) => {
6065
+ const p = studioSafe(rel);
6066
+ if (!p) return { ok: false, error: 'geçersiz yol' };
6067
+ try {
6068
+ const entries = fs.readdirSync(p, { withFileTypes: true })
6069
+ .filter((e) => e.name !== 'node_modules' && e.name !== '.git')
6070
+ .map((e) => {
6071
+ let size = 0;
6072
+ try { if (e.isFile()) size = fs.statSync(path.join(p, e.name)).size; } catch {}
6073
+ return { name: e.name, dir: e.isDirectory(), size };
6074
+ })
6075
+ .sort((a, b) => (a.dir === b.dir ? a.name.localeCompare(b.name) : a.dir ? -1 : 1));
6076
+ return { ok: true, workspace: studioRoot(), entries };
6077
+ } catch (e) {
6078
+ return { ok: false, error: String((e && e.message) || e) };
6079
+ }
6080
+ });
6081
+
6082
+ /* Studio video seçici: video bölümündeki "Aç" düğmesi — medya dosyası seçilir,
6083
+ yol düz döner (renderer file:// ile oynatır) */
6084
+ ipcMain.handle('studio:pickvideo', async () => {
6085
+ try {
6086
+ const r = await dialog.showOpenDialog({
6087
+ title: 'Video/ses dosyası seç',
6088
+ defaultPath: studioRoot(),
6089
+ properties: ['openFile'],
6090
+ filters: [
6091
+ { name: 'Medya', extensions: ['mp4', 'mkv', 'mov', 'avi', 'webm', 'm4v', 'mpg', 'mpeg', 'wmv', 'flv', '3gp', 'ogv', 'mp3', 'wav', 'ogg', 'm4a', 'flac', 'aac', 'opus'] },
6092
+ { name: 'Tüm dosyalar', extensions: ['*'] },
6093
+ ],
6094
+ });
6095
+ if (r.canceled || !r.filePaths || !r.filePaths[0]) return { ok: false, canceled: true };
6096
+ return { ok: true, path: r.filePaths[0] };
6097
+ } catch (e) {
6098
+ return { ok: false, error: String((e && e.message) || e) };
6099
+ }
6100
+ });
6101
+
6102
+ /* Studio ağaç canlı izleme: IDE izleyicisinin karşılığı — studioRoot kökü
6103
+ izlenir, değişim 'ide-tree-changed' ile düşer (renderFileTree moduna göre
6104
+ doğru ağacı tazeler). ffmpeg çıktısı da anında ağaca düşer. */
6105
+ let studioWatcher = null;
6106
+ let studioWatchTimer = null;
6107
+ let studioWatchRoot = '';
6108
+ function studioWatchStart() {
6109
+ const root = studioRoot();
6110
+ if (studioWatcher && studioWatchRoot === root) return;
6111
+ studioWatchStop();
6112
+ if (root === app.getPath('home')) return;
6113
+ try { fs.accessSync(root); } catch { return; }
6114
+ studioWatchRoot = root;
6115
+ try {
6116
+ studioWatcher = fs.watch(root, { recursive: true }, (_evType, fname) => {
6117
+ const f = String(fname || '').replace(/\\/g, '/');
6118
+ if (/^(node_modules|\.git|dist)(\/|$)/i.test(f)) return;
6119
+ if (studioWatchTimer) return;
6120
+ studioWatchTimer = setTimeout(() => {
6121
+ studioWatchTimer = null;
6122
+ try {
6123
+ if (win && !win.isDestroyed()) {
6124
+ win.webContents.send('agent:event', { type: 'ide-tree-changed' });
6125
+ }
6126
+ } catch {}
6127
+ }, 500);
6128
+ });
6129
+ studioWatcher.on('error', () => {
6130
+ studioWatchStop();
6131
+ setTimeout(() => { try { studioWatchStart(); } catch {} }, 3000);
6132
+ });
6133
+ } catch {}
6134
+ }
6135
+ function studioWatchStop() {
6136
+ if (studioWatcher) { try { studioWatcher.close(); } catch {} }
6137
+ studioWatcher = null;
6138
+ studioWatchRoot = '';
6139
+ if (studioWatchTimer) { clearTimeout(studioWatchTimer); studioWatchTimer = null; }
6140
+ }
6141
+
5823
6142
  /* düşünme (reasoning) seviyesi */
5824
6143
  ipcMain.handle('think:set', (_e, v) => {
5825
6144
  setThinkLevel(v);
5826
6145
  return engine.publicState();
5827
6146
  });
5828
6147
 
6148
+ /* ---------- PANO KÖPRÜSÜ (uygulama geneli sağ tık menüsü) ----------
6149
+ Chromium rendererdaki execCommand('paste') güvenilir değil; Kes/Kopyala/
6150
+ Yapıştır'ı pano köprüsüyle MANUEL yapıyoruz (imleç konumunda ekleme). */
6151
+ ipcMain.handle('clip:read', () => {
6152
+ try { return clipboard.readText(); } catch { return ''; }
6153
+ });
6154
+ ipcMain.handle('clip:write', (_e, t) => {
6155
+ try { clipboard.writeText(String(t ?? '')); return { ok: true }; } catch (e) {
6156
+ return { ok: false, error: String((e && e.message) || e) };
6157
+ }
6158
+ });
6159
+
5829
6160
 
5830
6161
  /* Arama zinciri sırası (Ayarlar → Web Arama'dan değiştirilir) */
5831
6162
  ipcMain.handle('searchorder:get', () => ({ chain: toolsMod.getSearchChain() }));
@@ -5942,10 +6273,32 @@ ipcMain.handle('store:export', (_e, id) => storeMod.exportEntry(id));
5942
6273
 
5943
6274
  /* ---------- IDE MODU (sol: dosya gezgini · orta: chat · sağ: preview) ---------- */
5944
6275
 
6276
+ /* opencode disiplini: editör TÜM kod altyapısını açar — web-only değil.
6277
+ İkili (binary) koruması uzantı listesiyle değil, okuma anındaki NUL-byte
6278
+ sniffing ile yapılır (ide:read). Liste yalnız bilinen metin türlerini
6279
+ hızlandırır; bilinmeyen uzantılar da denenir. */
5945
6280
  const IDE_TEXT_EXT = new Set([
5946
- '.html', '.htm', '.css', '.js', '.mjs', '.cjs', '.ts', '.jsx', '.tsx', '.json',
5947
- '.md', '.txt', '.csv', '.py', '.ps1', '.bat', '.cmd', '.sh', '.yaml', '.yml',
5948
- '.xml', '.ini', '.svg', '.gitignore',
6281
+ '.html', '.htm', '.css', '.scss', '.sass', '.less', '.js', '.mjs', '.cjs', '.ts',
6282
+ '.tsx', '.jsx', '.mts', '.cts', '.json', '.jsonc', '.json5', '.md', '.mdx', '.txt',
6283
+ '.csv', '.tsv', '.log', '.py', '.pyi', '.pyw', '.ps1', '.psm1', '.bat', '.cmd',
6284
+ '.sh', '.bash', '.zsh', '.yaml', '.yml', '.toml', '.xml', '.ini', '.cfg', '.conf',
6285
+ '.env', '.properties', '.svg', '.gitignore', '.gitattributes', '.editorconfig',
6286
+ '.npmrc', '.nvmrc', '.babelrc', '.prettierrc', '.eslintrc', '.go', '.mod', '.sum',
6287
+ '.rs', '.java', '.kt', '.kts', '.swift', '.rb', '.erb', '.php', '.cs', '.csproj',
6288
+ '.sln', '.vb', '.fs', '.c', '.h', '.cpp', '.hpp', '.cc', '.hh', '.cxx', '.hxx',
6289
+ '.m', '.mm', '.sql', '.prisma', '.graphql', '.gql', '.proto', '.vue', '.svelte',
6290
+ '.astro', '.lua', '.pl', '.pm', '.r', '.R', '.jl', '.dart', '.scala', '.groovy',
6291
+ '.gradle', '.cmake', '.mk', '.make', '.dockerfile', '.terraform', '.tf', '.hcl',
6292
+ '.asm', '.s', '.vbs', '.reg', '.htaccess', '.lock', '.patch', '.diff', '.ipynb',
6293
+ ]);
6294
+ const IDE_BINARY_EXT = new Set([
6295
+ '.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp', '.ico', '.icns', '.tiff',
6296
+ '.mp4', '.mkv', '.mov', '.avi', '.webm', '.m4v', '.mpg', '.mpeg', '.wmv', '.flv',
6297
+ '.3gp', '.ogv', '.mp3', '.wav', '.ogg', '.m4a', '.flac', '.aac', '.opus', '.wma',
6298
+ '.zip', '.7z', '.rar', '.gz', '.tar', '.bz2', '.xz', '.exe', '.dll', '.so',
6299
+ '.dylib', '.bin', '.dat', '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt',
6300
+ '.pptx', '.ttf', '.otf', '.woff', '.woff2', '.eot', '.db', '.sqlite', '.pyc',
6301
+ '.class', '.jar', '.wasm', '.psd', '.ai', '.prproj', '.aep', '.fcpxml',
5949
6302
  ]);
5950
6303
  const IDE_MAX_BYTES = 400 * 1024;
5951
6304
 
@@ -6051,7 +6404,7 @@ ipcMain.handle('ide:read', (_e, rel) => {
6051
6404
  const p = ideSafe(rel);
6052
6405
  if (!p) return { ok: false, error: 'geçersiz yol' };
6053
6406
  const ext = path.extname(p).toLowerCase();
6054
- if (ext && !IDE_TEXT_EXT.has(ext)) return { ok: false, error: 'metin dosyası değil — düzenlenemez' };
6407
+ if (ext && IDE_BINARY_EXT.has(ext)) return { ok: false, error: 'ikili (binary) dosya — düzenlenemez' };
6055
6408
  try {
6056
6409
  const st = fs.statSync(p);
6057
6410
  if (st.isDirectory()) return { ok: false, error: 'klasör' };
@@ -6068,7 +6421,7 @@ ipcMain.handle('ide:write', (_e, p) => {
6068
6421
  const target = ideSafe(p && p.rel);
6069
6422
  if (!target) return { ok: false, error: 'geçersiz yol' };
6070
6423
  const ext = path.extname(target).toLowerCase();
6071
- if (ext && !IDE_TEXT_EXT.has(ext)) return { ok: false, error: 'metin dosyası değil — yazılamaz' };
6424
+ if (ext && IDE_BINARY_EXT.has(ext)) return { ok: false, error: 'ikili (binary) dosya — yazılamaz' };
6072
6425
  try {
6073
6426
  const body = String((p && p.content) ?? '');
6074
6427
  if (Buffer.byteLength(body, 'utf8') > IDE_MAX_BYTES) return { ok: false, error: 'içerik çok büyük (max 400KB)' };
@@ -6105,6 +6458,32 @@ ipcMain.handle('ide:delete', async (_e, rel) => {
6105
6458
  }
6106
6459
  });
6107
6460
 
6461
+ /* Studio silme: IDE kökünden BAĞIMSIZ studioRoot üzerinde çalışır */
6462
+ ipcMain.handle('studio:delete', async (_e, rel) => {
6463
+ const p = studioSafe(rel);
6464
+ if (!p || p === studioRoot()) return { ok: false, error: 'geçersiz yol' };
6465
+ try {
6466
+ const st = fs.statSync(p);
6467
+ const isDir = st.isDirectory();
6468
+ const owner = win && !win.isDestroyed() ? win : undefined;
6469
+ const r = owner
6470
+ ? await dialog.showMessageBox(owner, {
6471
+ type: 'warning',
6472
+ title: 'Sil',
6473
+ message: `"${rel}" ${isDir ? 'klasörünü (içi dahil)' : 'dosyasını'} silmek istiyor musun?`,
6474
+ buttons: ['Sil', 'Vazgeç'],
6475
+ defaultId: 1,
6476
+ cancelId: 1,
6477
+ })
6478
+ : { response: 1 };
6479
+ if (r.response !== 0) return { ok: false, canceled: true };
6480
+ fs.rmSync(p, { recursive: true, force: true });
6481
+ return { ok: true };
6482
+ } catch (e) {
6483
+ return { ok: false, error: String((e && e.message) || e) };
6484
+ }
6485
+ });
6486
+
6108
6487
  /* Sağ tık menüsü: HTML dosyasını dahili tarayıcıda GÖRÜNÜR aç */
6109
6488
  /* ---------- BC DAHİLİ STATİK SUNUCU ----------
6110
6489
  Beast Code çıktısı ASLA file:// ile açılmaz: ES modülleri, fetch, ServiceWorker
package/src/preload.js CHANGED
@@ -42,6 +42,10 @@ contextBridge.exposeInMainWorld('beast', {
42
42
  getSettings: () => ipcRenderer.invoke('settings:get'),
43
43
  getFallout: () => ipcRenderer.invoke('fallout:get'),
44
44
  setFallout: (cfg) => ipcRenderer.invoke('fallout:set', cfg),
45
+ mcpStatus: () => ipcRenderer.invoke('mcp:status'),
46
+ mcpConfigGet: () => ipcRenderer.invoke('mcp:config:get'),
47
+ mcpConfigSet: (raw) => ipcRenderer.invoke('mcp:config:set', raw),
48
+ mcpRefresh: (name) => ipcRenderer.invoke('mcp:refresh', name),
45
49
  getLimits: () => ipcRenderer.invoke('limits:get'),
46
50
  setLimits: (cfg) => ipcRenderer.invoke('limits:set', cfg),
47
51
  secGet: () => ipcRenderer.invoke('sec:get'),
@@ -73,6 +77,15 @@ contextBridge.exposeInMainWorld('beast', {
73
77
  bcUndo: (sessionId, todoId) => ipcRenderer.invoke('bc:undo', { sessionId, todoId }),
74
78
  beastcodeStop: () => ipcRenderer.invoke('beastcode:stop'),
75
79
  beastcodeNew: () => ipcRenderer.invoke('beastcode:new'),
80
+ studioSend: (msg, attachments) => ipcRenderer.invoke('studio:send', { msg, attachments }),
81
+ studioStop: () => ipcRenderer.invoke('studio:stop'),
82
+ studioNew: () => ipcRenderer.invoke('studio:new'),
83
+ studioSetRoot: () => ipcRenderer.invoke('studio:setroot'),
84
+ studioTree: (rel) => ipcRenderer.invoke('studio:tree', rel),
85
+ studioPickVideo: () => ipcRenderer.invoke('studio:pickvideo'),
86
+ studioDelete: (rel) => ipcRenderer.invoke('studio:delete', rel),
87
+ clipRead: () => ipcRenderer.invoke('clip:read'),
88
+ clipWrite: (t) => ipcRenderer.invoke('clip:write', t),
76
89
  thinkSet: (v) => ipcRenderer.invoke('think:set', v),
77
90
  searchOrderGet: () => ipcRenderer.invoke('searchorder:get'),
78
91
  searchOrderSet: (chain) => ipcRenderer.invoke('searchorder:set', chain),
@@ -1,73 +1,73 @@
1
- 'use strict';
2
-
3
- /* Dahili tarayıcı preload — Google girişinin "bu tarayıcı veya uygulama
4
- güvenli olmayabilir" engelini aşar. Electron'da eksik olan gerçek Chrome
5
- imzaları (window.chrome, navigator.plugins/mimeTypes/languages, webdriver)
6
- ana dünyada (main world) tamamlanır. Her belge yüklemesinde tekrar koşar. */
7
-
8
- const { webFrame } = require('electron');
9
-
10
- const PATCH = `(function () {
11
- try {
12
- try { Object.defineProperty(navigator, 'webdriver', { get: function () { return false; } }); } catch (e) {}
13
- try { Object.defineProperty(navigator, 'languages', { get: function () { return ['tr-TR', 'tr', 'en-US', 'en']; } }); } catch (e) {}
14
-
15
- if (!window.chrome) { try { window.chrome = {}; } catch (e) {} }
16
- if (!window.chrome.app) {
17
- window.chrome.app = {
18
- isInstalled: false,
19
- InstallState: { DISABLED: 'disabled', INSTALLED: 'installed', NOT_INSTALLED: 'not_installed' },
20
- RunningState: { CANNOT_RUN: 'cannot_run', READY_TO_RUN: 'ready_to_run', RUNNING: 'running' },
21
- getDetails: function () {},
22
- installState: function () { return 'not_installed'; },
23
- };
24
- }
25
- if (!window.chrome.runtime) {
26
- window.chrome.runtime = {
27
- PlatformOs: { MAC: 'mac', WIN: 'win', ANDROID: 'android', CROS: 'cros', LINUX: 'linux', OPENBSD: 'openbsd' },
28
- PlatformArch: { ARM: 'arm', X86_32: 'x86-32', X86_64: 'x86-64', MIPS: 'mips', MIPS64: 'mips64' },
29
- PlatformNaclArch: { ARM: 'arm', X86_32: 'x86-32', X86_64: 'x86-64', MIPS: 'mips', MIPS64: 'mips64' },
30
- RequestUpdateCheckStatus: { NO_UPDATE: 'no_update', THROTTLED: 'throttled', UPDATE_AVAILABLE: 'update_available' },
31
- OnInstalledReason: { CHROME_UPDATE: 'chrome_update', INSTALL: 'install', SHARED_MODULE_UPDATE: 'shared_module_update', UPDATE: 'update' },
32
- OnRestartRequiredReason: { APP_UPDATE: 'app_update', OS_UPDATE: 'os_update', PERIODIC: 'periodic' },
33
- connect: function () {},
34
- sendMessage: function () {},
35
- };
36
- }
37
-
38
- if (navigator.plugins && navigator.plugins.length === 0) {
39
- var pluginData = [
40
- { name: 'PDF Viewer', description: 'Portable Document Format', filename: 'internal-pdf-viewer', type: 'application/pdf', suffixes: 'pdf' },
41
- { name: 'Chrome PDF Viewer', description: 'Portable Document Format', filename: 'internal-pdf-viewer', type: 'application/pdf', suffixes: 'pdf' },
42
- { name: 'Chromium PDF Viewer', description: 'Portable Document Format', filename: 'internal-pdf-viewer', type: 'application/pdf', suffixes: 'pdf' },
43
- { name: 'Microsoft Edge PDF Viewer', description: 'Portable Document Format', filename: 'internal-pdf-viewer', type: 'application/pdf', suffixes: 'pdf' },
44
- { name: 'WebKit built-in PDF', description: 'Portable Document Format', filename: 'internal-pdf-viewer', type: 'application/pdf', suffixes: 'pdf' },
45
- ];
46
- var plugins = {
47
- length: pluginData.length,
48
- item: function (i) { return this[i] || null; },
49
- namedItem: function (n) { for (var k in this) { if (this[k] && this[k].name === n) return this[k]; } return null; },
50
- refresh: function () {},
51
- };
52
- pluginData.forEach(function (p, i) {
53
- var pl = { name: p.name, description: p.description, filename: p.filename, length: 1 };
54
- pl[0] = { type: p.type, suffixes: p.suffixes, description: p.description, enabledPlugin: pl };
55
- plugins[i] = pl;
56
- });
57
- try { Object.defineProperty(navigator, 'plugins', { get: function () { return plugins; } }); } catch (e) {}
58
- try {
59
- var mimes = {
60
- length: pluginData.length,
61
- item: function (i) { return (plugins[i] && plugins[i][0]) || null; },
62
- namedItem: function (n) { for (var k in this) { if (this[k] && this[k].type === n) return this[k]; } return null; },
63
- };
64
- pluginData.forEach(function (p, i) { mimes[p.type] = plugins[i] && plugins[i][0]; });
65
- Object.defineProperty(navigator, 'mimeTypes', { get: function () { return mimes; } });
66
- } catch (e) {}
67
- }
68
- } catch (e) {}
69
- })();`;
70
-
71
- try {
72
- webFrame.executeJavaScript(PATCH).catch(() => {});
73
- } catch {}
1
+ 'use strict';
2
+
3
+ /* Dahili tarayıcı preload — Google girişinin "bu tarayıcı veya uygulama
4
+ güvenli olmayabilir" engelini aşar. Electron'da eksik olan gerçek Chrome
5
+ imzaları (window.chrome, navigator.plugins/mimeTypes/languages, webdriver)
6
+ ana dünyada (main world) tamamlanır. Her belge yüklemesinde tekrar koşar. */
7
+
8
+ const { webFrame } = require('electron');
9
+
10
+ const PATCH = `(function () {
11
+ try {
12
+ try { Object.defineProperty(navigator, 'webdriver', { get: function () { return false; } }); } catch (e) {}
13
+ try { Object.defineProperty(navigator, 'languages', { get: function () { return ['tr-TR', 'tr', 'en-US', 'en']; } }); } catch (e) {}
14
+
15
+ if (!window.chrome) { try { window.chrome = {}; } catch (e) {} }
16
+ if (!window.chrome.app) {
17
+ window.chrome.app = {
18
+ isInstalled: false,
19
+ InstallState: { DISABLED: 'disabled', INSTALLED: 'installed', NOT_INSTALLED: 'not_installed' },
20
+ RunningState: { CANNOT_RUN: 'cannot_run', READY_TO_RUN: 'ready_to_run', RUNNING: 'running' },
21
+ getDetails: function () {},
22
+ installState: function () { return 'not_installed'; },
23
+ };
24
+ }
25
+ if (!window.chrome.runtime) {
26
+ window.chrome.runtime = {
27
+ PlatformOs: { MAC: 'mac', WIN: 'win', ANDROID: 'android', CROS: 'cros', LINUX: 'linux', OPENBSD: 'openbsd' },
28
+ PlatformArch: { ARM: 'arm', X86_32: 'x86-32', X86_64: 'x86-64', MIPS: 'mips', MIPS64: 'mips64' },
29
+ PlatformNaclArch: { ARM: 'arm', X86_32: 'x86-32', X86_64: 'x86-64', MIPS: 'mips', MIPS64: 'mips64' },
30
+ RequestUpdateCheckStatus: { NO_UPDATE: 'no_update', THROTTLED: 'throttled', UPDATE_AVAILABLE: 'update_available' },
31
+ OnInstalledReason: { CHROME_UPDATE: 'chrome_update', INSTALL: 'install', SHARED_MODULE_UPDATE: 'shared_module_update', UPDATE: 'update' },
32
+ OnRestartRequiredReason: { APP_UPDATE: 'app_update', OS_UPDATE: 'os_update', PERIODIC: 'periodic' },
33
+ connect: function () {},
34
+ sendMessage: function () {},
35
+ };
36
+ }
37
+
38
+ if (navigator.plugins && navigator.plugins.length === 0) {
39
+ var pluginData = [
40
+ { name: 'PDF Viewer', description: 'Portable Document Format', filename: 'internal-pdf-viewer', type: 'application/pdf', suffixes: 'pdf' },
41
+ { name: 'Chrome PDF Viewer', description: 'Portable Document Format', filename: 'internal-pdf-viewer', type: 'application/pdf', suffixes: 'pdf' },
42
+ { name: 'Chromium PDF Viewer', description: 'Portable Document Format', filename: 'internal-pdf-viewer', type: 'application/pdf', suffixes: 'pdf' },
43
+ { name: 'Microsoft Edge PDF Viewer', description: 'Portable Document Format', filename: 'internal-pdf-viewer', type: 'application/pdf', suffixes: 'pdf' },
44
+ { name: 'WebKit built-in PDF', description: 'Portable Document Format', filename: 'internal-pdf-viewer', type: 'application/pdf', suffixes: 'pdf' },
45
+ ];
46
+ var plugins = {
47
+ length: pluginData.length,
48
+ item: function (i) { return this[i] || null; },
49
+ namedItem: function (n) { for (var k in this) { if (this[k] && this[k].name === n) return this[k]; } return null; },
50
+ refresh: function () {},
51
+ };
52
+ pluginData.forEach(function (p, i) {
53
+ var pl = { name: p.name, description: p.description, filename: p.filename, length: 1 };
54
+ pl[0] = { type: p.type, suffixes: p.suffixes, description: p.description, enabledPlugin: pl };
55
+ plugins[i] = pl;
56
+ });
57
+ try { Object.defineProperty(navigator, 'plugins', { get: function () { return plugins; } }); } catch (e) {}
58
+ try {
59
+ var mimes = {
60
+ length: pluginData.length,
61
+ item: function (i) { return (plugins[i] && plugins[i][0]) || null; },
62
+ namedItem: function (n) { for (var k in this) { if (this[k] && this[k].type === n) return this[k]; } return null; },
63
+ };
64
+ pluginData.forEach(function (p, i) { mimes[p.type] = plugins[i] && plugins[i][0]; });
65
+ Object.defineProperty(navigator, 'mimeTypes', { get: function () { return mimes; } });
66
+ } catch (e) {}
67
+ }
68
+ } catch (e) {}
69
+ })();`;
70
+
71
+ try {
72
+ webFrame.executeJavaScript(PATCH).catch(() => {});
73
+ } catch {}