beast-agent 1.0.0 → 1.1.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "beast-agent",
3
3
  "productName": "Beast Agent",
4
- "version": "1.0.0",
4
+ "version": "1.1.0",
5
5
  "description": "Ultra-fast local agent shell for Windows.",
6
6
  "author": "algokodcom (AlgoKod)",
7
7
  "license": "MIT",
@@ -30,7 +30,9 @@
30
30
  },
31
31
  "files": [
32
32
  "src/**/*",
33
- "assets/**/*"
33
+ "assets/**/*",
34
+ "scripts/**/*",
35
+ "!**/__pycache__/**"
34
36
  ],
35
37
  "scripts": {
36
38
  "start": "electron .",
@@ -0,0 +1,126 @@
1
+ 'use strict';
2
+
3
+ /* BEAST — electron binary onarıcı.
4
+ SORUN: `electron` npm paketi binary'yi (dist/electron.exe) postinstall'da
5
+ GitHub'dan indirir. Taze makinalarda bu indirme SESSİZCE başarısız olabilir
6
+ (proxy/GitHub engeli, npm ignore-scripts=true, ağ kesintisi) — paket kurulmuş
7
+ görünür ama `require('electron')` "Electron failed to install correctly" fırlatır.
8
+ ÇÖZÜM: install.js'i elle çalıştır; olmazsa yedek aynadan (npmmirror) dene.
9
+ Kullanım yerleri:
10
+ - package.json postinstall → kurulumda otomatik (npm i -g beast-agent)
11
+ - bin/beast-agent.js → her başlatmada bozuksa otomatik onar */
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+ const { spawnSync } = require('child_process');
16
+
17
+ /* electron paket dizini (index.js'in yeri); paket hiç yoksa null */
18
+ function electronDir() {
19
+ try {
20
+ return path.dirname(require.resolve('electron'));
21
+ } catch {
22
+ return null;
23
+ }
24
+ }
25
+
26
+ /* binary sağlam mı? electron/index.js'in beklentisiyle aynı kontrol:
27
+ path.txt + dist/<exe> varlığı */
28
+ function status() {
29
+ const dir = electronDir();
30
+ if (!dir) return { ok: false, missing: true };
31
+ const exe = process.platform === 'win32' ? 'electron.exe' : 'electron';
32
+ const distOk = fs.existsSync(path.join(dir, 'dist', exe));
33
+ const txtOk = fs.existsSync(path.join(dir, 'path.txt'));
34
+ return distOk && txtOk ? { ok: true, dir } : { ok: false, dir };
35
+ }
36
+
37
+ /* platforma göre dist içindeki çalıştırılabilirin göreli yolu (electron/index.js ile aynı) */
38
+ function platformPath() {
39
+ switch (process.platform) {
40
+ case 'win32':
41
+ return 'electron.exe';
42
+ case 'darwin':
43
+ case 'mas':
44
+ return 'Electron.app/Contents/MacOS/Electron';
45
+ default:
46
+ return 'electron';
47
+ }
48
+ }
49
+
50
+ /* onarım — 3 katman:
51
+ 0) binary sağlam, yalnız path.txt eksik/bozuk → indirimsiz anında yazar
52
+ (install.js bu durumu "zaten kurulu" sanıp atlayabiliyor)
53
+ 1) dist bozuk/eksik → dist'i sil + install.js (GitHub) ile taze indir
54
+ 2) GitHub engelli → ELECTRON_MIRROR=npmmirror ile tekrar */
55
+ function repair({ quiet } = {}) {
56
+ let st = status();
57
+ if (st.ok) return { ok: true, dir: st.dir, skipped: true };
58
+ if (st.missing) return { ok: false, error: 'electron paketi hi\u00e7 yok — npm install -g beast-agent' };
59
+ const dir = st.dir;
60
+ const exeRel = platformPath();
61
+ const exeAbs = path.join(dir, 'dist', ...exeRel.split('/'));
62
+ const verFile = path.join(dir, 'dist', 'version');
63
+ let wantVer = null;
64
+ try { wantVer = String(require(path.join(dir, 'package.json')).version || ''); } catch {}
65
+ const distIntact =
66
+ fs.existsSync(exeAbs) &&
67
+ (!wantVer ||
68
+ (fs.existsSync(verFile) &&
69
+ fs.readFileSync(verFile, 'utf8').replace(/^v/, '').trim() === wantVer));
70
+
71
+ if (distIntact) {
72
+ /* KATMAN 0: hızlı onarım — path.txt'yi kendimiz yazıyoruz (indirim yok) */
73
+ try { fs.writeFileSync(path.join(dir, 'path.txt'), exeRel, 'utf8'); } catch {}
74
+ if (status().ok) return { ok: true, dir, fast: true };
75
+ }
76
+
77
+ /* KATMAN 1-2: tam indirim */
78
+ try { fs.rmSync(path.join(dir, 'dist'), { recursive: true, force: true }); } catch {}
79
+ try { fs.unlinkSync(path.join(dir, 'path.txt')); } catch {}
80
+ const installJs = path.join(dir, 'install.js');
81
+ if (!fs.existsSync(installJs)) {
82
+ return { ok: false, error: 'install.js yok — yeniden kur: npm install -g beast-agent' };
83
+ }
84
+
85
+ const sources = [null, 'https://npmmirror.com/mirrors/electron/'];
86
+ for (let i = 0; i < sources.length; i++) {
87
+ const env = { ...process.env };
88
+ if (sources[i]) {
89
+ env.ELECTRON_MIRROR = sources[i];
90
+ if (!quiet) console.log(' \u2022 varsay\u0131lan kaynak ba\u015Far\u0131s\u0131z \u2014 yedek ayna deneniyor (npmmirror)\u2026');
91
+ } else if (!quiet) {
92
+ console.log(' \u2022 electron binary indiriliyor (ilk sefer ~110 MB, 1-2 dk)\u2026');
93
+ }
94
+ const r = spawnSync(process.execPath, [installJs], {
95
+ cwd: dir,
96
+ env,
97
+ stdio: quiet ? 'ignore' : 'inherit',
98
+ timeout: 600000,
99
+ });
100
+ if (!r.error && r.status === 0 && status().ok) {
101
+ return { ok: true, dir, mirror: sources[i] || 'github' };
102
+ }
103
+ if (!quiet && r.error) {
104
+ console.log(' ! deneme ba\u015far\u0131s\u0131z: ' + String(r.error.message || r.error).slice(0, 160));
105
+ }
106
+ }
107
+ return { ok: false, error: 'electron binary indirilemedi (a\u011f/proxy engeli olabilir)' };
108
+ }
109
+
110
+ module.exports = { electronDir, status, repair };
111
+
112
+ /* CLI: package.json postinstall → `node scripts/fix-electron.js --soft`
113
+ (her durumda exit 0 — npm install bozulmasın, başlatma anında tekrar denenir)
114
+ elle çağrı → hata durumunda exit 1 */
115
+ if (require.main === module) {
116
+ const soft = process.argv.includes('--soft');
117
+ const r = repair({ quiet: false });
118
+ if (r.ok) {
119
+ console.log(r.skipped ? '\u2713 electron binary tamam' : '\u2713 electron binary onar\u0131ld\u0131');
120
+ process.exit(0);
121
+ }
122
+ console.error('\u2717 electron onar\u0131lamad\u0131: ' + (r.error || '?'));
123
+ console.error(' elle \u00e7\u00f6z\u00fcm: npm config set ignore-scripts false');
124
+ console.error(' npm install -g beast-agent');
125
+ process.exit(soft ? 0 : 1);
126
+ }
@@ -0,0 +1,121 @@
1
+ 'use strict';
2
+
3
+ /* Beast Agent — Dağıtım / Senkron Sistemi
4
+ Tek komutla tam sürüm akışı (EXE/INSTALLER YOK — npm + kaynak dağıtımı):
5
+ npm run release → otomatik patch bump (0.20.0 → 0.20.1)
6
+ npm run release -- minor → 0.21.0
7
+ npm run release -- 0.22.0 → belirli sürüm
8
+
9
+ Adımlar:
10
+ 1) package.json sürümü yükselt
11
+ 2) commit + tag + push (main + tag)
12
+ 3) GitHub Release (yalnız kaynak — exe/asset yüklenmez)
13
+ 4) npm publish (NPM_TOKEN env var ise; yoksa atlar ve uyarır)
14
+ 5) OneDrive yedek klasörüne kaynak kopyası (beast-v< sürüm >)
15
+ */
16
+
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+ const { execSync } = require('child_process');
20
+
21
+ const ROOT = path.join(__dirname, '..');
22
+ const ONE_DRIVE_DIR = process.env.BEAST_BACKUP_DIR
23
+ || 'C:\\Users\\batuh\\OneDrive\\Masaüstü\\Beast Agent';
24
+
25
+ const step = (msg) => console.log('\n\x1b[1m▶ ' + msg + '\x1b[0m');
26
+ const ok = (msg) => console.log(' \x1b[32m✓\x1b[0m ' + msg);
27
+ const warn = (msg) => console.log(' \x1b[33m!\x1b[0m ' + msg);
28
+ const fail = (msg) => { console.error(' \x1b[31m✗ ' + msg + '\x1b[0m'); process.exit(1); };
29
+
30
+ function run(cmd, opts = {}) {
31
+ /* stdio:'inherit' iken execSync null döner — trim patlamasın */
32
+ return String(execSync(cmd, { cwd: ROOT, stdio: opts.inherit ? 'inherit' : 'pipe', encoding: 'utf8', ...opts }) ?? '').trim();
33
+ }
34
+
35
+ function bump(version, kind) {
36
+ const [ma, mi, pa] = version.split('.').map(Number);
37
+ if (kind === 'major') return `${ma + 1}.0.0`;
38
+ if (kind === 'minor') return `${ma}.${mi + 1}.0`;
39
+ return `${ma}.${mi}.${pa + 1}`;
40
+ }
41
+
42
+ /* ---------- argümanlar ---------- */
43
+ const arg = process.argv[2] || 'patch';
44
+ const pkgPath = path.join(ROOT, 'package.json');
45
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
46
+ const current = pkg.version;
47
+ const next = ['major', 'minor', 'patch'].includes(arg) ? bump(current, arg) : arg.replace(/^v/, '');
48
+ if (!/^\d+\.\d+\.\d+$/.test(next)) fail('geçersiz sürüm: ' + next);
49
+ const tag = 'v' + next;
50
+
51
+ console.log(`\x1b[1mBeast Agent release: ${current} → ${next}\x1b[0m`);
52
+
53
+ /* ---------- 1) sürüm bump ---------- */
54
+ step('1/5 sürüm yükselt: ' + current + ' → ' + next);
55
+ pkg.version = next;
56
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 4) + '\n');
57
+ ok('package.json → ' + next);
58
+
59
+ /* ---------- 2) commit + push ---------- */
60
+ step('2/5 git: commit + tag + push');
61
+ try {
62
+ run('git add -A');
63
+ run(`git commit -m "v${next}"`);
64
+ } catch { warn('commit edilecek değişiklik yoktu'); }
65
+ try { run(`git tag ${tag} -f`); } catch {}
66
+ run('git push origin main');
67
+ run(`git push origin ${tag}`);
68
+ ok('pushed: main + ' + tag);
69
+
70
+ /* ---------- 3) GitHub Release (kaynak — exe yok) ---------- */
71
+ step('3/5 GitHub Release ' + tag);
72
+ const gh = process.env.GH || 'gh';
73
+ try {
74
+ const notes = [
75
+ `## Beast Agent ${tag}`,
76
+ '',
77
+ '- \`npm i -g beast-agent@\`' + next,
78
+ '',
79
+ 'Dağıtım npm üzerinden yapılır — exe/installer sürümü kaldırıldı.',
80
+ 'Tam değişiklik listesi: commit geçmişi.',
81
+ ].join('\n');
82
+ const notesFile = path.join(ROOT, 'dist', 'release-notes.md');
83
+ fs.mkdirSync(path.dirname(notesFile), { recursive: true });
84
+ fs.writeFileSync(notesFile, notes);
85
+ try { run(`${gh} release delete ${tag} --yes --cleanup-tag`); } catch {}
86
+ run(`${gh} release create ${tag} --title "Beast Agent ${tag}" --notes-file "${notesFile}"`, { inherit: true });
87
+ ok('release yayında: https://github.com/algokodcom/beast-agent/releases/tag/' + tag);
88
+ } catch (e) {
89
+ fail('GitHub release: ' + String(e));
90
+ }
91
+
92
+ /* ---------- 4) npm publish ---------- */
93
+ step('4/5 npm publish');
94
+ if (process.env.NPM_TOKEN) {
95
+ try {
96
+ run(`npm publish --//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}`, { inherit: true });
97
+ ok('npm: beast-agent@' + next);
98
+ } catch (e) {
99
+ warn('npm publish başarısız (sürüm zaten var olabilir): ' + String(e).slice(0, 200));
100
+ }
101
+ } else {
102
+ warn('NPM_TOKEN env yok — npm adımı atlandı.');
103
+ warn('Elle: set NPM_TOKEN=<token> && npm publish');
104
+ }
105
+
106
+ /* ---------- 5) OneDrive kaynak yedeği ---------- */
107
+ step('5/5 OneDrive yedek (beast-v' + next + ')');
108
+ try {
109
+ const dest = path.join(ONE_DRIVE_DIR, 'beast-v' + next);
110
+ fs.mkdirSync(dest, { recursive: true });
111
+ run(`robocopy "${ROOT}" "${dest}" /E /XD node_modules dist "beast agent web" .git /NFL /NDL /NJH`);
112
+ const info = path.join(dest, `YEDEK-BILGI-v${next}.txt`);
113
+ fs.writeFileSync(info, `BEAST AGENT v${next} — ${new Date().toLocaleString('tr-TR')}\nKaynak: ${ROOT}\nGitHub: https://github.com/algokodcom/beast-agent/releases/tag/${tag}\nnpm: https://www.npmjs.com/package/beast-agent\n`);
114
+ ok(dest);
115
+ } catch (e) {
116
+ warn('OneDrive yedeği atlandı: ' + String(e).slice(0, 160));
117
+ }
118
+
119
+ console.log(`\n\x1b[1m\x1b[32m✓ v${next} dağıtımı tamam.\x1b[0m`);
120
+ console.log(' GitHub : https://github.com/algokodcom/beast-agent/releases/tag/' + tag);
121
+ console.log(' npm : https://www.npmjs.com/package/beast-agent');
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ /* electron yer değiştirici:
4
+ - `deps` : electron'u devDependencies → dependencies taşır (npm publish öncesi;
5
+ global kurulumda electron runtime'ı inmesi için)
6
+ - `devdeps`: geri taşır (electron-builder yalnız devDependencies kabul eder;
7
+ repo normal durumu budur)
8
+ npm lifecycle: prepublishOnly → deps, postpublish → devdeps */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+
13
+ const mode = process.argv[2];
14
+ const pkgPath = path.join(__dirname, '..', 'package.json');
15
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
16
+ const VER = pkg.devDependencies && pkg.devDependencies.electron
17
+ ? pkg.devDependencies.electron
18
+ : (pkg.dependencies && pkg.dependencies.electron);
19
+
20
+ if (!VER) {
21
+ console.error('electron sürümü package.json içinde bulunamadı');
22
+ process.exit(1);
23
+ }
24
+
25
+ if (mode === 'deps') {
26
+ delete pkg.devDependencies.electron;
27
+ pkg.dependencies = pkg.dependencies || {};
28
+ pkg.dependencies.electron = VER;
29
+ console.log('electron → dependencies (' + VER + ')');
30
+ } else if (mode === 'devdeps') {
31
+ delete pkg.dependencies.electron;
32
+ pkg.devDependencies = pkg.devDependencies || {};
33
+ pkg.devDependencies.electron = VER;
34
+ console.log('electron → devDependencies (' + VER + ')');
35
+ } else {
36
+ console.error('kullanım: node scripts/swap-electron.js deps|devdeps');
37
+ process.exit(1);
38
+ }
39
+
40
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 4) + '\n');
@@ -1333,6 +1333,7 @@ class Engine {
1333
1333
  '3) EDİT: VAR OLAN dosyada önce edit_file kullan (old_string/new_string ile yalnız ilgili bölümü değiştir; birden çok eşleşme varsa bağlam ekle ya da replace_all); write_file yalnız YENİ dosya ya da tam yeniden yazım için. İlgisiz yeniden biçimleme/kayıt boşluk değişikliği YAPMA.\n' +
1334
1334
  '4) DOĞRULA: edit sonrası mümkünse derle/test et/lint çalıştır (run_command); hata varsa DÜZELT ve TEKRAR dene (en fazla 2 doğrulama turu) — kırmızı bırakma.\n' +
1335
1335
  '5) RAPOR: 1-3 satır — ne değişti + doğrulama sonucu (ör. "npm test ✓ 154/154"). Uzun açıklama yok.\n' +
1336
+ 'CANLI ÖNİZLEME: web sitesi/app üretirsen son adımda ÇALIŞIR halde bırak (dev server ayakta ya da index.html yazılmış) — panel iş bitince ürettiğin şeyi dahili tarayıcıda otomatik canlı açar.\n' +
1336
1337
  'HIZ KURALLARI:\n' +
1337
1338
  '- Kodu ve dosyaları DOĞRUDAN write_file ile yaz; basit dosya oluşturma/düzenleme için Python scripti yazma; python_run yalnız gerçek hesap/veri işleme gerekiyorsa.\n' +
1338
1339
  '- Bağımsız araç çağrılarını AYNI TURDA paralel ver (birden çok read_file tek turda).\n' +
@@ -2786,6 +2787,9 @@ class Engine {
2786
2787
  let usageTotal = 0; // en yüksek görülen total_tokens — compaction tetiği
2787
2788
  let compacted = false; // run başına en fazla 1 compaction
2788
2789
  const recentSigs = []; // doom-loop dedektörü: son araç imzaları
2790
+ /* Beast Code canlı önizleme: run boyunca üretilen eserleri topla —
2791
+ iş bitince dahili tarayıcıda CANLI açılır (site/dev server/HTML) */
2792
+ const bcArtifacts = session.bcCode ? { html: [], serverUrl: null } : null;
2789
2793
  for (let turn = 0; turn < MAX_TURNS; turn++) {
2790
2794
  /* SÜRE SINIRI YOK — ama sonsuz tur da yok: bg ajan son 3 tura gelirken
2791
2795
  "raporu yaz ve bitir" uyarısı alır; MAX_TURNS sert tavan olarak kalır. */
@@ -2872,6 +2876,20 @@ class Engine {
2872
2876
  this._clearCrash();
2873
2877
  this._maybeCompact(sid);
2874
2878
  this._pruneSession(session); // opencode port: eski araç çıktıları temizlenir (fork edilen prune)
2879
+ /* Beast Code canlı önizleme: iş bitince üretilen site/app dahili
2880
+ tarayıcıda otomatik açılır (dev server öncelikli, sonra HTML) */
2881
+ if (bcArtifacts && (bcArtifacts.serverUrl || bcArtifacts.html.length)) {
2882
+ const url =
2883
+ bcArtifacts.serverUrl ||
2884
+ 'file:///' +
2885
+ path
2886
+ .resolve(
2887
+ this._sessionWorkspace(sid),
2888
+ bcArtifacts.html[bcArtifacts.html.length - 1]
2889
+ )
2890
+ .replace(/\\/g, '/');
2891
+ emit({ type: 'bc-preview', url });
2892
+ }
2875
2893
  emit({ type: 'done', usage: res.usage || null, meta: res.meta || null });
2876
2894
  this._bgFinish(sid, 'done');
2877
2895
  this.flushPendingReports(sid);
@@ -2920,6 +2938,34 @@ class Engine {
2920
2938
  } else {
2921
2939
  out = await this._execTool(name, args, ctrl.signal, sid);
2922
2940
  }
2941
+ /* Beast Code eser takibi: yazılan HTML + başlatılan dev server */
2942
+ if (bcArtifacts) {
2943
+ try {
2944
+ if (
2945
+ (name === 'write_file' || name === 'edit_file') &&
2946
+ args && args.path && /\.html?$/i.test(String(args.path))
2947
+ ) {
2948
+ bcArtifacts.html.push(String(args.path));
2949
+ }
2950
+ if (name === 'run_command') {
2951
+ const cmdStr = String((args && args.command) || '');
2952
+ const hay = cmdStr + '\n' + String(out || '').slice(0, 6000);
2953
+ const m = /https?:\/\/(?:localhost|127\.0\.0\.1)(?::\d{2,5})?[^\s'"<>]*/i.exec(hay);
2954
+ if (m) {
2955
+ bcArtifacts.serverUrl = m[0].replace(/[)\].,;:'"]+$/, '');
2956
+ } else {
2957
+ let port = 0;
2958
+ const hs = /python\s+-m\s+http\.server(?:[^\n]*?(\d{2,5}))?/i.exec(cmdStr);
2959
+ if (hs) port = Number(hs[1]) || 8000;
2960
+ else if (/\bvite\b/i.test(cmdStr)) port = 5173;
2961
+ else if (/\bnext dev\b/i.test(cmdStr)) port = 3000;
2962
+ else if (/\bng serve\b/i.test(cmdStr)) port = 4200;
2963
+ else if (/\b(npm (run )?(dev|start)|npx serve|live-server)\b/i.test(cmdStr)) port = 3000;
2964
+ if (port) bcArtifacts.serverUrl = 'http://localhost:' + port;
2965
+ }
2966
+ }
2967
+ } catch {}
2968
+ }
2923
2969
  // Ekran görüntüsü gibi araçlar görseli sonraki tura enjekte eder
2924
2970
  let injectedImage = null;
2925
2971
  try {
package/src/main.js CHANGED
@@ -5607,6 +5607,26 @@ ipcMain.handle('ide:preview', () => { try {
5607
5607
  }
5608
5608
  });
5609
5609
 
5610
+ /* BEAST CODE otomatik canlı önizleme: iş bitince üretilen site/app dahili
5611
+ tarayıcıda GÖRÜNÜR açılır. Yalnız localhost + file:// kabul edilir —
5612
+ dış adresler güvenlik için reddedilir. */
5613
+ ipcMain.handle('ide:previewUrl', (_e, url) => {
5614
+ try {
5615
+ const u = String(url || '');
5616
+ const okUrl =
5617
+ /^https?:\/\/(?:localhost|127\.0\.0\.1)(?::\d{2,5})?(?:\/|$)/i.test(u) ||
5618
+ /^file:\/\/\//i.test(u);
5619
+ if (!okUrl) return { ok: false, error: 'yalnız localhost/file:// adresleri önizlenebilir' };
5620
+ /* forceVisible: preview'a basmaya gerek kalmasın — otomatik ve GÖRÜNÜR açılır */
5621
+ setBrowserOpen(true, true);
5622
+ browser.view.webContents.loadURL(u).catch(() => {});
5623
+ browserEmit({ open: true, width: browser.width, url: u });
5624
+ return { ok: true, url: u };
5625
+ } catch (e) {
5626
+ return { ok: false, error: String((e && e.message) || e) };
5627
+ }
5628
+ });
5629
+
5610
5630
  ipcMain.handle('custom:set', (_e, list) => {
5611
5631
  settings.customProviders = Array.isArray(list) ? list : [];
5612
5632
  saveSettings();
package/src/preload.js CHANGED
@@ -179,6 +179,7 @@ contextBridge.exposeInMainWorld('beast', {
179
179
  ideWrite: (rel, content) => ipcRenderer.invoke('ide:write', { rel, content }),
180
180
  idePreview: () => ipcRenderer.invoke('ide:preview'),
181
181
  idePreviewFile: (rel) => ipcRenderer.invoke('ide:previewFile', rel),
182
+ idePreviewUrl: (url) => ipcRenderer.invoke('ide:previewUrl', url),
182
183
  ideDelete: (rel) => ipcRenderer.invoke('ide:delete', rel),
183
184
  onWaEvent: (cb) => ipcRenderer.on('wa:event', (_e, ev) => cb(ev)),
184
185
  onEvent: (cb) => ipcRenderer.on('agent:event', (_e, ev) => cb(ev)),
@@ -6278,6 +6278,25 @@ function bcRefreshPreview() {
6278
6278
  beast.idePreview().catch(() => {});
6279
6279
  }
6280
6280
 
6281
+ /* BEAST CODE canlı önizleme: engine iş sonunda eser tespit ederse
6282
+ (dev server / HTML) dahili tarayıcı otomatik GÖRÜNÜR açılır —
6283
+ kullanıcı preview tuşuna basmak zorunda kalmaz */
6284
+ function bcAutoPreview(url) {
6285
+ const u = String(url || '');
6286
+ if (
6287
+ !u ||
6288
+ !(
6289
+ /^https?:\/\/(?:localhost|127\.0\.0\.1)(?::\d{2,5})?(?:\/|$)/i.test(u) ||
6290
+ /^file:\/\/\//i.test(u)
6291
+ )
6292
+ ) {
6293
+ return;
6294
+ }
6295
+ bcPrevAt = Date.now(); /* ardından gelen done/idle çift yenilemesin */
6296
+ beast.idePreviewUrl(u).catch(() => {});
6297
+ bcLine('t-dim', '[canlı önizleme açıldı — ' + u + ']');
6298
+ }
6299
+
6281
6300
  /* ---------- Beast Code araç kutuları ----------
6282
6301
  Ard arda gelen araç çağrıları TEK kutuda toplanır. Kural: engine mesajı
6283
6302
  tool_calls İÇERİYORSA (iş turu) grup AÇIK kalır — aradaki ara yazılar kutu
@@ -6457,6 +6476,10 @@ function bcIngest(ev) {
6457
6476
  codeReloadIfOpen(wp);
6458
6477
  }
6459
6478
  break;
6479
+ case 'bc-preview':
6480
+ /* iş bitince üretilen site/app dahili tarayıcıda CANLI açılır */
6481
+ bcAutoPreview(ev.url);
6482
+ break;
6460
6483
  case 'bc-mode':
6461
6484
  /* OpenCode disiplini çalışma modu: başlıkta rozet + panelde bilgi satırı */
6462
6485
  if (els.bcTitle) {