beast-agent 2.44.13 → 2.44.14
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/main.js +39 -4
- package/src/renderer/renderer.js +59 -29
package/package.json
CHANGED
package/src/main.js
CHANGED
|
@@ -7985,6 +7985,36 @@ function termSend(ev) {
|
|
|
7985
7985
|
if (win && !win.isDestroyed()) win.webContents.send('agent:event', ev);
|
|
7986
7986
|
}
|
|
7987
7987
|
|
|
7988
|
+
/* TERMİNAL ÇIKTI COALESCE: alt süreçten gelen data chunk'ları 80ms'de bir TEK
|
|
7989
|
+
'term-batch' IPC'sinde birleştirilir. Aksi halde saniyede yüzlerce IPC +
|
|
7990
|
+
renderer'da satır satır DOM/layout = "Yanıt vermiyor" donması. */
|
|
7991
|
+
const TERM_BATCH_MS = 80;
|
|
7992
|
+
const TERM_BATCH_BYTES = 48 * 1024;
|
|
7993
|
+
const termBatches = new Map(); // id -> { timer, bytes, events: [{stream,text}] }
|
|
7994
|
+
|
|
7995
|
+
function termQueue(id, stream, text) {
|
|
7996
|
+
const key = String(id || termShellId || '');
|
|
7997
|
+
let b = termBatches.get(key);
|
|
7998
|
+
if (!b) {
|
|
7999
|
+
b = { timer: null, bytes: 0, events: [] };
|
|
8000
|
+
termBatches.set(key, b);
|
|
8001
|
+
}
|
|
8002
|
+
b.events.push({ stream, chunk: String(text) });
|
|
8003
|
+
b.bytes += String(text).length;
|
|
8004
|
+
if (b.bytes >= TERM_BATCH_BYTES) return termFlush(key); // tampon taştı — hemen boşalt
|
|
8005
|
+
if (!b.timer) b.timer = setTimeout(() => termFlush(key), TERM_BATCH_MS);
|
|
8006
|
+
}
|
|
8007
|
+
|
|
8008
|
+
function termFlush(id) {
|
|
8009
|
+
const key = String(id || '');
|
|
8010
|
+
const b = termBatches.get(key);
|
|
8011
|
+
if (!b) return;
|
|
8012
|
+
if (b.timer) { clearTimeout(b.timer); b.timer = null; }
|
|
8013
|
+
termBatches.delete(key);
|
|
8014
|
+
if (!b.events.length) return;
|
|
8015
|
+
termSend({ type: 'term-batch', id: key, events: b.events });
|
|
8016
|
+
}
|
|
8017
|
+
|
|
7988
8018
|
/* Kalıcı kabuğu başlat: cmd /q /k — girdi pipe'ından satır satır okur,
|
|
7989
8019
|
prompt yazmaz. chcp 65001 → Türkçe yollar (Masaüstü vb.) doğru çözülür. */
|
|
7990
8020
|
function termShellSpawn() {
|
|
@@ -8009,14 +8039,15 @@ function termShellSpawn() {
|
|
|
8009
8039
|
if (termForwarded > TERM_FWD_CAP) {
|
|
8010
8040
|
if (!termCapNotified) {
|
|
8011
8041
|
termCapNotified = true;
|
|
8042
|
+
termFlush(termShellId);
|
|
8012
8043
|
termSend({ type: 'term-out', id: termShellId, stream: 'out', chunk: '\n[beast] çıktı çok büyük — iletim durduruldu (komut sürüyor)\n' });
|
|
8013
8044
|
}
|
|
8014
8045
|
return;
|
|
8015
8046
|
}
|
|
8016
|
-
|
|
8047
|
+
termQueue(termShellId, 'out', String(d));
|
|
8017
8048
|
});
|
|
8018
8049
|
child.stderr.on('data', (d) => {
|
|
8019
|
-
|
|
8050
|
+
termQueue(termShellId, 'err', String(d));
|
|
8020
8051
|
});
|
|
8021
8052
|
child.on('exit', () => {
|
|
8022
8053
|
if (termChild === child) termChild = null;
|
|
@@ -8041,6 +8072,7 @@ ipcMain.handle('terminal:run', (_e, payload) => {
|
|
|
8041
8072
|
if (!termChild || !termChild.stdin.writable) termShellSpawn();
|
|
8042
8073
|
if (!termChild) return { ok: false, error: 'kabuk başlatılamadı' };
|
|
8043
8074
|
const id = 't' + Date.now().toString(36) + ++termShellSeq;
|
|
8075
|
+
termFlush(termShellId); // önceki komuttan kalan çıktı sırayı bozmasın
|
|
8044
8076
|
termShellId = id;
|
|
8045
8077
|
termForwarded = 0;
|
|
8046
8078
|
termCapNotified = false;
|
|
@@ -8073,12 +8105,14 @@ ipcMain.handle('terminal:run', (_e, payload) => {
|
|
|
8073
8105
|
}
|
|
8074
8106
|
child.stdout.setEncoding('utf8');
|
|
8075
8107
|
child.stderr.setEncoding('utf8');
|
|
8076
|
-
child.stdout.on('data', (d) =>
|
|
8077
|
-
child.stderr.on('data', (d) =>
|
|
8108
|
+
child.stdout.on('data', (d) => termQueue(id, 'out', String(d)));
|
|
8109
|
+
child.stderr.on('data', (d) => termQueue(id, 'err', String(d)));
|
|
8078
8110
|
child.on('error', (err) => {
|
|
8111
|
+
termFlush(id);
|
|
8079
8112
|
termSend({ type: 'term-end', id, code: -1, error: String((err && err.message) || err) });
|
|
8080
8113
|
});
|
|
8081
8114
|
child.on('close', (code) => {
|
|
8115
|
+
termFlush(id);
|
|
8082
8116
|
termSend({ type: 'term-end', id, code: code == null ? -1 : code });
|
|
8083
8117
|
});
|
|
8084
8118
|
return { ok: true, id };
|
|
@@ -8092,6 +8126,7 @@ ipcMain.handle('terminal:stop', () => {
|
|
|
8092
8126
|
try { termChild.kill(); } catch {}
|
|
8093
8127
|
termChild = null;
|
|
8094
8128
|
}
|
|
8129
|
+
termFlush(termShellId);
|
|
8095
8130
|
termSend({ type: 'term-end', id: termShellId, code: 130, error: 'komut durduruldu — kalıcı CMD yeniden hazır' });
|
|
8096
8131
|
termShellId = null;
|
|
8097
8132
|
return { ok: true };
|
package/src/renderer/renderer.js
CHANGED
|
@@ -6187,29 +6187,13 @@ function onEvent(ev) {
|
|
|
6187
6187
|
if (!busy) break;
|
|
6188
6188
|
setStatus(ev.status === 'idle' ? (busy ? 'düşünüyor…' : '') : ev.status === 'thinking' ? 'düşünüyor…' : ev.status + '…');
|
|
6189
6189
|
break;
|
|
6190
|
-
case 'term-out':
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
const parts = termPendBuf.split(/\r?\n/);
|
|
6197
|
-
termPendBuf = parts.pop(); /* son yarım satır bekler */
|
|
6198
|
-
for (const line of parts) {
|
|
6199
|
-
const m = /__BEAST_EOF__(.*)__BEAST_EOF__/.exec(line.trim());
|
|
6200
|
-
if (m) {
|
|
6201
|
-
const cwd2 = m[1].trim();
|
|
6202
|
-
if (cwd2) {
|
|
6203
|
-
els.termCwd.textContent = cwd2;
|
|
6204
|
-
els.termCwd.title = cwd2;
|
|
6205
|
-
}
|
|
6206
|
-
termCmdDone({ code: 0, silent: true });
|
|
6207
|
-
continue;
|
|
6208
|
-
}
|
|
6209
|
-
if (line.trim()) termLine('t-out', line, false);
|
|
6210
|
-
}
|
|
6190
|
+
case 'term-out':
|
|
6191
|
+
termHandleOut(ev);
|
|
6192
|
+
break;
|
|
6193
|
+
case 'term-batch':
|
|
6194
|
+
/* main 80ms'de bir birleştirilmiş çıktı paketi gönderir (IPC/satır yükü azalır) */
|
|
6195
|
+
for (const sub of (ev.events || [])) termHandleOut({ ...sub, id: ev.id });
|
|
6211
6196
|
break;
|
|
6212
|
-
}
|
|
6213
6197
|
case 'term-end':
|
|
6214
6198
|
termCmdDone(ev);
|
|
6215
6199
|
break;
|
|
@@ -6316,6 +6300,7 @@ function termSetHeight(h) {
|
|
|
6316
6300
|
function termSetOpen(v) {
|
|
6317
6301
|
termOpen = !!v;
|
|
6318
6302
|
els.termPanel.hidden = !v;
|
|
6303
|
+
if (v) termFlushLines(); // panel kapalıyken biriken satırlar şimdi basılır
|
|
6319
6304
|
els.termResize.hidden = !v || ideModeOn(); /* IDE'de terminal bölme içi — boyutlandırma yok */
|
|
6320
6305
|
document.body.classList.toggle('term-open', v);
|
|
6321
6306
|
termSetShell(termShell);
|
|
@@ -6344,16 +6329,38 @@ function termScroll(force) {
|
|
|
6344
6329
|
if (force || near) b.scrollTop = b.scrollHeight;
|
|
6345
6330
|
}
|
|
6346
6331
|
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
6332
|
+
/* satır KUYRUĞU: komut çıktısı hızlı akarken satır satır DOM + scroll/layout
|
|
6333
|
+
renderer'ı kilitliyordu ("Yanıt vermiyor"). Satırlar tampona girer, 100ms'de
|
|
6334
|
+
bir TEK fragment ile DOM'a basılır; panel kapalıysa DOM'a hiç dokunulmaz. */
|
|
6335
|
+
let termLineBuf = [];
|
|
6336
|
+
let termLineTimer = null;
|
|
6337
|
+
|
|
6338
|
+
function termFlushLines() {
|
|
6339
|
+
if (termLineTimer) { clearTimeout(termLineTimer); termLineTimer = null; }
|
|
6340
|
+
if (!termLineBuf.length || !els.termOut) return;
|
|
6341
|
+
const items = termLineBuf.splice(0);
|
|
6342
|
+
const frag = document.createDocumentFragment();
|
|
6343
|
+
for (const it of items) {
|
|
6344
|
+
const el = document.createElement('div');
|
|
6345
|
+
el.className = 't-line ' + (it.cls || '');
|
|
6346
|
+
const ts = it.time ? '<span class="t-time">' + new Date().toTimeString().slice(0, 8) + '</span> ' : '';
|
|
6347
|
+
el.innerHTML = ts + escapeHtml(String(it.text ?? ''));
|
|
6348
|
+
frag.appendChild(el);
|
|
6349
|
+
}
|
|
6350
|
+
els.termOut.appendChild(frag);
|
|
6353
6351
|
while (els.termOut.childElementCount > TERM_MAX_LINES) els.termOut.removeChild(els.termOut.firstChild);
|
|
6354
6352
|
termScroll();
|
|
6355
6353
|
}
|
|
6356
6354
|
|
|
6355
|
+
function termLine(cls, text, time = true) {
|
|
6356
|
+
termLineBuf.push({ cls, text, time });
|
|
6357
|
+
const cap = TERM_MAX_LINES * 2;
|
|
6358
|
+
if (termLineBuf.length > cap) termLineBuf.splice(0, termLineBuf.length - cap);
|
|
6359
|
+
if (!termOpen) return; /* panel kapalı — açılınca termFlushLines ile basılır */
|
|
6360
|
+
if (termLineBuf.length >= 300) termFlushLines();
|
|
6361
|
+
else if (!termLineTimer) termLineTimer = setTimeout(termFlushLines, 100);
|
|
6362
|
+
}
|
|
6363
|
+
|
|
6357
6364
|
function termBanner(cwd) {
|
|
6358
6365
|
if (termBannerDone) return;
|
|
6359
6366
|
termBannerDone = true;
|
|
@@ -6392,6 +6399,29 @@ function termAgentEvent(ev) {
|
|
|
6392
6399
|
}
|
|
6393
6400
|
}
|
|
6394
6401
|
|
|
6402
|
+
/* KALICI CMD çıktısı: her komutun sonunda marker satırı gelir —
|
|
6403
|
+
__BEAST_EOF__<yol>__BEAST_EOF__ → yazdırılmaz, cwd güncellenir, kilit açılır */
|
|
6404
|
+
function termHandleOut(ev) {
|
|
6405
|
+
const chunk = String(ev.chunk || '');
|
|
6406
|
+
if (ev.stream === 'err') { termLine('t-err', chunk, false); return; }
|
|
6407
|
+
termPendBuf += chunk;
|
|
6408
|
+
const parts = termPendBuf.split(/\r?\n/);
|
|
6409
|
+
termPendBuf = parts.pop(); /* son yarım satır bekler */
|
|
6410
|
+
for (const line of parts) {
|
|
6411
|
+
const m = /__BEAST_EOF__(.*)__BEAST_EOF__/.exec(line.trim());
|
|
6412
|
+
if (m) {
|
|
6413
|
+
const cwd2 = m[1].trim();
|
|
6414
|
+
if (cwd2) {
|
|
6415
|
+
els.termCwd.textContent = cwd2;
|
|
6416
|
+
els.termCwd.title = cwd2;
|
|
6417
|
+
}
|
|
6418
|
+
termCmdDone({ code: 0, silent: true });
|
|
6419
|
+
continue;
|
|
6420
|
+
}
|
|
6421
|
+
if (line.trim()) termLine('t-out', line, false);
|
|
6422
|
+
}
|
|
6423
|
+
}
|
|
6424
|
+
|
|
6395
6425
|
function termCmdDone(ev) {
|
|
6396
6426
|
termRunning = false;
|
|
6397
6427
|
els.termStop.hidden = true;
|
|
@@ -7712,7 +7742,7 @@ async function init() {
|
|
|
7712
7742
|
try { termSetHeight(parseInt(localStorage.getItem('beast.termH')) || 180); } catch {}
|
|
7713
7743
|
if (els.termCBtn) els.termCBtn.addEventListener('click', () => termToggle('cmd'));
|
|
7714
7744
|
if (els.termClose) els.termClose.addEventListener('click', () => termSetOpen(false));
|
|
7715
|
-
if (els.termClear) els.termClear.addEventListener('click', () => { els.termOut.innerHTML = ''; });
|
|
7745
|
+
if (els.termClear) els.termClear.addEventListener('click', () => { els.termOut.innerHTML = ''; termLineBuf = []; });
|
|
7716
7746
|
if (els.termStop) els.termStop.addEventListener('click', () => beast.terminalStop().catch(() => {}));
|
|
7717
7747
|
if (els.termInput) els.termInput.addEventListener('keydown', (e) => {
|
|
7718
7748
|
if (e.key === 'Enter') {
|