beast-agent 1.8.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +130 -128
- package/bin/beast-agent.js +137 -137
- package/package.json +1 -1
- package/scripts/fix-electron.js +138 -138
- package/scripts/release.js +137 -131
- package/scripts/swap-electron.js +40 -40
- package/src/agent/agentdefs.js +122 -122
- package/src/agent/bots.js +580 -580
- package/src/agent/bus.js +389 -389
- package/src/agent/computeruse.js +200 -200
- package/src/agent/config.js +284 -284
- package/src/agent/discord.js +332 -332
- package/src/agent/engine.js +85 -11
- package/src/agent/kb.js +123 -123
- package/src/agent/llm.js +430 -430
- package/src/agent/logger.js +90 -90
- package/src/agent/mcp.js +427 -0
- package/src/agent/mem0.js +605 -605
- package/src/agent/memory.js +427 -427
- package/src/agent/mqueue.js +124 -124
- package/src/agent/pdf.js +20 -20
- package/src/agent/research.js +133 -133
- package/src/agent/scripts/news.py +113 -113
- package/src/agent/scripts/stealthsearch.py +30 -30
- package/src/agent/scripts/websearch.py +225 -225
- package/src/agent/searxng.js +325 -325
- package/src/agent/seeds/brainstorming/SKILL.md +90 -90
- package/src/agent/seeds/dispatching-parallel-agents/SKILL.md +120 -120
- package/src/agent/seeds/executing-plans/SKILL.md +60 -60
- package/src/agent/seeds/subagent-driven-development/SKILL.md +167 -167
- package/src/agent/seeds/systematic-debugging/SKILL.md +131 -131
- package/src/agent/seeds/test-driven-development/SKILL.md +152 -152
- package/src/agent/seeds/verification-before-completion/SKILL.md +63 -63
- package/src/agent/seeds/writing-plans/SKILL.md +162 -162
- package/src/agent/seeds/writing-skills/SKILL.md +229 -229
- package/src/agent/skills.js +652 -651
- package/src/agent/store.js +378 -378
- package/src/agent/telegram.js +155 -155
- package/src/agent/tokens.js +39 -39
- package/src/agent/usage.js +125 -125
- package/src/agent/watchers.js +312 -312
- package/src/agent/watext.js +80 -80
- package/src/agent/whatsapp.js +555 -555
- package/src/cron.js +255 -255
- package/src/main.js +385 -6
- package/src/preload.js +13 -0
- package/src/renderer/browserPreload.js +73 -73
- package/src/renderer/i18n.js +38 -0
- package/src/renderer/index.html +448 -407
- package/src/renderer/renderer.js +897 -42
- package/src/renderer/style.css +275 -11
package/src/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', '.
|
|
5947
|
-
'.
|
|
5948
|
-
'.
|
|
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 &&
|
|
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 &&
|
|
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 {}
|