beast-agent 1.9.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +130 -130
  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 +75 -10
  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 -427
  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 -652
  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 +348 -6
  47. package/src/preload.js +9 -0
  48. package/src/renderer/browserPreload.js +73 -73
  49. package/src/renderer/i18n.js +4 -0
  50. package/src/renderer/index.html +448 -409
  51. package/src/renderer/renderer.js +824 -41
  52. package/src/renderer/style.css +264 -5
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');
@@ -2617,6 +2617,7 @@ function reloadBackend() {
2617
2617
  if (win && !win.isDestroyed()) win.webContents.send('agent:event', ev);
2618
2618
  flushDesktopOnDone(ev); /* biriken desktop mesajlarını sıraya bas */
2619
2619
  bcFlushOnDone(ev); /* Beast Code kuyruğunu iş bitiminde boşalt */
2620
+ stFlushOnDone(ev); /* Beast Studio kuyruğunu iş bitiminde boşalt */
2620
2621
  /* BC canlı önizleme: ajan bir dev server başlattıysa adresi yakala —
2621
2622
  preview butonu ve otomatik açılış DAİMA bu sunucuyu öncelikli kullanır */
2622
2623
  if (ev.type === 'bc-preview' && /^https?:\/\/(?:localhost|127\.0\.0\.1)(?::\d{2,5})?/i.test(String(ev.url || ''))) {
@@ -2932,6 +2933,7 @@ app.whenReady().then(() => {
2932
2933
  watchers.start({ onTrigger: watcherFire });
2933
2934
  startEventBus();
2934
2935
  ideWatchStart(); // soldaki dosya ağacı canlı izlemede
2936
+ studioWatchStart(); // Beast Studio klasörü canlı izlemede
2935
2937
  maybeRunWhereWasI();
2936
2938
  falloutResume();
2937
2939
  startAutoUpdater(); // #3 sessiz güncelleme
@@ -5857,12 +5859,304 @@ ipcMain.handle('beastcode:new', async () => {
5857
5859
  return { ok: true };
5858
5860
  });
5859
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
+
5860
6142
  /* düşünme (reasoning) seviyesi */
5861
6143
  ipcMain.handle('think:set', (_e, v) => {
5862
6144
  setThinkLevel(v);
5863
6145
  return engine.publicState();
5864
6146
  });
5865
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
+
5866
6160
 
5867
6161
  /* Arama zinciri sırası (Ayarlar → Web Arama'dan değiştirilir) */
5868
6162
  ipcMain.handle('searchorder:get', () => ({ chain: toolsMod.getSearchChain() }));
@@ -5979,10 +6273,32 @@ ipcMain.handle('store:export', (_e, id) => storeMod.exportEntry(id));
5979
6273
 
5980
6274
  /* ---------- IDE MODU (sol: dosya gezgini · orta: chat · sağ: preview) ---------- */
5981
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. */
5982
6280
  const IDE_TEXT_EXT = new Set([
5983
- '.html', '.htm', '.css', '.js', '.mjs', '.cjs', '.ts', '.jsx', '.tsx', '.json',
5984
- '.md', '.txt', '.csv', '.py', '.ps1', '.bat', '.cmd', '.sh', '.yaml', '.yml',
5985
- '.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',
5986
6302
  ]);
5987
6303
  const IDE_MAX_BYTES = 400 * 1024;
5988
6304
 
@@ -6088,7 +6404,7 @@ ipcMain.handle('ide:read', (_e, rel) => {
6088
6404
  const p = ideSafe(rel);
6089
6405
  if (!p) return { ok: false, error: 'geçersiz yol' };
6090
6406
  const ext = path.extname(p).toLowerCase();
6091
- 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' };
6092
6408
  try {
6093
6409
  const st = fs.statSync(p);
6094
6410
  if (st.isDirectory()) return { ok: false, error: 'klasör' };
@@ -6105,7 +6421,7 @@ ipcMain.handle('ide:write', (_e, p) => {
6105
6421
  const target = ideSafe(p && p.rel);
6106
6422
  if (!target) return { ok: false, error: 'geçersiz yol' };
6107
6423
  const ext = path.extname(target).toLowerCase();
6108
- 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' };
6109
6425
  try {
6110
6426
  const body = String((p && p.content) ?? '');
6111
6427
  if (Buffer.byteLength(body, 'utf8') > IDE_MAX_BYTES) return { ok: false, error: 'içerik çok büyük (max 400KB)' };
@@ -6142,6 +6458,32 @@ ipcMain.handle('ide:delete', async (_e, rel) => {
6142
6458
  }
6143
6459
  });
6144
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
+
6145
6487
  /* Sağ tık menüsü: HTML dosyasını dahili tarayıcıda GÖRÜNÜR aç */
6146
6488
  /* ---------- BC DAHİLİ STATİK SUNUCU ----------
6147
6489
  Beast Code çıktısı ASLA file:// ile açılmaz: ES modülleri, fetch, ServiceWorker
package/src/preload.js CHANGED
@@ -77,6 +77,15 @@ contextBridge.exposeInMainWorld('beast', {
77
77
  bcUndo: (sessionId, todoId) => ipcRenderer.invoke('bc:undo', { sessionId, todoId }),
78
78
  beastcodeStop: () => ipcRenderer.invoke('beastcode:stop'),
79
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),
80
89
  thinkSet: (v) => ipcRenderer.invoke('think:set', v),
81
90
  searchOrderGet: () => ipcRenderer.invoke('searchorder:get'),
82
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 {}
@@ -512,6 +512,7 @@
512
512
  tipStore: 'Skills Store',
513
513
  tipGithub: 'GitHub Trending — repoları favorile, chate at, ajana araştır',
514
514
  tipIde: 'IDE Modu — dosyalar + chat + preview',
515
+ tipStudio: 'Beast Studio — video yapma/düzenleme modu',
515
516
  tipCodeHide: 'Editörü kapat',
516
517
  tipCodeShow: 'Editörü göster',
517
518
  ide_files: 'DOSYALAR',
@@ -522,6 +523,7 @@
522
523
  ide_preview: '▶ Preview',
523
524
  ide_saved: 'Kaydedildi — preview\u2019ı yenile',
524
525
  bc_ph: 'Beast Code mesajı yaz — Enter ile gönder…',
526
+ st_ph: 'Beast Studio mesajı yaz — Enter ile gönder…',
525
527
  bc_new: 'Yeni oturum',
526
528
  bc_clear: 'Çıktıyı temizle',
527
529
  bc_stop: 'Çalışan mesajı durdur',
@@ -1131,6 +1133,7 @@
1131
1133
  tipStore: 'Skills Store',
1132
1134
  tipGithub: 'GitHub Trending — favorite repos, send to chat, ask the agent',
1133
1135
  tipIde: 'IDE Mode — files + chat + preview',
1136
+ tipStudio: 'Beast Studio — video making/editing mode',
1134
1137
  tipCodeHide: 'Hide editor',
1135
1138
  tipCodeShow: 'Show editor',
1136
1139
  ide_files: 'FILES',
@@ -1141,6 +1144,7 @@
1141
1144
  ide_preview: '▶ Preview',
1142
1145
  ide_saved: 'Saved — refresh the preview',
1143
1146
  bc_ph: 'Type a message for Beast Code — press Enter to send…',
1147
+ st_ph: 'Type a message for Beast Studio — press Enter to send…',
1144
1148
  bc_new: 'New session',
1145
1149
  bc_clear: 'Clear output',
1146
1150
  bc_stop: 'Stop running message',