beast-agent 2.41.0 → 2.42.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/index.html +8 -3
- package/src/renderer/renderer.js +177 -13
- package/src/renderer/style.css +62 -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/index.html
CHANGED
|
@@ -419,20 +419,24 @@
|
|
|
419
419
|
<div id="sbStatus" hidden></div>
|
|
420
420
|
<div id="sbInputRow">
|
|
421
421
|
<textarea id="sbInput" rows="1" spellcheck="false" autocomplete="off" placeholder="Sandbox mesajı — ajan bu repo klasöründe çalışır…"></textarea>
|
|
422
|
+
<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
423
|
<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
424
|
</div>
|
|
424
425
|
</section>
|
|
425
426
|
|
|
427
|
+
<div id="sbSplit" title="Sürükleyerek boyutlandır"></div>
|
|
428
|
+
|
|
426
429
|
<section id="sbRun">
|
|
427
430
|
<div id="sbRunHead">
|
|
428
431
|
<span id="sbRunTitle">ÇALIŞTIR</span>
|
|
429
432
|
<span id="sbRunKind"></span>
|
|
430
433
|
<span id="sbRunCwd" title="">—</span>
|
|
434
|
+
<span class="file-spacer"></span>
|
|
435
|
+
<button id="sbRunView" class="on" title="Görsel önizleme açık — çıktıya dön">Görsel</button>
|
|
431
436
|
</div>
|
|
432
437
|
<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>
|
|
438
|
+
<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>
|
|
439
|
+
<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
440
|
<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
441
|
</div>
|
|
438
442
|
<div id="sbRunCustom">
|
|
@@ -440,6 +444,7 @@
|
|
|
440
444
|
<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
445
|
<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
446
|
</div>
|
|
447
|
+
<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
448
|
<div id="sbRunOut"></div>
|
|
444
449
|
<div id="sbRunFoot">
|
|
445
450
|
<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>
|
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'),
|
|
@@ -6000,6 +6003,7 @@ function onEvent(ev) {
|
|
|
6000
6003
|
/* IDE modunda tarayıcı açılır/kapanır/genişlik değişirse row yeniden bölünür —
|
|
6001
6004
|
editör + Beast Code ORTAK kırpılıp ORTAK açılır (kullanıcı payı korunur) */
|
|
6002
6005
|
if (ideModeOn()) ideSplitApplyFrac();
|
|
6006
|
+
if (sbModeOn()) sbSplitApplyFrac();
|
|
6003
6007
|
if (shown) {
|
|
6004
6008
|
els.browserBtn.classList.add('on');
|
|
6005
6009
|
if (ev.url && document.activeElement !== els.bbUrl) {
|
|
@@ -11967,6 +11971,10 @@ const sbTreeState = { cache: new Map(), open: new Set(['']), path: '' };
|
|
|
11967
11971
|
let sbRunUrl = '';
|
|
11968
11972
|
let sbRunRunning = false;
|
|
11969
11973
|
let sbRunInfo = null;
|
|
11974
|
+
let sbAutoAssist = null; /* butonla başlatılan süreç hızlı çökerse: 'install' | 'run' */
|
|
11975
|
+
let sbPreviewOn = true; /* ÇALIŞTIR içi görsel önizleme tercihi */
|
|
11976
|
+
let sbPreviewShown = false;
|
|
11977
|
+
let sbPreviewSuspend = false; /* ayırıcı sürüklenirken native view gizli tutulur */
|
|
11970
11978
|
|
|
11971
11979
|
function sbModeOn() {
|
|
11972
11980
|
return document.body.classList.contains('sandbox-mode');
|
|
@@ -12168,6 +12176,7 @@ async function sbSelectCurrent() {
|
|
|
12168
12176
|
sbRunLine('ℹ ' + (det.info.label || 'proje') + ' · kur: ' + (det.info.install || '—') + ' · çalıştır: ' + (det.info.run || '—'), 't-dim');
|
|
12169
12177
|
}
|
|
12170
12178
|
}
|
|
12179
|
+
sbPreviewApply();
|
|
12171
12180
|
/* sol konsol: seçilen reponun klasörü — oturum açıldıktan sonra da garanti tazele */
|
|
12172
12181
|
sbTreeState.cache.clear();
|
|
12173
12182
|
if (sbModeOn()) renderFileTree().catch(() => {});
|
|
@@ -12183,7 +12192,8 @@ function sbInputResize() {
|
|
|
12183
12192
|
|
|
12184
12193
|
function sbRunCurrent() {
|
|
12185
12194
|
const msg = els.sbInput.value.trim();
|
|
12186
|
-
if (!msg ||
|
|
12195
|
+
if (!msg || sbCloning) return;
|
|
12196
|
+
if (!sbFolder) { toast('Önce repo indir ya da seç'); return; }
|
|
12187
12197
|
els.sbInput.value = '';
|
|
12188
12198
|
sbInputResize();
|
|
12189
12199
|
sbLine('t-cmd', 'sen> ' + msg);
|
|
@@ -12254,6 +12264,7 @@ function setSandboxMode(on) {
|
|
|
12254
12264
|
if (on && financeModeOn()) { setFinanceMode(false); }
|
|
12255
12265
|
document.body.classList.toggle('sandbox-mode', !!on);
|
|
12256
12266
|
if (els.sbBtn) els.sbBtn.classList.toggle('on', !!on);
|
|
12267
|
+
sbPreviewApply();
|
|
12257
12268
|
/* marka + sol konsol başlığı: moduna göre BEAST Agent/Code/Studio/Sandbox */
|
|
12258
12269
|
const brandSub = document.querySelector('#brand .brand-sub');
|
|
12259
12270
|
if (brandSub) brandSub.textContent = on ? 'Sandbox' : 'Agent';
|
|
@@ -12261,6 +12272,7 @@ function setSandboxMode(on) {
|
|
|
12261
12272
|
if (ftp && on) ftp.textContent = 'REPO DOSYALARI';
|
|
12262
12273
|
if (on) {
|
|
12263
12274
|
loadSandboxList();
|
|
12275
|
+
sbSplitRestore();
|
|
12264
12276
|
sbTreeState.cache.clear();
|
|
12265
12277
|
renderFileTree().catch(() => {});
|
|
12266
12278
|
} else if (!ideModeOn() && !studioModeOn()) {
|
|
@@ -12272,17 +12284,20 @@ function setSandboxMode(on) {
|
|
|
12272
12284
|
|
|
12273
12285
|
/* ---------- ÇALIŞTIRICI v2: butonlar DETERMİNİSTİK ----------
|
|
12274
12286
|
Proje tipi algılanır (package.json/requirements.txt/pyproject/Cargo.toml/
|
|
12275
|
-
go.mod/index.html)
|
|
12276
|
-
|
|
12287
|
+
go.mod/hugo/jekyll/mkdocs/index.html); Başlat/Dev gerekirse bağımlılıkları
|
|
12288
|
+
ÖNCE kurar (npm install && npm run dev gibi), süreç panelde canlı akar. */
|
|
12277
12289
|
async function sbRunLaunch(mode) {
|
|
12278
12290
|
if (!sbFolder) { toast('Önce repo indir ya da seç'); return; }
|
|
12279
12291
|
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) }));
|
|
12292
|
+
sbAutoAssist = mode;
|
|
12293
|
+
const r = await beast.sandboxStart({ folder: sbFolder, mode: mode === 'dev' ? 'dev' : 'run' })
|
|
12294
|
+
.catch((e) => ({ ok: false, error: String((e && e.message) || e) }));
|
|
12284
12295
|
if (!r || !r.ok) {
|
|
12285
|
-
|
|
12296
|
+
sbAutoAssist = null;
|
|
12297
|
+
const err = (r && r.error) || 'başlatılamadı';
|
|
12298
|
+
sbRunLine('[hata] ' + err, 't-err');
|
|
12299
|
+
/* algılama komut bulamadıysa ajan devralır: repo yapısından doğru komutu bulur */
|
|
12300
|
+
if (/algılanamadı/.test(err)) sbAskAgent(mode);
|
|
12286
12301
|
return;
|
|
12287
12302
|
}
|
|
12288
12303
|
sbRunRunning = true;
|
|
@@ -12332,24 +12347,97 @@ function sbRunIngest(ev) {
|
|
|
12332
12347
|
if (els.sbRunOpen) els.sbRunOpen.disabled = !sbRunUrl;
|
|
12333
12348
|
if (els.sbRunUrl) els.sbRunUrl.textContent = sbRunUrl;
|
|
12334
12349
|
sbBadge(folder || sbFolder, true);
|
|
12335
|
-
/*
|
|
12336
|
-
|
|
12350
|
+
/* ÇALIŞTIR panelinde canlı önizleme otomatik açılır */
|
|
12351
|
+
sbPreviewApply();
|
|
12337
12352
|
return;
|
|
12338
12353
|
}
|
|
12339
12354
|
if (ev.type === 'sb-run-end') {
|
|
12340
12355
|
sbRunRunning = false;
|
|
12341
12356
|
if (els.sbRunStop) els.sbRunStop.hidden = true;
|
|
12342
12357
|
sbBadge(folder || sbFolder, false);
|
|
12358
|
+
const assist = sbAutoAssist;
|
|
12359
|
+
sbAutoAssist = null;
|
|
12360
|
+
if (ev.quickFail && assist) {
|
|
12361
|
+
const kind = ev.kind === 'install' ? 'install' : 'run';
|
|
12362
|
+
sbRunLine('[hata] komut başarısız bitti — ajan doğru komutu arıyor…', 't-err');
|
|
12363
|
+
sbAskAgent(kind);
|
|
12364
|
+
}
|
|
12365
|
+
}
|
|
12366
|
+
}
|
|
12367
|
+
|
|
12368
|
+
/* ---------- ÇALIŞTIR içi CANLI ÖNİZLEME: DOM dikdörtgenini main'e bildir ---------- */
|
|
12369
|
+
function sbPreviewLayout() {
|
|
12370
|
+
if (!sbPreviewShown || sbPreviewSuspend) return;
|
|
12371
|
+
const host = document.getElementById('sbPreviewHost');
|
|
12372
|
+
if (!host) return;
|
|
12373
|
+
const r = host.getBoundingClientRect();
|
|
12374
|
+
if (!r.width || !r.height) return;
|
|
12375
|
+
beast.sbPreviewSet({
|
|
12376
|
+
url: sbRunUrl,
|
|
12377
|
+
visible: true,
|
|
12378
|
+
bounds: { x: r.left, y: r.top, width: r.width, height: r.height },
|
|
12379
|
+
}).catch(() => {});
|
|
12380
|
+
}
|
|
12381
|
+
|
|
12382
|
+
function sbPreviewApply() {
|
|
12383
|
+
const show = sbPreviewOn && sbModeOn() && !!sbFolder && !!sbRunUrl && !sbPreviewSuspend;
|
|
12384
|
+
sbPreviewShown = show;
|
|
12385
|
+
const host = document.getElementById('sbPreviewHost');
|
|
12386
|
+
if (host) host.hidden = !show;
|
|
12387
|
+
if (els.sbRunOut) els.sbRunOut.hidden = show;
|
|
12388
|
+
if (show) {
|
|
12389
|
+
sbPreviewLayout();
|
|
12390
|
+
/* görünür olunca yerleşim oturana kadar birkaç kez tazele */
|
|
12391
|
+
setTimeout(sbPreviewLayout, 50);
|
|
12392
|
+
setTimeout(sbPreviewLayout, 250);
|
|
12393
|
+
} else {
|
|
12394
|
+
beast.sbPreviewSet({ visible: false }).catch(() => {});
|
|
12395
|
+
}
|
|
12396
|
+
}
|
|
12397
|
+
|
|
12398
|
+
function sbPreviewToggle() {
|
|
12399
|
+
sbPreviewOn = !sbPreviewOn;
|
|
12400
|
+
if (els.sbRunView) {
|
|
12401
|
+
els.sbRunView.classList.toggle('on', sbPreviewOn);
|
|
12402
|
+
els.sbRunView.textContent = sbPreviewOn ? 'Görsel' : 'Çıktı';
|
|
12403
|
+
els.sbRunView.title = sbPreviewOn ? 'Görsel önizleme açık — çıktıya dön' : 'Çıktı görünümü — görsele dön';
|
|
12343
12404
|
}
|
|
12405
|
+
sbPreviewApply();
|
|
12406
|
+
}
|
|
12407
|
+
|
|
12408
|
+
/* Başlat/Dev başarısız olunca ajanı devreye sokar: repo yapısına göre
|
|
12409
|
+
DOĞRU komutu bulup panel_run ile başlatmasını ister (otomatik devralma). */
|
|
12410
|
+
function sbAskAgent(kind) {
|
|
12411
|
+
if (!sbFolder) return;
|
|
12412
|
+
const repoName = (sbItems.find((x) => x.folder === sbFolder) || {}).name || 'repo';
|
|
12413
|
+
const msg = kind === 'install'
|
|
12414
|
+
? `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.`
|
|
12415
|
+
: `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.`;
|
|
12416
|
+
sbLine('t-sys', '⚙ ajan devrede — doğru komutu bulup başlatacak…');
|
|
12417
|
+
sbSetBusy(true);
|
|
12418
|
+
beast.sandboxSend({ folder: sbFolder, msg }).then((r) => {
|
|
12419
|
+
if (r && r.ok) {
|
|
12420
|
+
if (r.sessionId) sbSessionId = r.sessionId;
|
|
12421
|
+
if (r.queued) sbLine('t-dim', '⏳ kuyrukta (' + r.count + ') — iş bitince gönderilir');
|
|
12422
|
+
} else {
|
|
12423
|
+
sbSetBusy(false);
|
|
12424
|
+
sbLine('t-err', (r && r.error) || 'gönderilemedi');
|
|
12425
|
+
}
|
|
12426
|
+
}).catch((e) => {
|
|
12427
|
+
sbSetBusy(false);
|
|
12428
|
+
sbLine('t-err', String((e && e.message) || e));
|
|
12429
|
+
});
|
|
12344
12430
|
}
|
|
12345
12431
|
|
|
12346
12432
|
function sbRunExec(cmd) {
|
|
12347
12433
|
if (!sbFolder) { toast('Önce repo indir ya da seç'); return; }
|
|
12348
12434
|
if (sbRunRunning) { toast('Zaten çalışıyor — önce ■ ile durdur'); return; }
|
|
12349
12435
|
sbRunRunning = true;
|
|
12436
|
+
sbAutoAssist = 'run';
|
|
12350
12437
|
if (els.sbRunStop) els.sbRunStop.hidden = false;
|
|
12351
12438
|
beast.sandboxRun({ folder: sbFolder, cmd }).then((r) => {
|
|
12352
12439
|
if (!r || !r.ok) {
|
|
12440
|
+
sbAutoAssist = null;
|
|
12353
12441
|
sbRunRunning = false;
|
|
12354
12442
|
if (els.sbRunStop) els.sbRunStop.hidden = true;
|
|
12355
12443
|
sbRunLine('[hata] ' + ((r && r.error) || 'çalıştırılamadı'), 't-err');
|
|
@@ -12357,6 +12445,7 @@ function sbRunExec(cmd) {
|
|
|
12357
12445
|
sbBadge(sbFolder, true);
|
|
12358
12446
|
}
|
|
12359
12447
|
}).catch((e) => {
|
|
12448
|
+
sbAutoAssist = null;
|
|
12360
12449
|
sbRunRunning = false;
|
|
12361
12450
|
if (els.sbRunStop) els.sbRunStop.hidden = true;
|
|
12362
12451
|
sbRunLine('[hata] ' + String((e && e.message) || e), 't-err');
|
|
@@ -12412,6 +12501,10 @@ if (els.sbInput) {
|
|
|
12412
12501
|
}
|
|
12413
12502
|
});
|
|
12414
12503
|
}
|
|
12504
|
+
if (els.sbSend) els.sbSend.addEventListener('click', () => {
|
|
12505
|
+
sbRunCurrent();
|
|
12506
|
+
if (els.sbInput) els.sbInput.focus();
|
|
12507
|
+
});
|
|
12415
12508
|
if (els.sbStop) {
|
|
12416
12509
|
els.sbStop.addEventListener('click', () => {
|
|
12417
12510
|
beast.sandboxStop({ folder: sbFolder }).then((r) => {
|
|
@@ -12422,8 +12515,7 @@ if (els.sbStop) {
|
|
|
12422
12515
|
}).catch(() => {});
|
|
12423
12516
|
});
|
|
12424
12517
|
}
|
|
12425
|
-
/* ÇALIŞTIRICI butonları: algılanan komutu
|
|
12426
|
-
if (els.sbRunInstall) els.sbRunInstall.addEventListener('click', () => sbRunLaunch('install'));
|
|
12518
|
+
/* ÇALIŞTIRICI butonları: Başlat/Dev algılanan komutu (gerekirse kurup) çalıştırır */
|
|
12427
12519
|
if (els.sbRunStart) els.sbRunStart.addEventListener('click', () => sbRunLaunch('run'));
|
|
12428
12520
|
if (els.sbRunDev) els.sbRunDev.addEventListener('click', () => sbRunLaunch('dev'));
|
|
12429
12521
|
if (els.sbRunGo) els.sbRunGo.addEventListener('click', () => {
|
|
@@ -12475,3 +12567,75 @@ if (els.sbRunOpen) {
|
|
|
12475
12567
|
if (!r || !r.ok) toast('Açılamadı: ' + ((r && r.error) || 'bilinmeyen hata'));
|
|
12476
12568
|
});
|
|
12477
12569
|
}
|
|
12570
|
+
if (els.sbRunView) els.sbRunView.addEventListener('click', sbPreviewToggle);
|
|
12571
|
+
|
|
12572
|
+
/* görsel önizleme boyutu her yerleşim değişiminde main'e bildirilir
|
|
12573
|
+
(ayırıcı, tarayıcı dock'u, pencere boyutu, mod geçişi) */
|
|
12574
|
+
if (window.ResizeObserver) {
|
|
12575
|
+
const host = document.getElementById('sbPreviewHost');
|
|
12576
|
+
if (host) new ResizeObserver(() => sbPreviewLayout()).observe(host);
|
|
12577
|
+
}
|
|
12578
|
+
|
|
12579
|
+
/* ---------- sohbet/çalıştır ayırıcı (Beast Code ideSplit ile aynı desen) ----------
|
|
12580
|
+
Orantılı model: kaydedilen değer sohbet panelinin sandboxRow içindeki PAYI (0-1);
|
|
12581
|
+
sürükle-bırak anında --sbSplit yazar, bırakınca localStorage'a kaydeder. */
|
|
12582
|
+
let sbSplitFrac = 0;
|
|
12583
|
+
|
|
12584
|
+
function sbSplitApplyFrac() {
|
|
12585
|
+
const rowW = els.sandboxRow && els.sandboxRow.clientWidth ? els.sandboxRow.clientWidth : window.innerWidth - 250;
|
|
12586
|
+
/* kayıt yoksa eski varsayılan görünüm korunur: sohbet 480px, çalıştır kalanı */
|
|
12587
|
+
if (!sbSplitFrac) {
|
|
12588
|
+
const w = Math.max(280, Math.min(rowW - 480, Math.max(320, rowW - 300)));
|
|
12589
|
+
document.body.style.setProperty('--sbSplit', Math.round(w) + 'px');
|
|
12590
|
+
return;
|
|
12591
|
+
}
|
|
12592
|
+
sbSplitFrac = Math.max(0.2, Math.min(sbSplitFrac, 0.8));
|
|
12593
|
+
const w = Math.max(280, Math.min(Math.round(rowW * sbSplitFrac), Math.max(320, rowW - 300)));
|
|
12594
|
+
document.body.style.setProperty('--sbSplit', w + 'px');
|
|
12595
|
+
}
|
|
12596
|
+
|
|
12597
|
+
function sbSplitSave() {
|
|
12598
|
+
try { localStorage.setItem('beast.sbSplit', String(sbSplitFrac)); } catch {}
|
|
12599
|
+
}
|
|
12600
|
+
|
|
12601
|
+
function sbSplitRestore() {
|
|
12602
|
+
let saved = 0;
|
|
12603
|
+
try { saved = parseFloat(localStorage.getItem('beast.sbSplit')) || 0; } catch {}
|
|
12604
|
+
sbSplitFrac = saved > 0.05 && saved < 0.95 ? saved : 0;
|
|
12605
|
+
sbSplitApplyFrac();
|
|
12606
|
+
}
|
|
12607
|
+
|
|
12608
|
+
if (els.sbSplit) {
|
|
12609
|
+
els.sbSplit.addEventListener('mousedown', (e) => {
|
|
12610
|
+
e.preventDefault();
|
|
12611
|
+
els.sbSplit.classList.add('dragging');
|
|
12612
|
+
/* native önizleme view'i fare olaylarını yutabilir — sürükleme boyunca gizle,
|
|
12613
|
+
bırakınca geri getir (IDE'deki ayırıcı da aynı nedenle DOM üstünde çizilir) */
|
|
12614
|
+
sbPreviewSuspend = true;
|
|
12615
|
+
if (sbPreviewShown) beast.sbPreviewSet({ visible: false }).catch(() => {});
|
|
12616
|
+
const rightEdge = els.sbRun ? els.sbRun.getBoundingClientRect().right : window.innerWidth;
|
|
12617
|
+
const rowW = Math.max(600, els.sandboxRow && els.sandboxRow.clientWidth ? els.sandboxRow.clientWidth : window.innerWidth - 250);
|
|
12618
|
+
const move = (ev) => {
|
|
12619
|
+
const w = Math.max(280, Math.min(rightEdge - ev.clientX, rowW - 300));
|
|
12620
|
+
sbSplitFrac = Math.max(0.2, Math.min(w / rowW, 0.8));
|
|
12621
|
+
document.body.style.setProperty('--sbSplit', Math.round(w) + 'px');
|
|
12622
|
+
sbPreviewLayout();
|
|
12623
|
+
};
|
|
12624
|
+
const up = () => {
|
|
12625
|
+
document.removeEventListener('mousemove', move);
|
|
12626
|
+
document.removeEventListener('mouseup', up);
|
|
12627
|
+
els.sbSplit.classList.remove('dragging');
|
|
12628
|
+
sbSplitSave();
|
|
12629
|
+
sbPreviewSuspend = false;
|
|
12630
|
+
sbPreviewApply();
|
|
12631
|
+
};
|
|
12632
|
+
document.addEventListener('mousemove', move);
|
|
12633
|
+
document.addEventListener('mouseup', up);
|
|
12634
|
+
});
|
|
12635
|
+
window.addEventListener('resize', () => {
|
|
12636
|
+
if (sbModeOn()) {
|
|
12637
|
+
sbSplitApplyFrac();
|
|
12638
|
+
sbPreviewLayout();
|
|
12639
|
+
}
|
|
12640
|
+
});
|
|
12641
|
+
}
|
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,33 @@ 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
|
+
}
|
|
4433
4492
|
#sbRunBtns {
|
|
4434
4493
|
flex: none;
|
|
4435
4494
|
display: flex;
|