beast-agent 2.41.0 → 2.43.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/assets/app.ico +0 -0
- package/package.json +1 -1
- package/src/agent/engine.js +1 -1
- package/src/agent/opencode/agents.js +3 -3
- package/src/agent/tools.js +1 -1
- package/src/main.js +185 -9
- package/src/preload.js +1 -0
- package/src/renderer/i18n.js +2 -0
- package/src/renderer/index.html +40 -3
- package/src/renderer/renderer.js +347 -13
- package/src/renderer/style.css +262 -3
package/assets/app.ico
CHANGED
|
Binary file
|
package/package.json
CHANGED
package/src/agent/engine.js
CHANGED
|
@@ -5030,7 +5030,7 @@ const skills = require('./skills');
|
|
|
5030
5030
|
folder: r.folder,
|
|
5031
5031
|
detected: info ? { kind: info.kind, label: info.label, install: info.install, run: info.run } : undefined,
|
|
5032
5032
|
note:
|
|
5033
|
-
'Repo "' + r.name + '" → ' + r.folder + ' klasörüne indirildi. Kurmak için sandbox_repo action=kur, çalıştırmak için action=baslat; kullanıcı Sandbox panelindeki
|
|
5033
|
+
'Repo "' + r.name + '" → ' + r.folder + ' klasörüne indirildi. Kurmak için sandbox_repo action=kur, çalıştırmak için action=baslat (bağımlılıklar eksikse önce kurar); kullanıcı Sandbox panelindeki Başlat/Dev butonlarını da kullanabilir.',
|
|
5034
5034
|
};
|
|
5035
5035
|
}
|
|
5036
5036
|
if (action !== 'kur' && action !== 'baslat' && action !== 'durdur') {
|
|
@@ -131,9 +131,9 @@ function build(opts = {}) {
|
|
|
131
131
|
),
|
|
132
132
|
prompt: [
|
|
133
133
|
'BEAST SANDBOX MODUNDASIN: GitHub\u2019dan indirilmi\u015f A\u00c7IK KAYNAK bir repo klas\u00f6r\u00fcndesin (Beast-Sandbox). Bu kodun sahibi de\u011filsin \u2014 haz\u0131r bir d\u0131\u015f proje; repo sahibinin konvansiyonlar\u0131na uy, gereksiz yeniden bi\u00e7imlendirme yapma.',
|
|
134
|
-
'PANEL: \u00c7ALI\u015eTIR b\u00f6l\u00fcm\u00fcndeki
|
|
135
|
-
'\u0130\u015fe README + paket bildirim dosyalar\u0131yla ba\u015fla (list/glob);
|
|
136
|
-
'UZUN S\u00dcREL\u0130 sunucu/s\u00fcre\u00e7 (npm start, npm run dev, python app.py vb.) bash ile ASLA ba\u015flatma \u2014 tur kilitlenir; kullan\u0131c\u0131 senden isterse panel_run ile ba\u015flat (\u00e7\u0131kt\u0131 panelde akar, adres
|
|
134
|
+
'PANEL: \u00c7ALI\u015eTIR b\u00f6l\u00fcm\u00fcndeki Ba\u015flat/Dev butonlar\u0131 proje tipini OTOMAT\u0130K alg\u0131lar (package.json scripts + npm/pnpm/yarn/bun kilidi; requirements.txt/pyproject + uv; hugo/jekyll/mkdocs; Cargo.toml; go.mod; statik index.html) ve gerekirse \u00d6NCE ba\u011f\u0131ml\u0131l\u0131klar\u0131 kurup sonra do\u011fru komutu \u00e7al\u0131\u015ft\u0131r\u0131r. Alg\u0131lama komut bulamazsa ya da komut 10 sn i\u00e7inde hata verirse sistem sana OTOMAT\u0130K mesaj d\u00fc\u015f\u00fcr\u00fcr: repo yap\u0131s\u0131na g\u00f6re (README, betikler, site ayarlar\u0131, ana dosyalar) DO\u011eRU komutu bul ve panel_run ile ba\u015flat. \u00d6zel komut kutusu ad-hoc komut \u00e7al\u0131\u015ft\u0131r\u0131r; kaydet butonu o komutu repo i\u00e7in kal\u0131c\u0131 ba\u015flatma komutu yapar. Kullan\u0131c\u0131 butonla ba\u015flatt\u0131ysa \u00e7\u0131kt\u0131 panelde canl\u0131 akar, localhost adresi yakalan\u0131nca \u00c7ALI\u015eTIR panelinde CANLI \u00d6N\u0130ZLEME a\u00e7\u0131l\u0131r (kullan\u0131c\u0131 G\u00f6rsel/\u00c7\u0131kt\u0131 d\u00fc\u011fmesiyle ge\u00e7i\u015f yapar).',
|
|
135
|
+
'\u0130\u015fe README + paket bildirim dosyalar\u0131yla ba\u015fla (list/glob); ba\u011f\u0131ml\u0131l\u0131klar kurulu de\u011filse kurulumu sen yapabilirsin (npm install, pip install -r requirements.txt vb.) \u2014 Ba\u015flat/Dev butonlar\u0131 da gerekirse \u00f6nce kurar. Komut ba\u015far\u0131s\u0131z olursa ger\u00e7ek hatay\u0131 g\u00f6rmek i\u00e7in ayn\u0131 komutu bash ile \u00e7al\u0131\u015ft\u0131r, nedenini bul, gerekiyorsa d\u00fczelt ve kullan\u0131c\u0131ya do\u011fru \u00f6zel komutu s\u00f6yle (kutuya yaz\u0131p kaydetsin).',
|
|
136
|
+
'UZUN S\u00dcREL\u0130 sunucu/s\u00fcre\u00e7 (npm start, npm run dev, hugo server, python app.py vb.) bash ile ASLA ba\u015flatma \u2014 tur kilitlenir; kullan\u0131c\u0131 senden isterse panel_run ile ba\u015flat (\u00e7\u0131kt\u0131 panelde akar, adres \u00c7ALI\u015eTIR panelinde canl\u0131 \u00f6nizlemede a\u00e7\u0131l\u0131r). Repo ba\u015f\u0131na TEK s\u00fcre\u00e7: kullan\u0131c\u0131 zaten ba\u015flatt\u0131ysa panel_run hata verir \u2014 kullan\u0131c\u0131ya \u00f6nce Durdur demesini s\u00f6yle.',
|
|
137
137
|
].join('\n'),
|
|
138
138
|
mode: 'all',
|
|
139
139
|
native: false,
|
package/src/agent/tools.js
CHANGED
|
@@ -1618,7 +1618,7 @@ const definitions = [
|
|
|
1618
1618
|
function: {
|
|
1619
1619
|
name: 'sandbox_repo',
|
|
1620
1620
|
description:
|
|
1621
|
-
'Beast Sandbox yönetimi — kullanıcı GitHub repo adresi/linki verdiğinde ya da indirilmiş bir repoyu kurmak/çalıştırmak istediğinde kullan. action=indir: repoyu ~/Beast-Sandbox klasörüne klonlar (owner/repo ya da tam URL); action=kur: algılanan kurulum komutunu (npm install, pip install -r requirements.txt, uv sync, cargo fetch, go mod download) ÇALIŞTIR panelinde başlatır; action=baslat:
|
|
1621
|
+
'Beast Sandbox yönetimi — kullanıcı GitHub repo adresi/linki verdiğinde ya da indirilmiş bir repoyu kurmak/çalıştırmak istediğinde kullan. action=indir: repoyu ~/Beast-Sandbox klasörüne klonlar (owner/repo ya da tam URL); action=kur: algılanan kurulum komutunu (npm install, pip install -r requirements.txt, uv sync, cargo fetch, go mod download) ÇALIŞTIR panelinde başlatır; action=baslat: çalıştırma komutunu başlatır — bağımlılıklar eksikse önce kurar (npm install && npm run dev, python app.py vb.); localhost adresi yakalanınca ÇALIŞTIR panelinde canlı önizlemede açılır; action=durdur: repodaki çalışan süreci durdurur. Kur/Başlat/Dev turu KİLİTLEMEZ, çıktı panelde canlı akar. repo alanı boşsa panelde son kullanılan repo kullanılır.',
|
|
1622
1622
|
parameters: {
|
|
1623
1623
|
type: 'object',
|
|
1624
1624
|
properties: {
|
package/src/main.js
CHANGED
|
@@ -272,8 +272,15 @@ try {
|
|
|
272
272
|
try { nodemailer = require('nodemailer'); } catch {}
|
|
273
273
|
|
|
274
274
|
const APP_DIR = path.join(app.getPath('appData'), 'beast');
|
|
275
|
-
/* Windows toast bildirimleri için AppUserModelID erken
|
|
276
|
-
|
|
275
|
+
/* Windows toast bildirimleri için AppUserModelID erken ayarlanmalı. ANCAK özel
|
|
276
|
+
AUMID, Windows'ta kayıtlı kısayol yoksa taskbar ikonunu electron.exe logosuna
|
|
277
|
+
düşürür. Bu yüzden yalnız paketli kurulumda ya da npm modunda masaüstü
|
|
278
|
+
kısayolu (aynı AUMID ile oluşturulur) mevcutsa atanır. */
|
|
279
|
+
try {
|
|
280
|
+
let aumidOk = app.isPackaged;
|
|
281
|
+
if (!aumidOk) aumidOk = fs.existsSync(path.join(app.getPath('desktop'), 'Beast Agent.lnk'));
|
|
282
|
+
if (aumidOk) app.setAppUserModelId('com.quantumalgo.beastagent');
|
|
283
|
+
} catch {}
|
|
277
284
|
/* mem0-native embedding modeli whisper ile AYNI cache'i kullanır (src/agent/mem0.js okur) */
|
|
278
285
|
process.env.BEAST_MODELS_DIR = path.join(APP_DIR, 'models');
|
|
279
286
|
|
|
@@ -3603,6 +3610,7 @@ function ensureDesktopShortcut() {
|
|
|
3603
3610
|
description: 'Beast Agent — hızlı, hafif ve becerikli',
|
|
3604
3611
|
icon: path.join(__dirname, '..', 'assets', 'app.ico'),
|
|
3605
3612
|
iconIndex: 0,
|
|
3613
|
+
appUserModelId: 'com.quantumalgo.beastagent',
|
|
3606
3614
|
});
|
|
3607
3615
|
log.info('main', ok ? 'Masaüstü kısayolu oluşturuldu (npm modu)' : 'Masaüstü kısayolu oluşturulamadı');
|
|
3608
3616
|
} catch (e) {
|
|
@@ -11152,6 +11160,7 @@ ipcMain.handle('sandbox:remove', async (_e, payload) => {
|
|
|
11152
11160
|
delete sbCfg[folder];
|
|
11153
11161
|
sbSaveCfg();
|
|
11154
11162
|
}
|
|
11163
|
+
try { fs.rmSync(path.join(beastDir(), 'sandbox-installed', path.basename(folder)), { force: true }); } catch {}
|
|
11155
11164
|
return { ok: true };
|
|
11156
11165
|
});
|
|
11157
11166
|
|
|
@@ -11211,7 +11220,7 @@ ipcMain.handle('sandbox:tree', (_e, payload) => {
|
|
|
11211
11220
|
});
|
|
11212
11221
|
|
|
11213
11222
|
/* Sandbox ÇALIŞTIRICI v2: repo başına YÖNETİLEN SÜREÇLER.
|
|
11214
|
-
|
|
11223
|
+
Başlat/Dev/Durdur butonları artık deterministik: proje tipi algılanır
|
|
11215
11224
|
(package.json, requirements.txt, pyproject.toml, Cargo.toml, go.mod,
|
|
11216
11225
|
index.html) ve doğru komut DOĞRUDAN çalıştırılır. Her repo kendi süreç
|
|
11217
11226
|
yuvasında koşar — birden çok repo aynı anda çalışabilir; çıktı tamponlanır,
|
|
@@ -11253,6 +11262,25 @@ function sbPythonCmd() {
|
|
|
11253
11262
|
return 'python';
|
|
11254
11263
|
}
|
|
11255
11264
|
|
|
11265
|
+
/* statik site üreticileri: hugo / jekyll / mkdocs — doküman repoları sık böyle;
|
|
11266
|
+
Başlat/Dev butonları bunları da tanısın (ör. docs/ altında hugo.yaml) */
|
|
11267
|
+
function sbSiteGenInfo(folder) {
|
|
11268
|
+
for (const d of ['', 'docs', 'site', 'website']) {
|
|
11269
|
+
const base = d ? path.join(folder, d) : folder;
|
|
11270
|
+
const has = (f) => { try { return fs.existsSync(path.join(base, f)); } catch { return false; } };
|
|
11271
|
+
if (has('hugo.toml') || has('hugo.yaml') || has('hugo.json') || (has('config.toml') && (has('content') || has('themes')))) {
|
|
11272
|
+
return { kind: 'static', label: 'hugo', install: '', run: 'hugo server' + (d ? ' -s ' + d : '') };
|
|
11273
|
+
}
|
|
11274
|
+
if (has('_config.yml') && (has('Gemfile') || has('Gemfile.lock'))) {
|
|
11275
|
+
return { kind: 'ruby', label: 'jekyll', install: 'bundle install', run: 'bundle exec jekyll serve' + (d ? ' -s ' + d : '') };
|
|
11276
|
+
}
|
|
11277
|
+
if (has('mkdocs.yml') || has('mkdocs.yaml')) {
|
|
11278
|
+
return { kind: 'python', label: 'mkdocs', install: sbPythonCmd() + ' -m pip install mkdocs', run: sbPythonCmd() + ' -m mkdocs serve' };
|
|
11279
|
+
}
|
|
11280
|
+
}
|
|
11281
|
+
return null;
|
|
11282
|
+
}
|
|
11283
|
+
|
|
11256
11284
|
/* repo köküne bakıp proje tipini + kur/çalıştır komutlarını çıkarır */
|
|
11257
11285
|
function sbProjectInfo(folder) {
|
|
11258
11286
|
const out = { kind: 'unknown', label: 'bilinmiyor', name: path.basename(folder), install: '', run: '', dev: '', build: '' };
|
|
@@ -11275,6 +11303,21 @@ function sbProjectInfo(folder) {
|
|
|
11275
11303
|
out.build = s.build ? pm + ' run build' : '';
|
|
11276
11304
|
return out;
|
|
11277
11305
|
}
|
|
11306
|
+
/* statik site üreticisi (hugo/jekyll/mkdocs) python paketinden ÖNCE gelir:
|
|
11307
|
+
docs/ altındaki hugo.yaml, kökteki requirements.txt'i gölgeleyebilsin */
|
|
11308
|
+
const site = sbSiteGenInfo(folder);
|
|
11309
|
+
if (site) {
|
|
11310
|
+
out.kind = site.kind;
|
|
11311
|
+
out.label = site.label;
|
|
11312
|
+
if (site.install) out.install = site.install;
|
|
11313
|
+
if (site.run) { out.run = site.run; out.dev = site.run; }
|
|
11314
|
+
if (!out.install) {
|
|
11315
|
+
const py = sbPythonCmd();
|
|
11316
|
+
if (fs.existsSync(path.join(folder, 'requirements.txt'))) out.install = py + ' -m pip install -r requirements.txt';
|
|
11317
|
+
else if (fs.existsSync(path.join(folder, 'pyproject.toml'))) out.install = py + ' -m pip install -e .';
|
|
11318
|
+
}
|
|
11319
|
+
return out;
|
|
11320
|
+
}
|
|
11278
11321
|
const hasPy = ['pyproject.toml', 'requirements.txt', 'setup.py'].some((f) => fs.existsSync(path.join(folder, f)));
|
|
11279
11322
|
if (hasPy) {
|
|
11280
11323
|
const py = sbPythonCmd();
|
|
@@ -11350,7 +11393,7 @@ function sbSlotPush(slot, folder, text) {
|
|
|
11350
11393
|
sbRunEmit(folder, text, slot.kind);
|
|
11351
11394
|
}
|
|
11352
11395
|
|
|
11353
|
-
function sbRunStartManaged(folder, cmd, kind) {
|
|
11396
|
+
function sbRunStartManaged(folder, cmd, kind, opts) {
|
|
11354
11397
|
folder = String(folder || '');
|
|
11355
11398
|
cmd = String(cmd || '').trim();
|
|
11356
11399
|
kind = kind === 'install' ? 'install' : 'run';
|
|
@@ -11365,7 +11408,7 @@ function sbRunStartManaged(folder, cmd, kind) {
|
|
|
11365
11408
|
windowsHide: true,
|
|
11366
11409
|
env: { ...process.env, FORCE_COLOR: '0', NO_COLOR: '1' },
|
|
11367
11410
|
});
|
|
11368
|
-
const slot = { proc, kind, cmd, url: '', lines: [], startedAt: Date.now() };
|
|
11411
|
+
const slot = { proc, kind, cmd, url: '', lines: [], startedAt: Date.now(), installCmd: (opts && opts.installCmd) || '' };
|
|
11369
11412
|
sbProcs.set(folder, slot);
|
|
11370
11413
|
const onLine = (buf) => {
|
|
11371
11414
|
for (const piece of String(buf).split(/\r?\n/)) {
|
|
@@ -11387,9 +11430,20 @@ function sbRunStartManaged(folder, cmd, kind) {
|
|
|
11387
11430
|
proc.on('close', (code) => {
|
|
11388
11431
|
sbSlotPush(slot, folder, '[süreç bitti' + (code != null ? ' — kod ' + code : '') + ']');
|
|
11389
11432
|
slot.proc = null;
|
|
11433
|
+
/* başarılı kurulum damgalanır: sonraki Başlat/Dev kurulumu tekrarlamaz */
|
|
11434
|
+
if (code === 0 && (slot.kind === 'install' || slot.installCmd)) sbMarkInstalled(folder);
|
|
11435
|
+
/* hızlı çöküş (10 sn içinde sıfırdan farklı çıkış): renderer bunu ajan
|
|
11436
|
+
devralması için işaret sayar — yanlış algılanan komut ajanla düzeltilir */
|
|
11437
|
+
const quickFail = code != null && Number(code) !== 0 && Date.now() - slot.startedAt < 10000;
|
|
11390
11438
|
try {
|
|
11391
11439
|
if (win && !win.isDestroyed()) {
|
|
11392
|
-
win.webContents.send('agent:event', {
|
|
11440
|
+
win.webContents.send('agent:event', {
|
|
11441
|
+
type: 'sb-run-end',
|
|
11442
|
+
folder,
|
|
11443
|
+
code: code == null ? null : Number(code),
|
|
11444
|
+
kind: slot.kind,
|
|
11445
|
+
quickFail,
|
|
11446
|
+
});
|
|
11393
11447
|
}
|
|
11394
11448
|
} catch {}
|
|
11395
11449
|
});
|
|
@@ -11446,7 +11500,35 @@ function sbInstallRepo(folder) {
|
|
|
11446
11500
|
|
|
11447
11501
|
ipcMain.handle('sandbox:install', async (_e, payload) => sbInstallRepo(String((payload && payload.folder) || '')));
|
|
11448
11502
|
|
|
11449
|
-
/* Başlat/Dev
|
|
11503
|
+
/* bağımlılıklar eksik mi? — Başlat/Dev gerekirse ÖNCE kurar; kurulum bir kez
|
|
11504
|
+
yapıldıktan sonra damga dosyasıyla (node_modules var / %APPDATA% damgası)
|
|
11505
|
+
tekrarlanmaz */
|
|
11506
|
+
function sbInstallNeeded(folder, info) {
|
|
11507
|
+
try {
|
|
11508
|
+
if (!info.install) return false;
|
|
11509
|
+
if (info.kind === 'node') {
|
|
11510
|
+
const nm = path.join(folder, 'node_modules');
|
|
11511
|
+
return !fs.existsSync(nm) || !fs.readdirSync(nm).length;
|
|
11512
|
+
}
|
|
11513
|
+
if (info.label === 'jekyll') return !fs.existsSync(path.join(folder, 'Gemfile.lock'));
|
|
11514
|
+
if (info.kind === 'python' || info.label === 'mkdocs') {
|
|
11515
|
+
if (fs.existsSync(path.join(folder, '.venv'))) return false;
|
|
11516
|
+
return !fs.existsSync(path.join(beastDir(), 'sandbox-installed', path.basename(folder)));
|
|
11517
|
+
}
|
|
11518
|
+
} catch {}
|
|
11519
|
+
return false;
|
|
11520
|
+
}
|
|
11521
|
+
|
|
11522
|
+
function sbMarkInstalled(folder) {
|
|
11523
|
+
try {
|
|
11524
|
+
const dir = path.join(beastDir(), 'sandbox-installed');
|
|
11525
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
11526
|
+
fs.writeFileSync(path.join(dir, path.basename(folder)), new Date().toISOString());
|
|
11527
|
+
} catch {}
|
|
11528
|
+
}
|
|
11529
|
+
|
|
11530
|
+
/* Başlat/Dev: algılanan çalıştırma komutunu başlatır; bağımlılıklar eksikse
|
|
11531
|
+
önce kurulum komutunu zincirler (npm install && npm run dev gibi) */
|
|
11450
11532
|
function sbStartRepo(folder, mode) {
|
|
11451
11533
|
folder = String(folder || '');
|
|
11452
11534
|
mode = String(mode || 'run') === 'dev' ? 'dev' : 'run';
|
|
@@ -11454,8 +11536,10 @@ function sbStartRepo(folder, mode) {
|
|
|
11454
11536
|
const info = sbProjectInfoMerged(folder);
|
|
11455
11537
|
const cmd = mode === 'dev' ? info.dev || info.run : info.run || info.dev;
|
|
11456
11538
|
if (!cmd) return { ok: false, error: 'Bu repo için çalıştırma komutu algılanamadı — özel komutu kutuya yazıp ▶ ile çalıştır' };
|
|
11457
|
-
const
|
|
11458
|
-
|
|
11539
|
+
const pre = sbInstallNeeded(folder, info) ? info.install : '';
|
|
11540
|
+
const full = pre ? pre + ' && ' + cmd : cmd;
|
|
11541
|
+
const r = sbRunStartManaged(folder, full, 'run', pre ? { installCmd: pre } : null);
|
|
11542
|
+
if (r.ok) r.cmd = full;
|
|
11459
11543
|
return r;
|
|
11460
11544
|
}
|
|
11461
11545
|
|
|
@@ -11524,6 +11608,98 @@ ipcMain.handle('sandbox:openurl', async (_e, url) => {
|
|
|
11524
11608
|
}
|
|
11525
11609
|
});
|
|
11526
11610
|
|
|
11611
|
+
/* ---------- SANDBOX PANEL İÇİ CANLI ÖNİZLEME (native WebContentsView) ----------
|
|
11612
|
+
ÇALIŞTIR bölümünde, çıktı günlüğünün yerine repo'nun çalışan hâlini gösterir.
|
|
11613
|
+
Tarayıcı dock'undan bağımsızdır: renderer host alanının DOM dikdörtgenini
|
|
11614
|
+
gönderir, view tam o alana oturur. Yalnız localhost adresleri yüklenir. */
|
|
11615
|
+
const sbPreview = { view: null, attached: false, visible: false, url: '', bounds: null };
|
|
11616
|
+
|
|
11617
|
+
function ensureSbPreview() {
|
|
11618
|
+
if (sbPreview.view) return sbPreview.view;
|
|
11619
|
+
const view = new WebContentsView({
|
|
11620
|
+
webPreferences: {
|
|
11621
|
+
partition: 'persist:sandbox-preview',
|
|
11622
|
+
contextIsolation: true,
|
|
11623
|
+
nodeIntegration: false,
|
|
11624
|
+
sandbox: true,
|
|
11625
|
+
spellcheck: false,
|
|
11626
|
+
backgroundThrottling: false,
|
|
11627
|
+
},
|
|
11628
|
+
});
|
|
11629
|
+
view.setBackgroundColor(settings.theme === 'dark' ? '#0d0d0f' : '#ffffff');
|
|
11630
|
+
const wc = view.webContents;
|
|
11631
|
+
try {
|
|
11632
|
+
const chromeUA = `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${process.versions.chrome} Safari/537.36`;
|
|
11633
|
+
wc.setUserAgent(chromeUA);
|
|
11634
|
+
} catch {}
|
|
11635
|
+
wc.setWindowOpenHandler(({ url }) => {
|
|
11636
|
+
if (/^https?:\/\//i.test(url)) wc.loadURL(url).catch(() => {});
|
|
11637
|
+
return { action: 'deny' };
|
|
11638
|
+
});
|
|
11639
|
+
wc.on('render-process-gone', () => {
|
|
11640
|
+
if (win && !win.isDestroyed() && sbPreview.view) {
|
|
11641
|
+
try { win.contentView.removeChildView(sbPreview.view); } catch {}
|
|
11642
|
+
}
|
|
11643
|
+
sbPreview.view = null;
|
|
11644
|
+
sbPreview.attached = false;
|
|
11645
|
+
sbPreview.visible = false;
|
|
11646
|
+
});
|
|
11647
|
+
sbPreview.view = view;
|
|
11648
|
+
return view;
|
|
11649
|
+
}
|
|
11650
|
+
|
|
11651
|
+
function sbPreviewDetach() {
|
|
11652
|
+
if (sbPreview.view && win && !win.isDestroyed()) {
|
|
11653
|
+
try { sbPreview.view.setVisible(false); } catch {}
|
|
11654
|
+
try { win.contentView.removeChildView(sbPreview.view); } catch {}
|
|
11655
|
+
}
|
|
11656
|
+
sbPreview.attached = false;
|
|
11657
|
+
sbPreview.visible = false;
|
|
11658
|
+
}
|
|
11659
|
+
|
|
11660
|
+
function sbPreviewSet(payload) {
|
|
11661
|
+
if (!win || win.isDestroyed()) return { ok: false, error: 'pencere yok' };
|
|
11662
|
+
const p = payload || {};
|
|
11663
|
+
if (p.bounds && typeof p.bounds === 'object') {
|
|
11664
|
+
sbPreview.bounds = {
|
|
11665
|
+
x: Math.max(0, Math.round(Number(p.bounds.x) || 0)),
|
|
11666
|
+
y: Math.max(0, Math.round(Number(p.bounds.y) || 0)),
|
|
11667
|
+
width: Math.max(0, Math.round(Number(p.bounds.width) || 0)),
|
|
11668
|
+
height: Math.max(0, Math.round(Number(p.bounds.height) || 0)),
|
|
11669
|
+
};
|
|
11670
|
+
}
|
|
11671
|
+
if (p.url) {
|
|
11672
|
+
const u = String(p.url);
|
|
11673
|
+
if (/^https?:\/\/(?:localhost|127\.0\.0\.1)(?::\d{2,5})?(?:[/?#]|$)/i.test(u)) sbPreview.url = u;
|
|
11674
|
+
}
|
|
11675
|
+
const b = sbPreview.bounds;
|
|
11676
|
+
const want = p.visible !== false && !!sbPreview.url && !!b && b.width > 0 && b.height > 0;
|
|
11677
|
+
if (!want) {
|
|
11678
|
+
if (sbPreview.view) {
|
|
11679
|
+
try { sbPreview.view.setVisible(false); } catch {}
|
|
11680
|
+
}
|
|
11681
|
+
sbPreview.visible = false;
|
|
11682
|
+
return { ok: true, visible: false };
|
|
11683
|
+
}
|
|
11684
|
+
const view = ensureSbPreview();
|
|
11685
|
+
if (sbPreview.url) {
|
|
11686
|
+
let cur = '';
|
|
11687
|
+
try { cur = view.webContents.getURL(); } catch {}
|
|
11688
|
+
if (cur !== sbPreview.url) view.webContents.loadURL(sbPreview.url).catch(() => {});
|
|
11689
|
+
}
|
|
11690
|
+
if (!sbPreview.attached) {
|
|
11691
|
+
try { win.contentView.addChildView(view); sbPreview.attached = true; } catch {}
|
|
11692
|
+
}
|
|
11693
|
+
try {
|
|
11694
|
+
view.setBounds({ x: b.x, y: b.y, width: b.width, height: b.height });
|
|
11695
|
+
view.setVisible(true);
|
|
11696
|
+
sbPreview.visible = true;
|
|
11697
|
+
} catch {}
|
|
11698
|
+
return { ok: true, visible: true, url: sbPreview.url };
|
|
11699
|
+
}
|
|
11700
|
+
|
|
11701
|
+
ipcMain.handle('sbpreview:set', async (_e, payload) => sbPreviewSet(payload || {}));
|
|
11702
|
+
|
|
11527
11703
|
/* Sağ tık menüsü: HTML dosyasını dahili tarayıcıda GÖRÜNÜR aç */
|
|
11528
11704
|
/* ---------- BC DAHİLİ STATİK SUNUCU ----------
|
|
11529
11705
|
Beast Code çıktısı ASLA file:// ile açılmaz: ES modülleri, fetch, ServiceWorker
|
package/src/preload.js
CHANGED
|
@@ -192,6 +192,7 @@ contextBridge.exposeInMainWorld('beast', {
|
|
|
192
192
|
sandboxProcState: (payload) => ipcRenderer.invoke('sandbox:procstate', payload),
|
|
193
193
|
sandboxCfgSet: (payload) => ipcRenderer.invoke('sandbox:cfg:set', payload),
|
|
194
194
|
sandboxOpenUrl: (url) => ipcRenderer.invoke('sandbox:openurl', url),
|
|
195
|
+
sbPreviewSet: (payload) => ipcRenderer.invoke('sbpreview:set', payload),
|
|
195
196
|
waStart: () => ipcRenderer.invoke('wa:start'),
|
|
196
197
|
waStop: () => ipcRenderer.invoke('wa:stop'),
|
|
197
198
|
waReset: () => ipcRenderer.invoke('wa:reset'),
|
package/src/renderer/i18n.js
CHANGED
|
@@ -594,6 +594,7 @@
|
|
|
594
594
|
tipIde: 'IDE Modu — dosyalar + chat + preview',
|
|
595
595
|
tipStudio: 'Beast Studio — video yapma/düzenleme modu',
|
|
596
596
|
tipSandbox: 'Beast Sandbox — GitHub reposu indir & içinde çalış',
|
|
597
|
+
tipMcp: 'Beast MCP — dış araç sunucuları (Model Context Protocol)',
|
|
597
598
|
tipCodeHide: 'Editörü kapat',
|
|
598
599
|
tipCodeShow: 'Editörü göster',
|
|
599
600
|
ide_files: 'DOSYALAR',
|
|
@@ -1387,6 +1388,7 @@
|
|
|
1387
1388
|
tipIde: 'IDE Mode — files + chat + preview',
|
|
1388
1389
|
tipStudio: 'Beast Studio — video making/editing mode',
|
|
1389
1390
|
tipSandbox: 'Beast Sandbox — download a GitHub repo & work inside it',
|
|
1391
|
+
tipMcp: 'Beast MCP — external tool servers (Model Context Protocol)',
|
|
1390
1392
|
tipCodeHide: 'Hide editor',
|
|
1391
1393
|
tipCodeShow: 'Show editor',
|
|
1392
1394
|
ide_files: 'FILES',
|
package/src/renderer/index.html
CHANGED
|
@@ -103,6 +103,7 @@
|
|
|
103
103
|
<button id="studioBtn" class="dd-btn dd-icon-btn" title="Beast Studio — video yapma/düzenleme" data-i18n-title="tipStudio"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="13" height="12" rx="2"/><path d="M15 10l7-4v12l-7-4"/></svg></button>
|
|
104
104
|
<button id="finBtn" class="dd-btn dd-icon-btn" title="Beast Finance — MT5 trade paneli (bilgisayardaki MetaTrader 5 ile çalışır)"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3v18h18"/><path d="M7 15l4-5 3 3 5-7"/></svg></button>
|
|
105
105
|
<button id="sbBtn" class="dd-btn dd-icon-btn" title="Beast Sandbox — GitHub reposu indir & içinde çalış" data-i18n-title="tipSandbox"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg></button>
|
|
106
|
+
<button id="mcpBtn" class="dd-btn dd-icon-btn" title="Beast MCP — dış araç sunucuları (Model Context Protocol)" data-i18n-title="tipMcp"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><line x1="7" y1="7.5" x2="7.01" y2="7.5"/><line x1="7" y1="16.5" x2="7.01" y2="16.5"/></svg></button>
|
|
106
107
|
<button id="railBtn" class="dd-btn dd-icon-btn" title="Paralel Ajan Konsolu" data-i18n-title="tipRail">▤</button>
|
|
107
108
|
<button id="dmBtn" class="dd-btn dd-icon-btn" title="Ajan DM — ajanlar arası konuşma" data-i18n-title="tipAgentDm">✉︎</button>
|
|
108
109
|
<button id="watchBtn" class="dd-btn dd-icon-btn" title="İzleyiciler (Watchers)" data-i18n-title="tipWatch">◎</button>
|
|
@@ -419,20 +420,24 @@
|
|
|
419
420
|
<div id="sbStatus" hidden></div>
|
|
420
421
|
<div id="sbInputRow">
|
|
421
422
|
<textarea id="sbInput" rows="1" spellcheck="false" autocomplete="off" placeholder="Sandbox mesajı — ajan bu repo klasöründe çalışır…"></textarea>
|
|
423
|
+
<button id="sbSend" title="Gönder (Enter)"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg></button>
|
|
422
424
|
<button id="sbStop" title="Çalışan mesajı durdur" hidden data-i18n-title="bc_stop"><svg viewBox="0 0 24 24" width="13" height="13" fill="currentColor" stroke="none"><rect x="6" y="6" width="12" height="12" rx="2"/></svg></button>
|
|
423
425
|
</div>
|
|
424
426
|
</section>
|
|
425
427
|
|
|
428
|
+
<div id="sbSplit" title="Sürükleyerek boyutlandır"></div>
|
|
429
|
+
|
|
426
430
|
<section id="sbRun">
|
|
427
431
|
<div id="sbRunHead">
|
|
428
432
|
<span id="sbRunTitle">ÇALIŞTIR</span>
|
|
429
433
|
<span id="sbRunKind"></span>
|
|
430
434
|
<span id="sbRunCwd" title="">—</span>
|
|
435
|
+
<span class="file-spacer"></span>
|
|
436
|
+
<button id="sbRunView" class="on" title="Görsel önizleme açık — çıktıya dön">Görsel</button>
|
|
431
437
|
</div>
|
|
432
438
|
<div id="sbRunBtns">
|
|
433
|
-
<button id="
|
|
434
|
-
<button id="
|
|
435
|
-
<button id="sbRunDev" title="Geliştirme modunda başlat (npm run dev, vite, expo…)"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:3px"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>Dev</button>
|
|
439
|
+
<button id="sbRunStart" title="Başlat — gerekirse bağımlılıkları kurar, sonra çalıştırır (adres panelde canlı önizlemede açılır)"><svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor" stroke="none" style="vertical-align:-2px;margin-right:3px"><polygon points="6 3 20 12 6 21 6 3"/></svg>Başlat</button>
|
|
440
|
+
<button id="sbRunDev" title="Geliştirme modunda başlat (gerekirse önce kurar)"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:3px"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>Dev</button>
|
|
436
441
|
<button id="sbRunStop" title="Süreci durdur" hidden><svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor" stroke="none" style="vertical-align:-2px;margin-right:3px"><rect x="6" y="6" width="12" height="12" rx="2"/></svg>Durdur</button>
|
|
437
442
|
</div>
|
|
438
443
|
<div id="sbRunCustom">
|
|
@@ -440,6 +445,7 @@
|
|
|
440
445
|
<button id="sbRunGo" title="Çalıştır"><svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor" stroke="none"><polygon points="6 3 20 12 6 21 6 3"/></svg></button>
|
|
441
446
|
<button id="sbRunSave" title="Yazılan komutu bu reponun başlatma komutu olarak kaydet"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg></button>
|
|
442
447
|
</div>
|
|
448
|
+
<div id="sbPreviewHost" hidden><div id="sbPreviewHint">🌐 canlı önizleme — Başlat/Dev ile sunucu açılınca burada görünür</div></div>
|
|
443
449
|
<div id="sbRunOut"></div>
|
|
444
450
|
<div id="sbRunFoot">
|
|
445
451
|
<button id="sbRunOpen" title="Önizlemeyi sağdaki dahili tarayıcıda aç" disabled><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:3px"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg><span id="sbRunOpenLabel">Tarayıcıda aç</span></button>
|
|
@@ -447,6 +453,37 @@
|
|
|
447
453
|
</div>
|
|
448
454
|
</section>
|
|
449
455
|
</div>
|
|
456
|
+
|
|
457
|
+
<div id="mcpRow">
|
|
458
|
+
<section id="mcpPanel">
|
|
459
|
+
<div id="mcpHead">
|
|
460
|
+
<span id="mcpTitle">BEAST MCP</span>
|
|
461
|
+
<span class="file-spacer"></span>
|
|
462
|
+
<button id="mcpReload" title="Durumu yenile">⟳︎</button>
|
|
463
|
+
</div>
|
|
464
|
+
<div id="mcpList"></div>
|
|
465
|
+
<div id="mcpFoot">
|
|
466
|
+
<button id="mcpAddBtn" title="mcp.json'a örnek bir server bloğu ekler">+ Yeni Server</button>
|
|
467
|
+
</div>
|
|
468
|
+
</section>
|
|
469
|
+
<section id="mcpDetail">
|
|
470
|
+
<div id="mcpDetailHead">
|
|
471
|
+
<span id="mcpDetailTitle">Detay</span>
|
|
472
|
+
<span id="mcpDetailState" class="mcp-badge"></span>
|
|
473
|
+
</div>
|
|
474
|
+
<div id="mcpDetailBody"></div>
|
|
475
|
+
<div id="mcpJsonWrap">
|
|
476
|
+
<div id="mcpJsonHead">
|
|
477
|
+
<span>mcp.json</span>
|
|
478
|
+
<span id="mcpJsonPath" title=""></span>
|
|
479
|
+
<span class="file-spacer"></span>
|
|
480
|
+
<span id="mcpMsg"></span>
|
|
481
|
+
<button id="mcpSave">Kaydet</button>
|
|
482
|
+
</div>
|
|
483
|
+
<textarea id="mcpJson" spellcheck="false"></textarea>
|
|
484
|
+
</div>
|
|
485
|
+
</section>
|
|
486
|
+
</div>
|
|
450
487
|
</main>
|
|
451
488
|
|
|
452
489
|
<aside id="rail">
|
package/src/renderer/renderer.js
CHANGED
|
@@ -135,9 +135,12 @@ const els = {
|
|
|
135
135
|
sbStatus: $('#sbStatus'),
|
|
136
136
|
sbInput: $('#sbInput'),
|
|
137
137
|
sbStop: $('#sbStop'),
|
|
138
|
+
sbSend: $('#sbSend'),
|
|
139
|
+
sbSplit: $('#sbSplit'),
|
|
140
|
+
sbRun: $('#sbRun'),
|
|
138
141
|
sbRunCwd: $('#sbRunCwd'),
|
|
142
|
+
sbRunView: $('#sbRunView'),
|
|
139
143
|
sbRunKind: $('#sbRunKind'),
|
|
140
|
-
sbRunInstall: $('#sbRunInstall'),
|
|
141
144
|
sbRunStart: $('#sbRunStart'),
|
|
142
145
|
sbRunDev: $('#sbRunDev'),
|
|
143
146
|
sbRunStop: $('#sbRunStop'),
|
|
@@ -147,6 +150,18 @@ const els = {
|
|
|
147
150
|
sbRunOut: $('#sbRunOut'),
|
|
148
151
|
sbRunOpen: $('#sbRunOpen'),
|
|
149
152
|
sbRunUrl: $('#sbRunUrl'),
|
|
153
|
+
mcpBtn: $('#mcpBtn'),
|
|
154
|
+
mcpRow: $('#mcpRow'),
|
|
155
|
+
mcpList: $('#mcpList'),
|
|
156
|
+
mcpReload: $('#mcpReload'),
|
|
157
|
+
mcpAddBtn: $('#mcpAddBtn'),
|
|
158
|
+
mcpDetailTitle: $('#mcpDetailTitle'),
|
|
159
|
+
mcpDetailState: $('#mcpDetailState'),
|
|
160
|
+
mcpDetailBody: $('#mcpDetailBody'),
|
|
161
|
+
mcpJson: $('#mcpJson'),
|
|
162
|
+
mcpJsonPath: $('#mcpJsonPath'),
|
|
163
|
+
mcpSave: $('#mcpSave'),
|
|
164
|
+
mcpMsg: $('#mcpMsg'),
|
|
150
165
|
stPanel: $('#stPanel'),
|
|
151
166
|
stTitle: $('#stTitle'),
|
|
152
167
|
stCwd: $('#stCwd'),
|
|
@@ -6000,6 +6015,7 @@ function onEvent(ev) {
|
|
|
6000
6015
|
/* IDE modunda tarayıcı açılır/kapanır/genişlik değişirse row yeniden bölünür —
|
|
6001
6016
|
editör + Beast Code ORTAK kırpılıp ORTAK açılır (kullanıcı payı korunur) */
|
|
6002
6017
|
if (ideModeOn()) ideSplitApplyFrac();
|
|
6018
|
+
if (sbModeOn()) sbSplitApplyFrac();
|
|
6003
6019
|
if (shown) {
|
|
6004
6020
|
els.browserBtn.classList.add('on');
|
|
6005
6021
|
if (ev.url && document.activeElement !== els.bbUrl) {
|
|
@@ -8354,6 +8370,7 @@ async function setIdeMode(on) {
|
|
|
8354
8370
|
if (on && studioModeOn()) await setStudioMode(false); /* Studio açıkken IDE'ye geçiş — Studio kapanır */
|
|
8355
8371
|
if (on && sbModeOn()) setSandboxMode(false); /* Sandbox açıkken IDE'ye geçiş — Sandbox kapanır */
|
|
8356
8372
|
if (on && financeModeOn()) setFinanceMode(false); /* Finance açıkken IDE'ye geçiş — Finance kapanır */
|
|
8373
|
+
if (on && mcpModeOn()) setMcpMode(false); /* MCP açıkken IDE'ye geçiş — MCP kapanır */
|
|
8357
8374
|
document.body.classList.toggle('ide-mode', !!on);
|
|
8358
8375
|
if (els.ideBtn) els.ideBtn.classList.toggle('on', !!on);
|
|
8359
8376
|
/* soldaki marka: chat modunda BEAST Agent, IDE modunda BEAST Code, Studio modunda BEAST Studio */
|
|
@@ -8429,6 +8446,7 @@ async function setStudioMode(on) {
|
|
|
8429
8446
|
if (on && ideModeOn()) await setIdeMode(false); /* IDE açıkken Studio'ya geçiş — IDE kapanır */
|
|
8430
8447
|
if (on && sbModeOn()) setSandboxMode(false); /* Sandbox açıkken Studio'ya geçiş — Sandbox kapanır */
|
|
8431
8448
|
if (on && financeModeOn()) setFinanceMode(false); /* Finance açıkken Studio'ya geçiş — Finance kapanır */
|
|
8449
|
+
if (on && mcpModeOn()) setMcpMode(false); /* MCP açıkken Studio'ya geçiş — MCP kapanır */
|
|
8432
8450
|
document.body.classList.toggle('studio-mode', !!on);
|
|
8433
8451
|
if (els.studioBtn) els.studioBtn.classList.toggle('on', !!on);
|
|
8434
8452
|
/* ALT TERMINAL: yalnız Beast Code'a özgü — Studio'ya geçişte kapanır */
|
|
@@ -9725,6 +9743,7 @@ async function setFinanceMode(on) {
|
|
|
9725
9743
|
if (on && ideModeOn()) await setIdeMode(false);
|
|
9726
9744
|
if (on && studioModeOn()) await setStudioMode(false);
|
|
9727
9745
|
if (on && sbModeOn()) setSandboxMode(false);
|
|
9746
|
+
if (on && mcpModeOn()) setMcpMode(false); /* MCP açıkken Finance'a geçiş — MCP kapanır */
|
|
9728
9747
|
document.body.classList.toggle('finance-mode', !!on);
|
|
9729
9748
|
if (els.finBtn) els.finBtn.classList.toggle('on', !!on);
|
|
9730
9749
|
const brandSub = document.querySelector('#brand .brand-sub');
|
|
@@ -11967,6 +11986,10 @@ const sbTreeState = { cache: new Map(), open: new Set(['']), path: '' };
|
|
|
11967
11986
|
let sbRunUrl = '';
|
|
11968
11987
|
let sbRunRunning = false;
|
|
11969
11988
|
let sbRunInfo = null;
|
|
11989
|
+
let sbAutoAssist = null; /* butonla başlatılan süreç hızlı çökerse: 'install' | 'run' */
|
|
11990
|
+
let sbPreviewOn = true; /* ÇALIŞTIR içi görsel önizleme tercihi */
|
|
11991
|
+
let sbPreviewShown = false;
|
|
11992
|
+
let sbPreviewSuspend = false; /* ayırıcı sürüklenirken native view gizli tutulur */
|
|
11970
11993
|
|
|
11971
11994
|
function sbModeOn() {
|
|
11972
11995
|
return document.body.classList.contains('sandbox-mode');
|
|
@@ -12168,6 +12191,7 @@ async function sbSelectCurrent() {
|
|
|
12168
12191
|
sbRunLine('ℹ ' + (det.info.label || 'proje') + ' · kur: ' + (det.info.install || '—') + ' · çalıştır: ' + (det.info.run || '—'), 't-dim');
|
|
12169
12192
|
}
|
|
12170
12193
|
}
|
|
12194
|
+
sbPreviewApply();
|
|
12171
12195
|
/* sol konsol: seçilen reponun klasörü — oturum açıldıktan sonra da garanti tazele */
|
|
12172
12196
|
sbTreeState.cache.clear();
|
|
12173
12197
|
if (sbModeOn()) renderFileTree().catch(() => {});
|
|
@@ -12183,7 +12207,8 @@ function sbInputResize() {
|
|
|
12183
12207
|
|
|
12184
12208
|
function sbRunCurrent() {
|
|
12185
12209
|
const msg = els.sbInput.value.trim();
|
|
12186
|
-
if (!msg ||
|
|
12210
|
+
if (!msg || sbCloning) return;
|
|
12211
|
+
if (!sbFolder) { toast('Önce repo indir ya da seç'); return; }
|
|
12187
12212
|
els.sbInput.value = '';
|
|
12188
12213
|
sbInputResize();
|
|
12189
12214
|
sbLine('t-cmd', 'sen> ' + msg);
|
|
@@ -12252,8 +12277,10 @@ function setSandboxMode(on) {
|
|
|
12252
12277
|
if (on && ideModeOn()) { setIdeMode(false); }
|
|
12253
12278
|
if (on && studioModeOn()) { setStudioMode(false); }
|
|
12254
12279
|
if (on && financeModeOn()) { setFinanceMode(false); }
|
|
12280
|
+
if (on && mcpModeOn()) setMcpMode(false); /* MCP açıkken Sandbox'a geçiş — MCP kapanır */
|
|
12255
12281
|
document.body.classList.toggle('sandbox-mode', !!on);
|
|
12256
12282
|
if (els.sbBtn) els.sbBtn.classList.toggle('on', !!on);
|
|
12283
|
+
sbPreviewApply();
|
|
12257
12284
|
/* marka + sol konsol başlığı: moduna göre BEAST Agent/Code/Studio/Sandbox */
|
|
12258
12285
|
const brandSub = document.querySelector('#brand .brand-sub');
|
|
12259
12286
|
if (brandSub) brandSub.textContent = on ? 'Sandbox' : 'Agent';
|
|
@@ -12261,6 +12288,7 @@ function setSandboxMode(on) {
|
|
|
12261
12288
|
if (ftp && on) ftp.textContent = 'REPO DOSYALARI';
|
|
12262
12289
|
if (on) {
|
|
12263
12290
|
loadSandboxList();
|
|
12291
|
+
sbSplitRestore();
|
|
12264
12292
|
sbTreeState.cache.clear();
|
|
12265
12293
|
renderFileTree().catch(() => {});
|
|
12266
12294
|
} else if (!ideModeOn() && !studioModeOn()) {
|
|
@@ -12270,19 +12298,176 @@ function setSandboxMode(on) {
|
|
|
12270
12298
|
}
|
|
12271
12299
|
}
|
|
12272
12300
|
|
|
12301
|
+
/* ================= BEAST MCP MODU =================
|
|
12302
|
+
Model Context Protocol sunucuları: tek panelde durum, araç listesi,
|
|
12303
|
+
aç/kapat, yeniden bağlan ve mcp.json düzenleme. Ana sohbeti bozmaz —
|
|
12304
|
+
diğer modlar gibi body.mcp-mode ile ayrı satır. */
|
|
12305
|
+
function mcpModeOn() {
|
|
12306
|
+
return document.body.classList.contains('mcp-mode');
|
|
12307
|
+
}
|
|
12308
|
+
|
|
12309
|
+
const MCP_STATE_TR = { up: 'BAĞLI', starting: 'BAĞLANIYOR', down: 'HATA', idle: 'BEKLEMEDE', disabled: 'KAPALI' };
|
|
12310
|
+
let mcpSel = '';
|
|
12311
|
+
let mcpTimer = null;
|
|
12312
|
+
|
|
12313
|
+
async function setMcpMode(on) {
|
|
12314
|
+
if (on && ideModeOn()) await setIdeMode(false);
|
|
12315
|
+
if (on && studioModeOn()) await setStudioMode(false);
|
|
12316
|
+
if (on && sbModeOn()) setSandboxMode(false);
|
|
12317
|
+
if (on && financeModeOn()) setFinanceMode(false);
|
|
12318
|
+
document.body.classList.toggle('mcp-mode', !!on);
|
|
12319
|
+
if (els.mcpBtn) els.mcpBtn.classList.toggle('on', !!on);
|
|
12320
|
+
const brandSub = document.querySelector('#brand .brand-sub');
|
|
12321
|
+
if (brandSub) brandSub.textContent = on ? 'MCP' : 'Agent';
|
|
12322
|
+
if (on) {
|
|
12323
|
+
await renderMcpPanel();
|
|
12324
|
+
if (!mcpTimer) {
|
|
12325
|
+
mcpTimer = setInterval(() => { if (mcpModeOn()) renderMcpPanel(); }, 5000);
|
|
12326
|
+
}
|
|
12327
|
+
} else if (mcpTimer) {
|
|
12328
|
+
clearInterval(mcpTimer);
|
|
12329
|
+
mcpTimer = null;
|
|
12330
|
+
}
|
|
12331
|
+
}
|
|
12332
|
+
|
|
12333
|
+
async function renderMcpPanel() {
|
|
12334
|
+
if (!els.mcpList || !mcpModeOn()) return;
|
|
12335
|
+
const st = await beast.mcpStatus().catch(() => ({ path: '', servers: [] }));
|
|
12336
|
+
const cfg = await beast.mcpConfigGet().catch(() => ({ path: '', raw: '' }));
|
|
12337
|
+
const servers = st.servers || [];
|
|
12338
|
+
if (!servers.length) {
|
|
12339
|
+
els.mcpList.innerHTML = '<div class="file-empty">Henüz MCP server yok — aşağıdaki mcp.json\'a ekle ya da “Yeni Server”e bas.</div>';
|
|
12340
|
+
} else {
|
|
12341
|
+
if (!servers.some((s) => s.name === mcpSel)) mcpSel = servers[0].name;
|
|
12342
|
+
els.mcpList.innerHTML = servers.map((s) => {
|
|
12343
|
+
const badge = MCP_STATE_TR[s.state] || s.state;
|
|
12344
|
+
return '<div class="mcp-card' + (s.name === mcpSel ? ' sel' : '') + '" data-n="' + escapeHtml(s.name) + '">' +
|
|
12345
|
+
'<div class="mc-top"><span class="mc-name">' + escapeHtml(s.name) + '</span>' +
|
|
12346
|
+
'<span class="mcp-badge ' + escapeHtml(s.state) + '">' + escapeHtml(badge) + '</span>' +
|
|
12347
|
+
'<span class="file-spacer"></span>' +
|
|
12348
|
+
(s.enabled && s.toolCount ? '<span class="mcp-badge">' + s.toolCount + ' araç</span>' : '') + '</div>' +
|
|
12349
|
+
'<div class="mc-cmd">' + escapeHtml((s.command || '') + ' ' + (s.args || []).join(' ')) + '</div>' +
|
|
12350
|
+
(s.lastError && s.state === 'down' ? '<div class="mc-err">' + escapeHtml(String(s.lastError).slice(0, 140)) + '</div>' : '') +
|
|
12351
|
+
'<div class="mc-actions">' +
|
|
12352
|
+
'<button class="mcp-tgl" data-n="' + escapeHtml(s.name) + '">' + (s.enabled ? '⏸ Durdur' : '▶ Başlat') + '</button>' +
|
|
12353
|
+
'<button class="mcp-ref" data-n="' + escapeHtml(s.name) + '">⟳ Yenile</button>' +
|
|
12354
|
+
'</div></div>';
|
|
12355
|
+
}).join('');
|
|
12356
|
+
}
|
|
12357
|
+
renderMcpDetail(servers.find((s) => s.name === mcpSel) || null);
|
|
12358
|
+
if (els.mcpJson && document.activeElement !== els.mcpJson) {
|
|
12359
|
+
els.mcpJson.value = cfg.raw || JSON.stringify({ servers: {} }, null, 2);
|
|
12360
|
+
}
|
|
12361
|
+
if (els.mcpJsonPath) {
|
|
12362
|
+
els.mcpJsonPath.textContent = cfg.path || '';
|
|
12363
|
+
els.mcpJsonPath.title = cfg.path || '';
|
|
12364
|
+
}
|
|
12365
|
+
|
|
12366
|
+
els.mcpList.querySelectorAll('.mcp-card').forEach((c) => c.addEventListener('click', (ev) => {
|
|
12367
|
+
if (ev.target.closest('button')) return;
|
|
12368
|
+
mcpSel = c.dataset.n;
|
|
12369
|
+
renderMcpPanel();
|
|
12370
|
+
}));
|
|
12371
|
+
els.mcpList.querySelectorAll('.mcp-ref').forEach((b) => b.addEventListener('click', async () => {
|
|
12372
|
+
b.disabled = true;
|
|
12373
|
+
mcpSel = b.dataset.n;
|
|
12374
|
+
await beast.mcpRefresh(b.dataset.n).catch(() => {});
|
|
12375
|
+
renderMcpPanel();
|
|
12376
|
+
}));
|
|
12377
|
+
els.mcpList.querySelectorAll('.mcp-tgl').forEach((b) => b.addEventListener('click', async () => {
|
|
12378
|
+
b.disabled = true;
|
|
12379
|
+
try {
|
|
12380
|
+
const obj = JSON.parse(els.mcpJson.value || '{}');
|
|
12381
|
+
const name = b.dataset.n;
|
|
12382
|
+
if (obj.servers && obj.servers[name]) {
|
|
12383
|
+
obj.servers[name].enabled = obj.servers[name].enabled === false;
|
|
12384
|
+
await beast.mcpConfigSet(JSON.stringify(obj)).catch(() => {});
|
|
12385
|
+
mcpSel = name;
|
|
12386
|
+
}
|
|
12387
|
+
} catch (e) {
|
|
12388
|
+
toast('JSON hatası: ' + String((e && e.message) || e));
|
|
12389
|
+
}
|
|
12390
|
+
renderMcpPanel();
|
|
12391
|
+
}));
|
|
12392
|
+
}
|
|
12393
|
+
|
|
12394
|
+
function renderMcpDetail(s) {
|
|
12395
|
+
if (els.mcpDetailTitle) els.mcpDetailTitle.textContent = s ? s.name : 'Detay';
|
|
12396
|
+
if (els.mcpDetailState) {
|
|
12397
|
+
els.mcpDetailState.className = 'mcp-badge' + (s ? ' ' + s.state : '');
|
|
12398
|
+
els.mcpDetailState.textContent = s ? (MCP_STATE_TR[s.state] || s.state) : '';
|
|
12399
|
+
}
|
|
12400
|
+
if (!els.mcpDetailBody) return;
|
|
12401
|
+
if (!s) {
|
|
12402
|
+
els.mcpDetailBody.innerHTML = '<div class="file-empty">Soldan bir server seç.</div>';
|
|
12403
|
+
return;
|
|
12404
|
+
}
|
|
12405
|
+
const rows = [
|
|
12406
|
+
['Komut', (s.command || '') + ' ' + (s.args || []).join(' ')],
|
|
12407
|
+
['Durum', (MCP_STATE_TR[s.state] || s.state) + (s.enabled ? '' : ' (kapalı)')],
|
|
12408
|
+
['Araç', s.enabled ? String(s.toolCount || 0) + ' araç' : '—'],
|
|
12409
|
+
s.timeoutMs ? ['Zaman aşımı', s.timeoutMs + ' ms'] : null,
|
|
12410
|
+
s.tools && s.tools.length ? ['İzinli liste', s.tools.join(', ')] : null,
|
|
12411
|
+
].filter(Boolean);
|
|
12412
|
+
let html = rows.map(([k, v]) =>
|
|
12413
|
+
'<div class="mcp-drow"><span class="mcp-dk">' + escapeHtml(k) + '</span><span>' + escapeHtml(String(v)) + '</span></div>'
|
|
12414
|
+
).join('');
|
|
12415
|
+
if (s.lastError && s.state === 'down') {
|
|
12416
|
+
html += '<div class="mcp-drow"><span class="mcp-dk">Hata</span><span style="color:var(--err)">' + escapeHtml(s.lastError) + '</span></div>';
|
|
12417
|
+
}
|
|
12418
|
+
if (s.toolNames && s.toolNames.length) {
|
|
12419
|
+
html += '<div class="mcp-dk" style="margin-top:10px">Araçlar</div><div class="mcp-tools">' +
|
|
12420
|
+
s.toolNames.map((t) => '<span class="mcp-tool">' + escapeHtml(t) + '</span>').join('') + '</div>';
|
|
12421
|
+
} else if (s.enabled) {
|
|
12422
|
+
html += '<div class="file-empty">Araç listesi için ⟳ Yenile (server ilk kullanımda bağlanır).</div>';
|
|
12423
|
+
}
|
|
12424
|
+
els.mcpDetailBody.innerHTML = html;
|
|
12425
|
+
}
|
|
12426
|
+
|
|
12427
|
+
if (els.mcpBtn) els.mcpBtn.addEventListener('click', () => setMcpMode(!mcpModeOn()));
|
|
12428
|
+
if (els.mcpReload) els.mcpReload.addEventListener('click', () => renderMcpPanel());
|
|
12429
|
+
if (els.mcpSave) els.mcpSave.addEventListener('click', async () => {
|
|
12430
|
+
const r = await beast.mcpConfigSet(els.mcpJson.value || '').catch(() => ({ ok: false, error: 'IPC' }));
|
|
12431
|
+
if (els.mcpMsg) {
|
|
12432
|
+
els.mcpMsg.textContent = r && r.ok ? 'Kaydedildi' : ('Hata: ' + ((r && r.error) || '?'));
|
|
12433
|
+
els.mcpMsg.style.color = r && r.ok ? '' : 'var(--err)';
|
|
12434
|
+
}
|
|
12435
|
+
if (r && r.ok) renderMcpPanel();
|
|
12436
|
+
});
|
|
12437
|
+
if (els.mcpAddBtn) els.mcpAddBtn.addEventListener('click', () => {
|
|
12438
|
+
if (!els.mcpJson) return;
|
|
12439
|
+
try {
|
|
12440
|
+
const obj = JSON.parse(els.mcpJson.value || '{}') || {};
|
|
12441
|
+
obj.servers = obj.servers || {};
|
|
12442
|
+
let i = 1;
|
|
12443
|
+
let name = 'yeni-server';
|
|
12444
|
+
while (obj.servers[name]) name = 'yeni-server' + (++i);
|
|
12445
|
+
obj.servers[name] = { command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem', 'C:/'], enabled: false };
|
|
12446
|
+
els.mcpJson.value = JSON.stringify(obj, null, 2);
|
|
12447
|
+
els.mcpJson.focus();
|
|
12448
|
+
if (els.mcpMsg) {
|
|
12449
|
+
els.mcpMsg.textContent = 'örnek eklendi — komutu düzenleyip Kaydet';
|
|
12450
|
+
els.mcpMsg.style.color = '';
|
|
12451
|
+
}
|
|
12452
|
+
} catch {}
|
|
12453
|
+
});
|
|
12454
|
+
|
|
12273
12455
|
/* ---------- ÇALIŞTIRICI v2: butonlar DETERMİNİSTİK ----------
|
|
12274
12456
|
Proje tipi algılanır (package.json/requirements.txt/pyproject/Cargo.toml/
|
|
12275
|
-
go.mod/index.html)
|
|
12276
|
-
|
|
12457
|
+
go.mod/hugo/jekyll/mkdocs/index.html); Başlat/Dev gerekirse bağımlılıkları
|
|
12458
|
+
ÖNCE kurar (npm install && npm run dev gibi), süreç panelde canlı akar. */
|
|
12277
12459
|
async function sbRunLaunch(mode) {
|
|
12278
12460
|
if (!sbFolder) { toast('Önce repo indir ya da seç'); return; }
|
|
12279
12461
|
if (sbRunRunning) { toast('Bu repoda süreç çalışıyor — önce ■ Durdur'); return; }
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
const r = await call.catch((e) => ({ ok: false, error: String((e && e.message) || e) }));
|
|
12462
|
+
sbAutoAssist = mode;
|
|
12463
|
+
const r = await beast.sandboxStart({ folder: sbFolder, mode: mode === 'dev' ? 'dev' : 'run' })
|
|
12464
|
+
.catch((e) => ({ ok: false, error: String((e && e.message) || e) }));
|
|
12284
12465
|
if (!r || !r.ok) {
|
|
12285
|
-
|
|
12466
|
+
sbAutoAssist = null;
|
|
12467
|
+
const err = (r && r.error) || 'başlatılamadı';
|
|
12468
|
+
sbRunLine('[hata] ' + err, 't-err');
|
|
12469
|
+
/* algılama komut bulamadıysa ajan devralır: repo yapısından doğru komutu bulur */
|
|
12470
|
+
if (/algılanamadı/.test(err)) sbAskAgent(mode);
|
|
12286
12471
|
return;
|
|
12287
12472
|
}
|
|
12288
12473
|
sbRunRunning = true;
|
|
@@ -12332,24 +12517,97 @@ function sbRunIngest(ev) {
|
|
|
12332
12517
|
if (els.sbRunOpen) els.sbRunOpen.disabled = !sbRunUrl;
|
|
12333
12518
|
if (els.sbRunUrl) els.sbRunUrl.textContent = sbRunUrl;
|
|
12334
12519
|
sbBadge(folder || sbFolder, true);
|
|
12335
|
-
/*
|
|
12336
|
-
|
|
12520
|
+
/* ÇALIŞTIR panelinde canlı önizleme otomatik açılır */
|
|
12521
|
+
sbPreviewApply();
|
|
12337
12522
|
return;
|
|
12338
12523
|
}
|
|
12339
12524
|
if (ev.type === 'sb-run-end') {
|
|
12340
12525
|
sbRunRunning = false;
|
|
12341
12526
|
if (els.sbRunStop) els.sbRunStop.hidden = true;
|
|
12342
12527
|
sbBadge(folder || sbFolder, false);
|
|
12528
|
+
const assist = sbAutoAssist;
|
|
12529
|
+
sbAutoAssist = null;
|
|
12530
|
+
if (ev.quickFail && assist) {
|
|
12531
|
+
const kind = ev.kind === 'install' ? 'install' : 'run';
|
|
12532
|
+
sbRunLine('[hata] komut başarısız bitti — ajan doğru komutu arıyor…', 't-err');
|
|
12533
|
+
sbAskAgent(kind);
|
|
12534
|
+
}
|
|
12535
|
+
}
|
|
12536
|
+
}
|
|
12537
|
+
|
|
12538
|
+
/* ---------- ÇALIŞTIR içi CANLI ÖNİZLEME: DOM dikdörtgenini main'e bildir ---------- */
|
|
12539
|
+
function sbPreviewLayout() {
|
|
12540
|
+
if (!sbPreviewShown || sbPreviewSuspend) return;
|
|
12541
|
+
const host = document.getElementById('sbPreviewHost');
|
|
12542
|
+
if (!host) return;
|
|
12543
|
+
const r = host.getBoundingClientRect();
|
|
12544
|
+
if (!r.width || !r.height) return;
|
|
12545
|
+
beast.sbPreviewSet({
|
|
12546
|
+
url: sbRunUrl,
|
|
12547
|
+
visible: true,
|
|
12548
|
+
bounds: { x: r.left, y: r.top, width: r.width, height: r.height },
|
|
12549
|
+
}).catch(() => {});
|
|
12550
|
+
}
|
|
12551
|
+
|
|
12552
|
+
function sbPreviewApply() {
|
|
12553
|
+
const show = sbPreviewOn && sbModeOn() && !!sbFolder && !!sbRunUrl && !sbPreviewSuspend;
|
|
12554
|
+
sbPreviewShown = show;
|
|
12555
|
+
const host = document.getElementById('sbPreviewHost');
|
|
12556
|
+
if (host) host.hidden = !show;
|
|
12557
|
+
if (els.sbRunOut) els.sbRunOut.hidden = show;
|
|
12558
|
+
if (show) {
|
|
12559
|
+
sbPreviewLayout();
|
|
12560
|
+
/* görünür olunca yerleşim oturana kadar birkaç kez tazele */
|
|
12561
|
+
setTimeout(sbPreviewLayout, 50);
|
|
12562
|
+
setTimeout(sbPreviewLayout, 250);
|
|
12563
|
+
} else {
|
|
12564
|
+
beast.sbPreviewSet({ visible: false }).catch(() => {});
|
|
12565
|
+
}
|
|
12566
|
+
}
|
|
12567
|
+
|
|
12568
|
+
function sbPreviewToggle() {
|
|
12569
|
+
sbPreviewOn = !sbPreviewOn;
|
|
12570
|
+
if (els.sbRunView) {
|
|
12571
|
+
els.sbRunView.classList.toggle('on', sbPreviewOn);
|
|
12572
|
+
els.sbRunView.textContent = sbPreviewOn ? 'Görsel' : 'Çıktı';
|
|
12573
|
+
els.sbRunView.title = sbPreviewOn ? 'Görsel önizleme açık — çıktıya dön' : 'Çıktı görünümü — görsele dön';
|
|
12343
12574
|
}
|
|
12575
|
+
sbPreviewApply();
|
|
12576
|
+
}
|
|
12577
|
+
|
|
12578
|
+
/* Başlat/Dev başarısız olunca ajanı devreye sokar: repo yapısına göre
|
|
12579
|
+
DOĞRU komutu bulup panel_run ile başlatmasını ister (otomatik devralma). */
|
|
12580
|
+
function sbAskAgent(kind) {
|
|
12581
|
+
if (!sbFolder) return;
|
|
12582
|
+
const repoName = (sbItems.find((x) => x.folder === sbFolder) || {}).name || 'repo';
|
|
12583
|
+
const msg = kind === 'install'
|
|
12584
|
+
? `Kur butonu bu repoda başarısız oldu. ${repoName} reposunun dosyalarını incele (README, requirements.txt, package.json, pyproject.toml, Gemfile, mkdocs/hugo ayarları, alt klasörler) ve DOĞRU kurulum komutunu bulup panel_run ile ÇALIŞTIR panelinde çalıştır. Sonucu tek cümleyle bildir.`
|
|
12585
|
+
: `Başlat/Dev butonu bu repoda başarısız oldu. ${repoName} reposunun yapısını incele (README, package.json scripts, hugo/mkdocs/jekyll ayarları, main/app.py, Cargo.toml, go.mod…) ve GERÇEK çalıştırma komutunu bulup panel_run ile ÇALIŞTIR panelinde başlat. Web adresi çıkarsa kullanıcıya bildir.`;
|
|
12586
|
+
sbLine('t-sys', '⚙ ajan devrede — doğru komutu bulup başlatacak…');
|
|
12587
|
+
sbSetBusy(true);
|
|
12588
|
+
beast.sandboxSend({ folder: sbFolder, msg }).then((r) => {
|
|
12589
|
+
if (r && r.ok) {
|
|
12590
|
+
if (r.sessionId) sbSessionId = r.sessionId;
|
|
12591
|
+
if (r.queued) sbLine('t-dim', '⏳ kuyrukta (' + r.count + ') — iş bitince gönderilir');
|
|
12592
|
+
} else {
|
|
12593
|
+
sbSetBusy(false);
|
|
12594
|
+
sbLine('t-err', (r && r.error) || 'gönderilemedi');
|
|
12595
|
+
}
|
|
12596
|
+
}).catch((e) => {
|
|
12597
|
+
sbSetBusy(false);
|
|
12598
|
+
sbLine('t-err', String((e && e.message) || e));
|
|
12599
|
+
});
|
|
12344
12600
|
}
|
|
12345
12601
|
|
|
12346
12602
|
function sbRunExec(cmd) {
|
|
12347
12603
|
if (!sbFolder) { toast('Önce repo indir ya da seç'); return; }
|
|
12348
12604
|
if (sbRunRunning) { toast('Zaten çalışıyor — önce ■ ile durdur'); return; }
|
|
12349
12605
|
sbRunRunning = true;
|
|
12606
|
+
sbAutoAssist = 'run';
|
|
12350
12607
|
if (els.sbRunStop) els.sbRunStop.hidden = false;
|
|
12351
12608
|
beast.sandboxRun({ folder: sbFolder, cmd }).then((r) => {
|
|
12352
12609
|
if (!r || !r.ok) {
|
|
12610
|
+
sbAutoAssist = null;
|
|
12353
12611
|
sbRunRunning = false;
|
|
12354
12612
|
if (els.sbRunStop) els.sbRunStop.hidden = true;
|
|
12355
12613
|
sbRunLine('[hata] ' + ((r && r.error) || 'çalıştırılamadı'), 't-err');
|
|
@@ -12357,6 +12615,7 @@ function sbRunExec(cmd) {
|
|
|
12357
12615
|
sbBadge(sbFolder, true);
|
|
12358
12616
|
}
|
|
12359
12617
|
}).catch((e) => {
|
|
12618
|
+
sbAutoAssist = null;
|
|
12360
12619
|
sbRunRunning = false;
|
|
12361
12620
|
if (els.sbRunStop) els.sbRunStop.hidden = true;
|
|
12362
12621
|
sbRunLine('[hata] ' + String((e && e.message) || e), 't-err');
|
|
@@ -12412,6 +12671,10 @@ if (els.sbInput) {
|
|
|
12412
12671
|
}
|
|
12413
12672
|
});
|
|
12414
12673
|
}
|
|
12674
|
+
if (els.sbSend) els.sbSend.addEventListener('click', () => {
|
|
12675
|
+
sbRunCurrent();
|
|
12676
|
+
if (els.sbInput) els.sbInput.focus();
|
|
12677
|
+
});
|
|
12415
12678
|
if (els.sbStop) {
|
|
12416
12679
|
els.sbStop.addEventListener('click', () => {
|
|
12417
12680
|
beast.sandboxStop({ folder: sbFolder }).then((r) => {
|
|
@@ -12422,8 +12685,7 @@ if (els.sbStop) {
|
|
|
12422
12685
|
}).catch(() => {});
|
|
12423
12686
|
});
|
|
12424
12687
|
}
|
|
12425
|
-
/* ÇALIŞTIRICI butonları: algılanan komutu
|
|
12426
|
-
if (els.sbRunInstall) els.sbRunInstall.addEventListener('click', () => sbRunLaunch('install'));
|
|
12688
|
+
/* ÇALIŞTIRICI butonları: Başlat/Dev algılanan komutu (gerekirse kurup) çalıştırır */
|
|
12427
12689
|
if (els.sbRunStart) els.sbRunStart.addEventListener('click', () => sbRunLaunch('run'));
|
|
12428
12690
|
if (els.sbRunDev) els.sbRunDev.addEventListener('click', () => sbRunLaunch('dev'));
|
|
12429
12691
|
if (els.sbRunGo) els.sbRunGo.addEventListener('click', () => {
|
|
@@ -12475,3 +12737,75 @@ if (els.sbRunOpen) {
|
|
|
12475
12737
|
if (!r || !r.ok) toast('Açılamadı: ' + ((r && r.error) || 'bilinmeyen hata'));
|
|
12476
12738
|
});
|
|
12477
12739
|
}
|
|
12740
|
+
if (els.sbRunView) els.sbRunView.addEventListener('click', sbPreviewToggle);
|
|
12741
|
+
|
|
12742
|
+
/* görsel önizleme boyutu her yerleşim değişiminde main'e bildirilir
|
|
12743
|
+
(ayırıcı, tarayıcı dock'u, pencere boyutu, mod geçişi) */
|
|
12744
|
+
if (window.ResizeObserver) {
|
|
12745
|
+
const host = document.getElementById('sbPreviewHost');
|
|
12746
|
+
if (host) new ResizeObserver(() => sbPreviewLayout()).observe(host);
|
|
12747
|
+
}
|
|
12748
|
+
|
|
12749
|
+
/* ---------- sohbet/çalıştır ayırıcı (Beast Code ideSplit ile aynı desen) ----------
|
|
12750
|
+
Orantılı model: kaydedilen değer sohbet panelinin sandboxRow içindeki PAYI (0-1);
|
|
12751
|
+
sürükle-bırak anında --sbSplit yazar, bırakınca localStorage'a kaydeder. */
|
|
12752
|
+
let sbSplitFrac = 0;
|
|
12753
|
+
|
|
12754
|
+
function sbSplitApplyFrac() {
|
|
12755
|
+
const rowW = els.sandboxRow && els.sandboxRow.clientWidth ? els.sandboxRow.clientWidth : window.innerWidth - 250;
|
|
12756
|
+
/* kayıt yoksa eski varsayılan görünüm korunur: sohbet 480px, çalıştır kalanı */
|
|
12757
|
+
if (!sbSplitFrac) {
|
|
12758
|
+
const w = Math.max(280, Math.min(rowW - 480, Math.max(320, rowW - 300)));
|
|
12759
|
+
document.body.style.setProperty('--sbSplit', Math.round(w) + 'px');
|
|
12760
|
+
return;
|
|
12761
|
+
}
|
|
12762
|
+
sbSplitFrac = Math.max(0.2, Math.min(sbSplitFrac, 0.8));
|
|
12763
|
+
const w = Math.max(280, Math.min(Math.round(rowW * sbSplitFrac), Math.max(320, rowW - 300)));
|
|
12764
|
+
document.body.style.setProperty('--sbSplit', w + 'px');
|
|
12765
|
+
}
|
|
12766
|
+
|
|
12767
|
+
function sbSplitSave() {
|
|
12768
|
+
try { localStorage.setItem('beast.sbSplit', String(sbSplitFrac)); } catch {}
|
|
12769
|
+
}
|
|
12770
|
+
|
|
12771
|
+
function sbSplitRestore() {
|
|
12772
|
+
let saved = 0;
|
|
12773
|
+
try { saved = parseFloat(localStorage.getItem('beast.sbSplit')) || 0; } catch {}
|
|
12774
|
+
sbSplitFrac = saved > 0.05 && saved < 0.95 ? saved : 0;
|
|
12775
|
+
sbSplitApplyFrac();
|
|
12776
|
+
}
|
|
12777
|
+
|
|
12778
|
+
if (els.sbSplit) {
|
|
12779
|
+
els.sbSplit.addEventListener('mousedown', (e) => {
|
|
12780
|
+
e.preventDefault();
|
|
12781
|
+
els.sbSplit.classList.add('dragging');
|
|
12782
|
+
/* native önizleme view'i fare olaylarını yutabilir — sürükleme boyunca gizle,
|
|
12783
|
+
bırakınca geri getir (IDE'deki ayırıcı da aynı nedenle DOM üstünde çizilir) */
|
|
12784
|
+
sbPreviewSuspend = true;
|
|
12785
|
+
if (sbPreviewShown) beast.sbPreviewSet({ visible: false }).catch(() => {});
|
|
12786
|
+
const rightEdge = els.sbRun ? els.sbRun.getBoundingClientRect().right : window.innerWidth;
|
|
12787
|
+
const rowW = Math.max(600, els.sandboxRow && els.sandboxRow.clientWidth ? els.sandboxRow.clientWidth : window.innerWidth - 250);
|
|
12788
|
+
const move = (ev) => {
|
|
12789
|
+
const w = Math.max(280, Math.min(rightEdge - ev.clientX, rowW - 300));
|
|
12790
|
+
sbSplitFrac = Math.max(0.2, Math.min(w / rowW, 0.8));
|
|
12791
|
+
document.body.style.setProperty('--sbSplit', Math.round(w) + 'px');
|
|
12792
|
+
sbPreviewLayout();
|
|
12793
|
+
};
|
|
12794
|
+
const up = () => {
|
|
12795
|
+
document.removeEventListener('mousemove', move);
|
|
12796
|
+
document.removeEventListener('mouseup', up);
|
|
12797
|
+
els.sbSplit.classList.remove('dragging');
|
|
12798
|
+
sbSplitSave();
|
|
12799
|
+
sbPreviewSuspend = false;
|
|
12800
|
+
sbPreviewApply();
|
|
12801
|
+
};
|
|
12802
|
+
document.addEventListener('mousemove', move);
|
|
12803
|
+
document.addEventListener('mouseup', up);
|
|
12804
|
+
});
|
|
12805
|
+
window.addEventListener('resize', () => {
|
|
12806
|
+
if (sbModeOn()) {
|
|
12807
|
+
sbSplitApplyFrac();
|
|
12808
|
+
sbPreviewLayout();
|
|
12809
|
+
}
|
|
12810
|
+
});
|
|
12811
|
+
}
|
package/src/renderer/style.css
CHANGED
|
@@ -4271,7 +4271,7 @@ body.sandbox-mode #sandboxRow { display: flex; flex-direction: row; }
|
|
|
4271
4271
|
flex-direction: column;
|
|
4272
4272
|
min-height: 0;
|
|
4273
4273
|
min-width: 300px;
|
|
4274
|
-
flex:
|
|
4274
|
+
flex: 1 1 auto;
|
|
4275
4275
|
background: var(--bg);
|
|
4276
4276
|
overflow: hidden;
|
|
4277
4277
|
}
|
|
@@ -4280,10 +4280,20 @@ body.sandbox-mode #sandboxRow { display: flex; flex-direction: row; }
|
|
|
4280
4280
|
flex-direction: column;
|
|
4281
4281
|
min-height: 0;
|
|
4282
4282
|
min-width: 240px;
|
|
4283
|
-
flex:
|
|
4283
|
+
flex: 0 0 var(--sbSplit, 480px);
|
|
4284
4284
|
background: var(--bg);
|
|
4285
4285
|
overflow: hidden;
|
|
4286
|
-
|
|
4286
|
+
}
|
|
4287
|
+
#sbSplit {
|
|
4288
|
+
flex: none;
|
|
4289
|
+
width: 6px;
|
|
4290
|
+
cursor: col-resize;
|
|
4291
|
+
background: var(--border);
|
|
4292
|
+
opacity: 0.55;
|
|
4293
|
+
transition: opacity 0.15s;
|
|
4294
|
+
}
|
|
4295
|
+
#sbSplit:hover {
|
|
4296
|
+
opacity: 1;
|
|
4287
4297
|
}
|
|
4288
4298
|
|
|
4289
4299
|
#sbHead {
|
|
@@ -4394,9 +4404,31 @@ body.sandbox-mode #sandboxRow { display: flex; flex-direction: row; }
|
|
|
4394
4404
|
padding: 7px 9px;
|
|
4395
4405
|
border-radius: 8px;
|
|
4396
4406
|
font-family: inherit;
|
|
4407
|
+
overflow-y: hidden;
|
|
4408
|
+
max-height: 140px;
|
|
4409
|
+
line-height: 1.45;
|
|
4410
|
+
display: block;
|
|
4397
4411
|
}
|
|
4398
4412
|
#sbInput:focus { border-color: var(--accent); outline: none; }
|
|
4399
4413
|
#sbInput.expand { overflow-y: auto; }
|
|
4414
|
+
#sbInputRow button {
|
|
4415
|
+
flex: none;
|
|
4416
|
+
background: var(--panel2);
|
|
4417
|
+
border: 1px solid var(--border);
|
|
4418
|
+
color: var(--text);
|
|
4419
|
+
border-radius: 7px;
|
|
4420
|
+
cursor: pointer;
|
|
4421
|
+
font-size: 11px;
|
|
4422
|
+
padding: 6px 9px;
|
|
4423
|
+
line-height: 1;
|
|
4424
|
+
margin-bottom: 1px;
|
|
4425
|
+
}
|
|
4426
|
+
#sbInputRow button:hover { border-color: var(--accent); }
|
|
4427
|
+
#sbSend { color: var(--accent); }
|
|
4428
|
+
#sbSend:hover { background: var(--accent-dim); }
|
|
4429
|
+
#sbStop { color: var(--err); }
|
|
4430
|
+
#sbStop[hidden] { display: none; }
|
|
4431
|
+
#sbStop:hover { border-color: var(--err); }
|
|
4400
4432
|
|
|
4401
4433
|
/* ---------- ÇALIŞTIR bölmesi ---------- */
|
|
4402
4434
|
#sbRunHead {
|
|
@@ -4430,6 +4462,233 @@ body.sandbox-mode #sandboxRow { display: flex; flex-direction: row; }
|
|
|
4430
4462
|
text-overflow: ellipsis;
|
|
4431
4463
|
white-space: nowrap;
|
|
4432
4464
|
}
|
|
4465
|
+
#sbRunHead button {
|
|
4466
|
+
flex: none;
|
|
4467
|
+
background: var(--panel2);
|
|
4468
|
+
border: 1px solid var(--border);
|
|
4469
|
+
color: var(--muted);
|
|
4470
|
+
font-size: 11px;
|
|
4471
|
+
padding: 3px 9px;
|
|
4472
|
+
border-radius: 6px;
|
|
4473
|
+
cursor: pointer;
|
|
4474
|
+
}
|
|
4475
|
+
#sbRunHead button:hover { color: var(--text); border-color: var(--accent); }
|
|
4476
|
+
#sbRunHead button.on { color: var(--accent); border-color: var(--accent); }
|
|
4477
|
+
#sbPreviewHost {
|
|
4478
|
+
flex: 1;
|
|
4479
|
+
min-height: 0;
|
|
4480
|
+
display: flex;
|
|
4481
|
+
align-items: center;
|
|
4482
|
+
justify-content: center;
|
|
4483
|
+
background: var(--bg);
|
|
4484
|
+
}
|
|
4485
|
+
#sbPreviewHost[hidden] { display: none; }
|
|
4486
|
+
#sbPreviewHint {
|
|
4487
|
+
color: var(--muted);
|
|
4488
|
+
font-size: 12px;
|
|
4489
|
+
padding: 0 16px;
|
|
4490
|
+
text-align: center;
|
|
4491
|
+
}
|
|
4492
|
+
|
|
4493
|
+
/* ---------- MCP MODU ---------- */
|
|
4494
|
+
body.mcp-mode #chatScroll,
|
|
4495
|
+
body.mcp-mode #composerWrap,
|
|
4496
|
+
body.mcp-mode #ideRow,
|
|
4497
|
+
body.mcp-mode #studioRow,
|
|
4498
|
+
body.mcp-mode #sandboxRow { display: none; }
|
|
4499
|
+
|
|
4500
|
+
#mcpRow { display: none; flex: 1; min-height: 0; }
|
|
4501
|
+
body.mcp-mode #mcpRow { display: flex; flex-direction: row; }
|
|
4502
|
+
|
|
4503
|
+
#mcpPanel {
|
|
4504
|
+
display: flex;
|
|
4505
|
+
flex-direction: column;
|
|
4506
|
+
min-height: 0;
|
|
4507
|
+
min-width: 280px;
|
|
4508
|
+
flex: 0 0 380px;
|
|
4509
|
+
background: var(--bg);
|
|
4510
|
+
overflow: hidden;
|
|
4511
|
+
}
|
|
4512
|
+
#mcpDetail {
|
|
4513
|
+
display: flex;
|
|
4514
|
+
flex-direction: column;
|
|
4515
|
+
flex: 1;
|
|
4516
|
+
min-width: 0;
|
|
4517
|
+
min-height: 0;
|
|
4518
|
+
background: var(--bg);
|
|
4519
|
+
border-left: 1px solid var(--border);
|
|
4520
|
+
}
|
|
4521
|
+
#mcpHead {
|
|
4522
|
+
flex: none;
|
|
4523
|
+
display: flex;
|
|
4524
|
+
align-items: center;
|
|
4525
|
+
gap: 8px;
|
|
4526
|
+
padding: 9px 12px;
|
|
4527
|
+
border-bottom: 1px solid var(--border);
|
|
4528
|
+
background: var(--panel);
|
|
4529
|
+
}
|
|
4530
|
+
#mcpTitle { font-size: 11px; font-weight: 800; letter-spacing: 1px; color: var(--accent); flex: none; }
|
|
4531
|
+
#mcpHead button {
|
|
4532
|
+
background: none;
|
|
4533
|
+
border: none;
|
|
4534
|
+
color: var(--muted);
|
|
4535
|
+
font-size: 14px;
|
|
4536
|
+
cursor: pointer;
|
|
4537
|
+
padding: 2px 7px;
|
|
4538
|
+
border-radius: 6px;
|
|
4539
|
+
}
|
|
4540
|
+
#mcpHead button:hover { background: var(--panel2); color: var(--text); }
|
|
4541
|
+
#mcpList {
|
|
4542
|
+
flex: 1;
|
|
4543
|
+
min-height: 0;
|
|
4544
|
+
overflow-y: auto;
|
|
4545
|
+
padding: 10px 12px;
|
|
4546
|
+
}
|
|
4547
|
+
#mcpFoot {
|
|
4548
|
+
flex: none;
|
|
4549
|
+
padding: 8px 12px;
|
|
4550
|
+
border-top: 1px solid var(--border);
|
|
4551
|
+
background: var(--panel);
|
|
4552
|
+
}
|
|
4553
|
+
#mcpFoot button {
|
|
4554
|
+
width: 100%;
|
|
4555
|
+
background: var(--panel2);
|
|
4556
|
+
border: 1px solid var(--border);
|
|
4557
|
+
color: var(--text);
|
|
4558
|
+
font-size: 12px;
|
|
4559
|
+
padding: 6px 10px;
|
|
4560
|
+
border-radius: 7px;
|
|
4561
|
+
cursor: pointer;
|
|
4562
|
+
}
|
|
4563
|
+
#mcpFoot button:hover { border-color: var(--accent); }
|
|
4564
|
+
|
|
4565
|
+
.mcp-card {
|
|
4566
|
+
border: 1px solid var(--border);
|
|
4567
|
+
border-radius: 9px;
|
|
4568
|
+
padding: 9px 10px;
|
|
4569
|
+
margin-bottom: 8px;
|
|
4570
|
+
background: var(--panel);
|
|
4571
|
+
cursor: pointer;
|
|
4572
|
+
}
|
|
4573
|
+
.mcp-card:hover { border-color: var(--accent); }
|
|
4574
|
+
.mcp-card.sel { border-color: var(--accent); background: var(--panel2); }
|
|
4575
|
+
.mcp-card .mc-top { display: flex; align-items: center; gap: 7px; }
|
|
4576
|
+
.mcp-card .mc-name { font-weight: 700; font-size: 13px; }
|
|
4577
|
+
.mcp-card .mc-cmd {
|
|
4578
|
+
font-family: Consolas, monospace;
|
|
4579
|
+
font-size: 11px;
|
|
4580
|
+
color: var(--muted);
|
|
4581
|
+
margin-top: 4px;
|
|
4582
|
+
overflow: hidden;
|
|
4583
|
+
text-overflow: ellipsis;
|
|
4584
|
+
white-space: nowrap;
|
|
4585
|
+
}
|
|
4586
|
+
.mcp-card .mc-err {
|
|
4587
|
+
color: var(--err);
|
|
4588
|
+
font-size: 11px;
|
|
4589
|
+
margin-top: 4px;
|
|
4590
|
+
overflow: hidden;
|
|
4591
|
+
text-overflow: ellipsis;
|
|
4592
|
+
white-space: nowrap;
|
|
4593
|
+
}
|
|
4594
|
+
.mcp-card .mc-actions { display: flex; gap: 6px; margin-top: 7px; }
|
|
4595
|
+
.mcp-card .mc-actions button {
|
|
4596
|
+
background: var(--panel2);
|
|
4597
|
+
border: 1px solid var(--border);
|
|
4598
|
+
color: var(--text);
|
|
4599
|
+
font-size: 11px;
|
|
4600
|
+
padding: 3px 9px;
|
|
4601
|
+
border-radius: 6px;
|
|
4602
|
+
cursor: pointer;
|
|
4603
|
+
}
|
|
4604
|
+
.mcp-card .mc-actions button:hover { border-color: var(--accent); }
|
|
4605
|
+
|
|
4606
|
+
.mcp-badge {
|
|
4607
|
+
flex: none;
|
|
4608
|
+
font-size: 9.5px;
|
|
4609
|
+
font-weight: 800;
|
|
4610
|
+
letter-spacing: 0.5px;
|
|
4611
|
+
padding: 1px 6px;
|
|
4612
|
+
border-radius: 4px;
|
|
4613
|
+
border: 1px solid var(--border);
|
|
4614
|
+
color: var(--muted);
|
|
4615
|
+
text-transform: uppercase;
|
|
4616
|
+
}
|
|
4617
|
+
.mcp-badge.up { color: #22c55e; border-color: #22c55e; }
|
|
4618
|
+
.mcp-badge.down { color: var(--err); border-color: var(--err); }
|
|
4619
|
+
.mcp-badge.starting { color: var(--accent); border-color: var(--accent); }
|
|
4620
|
+
|
|
4621
|
+
#mcpDetailHead {
|
|
4622
|
+
flex: none;
|
|
4623
|
+
display: flex;
|
|
4624
|
+
align-items: center;
|
|
4625
|
+
gap: 10px;
|
|
4626
|
+
padding: 9px 14px;
|
|
4627
|
+
border-bottom: 1px solid var(--border);
|
|
4628
|
+
background: var(--panel);
|
|
4629
|
+
}
|
|
4630
|
+
#mcpDetailTitle { font-weight: 700; font-size: 13px; }
|
|
4631
|
+
#mcpDetailState { margin-left: auto; }
|
|
4632
|
+
#mcpDetailBody { flex: 1; min-height: 0; overflow-y: auto; padding: 12px 14px; }
|
|
4633
|
+
.mcp-drow { display: flex; gap: 8px; margin-bottom: 6px; font-size: 12.5px; }
|
|
4634
|
+
.mcp-dk { color: var(--muted); min-width: 76px; flex: none; }
|
|
4635
|
+
.mcp-tools { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
|
|
4636
|
+
.mcp-tool {
|
|
4637
|
+
font-family: Consolas, monospace;
|
|
4638
|
+
font-size: 11px;
|
|
4639
|
+
border: 1px solid var(--border);
|
|
4640
|
+
background: var(--panel2);
|
|
4641
|
+
padding: 2px 7px;
|
|
4642
|
+
border-radius: 6px;
|
|
4643
|
+
}
|
|
4644
|
+
#mcpJsonWrap {
|
|
4645
|
+
flex: none;
|
|
4646
|
+
display: flex;
|
|
4647
|
+
flex-direction: column;
|
|
4648
|
+
max-height: 40%;
|
|
4649
|
+
border-top: 1px solid var(--border);
|
|
4650
|
+
background: var(--panel);
|
|
4651
|
+
}
|
|
4652
|
+
#mcpJsonHead {
|
|
4653
|
+
flex: none;
|
|
4654
|
+
display: flex;
|
|
4655
|
+
align-items: center;
|
|
4656
|
+
gap: 8px;
|
|
4657
|
+
padding: 7px 12px;
|
|
4658
|
+
font-size: 11px;
|
|
4659
|
+
color: var(--muted);
|
|
4660
|
+
}
|
|
4661
|
+
#mcpJsonPath {
|
|
4662
|
+
max-width: 45%;
|
|
4663
|
+
overflow: hidden;
|
|
4664
|
+
text-overflow: ellipsis;
|
|
4665
|
+
white-space: nowrap;
|
|
4666
|
+
font-family: Consolas, monospace;
|
|
4667
|
+
}
|
|
4668
|
+
#mcpSave {
|
|
4669
|
+
background: var(--panel2);
|
|
4670
|
+
border: 1px solid var(--border);
|
|
4671
|
+
color: var(--accent);
|
|
4672
|
+
font-size: 11px;
|
|
4673
|
+
padding: 3px 10px;
|
|
4674
|
+
border-radius: 6px;
|
|
4675
|
+
cursor: pointer;
|
|
4676
|
+
}
|
|
4677
|
+
#mcpSave:hover { border-color: var(--accent); }
|
|
4678
|
+
#mcpJson {
|
|
4679
|
+
flex: 1;
|
|
4680
|
+
min-height: 110px;
|
|
4681
|
+
resize: none;
|
|
4682
|
+
background: var(--bg);
|
|
4683
|
+
border: none;
|
|
4684
|
+
border-top: 1px solid var(--border);
|
|
4685
|
+
color: var(--text);
|
|
4686
|
+
font-family: Consolas, monospace;
|
|
4687
|
+
font-size: 12px;
|
|
4688
|
+
padding: 8px 12px;
|
|
4689
|
+
outline: none;
|
|
4690
|
+
white-space: pre;
|
|
4691
|
+
}
|
|
4433
4692
|
#sbRunBtns {
|
|
4434
4693
|
flex: none;
|
|
4435
4694
|
display: flex;
|