beast-agent 1.2.3 → 1.3.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 +1 -1
- package/src/agent/engine.js +59 -62
- package/src/agent/tools.js +5 -3
- package/src/main.js +92 -9
- package/src/renderer/i18n.js +4 -0
- package/src/renderer/index.html +2 -0
- package/src/renderer/renderer.js +44 -4
- package/src/renderer/style.css +20 -0
package/package.json
CHANGED
package/src/agent/engine.js
CHANGED
|
@@ -16,10 +16,14 @@ const skills = require('./skills');
|
|
|
16
16
|
const { estTokens, estMsgTokens } = require('./tokens');
|
|
17
17
|
const log = require('./logger');
|
|
18
18
|
|
|
19
|
-
const MAX_TURNS =
|
|
19
|
+
const MAX_TURNS = 40;
|
|
20
20
|
const SUB_MAX_TURNS = 8;
|
|
21
21
|
const HISTORY_TOKEN_BUDGET = 18000;
|
|
22
22
|
const TOOL_OUT_KEEP = 1200;
|
|
23
|
+
/* read_file sonuçları dosya HAFIZASI'dır: 7200 char'a kırpma modeli aynı
|
|
24
|
+
dosyayı offset offset tekrar okuyor → tur limiti doluyordu. Son okuma
|
|
25
|
+
oturum sonuna kadar tam tutulur (yaklaşık 48k char ≈ orta boy kaynak dosya). */
|
|
26
|
+
const READ_OUT_KEEP = 48000;
|
|
23
27
|
const USER_MAX = 8000;
|
|
24
28
|
/* observe() ile enjekte edilen bağlam mesajlarının öneki — ardışık bağlam
|
|
25
29
|
mesajlarının tek mesajda birleşmesi bu işaretle anlaşılır */
|
|
@@ -1385,9 +1389,9 @@ class Engine {
|
|
|
1385
1389
|
? '# PROJE TALİMATLARI (workspace AGENTS/CLAUDE/CONTEXT dosyalarından — daima uy)\n' + proj + '\n'
|
|
1386
1390
|
: '') +
|
|
1387
1391
|
'WORKFLOW (her işte bu sıra):\n' +
|
|
1388
|
-
'1) BAĞLAM: değiştirmeden önce ilgili dosyaları OKU — read_file satır numaralı döner (N: içerik); büyük dosyada devamını offset parametresiyle oku, ASLA baştan okuma; bir dosyayı aynı oturumda BİR KEZ okumak yeter —
|
|
1392
|
+
'1) BAĞLAM: değiştirmeden önce ilgili dosyaları OKU — read_file satır numaralı döner (N: içerik); büyük dosyada devamını offset parametresiyle oku, ASLA baştan okuma; bir dosyayı aynı oturumda BİR KEZ okumak yeter — okuduğun içerik oturum SONUNA KADAR bağlamda KALIR, edit yaptıktan sonra dosyayı yeniden okuma YASAK (güncel durum = son okuma + kendi editlerin). İçerik araması için grep (regex), dosya adı için glob kullan; varsayım yapma, mevcut stili/konvansiyonu takip et.\n' +
|
|
1389
1393
|
'2) PLAN: 2+ adımlı işlerde İLK EYLEM todo_write olsun (2-6 madde); her adım bitince status:"done" ile GÜNCELLE — liste bitene kadar iş bitmiş sayılmaz.\n' +
|
|
1390
|
-
'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/
|
|
1394
|
+
'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. Dosya işlemleri için ÖZEL ARAÇLARI kullan (edit_file/write_file/read_file/grep/glob); run_command terminal işlerindir (build, git, kurulum, paket) — dosya düzenlemeyi komut/scripte yedirme, edit_file ile yap. İlgisiz yeniden biçimleme/kayıp boşluk değişikliği YAPMA. edit_file/write_file sonucu additions/deletions döner ve değişiklik diske ANINDA uygulanır — doğrulamak için dosyayı TEKRAR OKUMA YASAK; sonraki editi önceki okuduğun içerik + kendi değişikliklerin üzerinden zincirle.\n' +
|
|
1391
1395
|
'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. Doğrulama read_file ile DEĞİL run_command ile yapılır.\n' +
|
|
1392
1396
|
'5) RAPOR: 1-3 satır — ne değişti + doğrulama sonucu (ör. "npm test ✓ 154/154"). Uzun açıklama yok.\n' +
|
|
1393
1397
|
'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' +
|
|
@@ -1478,13 +1482,13 @@ class Engine {
|
|
|
1478
1482
|
'# ARAÇ KURALLARI\n' +
|
|
1479
1483
|
[
|
|
1480
1484
|
'Basit soruları araç kullanmadan doğrudan cevapla — hız önceliklidir.',
|
|
1481
|
-
'Kod/dosya işlerinde: içerik araması grep (regex), dosya adı araması glob, VAR OLAN dosyayı değiştirme edit_file (write_file yalnız yeni dosya/tam yeniden yazım). read_file satır numaralı döner; büyük dosyada devamını offset parametresiyle oku, ASLA baştan okuma; bir dosyayı aynı oturumda BİR KEZ okumak yeter. edit_file/write_file sonucu additions/deletions döner ve değişiklik diske ANINDA uygulanır — doğrulamak için dosyayı TEKRAR OKUMA; önceki okuduğun içerik + kendi değişikliklerin üzerinden devam et.',
|
|
1485
|
+
'Kod/dosya işlerinde: içerik araması grep (regex), dosya adı araması glob, VAR OLAN dosyayı değiştirme edit_file (write_file yalnız yeni dosya/tam yeniden yazım). read_file satır numaralı döner; büyük dosyada devamını offset parametresiyle oku, ASLA baştan okuma; bir dosyayı aynı oturumda BİR KEZ okumak yeter — okunan içerik oturum sonuna kadar bağlamda kalır, dosyayı tekrar okuma. Dosya işlemlerinde özel araçları kullan (edit_file/write_file/read_file/grep/glob); run_command terminal işlerindir (build, git, kurulum, paket) — dosya düzenlemeyi komutla değil edit_file ile yap. edit_file/write_file sonucu additions/deletions döner ve değişiklik diske ANINDA uygulanır — doğrulamak için dosyayı TEKRAR OKUMA; önceki okuduğun içerik + kendi değişikliklerin üzerinden devam et.',
|
|
1482
1486
|
'Kullanıcı bir tarihte/saatte hatırlatılmasını isterse set_reminder kullan; when değerini ORTAMdaki bugüne göre hesapla (yerel saat). "Her sabah/gün/hafta" gibi tekrarlı isteklerde repeat alanını da ver (daily/weekly/monthly/weekdays veya cron).',
|
|
1483
1487
|
'Kullanıcı kalıcı bir arka plan takibi isterse (fiyat eşiği, pil seviyesi, sayfa değişikliği) watcher_add ile izleyici kur; kurduktan sonra watcher_list ile doğrula ve kullanıcıya koşulu + kontrol sıklığını kısaca bildir.',
|
|
1484
1488
|
'Anlık olay takipleri için (yeni mail, fiyat eşiği, dosya değişimi, webhook) event_subscribe kullan — cron/polling gerekmez; listeyi event_list ile göster, vazgeçirirse event_unsubscribe.',
|
|
1485
1489
|
'Kullanıcı "artık hep böyle yap / bunu unutma" tarzı kalıcı talimat verirse kural olarak kaydet: sohbette /rule <metin> kullanmasını söyle VEYA kullanıcı isterse event_subscribe ile olaya bağlan (mail/fiyat/dosya/webhook).',
|
|
1486
1490
|
'Kullanıcının mesajında 2+ ayrı iş/hedef varsa (örn "X yap ve sonra Y\u2019i kontrol et") KODLAMAYA/İŞE BAŞLAMADAN önce todo_write ile plan çıkar ve sırayla yürüt; her adımı tamamlarken güncelle. LİSTE DİSİPLİNİ: her adım bittiği AN status:"done" yap; son cevabını vermeden önce tüm maddeler done olmalı — yapılmayacaksa listeden düş. Listeyi yarım bırakma.',
|
|
1487
|
-
'HIZ KURALI: Bağımsız işleri AYNI turda birden çok tool_calls ile PARALEL ver. Küçük işleri tek tek çağırma — her ayrı araç turu 5-15 sn LLM gecikmesidir: 3+ küçük komutu TEK run_command\u2019te `;` ile zincirle (örn `git status; node -v; dir`), döngülü/çoklu işleri TEK python_run betiğinde topla, çok dosyalık değişikliği TEK script ile yap. Her küçük işlem için ayrı araç çağrısı açmak yavaşlığın 1 numaralı sebebidir.',
|
|
1491
|
+
'HIZ KURALI: Bağımsız işleri AYNI turda birden çok tool_calls ile PARALEL ver. Küçük işleri tek tek çağırma — her ayrı araç turu 5-15 sn LLM gecikmesidir: 3+ küçük komutu TEK run_command\u2019te `;` ile zincirle (örn `git status; node -v; dir`), döngülü/çoklu işleri TEK python_run betiğinde topla, çok dosyalık değişikliği TEK script ile DEĞİL AYNI turda PARALEL edit_file çağrılarıyla yap (dosya düzenlemeyi komut/scripte yedirme). Her küçük işlem için ayrı araç çağrısı açmak yavaşlığın 1 numaralı sebebidir.',
|
|
1488
1492
|
this.ceoMode
|
|
1489
1493
|
? 'Bağımsız alt-işleri run_background ile PARALEL ajana devret; işi KENDİN YÜRÜTME — emri ver, takip et, raporla.'
|
|
1490
1494
|
: 'Bağımsız alt-işleri delegate_task ile devret; kendi başına halledebileceğin işleri devretme.',
|
|
@@ -1617,42 +1621,18 @@ class Engine {
|
|
|
1617
1621
|
return m;
|
|
1618
1622
|
});
|
|
1619
1623
|
/* opencode file-state portu: read_file sonuçları bağlamda YAŞAR —
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
const
|
|
1625
|
-
const s = String(m.content || '');
|
|
1626
|
-
try {
|
|
1627
|
-
const j = JSON.parse(s);
|
|
1628
|
-
if (j && j.path) return String(j.path);
|
|
1629
|
-
} catch {}
|
|
1630
|
-
const mm = /"path"\s*:\s*"((?:[^"\\]|\\.)*)"/.exec(s.slice(0, 600));
|
|
1631
|
-
return mm ? mm[1] : null;
|
|
1632
|
-
};
|
|
1633
|
-
const lastRead = new Map(); /* dosya yolu → flat'teki en son okuma indeksi */
|
|
1634
|
-
for (let k = 0; k < flat.length; k++) {
|
|
1635
|
-
const m = flat[k];
|
|
1636
|
-
if (m.role === 'tool' && m.name === 'read_file') {
|
|
1637
|
-
const p = readPathOf(m);
|
|
1638
|
-
if (p) lastRead.set(p, k);
|
|
1639
|
-
}
|
|
1640
|
-
}
|
|
1624
|
+
kırpma modeli "unuttu" diye tekrar tekrar okumaya zorluyordu.
|
|
1625
|
+
opencode'ta araç çıktıları tam tutulur; eski okumalar stub'a inmez —
|
|
1626
|
+
bütçe dolunca en eski birimler doğal olarak pencere dışı kalır
|
|
1627
|
+
(opencode prune mantığıyla aynı). Okumalar READ_OUT_KEEP ile sınırlı. */
|
|
1628
|
+
const READ_KEEP = READ_OUT_KEEP; /* depolama tavanıyla hizalı */
|
|
1641
1629
|
for (let k = 0; k < flat.length; k++) {
|
|
1642
1630
|
const m = flat[k];
|
|
1643
1631
|
if (m.role !== 'tool') continue;
|
|
1644
1632
|
const len = String(m.content || '').length;
|
|
1645
1633
|
let content;
|
|
1646
1634
|
if (m.name === 'read_file') {
|
|
1647
|
-
|
|
1648
|
-
if (p && lastRead.get(p) !== k) {
|
|
1649
|
-
content =
|
|
1650
|
-
'[aynı dosyanın daha YENİ bir okuması bağlamda — bu ESKİ okuma bağlam tasarrufu için kırpıldı; en son okumayı esas al]';
|
|
1651
|
-
} else if (len > READ_KEEP) {
|
|
1652
|
-
content = String(m.content).slice(0, READ_KEEP) + '\n…[kırpıldı — devam için offset ile oku]';
|
|
1653
|
-
} else {
|
|
1654
|
-
content = null; /* TAM KORUNUR — kırpma yok */
|
|
1655
|
-
}
|
|
1635
|
+
content = len > READ_KEEP ? String(m.content).slice(0, READ_KEEP) + '\n…[kırpıldı — devam için offset ile oku]' : null; /* TAM KORUNUR */
|
|
1656
1636
|
} else {
|
|
1657
1637
|
content = len > TOOL_OUT_KEEP * 2 ? String(m.content).slice(0, TOOL_OUT_KEEP) + '\n…[kırpıldı]' : null;
|
|
1658
1638
|
}
|
|
@@ -1905,10 +1885,28 @@ class Engine {
|
|
|
1905
1885
|
const msgs = session.messages;
|
|
1906
1886
|
let total = 0, pruned = 0, turns = 0;
|
|
1907
1887
|
const targets = [];
|
|
1888
|
+
/* her dosyanın EN SON read_file sonucu asla prune edilmez — dosya
|
|
1889
|
+
hafızası oturum sonuna kadar yaşar; eski okumalar serbest */
|
|
1890
|
+
const readPathOf = (m) => {
|
|
1891
|
+
const s = String(m.content || '');
|
|
1892
|
+
const mm = /"path"\s*:\s*"((?:[^"\\]|\\.)*)"/.exec(s.slice(0, 600));
|
|
1893
|
+
return mm ? mm[1] : null;
|
|
1894
|
+
};
|
|
1895
|
+
const lastReadId = new Map();
|
|
1896
|
+
for (const m of msgs) {
|
|
1897
|
+
if (m.role === 'tool' && m.name === 'read_file' && m.tool_call_id) {
|
|
1898
|
+
const p = readPathOf(m);
|
|
1899
|
+
if (p) lastReadId.set(p, m.tool_call_id);
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1908
1902
|
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
1909
1903
|
const m = msgs[i];
|
|
1910
1904
|
if (m.role === 'user') turns++;
|
|
1911
1905
|
if (turns < 2) continue; // en yeni tur dokunulmaz
|
|
1906
|
+
if (
|
|
1907
|
+
m.role === 'tool' && m.name === 'read_file' && m.tool_call_id &&
|
|
1908
|
+
readPathOf(m) && lastReadId.get(readPathOf(m)) === m.tool_call_id
|
|
1909
|
+
) continue; // son dosya okuması korumalı
|
|
1912
1910
|
if (m.role === 'tool' && typeof m.content === 'string' && m.content.length > 400) {
|
|
1913
1911
|
const est = Math.ceil(estTokens(m.content) * this.tokRatio);
|
|
1914
1912
|
total += est;
|
|
@@ -2697,6 +2695,7 @@ class Engine {
|
|
|
2697
2695
|
(job.task ? `GÖREV: ${job.task}\n` : '') +
|
|
2698
2696
|
`Ortam: Windows + PowerShell; çalışma klasörü: ${this.workspace}\n` +
|
|
2699
2697
|
`GENEL AJAN DİSİPLİNİ: görevi A'dan Z'ye yürüt — bağlam topla, uygula, DOĞRULA; yarım bırakma; doğrulama sonucunu rapora yaz.\n` +
|
|
2698
|
+
`DOSYA KURALI: dosya işlemlerinde özel araçları kullan — VAR OLAN dosyayı edit_file ile düzenle, yeniyi write_file ile yaz, okuma/arama read_file/grep/glob; run_command terminal işlerindir (build, git, kurulum). Bir dosyayı BİR KEZ oku — içerik bağlamda kalır, tekrar okuma.\n` +
|
|
2700
2699
|
(proj ? `PROJE TALİMATLARI (workspace AGENTS/CLAUDE/CONTEXT — daima uy):\n${proj}\n` : '') +
|
|
2701
2700
|
`HIZ KURALLARI:\n` +
|
|
2702
2701
|
`- Döngülü işleri (çok URL/dosya/sayfa, tekrarlı parse-hesap) TEK python_run betiğinde topluca bitir.\n` +
|
|
@@ -2711,7 +2710,7 @@ class Engine {
|
|
|
2711
2710
|
|
|
2712
2711
|
/* uzun bg işlerinde geçmiş şişer → payload büyür, hız düşer. Son N mesaj kalsın
|
|
2713
2712
|
(+ asıl görev mesajı); kopuk tool çifti sınırı hizalanır */
|
|
2714
|
-
static BG_KEEP_MSGS =
|
|
2713
|
+
static BG_KEEP_MSGS = 48;
|
|
2715
2714
|
_bgTrim(session) {
|
|
2716
2715
|
const max = Engine.BG_KEEP_MSGS;
|
|
2717
2716
|
const msgs = session.messages;
|
|
@@ -2946,17 +2945,23 @@ class Engine {
|
|
|
2946
2945
|
let nudged = false; // görev listesi disiplini: run başına en fazla 1 hatırlatma
|
|
2947
2946
|
let wrapNudged = false; // tur limitine yaklaşınca zarif kapanış (bg ajanlar)
|
|
2948
2947
|
let usageTotal = 0; // en yüksek görülen total_tokens — compaction tetiği
|
|
2949
|
-
let
|
|
2950
|
-
/* opencode agent.steps port: özel ajanın kendi tur limiti (2-60)
|
|
2948
|
+
let lastCompactTurn = -99; // opencode: compaction run başına 1 DEĞİL — her taşmada tekrar eder
|
|
2949
|
+
/* opencode agent.steps port: özel ajanın kendi tur limiti (2-60).
|
|
2950
|
+
ANA OTURUMDA SERT TUR LİMİTİ YOK (opencode birebir): bağlam dolunca
|
|
2951
|
+
compaction özetler ve işin ORTASINDA devam eder; sonsuz döngüyü
|
|
2952
|
+
doom-loop koruması + kullanıcı ■ kırar. bg ajanlarda kapanış
|
|
2953
|
+
disiplini için tavan kalır. */
|
|
2951
2954
|
const runDef = this._agentDefFor(session, !!session.bgJob);
|
|
2952
|
-
const maxTurns =
|
|
2955
|
+
const maxTurns = session.bgJob
|
|
2956
|
+
? Math.max(2, Math.min(60, (runDef && runDef.steps) || MAX_TURNS))
|
|
2957
|
+
: Infinity;
|
|
2953
2958
|
const recentSigs = []; // doom-loop dedektörü: son araç imzaları
|
|
2954
2959
|
/* Beast Code canlı önizleme: run boyunca üretilen eserleri topla —
|
|
2955
2960
|
iş bitince dahili tarayıcıda CANLI açılır (site/dev server/HTML) */
|
|
2956
2961
|
const bcArtifacts = session.bcCode ? { html: [], serverUrl: null } : null;
|
|
2957
2962
|
for (let turn = 0; turn < maxTurns; turn++) {
|
|
2958
|
-
/* SÜRE SINIRI YOK
|
|
2959
|
-
"raporu yaz ve bitir" uyarısı alır
|
|
2963
|
+
/* SÜRE SINIRI YOK. Ana oturum sınırsız tur koşar (opencode birebir);
|
|
2964
|
+
yalnız bg ajan son 3 tura gelirken "raporu yaz ve bitir" uyarısı alır. */
|
|
2960
2965
|
if (session.bgJob && turn === maxTurns - 3 && !wrapNudged) {
|
|
2961
2966
|
wrapNudged = true;
|
|
2962
2967
|
const wmsg = {
|
|
@@ -2970,26 +2975,16 @@ class Engine {
|
|
|
2970
2975
|
} catch {}
|
|
2971
2976
|
emit({ type: 'message', message: wmsg });
|
|
2972
2977
|
}
|
|
2973
|
-
/* opencode port (prompt.ts:
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
const wmsg = {
|
|
2978
|
-
role: 'user',
|
|
2979
|
-
content:
|
|
2980
|
-
'[SON TUR] Tur limitine ulaşıldı: YENİ araç çağırma — eldeki bilgilerle NİHAİ cevabını şimdi ver. Eksikler varsa açıkça belirt.',
|
|
2981
|
-
};
|
|
2982
|
-
session.messages.push(wmsg);
|
|
2983
|
-
try {
|
|
2984
|
-
this._append(session, wmsg);
|
|
2985
|
-
} catch {}
|
|
2986
|
-
emit({ type: 'message', message: wmsg });
|
|
2987
|
-
}
|
|
2988
|
-
/* opencode port (prompt.ts:1161 + overflow.ts): bağlam dolduysa
|
|
2989
|
-
compaction checkpoint — kuyruk korunur, baş özetlenir */
|
|
2978
|
+
/* opencode port (prompt.ts:1161 + overflow.ts + processor.ts "compact"):
|
|
2979
|
+
bağlam dolduysa compaction — kuyruk korunur, baş özetlenir ve işin
|
|
2980
|
+
ORTASINDA devam edilir. Run içinde TEKRAR EDELİR; taze compaction'dan
|
|
2981
|
+
hemen sonra hâlâ taşarsa opencode ContextOverflowError gibi güvenli dur. */
|
|
2990
2982
|
const selNow = this.sessionModel.get(String(sid)) || this.modelFor(null) || this.sel;
|
|
2991
|
-
if (
|
|
2992
|
-
|
|
2983
|
+
if (this._overContext(session, selNow, usageTotal)) {
|
|
2984
|
+
if (turn - lastCompactTurn < 4) {
|
|
2985
|
+
throw new Error('ContextOverflow: compaction sonrası bağlam hâlâ model limitinin üstünde — oturum çok büyük');
|
|
2986
|
+
}
|
|
2987
|
+
lastCompactTurn = turn;
|
|
2993
2988
|
await this._compactHistory(session, selNow, ctrl.signal);
|
|
2994
2989
|
}
|
|
2995
2990
|
this._bgTrim(session); // #21 bg geçmişini olabildiğince ince tut
|
|
@@ -3147,7 +3142,7 @@ class Engine {
|
|
|
3147
3142
|
}
|
|
3148
3143
|
if (injectedImage || diffView) out = JSON.stringify(obj);
|
|
3149
3144
|
} catch {}
|
|
3150
|
-
const toolMsg = { role: 'tool', tool_call_id: tc.id, name, content: out.slice(0, TOOL_OUT_KEEP * 6) };
|
|
3145
|
+
const toolMsg = { role: 'tool', tool_call_id: tc.id, name, content: out.slice(0, name === 'read_file' ? READ_OUT_KEEP : TOOL_OUT_KEEP * 6) };
|
|
3151
3146
|
if (diffView) toolMsg.diffView = diffView; /* oturum dosyasına da düşer — geçmiş açılınca diff yeniden çizilir */
|
|
3152
3147
|
session.messages.push(toolMsg);
|
|
3153
3148
|
try {
|
|
@@ -3169,8 +3164,10 @@ class Engine {
|
|
|
3169
3164
|
})
|
|
3170
3165
|
);
|
|
3171
3166
|
}
|
|
3167
|
+
/* yalnız bg ajanlar tavanla buraya düşebilir — ana oturum sınırsız koşar */
|
|
3172
3168
|
emit({ type: 'done', usage: null });
|
|
3173
|
-
this._bgFinish(sid, 'error', 'tur
|
|
3169
|
+
this._bgFinish(sid, 'error', 'bg görevi tur limitine ulaştı (maxTurns)');
|
|
3170
|
+
} catch (e) {
|
|
3174
3171
|
const aborted = e && (e.name === 'AbortError' || ctrl.signal.aborted);
|
|
3175
3172
|
if (aborted) {
|
|
3176
3173
|
this._clearCrash(); // kullanıcı durdurdu — kurtarma yok
|
package/src/agent/tools.js
CHANGED
|
@@ -1327,7 +1327,7 @@ const definitions = [
|
|
|
1327
1327
|
function: {
|
|
1328
1328
|
name: 'run_command',
|
|
1329
1329
|
description:
|
|
1330
|
-
'
|
|
1330
|
+
'Executes a given PowerShell command on the user\'s Windows machine in the workspace directory and returns combined stdout/stderr. Use this tool for terminal operations like builds, git, npm installs, docker, etc. DO NOT use it for file operations (reading, writing, editing, searching, finding files) - use the specialized tools for this instead: read_file, write_file, edit_file, grep, glob.',
|
|
1331
1331
|
parameters: {
|
|
1332
1332
|
type: 'object',
|
|
1333
1333
|
properties: {
|
|
@@ -1354,7 +1354,8 @@ const definitions = [
|
|
|
1354
1354
|
'- Contents are returned with each line prefixed by its line number as `<line>: <content>`. For example, if a file has contents "foo\\n", you will receive "1: foo\\n".\n' +
|
|
1355
1355
|
'- Any line longer than 2000 characters is truncated.\n' +
|
|
1356
1356
|
'- Call this tool in parallel when you know there are multiple files you want to read.\n' +
|
|
1357
|
-
'- Avoid tiny repeated slices (30 line chunks). If you need more context, read a larger window
|
|
1357
|
+
'- Avoid tiny repeated slices (30 line chunks). If you need more context, read a larger window.\n' +
|
|
1358
|
+
'- File contents you read STAY in your context for the WHOLE session. Do NOT re-read a file you already read: chain edits from your previous read plus your own edit_file/write_file results. Re-reading the same file (same or overlapping range) wastes turns and is forbidden unless the file actually changed on disk outside your own edits.',
|
|
1358
1359
|
parameters: {
|
|
1359
1360
|
type: 'object',
|
|
1360
1361
|
properties: {
|
|
@@ -1402,7 +1403,8 @@ const definitions = [
|
|
|
1402
1403
|
'- The edit will FAIL if `old_string` is not found in the file with an error "oldString not found in content".\n' +
|
|
1403
1404
|
'- The edit will FAIL if `old_string` is found multiple times in the file with an error "Found multiple matches for oldString. Provide more surrounding lines in old_string to identify the correct match." Either provide a larger string with more surrounding context to make it unique or use `replace_all` to change every instance of `old_string`.\n' +
|
|
1404
1405
|
'- Use `replace_all` for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.\n' +
|
|
1405
|
-
'- The result includes additions/deletions counts — the change is APPLIED to disk immediately; do NOT read the file again to verify
|
|
1406
|
+
'- The result includes additions/deletions counts — the change is APPLIED to disk immediately; do NOT read the file again to verify.\n' +
|
|
1407
|
+
'- Chain follow-up edits from what you already read plus your own previous edits — do NOT re-read the file between edits. Multiple edit_file calls to different files can be issued in PARALLEL in one turn.',
|
|
1406
1408
|
parameters: {
|
|
1407
1409
|
type: 'object',
|
|
1408
1410
|
properties: {
|
package/src/main.js
CHANGED
|
@@ -2439,6 +2439,7 @@ function reloadBackend() {
|
|
|
2439
2439
|
emit: (ev) => {
|
|
2440
2440
|
if (win && !win.isDestroyed()) win.webContents.send('agent:event', ev);
|
|
2441
2441
|
flushDesktopOnDone(ev); /* biriken desktop mesajlarını sıraya bas */
|
|
2442
|
+
bcFlushOnDone(ev); /* Beast Code kuyruğunu iş bitiminde boşalt */
|
|
2442
2443
|
/* WA canlı iş takibi: oturum bir WhatsApp sohbetine bağlıysa araç
|
|
2443
2444
|
hareketlerini (terminal, web, dosya…) kısa satırla bildir.
|
|
2444
2445
|
Spam olmasın: sohbet başına en az 7 sn'de bir tek satır. */
|
|
@@ -5266,6 +5267,66 @@ function bcPanelEvent(sid, ev) {
|
|
|
5266
5267
|
} catch {}
|
|
5267
5268
|
}
|
|
5268
5269
|
|
|
5270
|
+
/* Beast Code mesaj kuyruğu: ajan çalışırken gelen mesajlar birikir, iş bitince
|
|
5271
|
+
TEK pakette (metinler \n ile birleşik) gönderilir. Boştayken de kısa pencere
|
|
5272
|
+
(debounce) vardır — ard arda hızlı mesajlar tek işte birleşir. */
|
|
5273
|
+
const BC_DEBOUNCE_MS = 900;
|
|
5274
|
+
const bcQueue = new Map(); /* klasör yolu → { timer, msgs[] } */
|
|
5275
|
+
|
|
5276
|
+
function bcQueuePush(ws, text) {
|
|
5277
|
+
let q = bcQueue.get(ws);
|
|
5278
|
+
if (!q) {
|
|
5279
|
+
q = { timer: null, msgs: [] };
|
|
5280
|
+
bcQueue.set(ws, q);
|
|
5281
|
+
}
|
|
5282
|
+
q.msgs.push({ text });
|
|
5283
|
+
return q;
|
|
5284
|
+
}
|
|
5285
|
+
|
|
5286
|
+
function bcFlush(folder) {
|
|
5287
|
+
const q = bcQueue.get(folder);
|
|
5288
|
+
if (!q || !q.msgs.length) return;
|
|
5289
|
+
const s = bcGetSession(folder); /* oturum yoksa oluşturur */
|
|
5290
|
+
if (engine.isBusy(s.id)) return; /* hâlâ çalışıyor — done/error eventini bekle */
|
|
5291
|
+
let merged = '';
|
|
5292
|
+
for (const m of q.msgs) if (m.text) merged += (merged ? '\n' : '') + m.text;
|
|
5293
|
+
if (!merged.trim()) {
|
|
5294
|
+
bcQueue.delete(folder);
|
|
5295
|
+
clearTimeout(q.timer);
|
|
5296
|
+
return;
|
|
5297
|
+
}
|
|
5298
|
+
s.workspace = folder;
|
|
5299
|
+
s.bcCode = true;
|
|
5300
|
+
engine.cache.set(s.id, s);
|
|
5301
|
+
if (engine.send(s.id, merged)) {
|
|
5302
|
+
bcQueue.delete(folder);
|
|
5303
|
+
clearTimeout(q.timer);
|
|
5304
|
+
} else {
|
|
5305
|
+
/* yarış: az önce meşgul oldu — kuyruk korunur, kısa süre sonra tekrar denenir */
|
|
5306
|
+
q.retries = (q.retries || 0) + 1;
|
|
5307
|
+
if (q.retries > 5) {
|
|
5308
|
+
bcQueue.delete(folder);
|
|
5309
|
+
clearTimeout(q.timer);
|
|
5310
|
+
try {
|
|
5311
|
+
if (win && !win.isDestroyed()) {
|
|
5312
|
+
win.webContents.send('agent:event', { sessionId: s.id, type: 'error', error: 'Beast Code mesajı gönderilemedi — panele tekrar yaz' });
|
|
5313
|
+
}
|
|
5314
|
+
} catch {}
|
|
5315
|
+
return;
|
|
5316
|
+
}
|
|
5317
|
+
setTimeout(() => { try { bcFlush(folder); } catch {} }, 800);
|
|
5318
|
+
}
|
|
5319
|
+
}
|
|
5320
|
+
|
|
5321
|
+
function bcFlushOnDone(ev) {
|
|
5322
|
+
if (!ev || (ev.type !== 'done' && ev.type !== 'error') || !ev.sessionId) return;
|
|
5323
|
+
for (const [folder, sid] of bcSessions) {
|
|
5324
|
+
if (String(sid) === String(ev.sessionId) && bcQueue.has(folder)) {
|
|
5325
|
+
setTimeout(() => { try { bcFlush(folder); } catch {} }, 150);
|
|
5326
|
+
}
|
|
5327
|
+
}
|
|
5328
|
+
}
|
|
5329
|
+
|
|
5269
5330
|
ipcMain.handle('beastcode:send', async (_e, payload) => {
|
|
5270
5331
|
const text = String((payload && payload.msg) || '').trim();
|
|
5271
5332
|
if (!text) return { ok: false, error: 'boş mesaj' };
|
|
@@ -5274,13 +5335,16 @@ ipcMain.handle('beastcode:send', async (_e, payload) => {
|
|
|
5274
5335
|
const modeM = /^\/(plan|build|auto)\b/i.exec(text);
|
|
5275
5336
|
|
|
5276
5337
|
if (!engine.publicState().hasModel) return { ok: false, error: 'model yok — Ayarlar → Provider sekmesinden ekle' };
|
|
5277
|
-
|
|
5338
|
+
/* oturumu HEMEN aç: cevap daima gerçek sessionId taşır — renderer paneli bu id ile
|
|
5339
|
+
eşler; boşta/kuyrukta olsa bile id yoksa panel olayları eşleyemez ve ölü kalır */
|
|
5278
5340
|
const s = bcGetSession(ws);
|
|
5279
5341
|
s.workspace = ws; /* soldaki klasörde çalış */
|
|
5280
5342
|
s.bcCode = true; /* todo disiplini + iş sonu hızlı kapanış (engine) */
|
|
5343
|
+
engine.cache.set(s.id, s);
|
|
5344
|
+
const busy = engine.isBusy(s.id);
|
|
5281
5345
|
if (modeM) {
|
|
5346
|
+
/* mod değişimi anında uygulanır — meşgulken de (yalnız bayrak; engine çakışmaz) */
|
|
5282
5347
|
s.bcMode = modeM[1].toLowerCase();
|
|
5283
|
-
engine.cache.set(s.id, s);
|
|
5284
5348
|
if (win && !win.isDestroyed()) {
|
|
5285
5349
|
const body = modeM[1].toLowerCase() === 'plan'
|
|
5286
5350
|
? 'PLAN MODU — dosyaları okuyup inceler, KOD YAZMAZ; adım adım uygulama planı verir.'
|
|
@@ -5291,25 +5355,44 @@ ipcMain.handle('beastcode:send', async (_e, payload) => {
|
|
|
5291
5355
|
}
|
|
5292
5356
|
return { ok: true, sessionId: s.id, mode: s.bcMode };
|
|
5293
5357
|
}
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5358
|
+
if (busy) {
|
|
5359
|
+
/* ajan çalışıyor → kuyruğa al; iş bitince (done/error) toplu gider */
|
|
5360
|
+
const q = bcQueuePush(ws, text);
|
|
5361
|
+
return { ok: true, queued: true, count: q.msgs.length, sessionId: s.id };
|
|
5362
|
+
}
|
|
5363
|
+
/* boşta: kısa pencere — hızlı ard arda mesajlar tek işte birleşir */
|
|
5364
|
+
const q = bcQueuePush(ws, text);
|
|
5365
|
+
clearTimeout(q.timer);
|
|
5366
|
+
q.timer = setTimeout(() => { try { bcFlush(ws); } catch {} }, BC_DEBOUNCE_MS);
|
|
5367
|
+
return { ok: true, sessionId: s.id, pending: true };
|
|
5298
5368
|
});
|
|
5299
5369
|
|
|
5300
5370
|
ipcMain.handle('beastcode:stop', async () => {
|
|
5301
5371
|
const ws = ideRoot();
|
|
5302
5372
|
const sid = bcSessions.get(ws);
|
|
5303
|
-
|
|
5373
|
+
/* durdurma: bekleyen kuyruğu da boşalt (kullanıcı vazgeçti) */
|
|
5374
|
+
const q = bcQueue.get(ws);
|
|
5375
|
+
if (q) {
|
|
5376
|
+
clearTimeout(q.timer);
|
|
5377
|
+
bcQueue.delete(ws);
|
|
5378
|
+
}
|
|
5379
|
+
const wasBusy = sid ? engine.isBusy(sid) : false;
|
|
5304
5380
|
let r = false;
|
|
5305
|
-
|
|
5306
|
-
|
|
5381
|
+
if (wasBusy) {
|
|
5382
|
+
try { r = engine.interrupt(sid, 'kullanıcı Beast Code panelinden ■ ile durdurdu'); } catch {}
|
|
5383
|
+
}
|
|
5384
|
+
return { ok: true, wasBusy, interrupted: r };
|
|
5307
5385
|
});
|
|
5308
5386
|
|
|
5309
5387
|
ipcMain.handle('beastcode:new', async () => {
|
|
5310
5388
|
const ws = ideRoot();
|
|
5311
5389
|
const sid = bcSessions.get(ws);
|
|
5312
5390
|
if (sid && engine.isBusy(sid)) return { ok: false, error: 'mesaj sürüyor — önce ■ ile durdur' };
|
|
5391
|
+
const q = bcQueue.get(ws);
|
|
5392
|
+
if (q) {
|
|
5393
|
+
clearTimeout(q.timer);
|
|
5394
|
+
bcQueue.delete(ws);
|
|
5395
|
+
}
|
|
5313
5396
|
if (sid) {
|
|
5314
5397
|
try { engine.deleteSession(sid); } catch {}
|
|
5315
5398
|
bcSessions.delete(ws);
|
package/src/renderer/i18n.js
CHANGED
|
@@ -509,6 +509,8 @@
|
|
|
509
509
|
tipStore: 'Skills Store',
|
|
510
510
|
tipGithub: 'GitHub Trending — repoları favorile, chate at, ajana araştır',
|
|
511
511
|
tipIde: 'IDE Modu — dosyalar + chat + preview',
|
|
512
|
+
tipCodeHide: 'Editörü kapat',
|
|
513
|
+
tipCodeShow: 'Editörü göster',
|
|
512
514
|
ide_files: 'DOSYALAR',
|
|
513
515
|
ide_pick: 'Klasör seç',
|
|
514
516
|
ide_refresh: 'Yenile',
|
|
@@ -1122,6 +1124,8 @@
|
|
|
1122
1124
|
tipStore: 'Skills Store',
|
|
1123
1125
|
tipGithub: 'GitHub Trending — favorite repos, send to chat, ask the agent',
|
|
1124
1126
|
tipIde: 'IDE Mode — files + chat + preview',
|
|
1127
|
+
tipCodeHide: 'Hide editor',
|
|
1128
|
+
tipCodeShow: 'Show editor',
|
|
1125
1129
|
ide_files: 'FILES',
|
|
1126
1130
|
ide_pick: 'Choose folder',
|
|
1127
1131
|
ide_refresh: 'Refresh',
|
package/src/renderer/index.html
CHANGED
|
@@ -111,6 +111,7 @@
|
|
|
111
111
|
<div id="codeTabs"></div>
|
|
112
112
|
<code id="codePath" title="">—</code>
|
|
113
113
|
<button id="codeSave" title="Kaydet (Ctrl+S)">Kaydet</button>
|
|
114
|
+
<button id="codeHide" title="Editörü kapat" data-i18n-title="tipCodeHide">✕︎</button>
|
|
114
115
|
</div>
|
|
115
116
|
<div id="codeBody">
|
|
116
117
|
<div id="codeGutter" aria-hidden="true"></div>
|
|
@@ -125,6 +126,7 @@
|
|
|
125
126
|
<span id="bcTitle">BEAST CODE</span>
|
|
126
127
|
<span id="bcCwd" title=""></span>
|
|
127
128
|
<span class="file-spacer"></span>
|
|
129
|
+
<button id="codeShow" title="Editörü göster" data-i18n-title="tipCodeShow" hidden>▣︎</button>
|
|
128
130
|
<button id="bcNew" title="Yeni oturum" data-i18n-title="bc_new">+</button>
|
|
129
131
|
<button id="bcClear" title="Çıktıyı temizle" data-i18n-title="bc_clear">Temizle</button>
|
|
130
132
|
</div>
|
package/src/renderer/renderer.js
CHANGED
|
@@ -83,6 +83,8 @@ const els = {
|
|
|
83
83
|
codeGutter: $('#codeGutter'),
|
|
84
84
|
codePath: $('#codePath'),
|
|
85
85
|
codeSave: $('#codeSave'),
|
|
86
|
+
codeHide: $('#codeHide'),
|
|
87
|
+
codeShow: $('#codeShow'),
|
|
86
88
|
ideRow: $('#ideRow'),
|
|
87
89
|
ideSplit: $('#ideSplit'),
|
|
88
90
|
bcPanel: $('#bcPanel'),
|
|
@@ -4167,6 +4169,8 @@ function onEvent(ev) {
|
|
|
4167
4169
|
break;
|
|
4168
4170
|
}
|
|
4169
4171
|
case 'status':
|
|
4172
|
+
/* kuyruktan tetiklenen yeni iş: kilitle kendiliğinden açılmışsa geri kapat */
|
|
4173
|
+
if (ev.status !== 'idle' && !busy) setBusy(true);
|
|
4170
4174
|
if (!busy) break;
|
|
4171
4175
|
setStatus(ev.status === 'idle' ? (busy ? 'düşünüyor…' : '') : ev.status === 'thinking' ? 'düşünüyor…' : ev.status + '…');
|
|
4172
4176
|
break;
|
|
@@ -5922,12 +5926,29 @@ async function setIdeMode(on) {
|
|
|
5922
5926
|
}
|
|
5923
5927
|
if (on) {
|
|
5924
5928
|
ideSplitRestore();
|
|
5929
|
+
setEditorHidden(localStorage.getItem('beast.editorHidden') === '1');
|
|
5925
5930
|
await loadIdeTree();
|
|
5926
5931
|
bcBanner();
|
|
5927
5932
|
codeGutterRender(); /* dosya açık olmasa bile rakamlar görünür */
|
|
5928
5933
|
}
|
|
5929
5934
|
}
|
|
5930
5935
|
|
|
5936
|
+
/* ---------- editör panelini kapat/göster ----------
|
|
5937
|
+
Kapatınca kod bölmesi gider, Beast Code tam genişlik alır; tercih
|
|
5938
|
+
localStorage'da kalıcıdır. Dosya ağacından dosya açınca geri açılır. */
|
|
5939
|
+
function editorHiddenOn() {
|
|
5940
|
+
return document.body.classList.contains('editor-hidden');
|
|
5941
|
+
}
|
|
5942
|
+
|
|
5943
|
+
function setEditorHidden(h) {
|
|
5944
|
+
document.body.classList.toggle('editor-hidden', !!h);
|
|
5945
|
+
if (els.codeShow) els.codeShow.hidden = !h;
|
|
5946
|
+
try { localStorage.setItem('beast.editorHidden', h ? '1' : '0'); } catch {}
|
|
5947
|
+
}
|
|
5948
|
+
|
|
5949
|
+
if (els.codeHide) els.codeHide.addEventListener('click', () => setEditorHidden(true));
|
|
5950
|
+
if (els.codeShow) els.codeShow.addEventListener('click', () => setEditorHidden(false));
|
|
5951
|
+
|
|
5931
5952
|
/* ---------- editor/chat ayırıcı (VS Code gibi sürükle-bırak) ----------
|
|
5932
5953
|
Orantılı model: kaydedilen, Beast Code'un ideRow içindeki PAYI'dır (0-1).
|
|
5933
5954
|
Tarayıcı açılınca/kapanınca/genişlik değişince row yeniden bölünür — editör
|
|
@@ -6215,6 +6236,7 @@ function codeActivate(i) {
|
|
|
6215
6236
|
}
|
|
6216
6237
|
|
|
6217
6238
|
async function codeOpen(rel) {
|
|
6239
|
+
if (editorHiddenOn()) setEditorHidden(false); /* dosya açılınca editör geri gelir */
|
|
6218
6240
|
const idx = codeTabs.findIndex((t) => t.rel === rel);
|
|
6219
6241
|
if (idx >= 0) {
|
|
6220
6242
|
codeActivate(idx);
|
|
@@ -6737,6 +6759,7 @@ function bcIngest(ev) {
|
|
|
6737
6759
|
bcRenderTodos(ev.todos);
|
|
6738
6760
|
break;
|
|
6739
6761
|
case 'tool-start':
|
|
6762
|
+
bcSetBusy(true); /* kuyruktan tetiklenen işte panel kendini kilitler */
|
|
6740
6763
|
bcToolBoxStart(ev.callId, ev.name, ev.args);
|
|
6741
6764
|
/* ajan dosya yazarsa/editlerse açık IDE sekmesini izlemeye al */
|
|
6742
6765
|
if ((ev.name === 'write_file' || ev.name === 'edit_file') && ev.args && ev.args.path) codeWriteWatch.set(ev.callId, ev.args.path);
|
|
@@ -6793,7 +6816,9 @@ function bcIngest(ev) {
|
|
|
6793
6816
|
bcStatusHide();
|
|
6794
6817
|
bcRefreshPreview();
|
|
6795
6818
|
} else {
|
|
6796
|
-
/* düşünüyor… / araç adı / bağlam durumu — input üstünde canlı balon
|
|
6819
|
+
/* düşünüyor… / araç adı / bağlam durumu — input üstünde canlı balon;
|
|
6820
|
+
kuyruktan tetiklenen yeni işte kilit geri kapanır */
|
|
6821
|
+
bcSetBusy(true);
|
|
6797
6822
|
bcStatusShow(ev.status === 'thinking' ? 'düşünüyor…' : String(ev.status || ''));
|
|
6798
6823
|
}
|
|
6799
6824
|
break;
|
|
@@ -6827,10 +6852,17 @@ function bcRunCurrent() {
|
|
|
6827
6852
|
if (r && r.ok && r.mode) {
|
|
6828
6853
|
/* /plan · /build · /auto: mod değişimi — tur AÇILMAZ, kilit anında açılır
|
|
6829
6854
|
(bilgi satırı bc-mode olayıyla düşer, başlık rozeti güncellenir) */
|
|
6830
|
-
bcSessionId = r.sessionId;
|
|
6855
|
+
if (r.sessionId) bcSessionId = r.sessionId;
|
|
6831
6856
|
bcSetBusy(false);
|
|
6857
|
+
} else if (r && r.ok && r.queued) {
|
|
6858
|
+
/* ajan çalışıyor → mesaj kuyrukta; iş bitince toplu gönderilir */
|
|
6859
|
+
if (r.sessionId) bcSessionId = r.sessionId;
|
|
6860
|
+
bcLine('t-dim', '⏳ kuyrukta (' + r.count + ') — iş bitince gönderilir');
|
|
6861
|
+
} else if (r && r.ok && r.pending) {
|
|
6862
|
+
/* boşta: kısa birleşme penceresi — aynı penceredeki mesajlar tek işte gider */
|
|
6863
|
+
if (r.sessionId) bcSessionId = r.sessionId;
|
|
6832
6864
|
} else if (r && r.ok) {
|
|
6833
|
-
bcSessionId = r.sessionId;
|
|
6865
|
+
if (r.sessionId) bcSessionId = r.sessionId;
|
|
6834
6866
|
} else if (r && r.busy) {
|
|
6835
6867
|
/* iş gerçekten sürüyor — kilit açılmaz, bilgi satırı düşer */
|
|
6836
6868
|
bcLine('t-dim', (r && r.error) || 'mesaj sürüyor');
|
|
@@ -6851,7 +6883,15 @@ if (els.bcInput) {
|
|
|
6851
6883
|
if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); bcRunCurrent(); }
|
|
6852
6884
|
});
|
|
6853
6885
|
}
|
|
6854
|
-
if (els.bcStop) els.bcStop.addEventListener('click', () =>
|
|
6886
|
+
if (els.bcStop) els.bcStop.addEventListener('click', () => {
|
|
6887
|
+
beast.beastcodeStop().then((r) => {
|
|
6888
|
+
/* kuyrukta bekleyen mesajlar da silindi; engine boştaysa kilidi aç */
|
|
6889
|
+
if (r && r.ok && r.wasBusy === false) {
|
|
6890
|
+
bcSetBusy(false);
|
|
6891
|
+
bcStatusHide();
|
|
6892
|
+
}
|
|
6893
|
+
}).catch(() => {});
|
|
6894
|
+
});
|
|
6855
6895
|
if (els.bcClear) els.bcClear.addEventListener('click', () => {
|
|
6856
6896
|
els.bcOut.innerHTML = '';
|
|
6857
6897
|
bcTools.clear();
|
package/src/renderer/style.css
CHANGED
|
@@ -2492,6 +2492,26 @@ body.ide-mode #codePane { display: flex; }
|
|
|
2492
2492
|
background: var(--border);
|
|
2493
2493
|
opacity: 0.55;
|
|
2494
2494
|
}
|
|
2495
|
+
/* editör kapatılabilir: kod bölmesi + ayırıcı gizlenir, Beast Code tam genişlik */
|
|
2496
|
+
body.ide-mode.editor-hidden #codePane,
|
|
2497
|
+
body.ide-mode.editor-hidden #ideSplit { display: none; }
|
|
2498
|
+
body.ide-mode.editor-hidden #ideRow #bcPanel { flex: 1 1 auto; min-width: 0; }
|
|
2499
|
+
#codeHide {
|
|
2500
|
+
flex: none;
|
|
2501
|
+
width: 24px;
|
|
2502
|
+
height: 24px;
|
|
2503
|
+
padding: 0;
|
|
2504
|
+
border: 1px solid var(--border);
|
|
2505
|
+
border-radius: 6px;
|
|
2506
|
+
background: transparent;
|
|
2507
|
+
color: var(--muted);
|
|
2508
|
+
cursor: pointer;
|
|
2509
|
+
font-size: 11px;
|
|
2510
|
+
line-height: 1;
|
|
2511
|
+
}
|
|
2512
|
+
#codeHide:hover { color: var(--text); border-color: var(--accent); background: var(--panel2); }
|
|
2513
|
+
#bcHead #codeShow { width: 26px; padding: 0; }
|
|
2514
|
+
#codeShow[hidden] { display: none; }
|
|
2495
2515
|
#codeTabsBar {
|
|
2496
2516
|
flex: none;
|
|
2497
2517
|
display: flex;
|