beast-agent 2.11.0 → 2.13.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 +34 -0
- package/src/agent/headroom.js +279 -0
- package/src/agent/llm.js +17 -1
- package/src/agent/tools.js +15 -0
- package/src/main.js +586 -7
- package/src/preload.js +18 -0
- package/src/renderer/i18n.js +6 -2
- package/src/renderer/index.html +62 -3
- package/src/renderer/renderer.js +734 -89
- package/src/renderer/style.css +322 -0
package/src/renderer/renderer.js
CHANGED
|
@@ -83,7 +83,34 @@ const els = {
|
|
|
83
83
|
bcAttach: $('#bcAttach'),
|
|
84
84
|
bcMic: $('#bcMic'),
|
|
85
85
|
bcChips: $('#bcChips'),
|
|
86
|
+
bcQrBtn: $('#bcQrBtn'),
|
|
87
|
+
bcQrCard: $('#bcQrCard'),
|
|
88
|
+
bcQrImg: $('#bcQrImg'),
|
|
89
|
+
bcQrUrl: $('#bcQrUrl'),
|
|
86
90
|
studioBtn: $('#studioBtn'),
|
|
91
|
+
sbBtn: $('#sbBtn'),
|
|
92
|
+
sandboxRow: $('#sandboxRow'),
|
|
93
|
+
sbRepo: $('#sbRepo'),
|
|
94
|
+
sbReveal: $('#sbReveal'),
|
|
95
|
+
sbRemove: $('#sbRemove'),
|
|
96
|
+
sbNew: $('#sbNew'),
|
|
97
|
+
sbCloneInput: $('#sbCloneInput'),
|
|
98
|
+
sbCloneBtn: $('#sbCloneBtn'),
|
|
99
|
+
sbGhBtn: $('#sbGhBtn'),
|
|
100
|
+
sbOut: $('#sbOut'),
|
|
101
|
+
sbStatus: $('#sbStatus'),
|
|
102
|
+
sbInput: $('#sbInput'),
|
|
103
|
+
sbStop: $('#sbStop'),
|
|
104
|
+
sbRunCwd: $('#sbRunCwd'),
|
|
105
|
+
sbRunInstall: $('#sbRunInstall'),
|
|
106
|
+
sbRunStart: $('#sbRunStart'),
|
|
107
|
+
sbRunDev: $('#sbRunDev'),
|
|
108
|
+
sbRunStop: $('#sbRunStop'),
|
|
109
|
+
sbRunCmd: $('#sbRunCmd'),
|
|
110
|
+
sbRunGo: $('#sbRunGo'),
|
|
111
|
+
sbRunOut: $('#sbRunOut'),
|
|
112
|
+
sbRunOpen: $('#sbRunOpen'),
|
|
113
|
+
sbRunUrl: $('#sbRunUrl'),
|
|
87
114
|
stPanel: $('#stPanel'),
|
|
88
115
|
stTitle: $('#stTitle'),
|
|
89
116
|
stCwd: $('#stCwd'),
|
|
@@ -1066,6 +1093,7 @@ function addFiles(files, mode) {
|
|
|
1066
1093
|
/* ---------------- settings ---------------- */
|
|
1067
1094
|
|
|
1068
1095
|
let setTab = 'lang'; /* ayarlar artık DİL sekmesiyle açılır */
|
|
1096
|
+
let hrPaneTimer = null; /* headroom-status → Kurulum sekmesi debounce tazeleme */
|
|
1069
1097
|
|
|
1070
1098
|
/* DİL sekmesi: arayüz dili seçimi (eski sağ-alt dil ikonunun yerine) */
|
|
1071
1099
|
function renderLangPane() {
|
|
@@ -1131,6 +1159,7 @@ async function renderActiveSettingsTab() {
|
|
|
1131
1159
|
case 'empati': await renderEmpatiPane(); break;
|
|
1132
1160
|
case 'cron': await openCron(); break;
|
|
1133
1161
|
case 'usage': await renderUsagePane(); break;
|
|
1162
|
+
case 'headroom': await renderHeadroomPane(); break;
|
|
1134
1163
|
case 'agents': await refreshAgentsPane(); break;
|
|
1135
1164
|
case 'logs': await renderLogPane(); break;
|
|
1136
1165
|
case 'dash': await renderDashboardPane(); break;
|
|
@@ -1214,7 +1243,7 @@ function switchTab(name) {
|
|
|
1214
1243
|
document.querySelectorAll('#setTabs .tab').forEach((b) =>
|
|
1215
1244
|
b.classList.toggle('active', b.dataset.tab === name)
|
|
1216
1245
|
);
|
|
1217
|
-
for (const p of ['lang', 'provider', 'fallout', 'skills', 'agents', 'tts', 'install', 'email', 'integrations', 'websearch', 'mcp', 'events', 'empati', 'cron', 'usage', 'logs', 'dash', 'sec', 'update']) {
|
|
1246
|
+
for (const p of ['lang', 'provider', 'fallout', 'skills', 'agents', 'tts', 'install', 'email', 'integrations', 'websearch', 'mcp', 'events', 'empati', 'cron', 'usage', 'headroom', 'logs', 'dash', 'sec', 'update']) {
|
|
1218
1247
|
const el = $('#tab-' + p);
|
|
1219
1248
|
if (el) el.hidden = p !== name; // guard: eksik pane tüm sekmeleri kilitlemesin
|
|
1220
1249
|
}
|
|
@@ -1222,6 +1251,7 @@ function switchTab(name) {
|
|
|
1222
1251
|
if (name === 'cron') openCron();
|
|
1223
1252
|
if (name === 'usage') renderUsagePane();
|
|
1224
1253
|
if (name === 'install') renderInstallPane();
|
|
1254
|
+
if (name === 'headroom') renderHeadroomPane();
|
|
1225
1255
|
if (name === 'events') renderEventsPane();
|
|
1226
1256
|
if (name === 'empati') renderEmpatiPane();
|
|
1227
1257
|
if (name === 'logs') renderLogPane();
|
|
@@ -1249,7 +1279,6 @@ async function renderUsagePane() {
|
|
|
1249
1279
|
} catch {
|
|
1250
1280
|
rep = { today: { total: {}, models: [] }, month: { total: {}, models: [] } };
|
|
1251
1281
|
}
|
|
1252
|
-
const wwi = await beast.whereWasIGet().catch(() => ({ enabled: false }));
|
|
1253
1282
|
const t = rep.today.total || {};
|
|
1254
1283
|
const mo = rep.month.total || {};
|
|
1255
1284
|
const card = (label, v) =>
|
|
@@ -1284,10 +1313,7 @@ async function renderUsagePane() {
|
|
|
1284
1313
|
'<div class="form-grid" style="grid-template-columns:auto auto;gap:8px;margin-top:8px">' +
|
|
1285
1314
|
'<button id="bkNow" class="btn ghost">' + _t('us_backup_now') + '</button>' +
|
|
1286
1315
|
'<button id="bkRestore" class="btn ghost">' + _t('us_backup_restore') + '</button>' +
|
|
1287
|
-
'</div>'
|
|
1288
|
-
'<div class="divider"></div><h2>' + _t('us_where_h2') + '</h2>' +
|
|
1289
|
-
'<div class="sub">' + _t('us_where_sub') + '</div>' +
|
|
1290
|
-
`<label class="lock-row" style="margin-top:6px"><input type="checkbox" id="wwiOn" ${wwi.enabled ? 'checked' : ''}/><span>${_t('us_where_on')}</span></label>`;
|
|
1316
|
+
'</div>';
|
|
1291
1317
|
$('#usReset').addEventListener('click', async () => {
|
|
1292
1318
|
await beast.resetUsage();
|
|
1293
1319
|
renderUsagePane();
|
|
@@ -1307,15 +1333,6 @@ async function renderUsagePane() {
|
|
|
1307
1333
|
toast(_t('us_backup_err') + (r.error || '?'));
|
|
1308
1334
|
}
|
|
1309
1335
|
});
|
|
1310
|
-
$('#wwiOn').addEventListener('change', async (e) => {
|
|
1311
|
-
await beast.whereWasISet({ enabled: e.target.checked });
|
|
1312
|
-
toast(e.target.checked ? _t('us_where_on_toast') : _t('us_where_off_toast'));
|
|
1313
|
-
});
|
|
1314
|
-
/* LİMİT ayarları aynı sekmenin alt bölümünde (Maliyet · Limit birleşik) */
|
|
1315
|
-
const limBox = document.createElement('div');
|
|
1316
|
-
limBox.id = 'limBox';
|
|
1317
|
-
pane.appendChild(limBox);
|
|
1318
|
-
await renderLimitsPane();
|
|
1319
1336
|
}
|
|
1320
1337
|
|
|
1321
1338
|
async function refreshFalloutPane() {
|
|
@@ -2192,6 +2209,93 @@ function ttsFlushTail() {
|
|
|
2192
2209
|
/* ---------------- KURULUM SEKMESİ: bileşenler OTOMATİK kurulur ----------------
|
|
2193
2210
|
Eksik/kısmen inmiş bileşen sekme açılınca kendiliğinden indirilir; kullanıcı
|
|
2194
2211
|
hiçbir düğmeye basmaz. Durum canlı güncellenir (4 sn'de bir). */
|
|
2212
|
+
/* ---------- TOKEN SIKIŞTIRMA (Headroom) sekmesi ----------
|
|
2213
|
+
Opsiyonel yerel sıkıştırma proxy'si: açıkken LLM girdisi %30-70 küçülür.
|
|
2214
|
+
Aç/Kapat buradan; CLI kurulumu Kurulum sekmesinde görülür. */
|
|
2215
|
+
let hrStatsTimer = null;
|
|
2216
|
+
|
|
2217
|
+
async function renderHeadroomPane() {
|
|
2218
|
+
const pane = $('#tab-headroom');
|
|
2219
|
+
if (!pane) return;
|
|
2220
|
+
const st = await beast.headroomStatus().catch(() => null);
|
|
2221
|
+
|
|
2222
|
+
const fmtN = (n) => new Intl.NumberFormat('tr-TR').format(Math.round(Number(n) || 0));
|
|
2223
|
+
let stHtml = '';
|
|
2224
|
+
if (st) {
|
|
2225
|
+
const readyN = (st.proxies || []).filter((p) => p.ready).length;
|
|
2226
|
+
let stateTxt;
|
|
2227
|
+
if (st.installing) stateTxt = '⏳ arka planda kuruluyor — uv tool install headroom-ai[proxy] (birkaç dakika)';
|
|
2228
|
+
else if (st.enabled && readyN) stateTxt = '🟢 açık — proxy: ' + (st.proxies || []).filter((p) => p.ready).map((p) => '127.0.0.1:' + p.port).join(', ');
|
|
2229
|
+
else if (st.enabled) stateTxt = '⏳ proxy başlatılıyor… (ilk açılış ~30 sn)';
|
|
2230
|
+
else if (st.failed) stateTxt = '⛔ ' + (st.error || 'kurulum başarısız');
|
|
2231
|
+
else if (st.installed) stateTxt = '⚪ kapalı — kurulu, aşağıdaki düğmeyle etkinleştir';
|
|
2232
|
+
else stateTxt = '⚪ kapalı — açınca uv ile otomatik kurulur (birkaç dakika)';
|
|
2233
|
+
stHtml = '<div class="sub" style="margin-top:10px;font-size:12px;text-align:center">' + escapeHtml(stateTxt) + '</div>';
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
const stats = await beast.headroomStats().catch(() => null);
|
|
2237
|
+
let statsHtml = '';
|
|
2238
|
+
if (stats && stats.ok && (stats.input || stats.saved)) {
|
|
2239
|
+
statsHtml =
|
|
2240
|
+
'<div class="divider"></div>' +
|
|
2241
|
+
'<h2 style="text-align:center">Tasarruf (proxy açıkken)</h2>' +
|
|
2242
|
+
'<div style="display:flex;gap:24px;flex-wrap:wrap;margin-top:8px;justify-content:center">' +
|
|
2243
|
+
'<div><div style="font-size:20px;font-weight:800;color:var(--ok)">%' + Math.round(stats.savingsPercent || 0) + '</div><div class="sub">sıkıştırma oranı</div></div>' +
|
|
2244
|
+
'<div><div style="font-size:20px;font-weight:800">' + new Intl.NumberFormat('tr-TR').format(stats.proxyCompressionSaved || 0) + '</div><div class="sub">kaydedilen token</div></div>' +
|
|
2245
|
+
'<div><div style="font-size:20px;font-weight:800">' + new Intl.NumberFormat('tr-TR').format(stats.input || 0) + '</div><div class="sub">toplam girdi token</div></div>' +
|
|
2246
|
+
'</div>';
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
/* AÇ/KAPAT düğmesi: ortalanmış + SVG ikonlu (play/pause — uygulama ikon stili) */
|
|
2250
|
+
const svgPlay =
|
|
2251
|
+
'<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polygon points="6 3 20 12 6 21 6 3"/></svg>';
|
|
2252
|
+
const svgPause =
|
|
2253
|
+
'<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="6" y="4" width="4" height="16" rx="1"/><rect x="14" y="4" width="4" height="16" rx="1"/></svg>';
|
|
2254
|
+
pane.innerHTML =
|
|
2255
|
+
'<h2 style="text-align:center">' + _t('tab_headroom') + '</h2>' +
|
|
2256
|
+
'<div class="sub" style="text-align:center;max-width:620px;margin:0 auto">Headroom yerel proxy\u2019si — araç çıktıları, loglar ve JSON yükleri modele gitmeden sıkıştırılır; orijinali yerelde saklanır. Token faturasını %30-70 düşürür. Yalnız OpenAI-uyumlu sağlayıcı trafiğini etkiler; kapalıyken hiçbir şey değişmez.</div>' +
|
|
2257
|
+
'<div style="display:flex;flex-direction:column;align-items:center;gap:10px;margin-top:18px">' +
|
|
2258
|
+
'<button id="hrToggle" class="btn" style="width:auto;padding:11px 16px;display:inline-flex;align-items:center;gap:8px;justify-content:center" title=""></button>' +
|
|
2259
|
+
'<span id="hrToggleMsg" class="sub" style="margin:0;text-align:center;max-width:560px"></span>' +
|
|
2260
|
+
'</div>' +
|
|
2261
|
+
stHtml + statsHtml;
|
|
2262
|
+
|
|
2263
|
+
const btn = $('#hrToggle');
|
|
2264
|
+
if (btn) {
|
|
2265
|
+
const on = !!(st && st.enabled);
|
|
2266
|
+
/* yalnız SVG ikon — anlamı durum satırı + tooltip taşır */
|
|
2267
|
+
btn.innerHTML = on ? svgPause : svgPlay;
|
|
2268
|
+
btn.title = on ? 'Token sıkıştırmayı kapat' : 'Token sıkıştırmayı aç';
|
|
2269
|
+
btn.setAttribute('aria-label', btn.title);
|
|
2270
|
+
btn.addEventListener('click', async () => {
|
|
2271
|
+
const msg = $('#hrToggleMsg');
|
|
2272
|
+
btn.disabled = true;
|
|
2273
|
+
btn.innerHTML = '<span>…</span>';
|
|
2274
|
+
const r = await beast.headroomToggle(!on).catch(() => null);
|
|
2275
|
+
if (msg) {
|
|
2276
|
+
if (r && r.installing) {
|
|
2277
|
+
msg.textContent = 'Headroom arka planda kuruluyor — birkaç dakika sonra hazır olur, bu sekme açık kalabilir.';
|
|
2278
|
+
} else if (r && r.error) {
|
|
2279
|
+
msg.textContent = r.error;
|
|
2280
|
+
} else {
|
|
2281
|
+
msg.textContent = !on ? 'Açıldı — proxy hazır olunca trafiği yönlendirir' : 'Kapatıldı — trafik sağlayıcıya düz gidiyor';
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
setTimeout(() => renderHeadroomPane(), 2500);
|
|
2285
|
+
});
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
/* açıkken istatistikler canlı aksın */
|
|
2289
|
+
if (hrStatsTimer) clearInterval(hrStatsTimer);
|
|
2290
|
+
hrStatsTimer = setInterval(async () => {
|
|
2291
|
+
if (pane.hidden) { clearInterval(hrStatsTimer); return; }
|
|
2292
|
+
const s2 = await beast.headroomStatus().catch(() => null);
|
|
2293
|
+
const cur = $('#hrToggle');
|
|
2294
|
+
if (s2 && cur && cur.disabled) return; /* toggle işlemi sürüyor */
|
|
2295
|
+
await renderHeadroomPane();
|
|
2296
|
+
}, 6000);
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2195
2299
|
async function renderInstallPane() {
|
|
2196
2300
|
const pane = $('#tab-install');
|
|
2197
2301
|
if (!pane) return;
|
|
@@ -2259,10 +2363,24 @@ async function renderInstallPane() {
|
|
|
2259
2363
|
'<div class="sub" style="font-size:11px">' + escapeHtml(r.detail || '') + (r.mb ? ' · ' + r.mb + ' MB' : '') + '</div>' +
|
|
2260
2364
|
bar(r) +
|
|
2261
2365
|
'</div>' +
|
|
2366
|
+
(r.canToggle
|
|
2367
|
+
? '<button class="btn hr-tgl" data-on="' + (r.toggleOn ? '1' : '0') + '" style="width:auto;padding:2px 12px;flex:none">' + (r.toggleOn ? 'KAPAT' : 'AÇ') + '</button>'
|
|
2368
|
+
: '') +
|
|
2262
2369
|
badge(r.state) +
|
|
2263
2370
|
pctLabel(r) +
|
|
2264
2371
|
'</div>'
|
|
2265
2372
|
)).join('');
|
|
2373
|
+
/* Headroom aç/kapa: toggle kurulum + proxy başlatmayı arka planda tetikler */
|
|
2374
|
+
el.querySelectorAll('.hr-tgl').forEach((b) => {
|
|
2375
|
+
b.addEventListener('click', async () => {
|
|
2376
|
+
const on = b.dataset.on !== '1';
|
|
2377
|
+
b.disabled = true;
|
|
2378
|
+
b.textContent = '…';
|
|
2379
|
+
const r = await beast.headroomToggle(on).catch(() => null);
|
|
2380
|
+
toast(r && r.error ? r.error : (r && r.installing ? 'Headroom kuruluyor — birkaç dakika sürer' : (on ? 'Headroom açıldı' : 'Headroom kapatıldı')));
|
|
2381
|
+
refresh();
|
|
2382
|
+
});
|
|
2383
|
+
});
|
|
2266
2384
|
};
|
|
2267
2385
|
|
|
2268
2386
|
const refresh = async () => {
|
|
@@ -2829,67 +2947,6 @@ async function renderDashboardPane() {
|
|
|
2829
2947
|
pane.appendChild(list);
|
|
2830
2948
|
}
|
|
2831
2949
|
|
|
2832
|
-
/* ---------------- Limit: provider bazlı girdi limiti ---------------- */
|
|
2833
|
-
|
|
2834
|
-
async function renderLimitsPane() {
|
|
2835
|
-
/* Maliyet sekmesine GÖMÜLÜ çalışır (ayrı sekme kaldırıldı) */
|
|
2836
|
-
const pane = $('#tab-limits') || $('#limBox');
|
|
2837
|
-
if (!pane) return;
|
|
2838
|
-
const cur = await beast.getLimits().catch(() => ({ enabled: false, compress: true, default: 0, perProvider: {} }));
|
|
2839
|
-
const provs = [...new Set((state.models || []).map((m) => m.providerName))].sort((a, b) => a.localeCompare(b));
|
|
2840
|
-
|
|
2841
|
-
const provRows = provs.length
|
|
2842
|
-
? provs
|
|
2843
|
-
.map((p) => {
|
|
2844
|
-
const v = cur.perProvider[p] || 0;
|
|
2845
|
-
return `<div class="usage-row" style="align-items:center">
|
|
2846
|
-
<span style="flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${escapeHtml(p)}</span>
|
|
2847
|
-
<input class="inp lim-prov" data-prov="${escapeHtml(p)}" type="number" min="0" step="1000"
|
|
2848
|
-
value="${v || ''}" placeholder="0 (${_t('lim_unlimited')})" style="width:130px;flex:none;margin:0" />
|
|
2849
|
-
</div>`;
|
|
2850
|
-
})
|
|
2851
|
-
.join('')
|
|
2852
|
-
: '<p class="sub">' + _t('p_no_model') + '</p>';
|
|
2853
|
-
|
|
2854
|
-
pane.innerHTML =
|
|
2855
|
-
'<h2>' + _t('lim_h2') + '</h2>' +
|
|
2856
|
-
'<div class="sub">' + _t('lim_sub') + '</div>' +
|
|
2857
|
-
`<div class="fo-toggles" style="margin-top:10px">
|
|
2858
|
-
<label class="lock-row"><input type="checkbox" id="limOn" ${cur.enabled ? 'checked' : ''}/><span>${_t('lim_enabled')}</span></label>
|
|
2859
|
-
</div>
|
|
2860
|
-
<div id="limDetail" style="${cur.enabled ? '' : 'opacity:.45'}">
|
|
2861
|
-
<label class="lock-row"><input type="checkbox" id="limCompress" ${cur.compress ? 'checked' : ''}/><span>${_t('lim_compress')}</span></label>
|
|
2862
|
-
<div class="form-grid" style="grid-template-columns:1fr auto;align-items:center;margin-top:8px">
|
|
2863
|
-
<label class="mem-label" style="margin:0">${_t('lim_default')}</label>
|
|
2864
|
-
<input id="limDefault" class="inp" type="number" min="0" step="1000" value="${cur.default || ''}" placeholder="0" style="width:130px;flex:none;margin:0" />
|
|
2865
|
-
</div>
|
|
2866
|
-
<h2 style="margin-top:16px">${_t('lim_prov_h2')}</h2>
|
|
2867
|
-
<div class="sub">${_t('lim_prov_sub')}</div>
|
|
2868
|
-
<div style="margin-top:6px">${provRows}</div>
|
|
2869
|
-
<button id="limSave" class="btn ghost" style="margin-top:12px">${_t('lim_save')}</button>
|
|
2870
|
-
</div>`;
|
|
2871
|
-
|
|
2872
|
-
const det = pane.querySelector('#limDetail');
|
|
2873
|
-
pane.querySelector('#limOn').addEventListener('change', (e) => {
|
|
2874
|
-
det.style.opacity = e.target.checked ? '' : '.45';
|
|
2875
|
-
});
|
|
2876
|
-
|
|
2877
|
-
pane.querySelector('#limSave').addEventListener('click', async () => {
|
|
2878
|
-
const perProvider = {};
|
|
2879
|
-
for (const inp of pane.querySelectorAll('.lim-prov')) {
|
|
2880
|
-
const n = Math.round(Number(inp.value) || 0);
|
|
2881
|
-
if (n > 0) perProvider[inp.dataset.prov] = n;
|
|
2882
|
-
}
|
|
2883
|
-
await beast.setLimits({
|
|
2884
|
-
enabled: pane.querySelector('#limOn').checked,
|
|
2885
|
-
compress: pane.querySelector('#limCompress').checked,
|
|
2886
|
-
default: Math.round(Number(pane.querySelector('#limDefault').value) || 0),
|
|
2887
|
-
perProvider,
|
|
2888
|
-
});
|
|
2889
|
-
toast(_t('lim_saved_toast'));
|
|
2890
|
-
});
|
|
2891
|
-
}
|
|
2892
|
-
|
|
2893
2950
|
/* ---------------- Güvenlik: ajan onay davranışı ---------------- */
|
|
2894
2951
|
|
|
2895
2952
|
async function renderSecurityPane() {
|
|
@@ -4959,6 +5016,19 @@ function onEvent(ev) {
|
|
|
4959
5016
|
return;
|
|
4960
5017
|
}
|
|
4961
5018
|
if (ev.type === 'install-progress') { updateInstallPct(ev); return; }
|
|
5019
|
+
/* Headroom durum değişimi → açık olan sekmeyi tazele (Token Sıkıştırma / Kurulum) */
|
|
5020
|
+
if (ev.type === 'headroom-status') {
|
|
5021
|
+
try {
|
|
5022
|
+
const iPane = document.getElementById('tab-install');
|
|
5023
|
+
const hPane = document.getElementById('tab-headroom');
|
|
5024
|
+
const open = (!iPane || iPane.hidden) && (!hPane || hPane.hidden) ? '' : (!hPane || hPane.hidden ? 'install' : 'headroom');
|
|
5025
|
+
if (open) {
|
|
5026
|
+
clearTimeout(hrPaneTimer);
|
|
5027
|
+
hrPaneTimer = setTimeout(() => { (open === 'headroom' ? renderHeadroomPane() : renderInstallPane()).catch(() => {}); }, 1500);
|
|
5028
|
+
}
|
|
5029
|
+
} catch {}
|
|
5030
|
+
return;
|
|
5031
|
+
}
|
|
4962
5032
|
/* EMPATİ LOOP: proaktif bildirim (masaüstü) + sekme canlı yenileme.
|
|
4963
5033
|
Toast'ta yalnız haber başlığı — link/markdown kalabalığı chat mesajında. */
|
|
4964
5034
|
if (ev.type === 'proactive') {
|
|
@@ -4984,6 +5054,19 @@ function onEvent(ev) {
|
|
|
4984
5054
|
}
|
|
4985
5055
|
/* OFFLINE MESAJ KUYRUĞU: bağlantı + kuyruk olayları (sessionId filtresinden önce) */
|
|
4986
5056
|
if (ev.type === 'net' || ev.type === 'netQueue') { onNetEvent(ev); return; }
|
|
5057
|
+
/* Sandbox klonlama progress'i (sessionId'siz global olay) */
|
|
5058
|
+
if (ev.type === 'sb-clone') { sbCloneProgress(ev.pct, ev.text, !!ev.done); return; }
|
|
5059
|
+
/* Sandbox ÇALIŞTIRICI süreç akışı: sessionId'siz global olaylar */
|
|
5060
|
+
if (ev.type === 'sb-run' || ev.type === 'sb-run-url' || ev.type === 'sb-run-end') {
|
|
5061
|
+
sbRunIngest(ev);
|
|
5062
|
+
return;
|
|
5063
|
+
}
|
|
5064
|
+
/* Beast Sandbox oturumu: olaylar SADECE Sandbox paneline akar — ana sohbeti
|
|
5065
|
+
ve Code/Studio panellerini kirletmez (dünyalar ayrı) */
|
|
5066
|
+
if (sbSessionId && ev.sessionId === sbSessionId) {
|
|
5067
|
+
sbIngest(ev);
|
|
5068
|
+
return;
|
|
5069
|
+
}
|
|
4987
5070
|
/* Beast Studio oturumu: olaylar SADECE Studio paneline akar — ana sohbeti
|
|
4988
5071
|
ve Beast Code panelini kirletmez (dünyalar ayrı) */
|
|
4989
5072
|
if (stSessionId && ev.sessionId === stSessionId) {
|
|
@@ -6896,6 +6979,7 @@ function ghCard(repo, isFav) {
|
|
|
6896
6979
|
<div class="gh-actions">
|
|
6897
6980
|
<button class="gh-fav ${isFav ? 'on' : ''}" data-act="fav">${isFav ? '★ Favori' : '☆ Favorile'}</button>
|
|
6898
6981
|
<button data-act="chat"><svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-1px;margin-right:4px"><path d="M22 2 11 13"/><path d="M22 2 15 22l-4-9-9-4z"/></svg>Chate at</button>
|
|
6982
|
+
<button data-act="dl" title="Sandbox'a indir (git clone)">⬇ İndir</button>
|
|
6899
6983
|
<button data-act="copy">⧉ Kopyala</button>
|
|
6900
6984
|
</div>
|
|
6901
6985
|
</div>`;
|
|
@@ -6911,6 +6995,12 @@ function wireGhCards(container, list, isFavPane) {
|
|
|
6911
6995
|
/* mesaj chate gitti — cevap chatten geleceği için modal kapanır */
|
|
6912
6996
|
closeGit();
|
|
6913
6997
|
});
|
|
6998
|
+
/* Sandbox'a indir: klonlama Sandbox panelinde görünür, panel açılır */
|
|
6999
|
+
card.querySelector('[data-act="dl"]').addEventListener('click', async () => {
|
|
7000
|
+
closeGit();
|
|
7001
|
+
setSandboxMode(true);
|
|
7002
|
+
sbClone(repo.full_name);
|
|
7003
|
+
});
|
|
6914
7004
|
card.querySelector('[data-act="copy"]').addEventListener('click', async () => {
|
|
6915
7005
|
try { await navigator.clipboard.writeText(repo.html_url); toast('Link kopyalandı'); } catch {}
|
|
6916
7006
|
});
|
|
@@ -7068,6 +7158,7 @@ function ideModeOn() {
|
|
|
7068
7158
|
|
|
7069
7159
|
async function setIdeMode(on) {
|
|
7070
7160
|
if (on && studioModeOn()) await setStudioMode(false); /* Studio açıkken IDE'ye geçiş — Studio kapanır */
|
|
7161
|
+
if (on && sbModeOn()) setSandboxMode(false); /* Sandbox açıkken IDE'ye geçiş — Sandbox kapanır */
|
|
7071
7162
|
document.body.classList.toggle('ide-mode', !!on);
|
|
7072
7163
|
if (els.ideBtn) els.ideBtn.classList.toggle('on', !!on);
|
|
7073
7164
|
/* soldaki marka: chat modunda BEAST Agent, IDE modunda BEAST Code, Studio modunda BEAST Studio */
|
|
@@ -7095,6 +7186,10 @@ async function setIdeMode(on) {
|
|
|
7095
7186
|
bcBanner();
|
|
7096
7187
|
renderBcHistory(); /* soldaki geçmiş listesi: IDE'ye girişte tazelenir */
|
|
7097
7188
|
codeGutterRender(); /* dosya açık olmasa bile rakamlar görünür */
|
|
7189
|
+
/* Expo QR daha önce üretildiyse kart geri gelsin */
|
|
7190
|
+
beast.ideExpQr().then((r) => {
|
|
7191
|
+
if (r && r.ok && r.qr) bcQrShow(r.qr, r.url);
|
|
7192
|
+
}).catch(() => {});
|
|
7098
7193
|
} else {
|
|
7099
7194
|
/* terminal bölmeye alınmadan önce kapatılır, sonra ALT DOCK'a geri taşınır */
|
|
7100
7195
|
if (termOpen) termSetOpen(false);
|
|
@@ -7137,6 +7232,7 @@ function studioModeOn() {
|
|
|
7137
7232
|
|
|
7138
7233
|
async function setStudioMode(on) {
|
|
7139
7234
|
if (on && ideModeOn()) await setIdeMode(false); /* IDE açıkken Studio'ya geçiş — IDE kapanır */
|
|
7235
|
+
if (on && sbModeOn()) setSandboxMode(false); /* Sandbox açıkken Studio'ya geçiş — Sandbox kapanır */
|
|
7140
7236
|
document.body.classList.toggle('studio-mode', !!on);
|
|
7141
7237
|
if (els.studioBtn) els.studioBtn.classList.toggle('on', !!on);
|
|
7142
7238
|
/* ALT TERMINAL: yalnız Beast Code'a özgü — Studio'ya geçişte kapanır */
|
|
@@ -7359,7 +7455,8 @@ if (els.ideSplit) {
|
|
|
7359
7455
|
}
|
|
7360
7456
|
|
|
7361
7457
|
async function loadIdeTree() {
|
|
7362
|
-
|
|
7458
|
+
/* hangi moddaysak o ağacın önbelleği tazelenir (Sandbox → repo ağacı) */
|
|
7459
|
+
(sbModeOn() ? sbTreeState : studioModeOn() ? studioState : ideState).cache.clear();
|
|
7363
7460
|
await renderFileTree();
|
|
7364
7461
|
}
|
|
7365
7462
|
|
|
@@ -7375,17 +7472,26 @@ async function renderFileTree() {
|
|
|
7375
7472
|
if (!tree) return;
|
|
7376
7473
|
tree.innerHTML = '';
|
|
7377
7474
|
const wsLabel = $('#filePanelPath');
|
|
7378
|
-
/* Studio modunda ağaç studioRoot'tan,
|
|
7379
|
-
|
|
7475
|
+
/* Studio modunda ağaç studioRoot'tan, Sandbox modunda seçili reponun
|
|
7476
|
+
klasöründen, IDE modunda ideRoot'tan okunur — aynı panel, aynı çizim */
|
|
7477
|
+
const sbx = sbModeOn();
|
|
7380
7478
|
const studio = studioModeOn();
|
|
7381
|
-
const st = studio ? studioState : ideState;
|
|
7382
|
-
const treeApi =
|
|
7479
|
+
const st = sbx ? sbTreeState : studio ? studioState : ideState;
|
|
7480
|
+
const treeApi = sbx
|
|
7481
|
+
? (rel) => beast.sandboxTree({ folder: sbFolder, rel })
|
|
7482
|
+
: studio
|
|
7483
|
+
? beast.studioTree
|
|
7484
|
+
: beast.ideTree;
|
|
7383
7485
|
const build = async (rel, depth, container) => {
|
|
7384
7486
|
let entries = st.cache.get(rel);
|
|
7385
7487
|
if (!entries) {
|
|
7386
7488
|
const r = await treeApi(rel).catch(() => null);
|
|
7387
7489
|
if (!r || !r.ok) {
|
|
7388
|
-
if (!rel)
|
|
7490
|
+
if (!rel) {
|
|
7491
|
+
container.innerHTML = sbx
|
|
7492
|
+
? '<div class="file-empty">Repo seçili değil — yukarıdan indir ya da seç</div>'
|
|
7493
|
+
: `<div class="file-empty">${escapeHtml((r && r.error) || 'okunamadı')}</div>`;
|
|
7494
|
+
}
|
|
7389
7495
|
return;
|
|
7390
7496
|
}
|
|
7391
7497
|
entries = r.entries;
|
|
@@ -7393,7 +7499,9 @@ async function renderFileTree() {
|
|
|
7393
7499
|
if (r.workspace) {
|
|
7394
7500
|
st.path = r.workspace;
|
|
7395
7501
|
if (wsLabel) { wsLabel.textContent = r.workspace; wsLabel.title = r.workspace; }
|
|
7396
|
-
if (
|
|
7502
|
+
if (sbx) {
|
|
7503
|
+
if (els.sbRunCwd) { els.sbRunCwd.textContent = r.workspace; els.sbRunCwd.title = r.workspace; }
|
|
7504
|
+
} else if (studio) {
|
|
7397
7505
|
if (els.stCwd) { els.stCwd.textContent = r.workspace; els.stCwd.title = r.workspace; }
|
|
7398
7506
|
stOnFolderChanged(r.workspace);
|
|
7399
7507
|
} else {
|
|
@@ -7418,6 +7526,13 @@ async function renderFileTree() {
|
|
|
7418
7526
|
if (st.open.has(child)) st.open.delete(child);
|
|
7419
7527
|
else st.open.add(child);
|
|
7420
7528
|
renderFileTree();
|
|
7529
|
+
} else if (sbx) {
|
|
7530
|
+
/* Sandbox: dosyayı chat'e bağlam olarak bırak — ajan incelesin */
|
|
7531
|
+
if (els.sbInput) {
|
|
7532
|
+
els.sbInput.value = 'Şu dosyayı incele: ' + child;
|
|
7533
|
+
els.sbInput.focus();
|
|
7534
|
+
sbInputResize();
|
|
7535
|
+
}
|
|
7421
7536
|
} else if (studio && MEDIA_FILE_RE.test(e.name)) {
|
|
7422
7537
|
stVideoPlay(child); /* video/ses → sağdaki video bölümünde oynat */
|
|
7423
7538
|
} else if (studio) {
|
|
@@ -7449,7 +7564,8 @@ function ideRefreshTree() {
|
|
|
7449
7564
|
ideTreeTimer = null;
|
|
7450
7565
|
try {
|
|
7451
7566
|
/* hangi moddaysak o ağacın önbelleği tazelenir */
|
|
7452
|
-
if (
|
|
7567
|
+
if (sbModeOn()) sbTreeState.cache.clear();
|
|
7568
|
+
else if (studioModeOn()) studioState.cache.clear();
|
|
7453
7569
|
else ideState.cache.clear();
|
|
7454
7570
|
renderFileTree().catch(() => {});
|
|
7455
7571
|
} catch {}
|
|
@@ -7943,11 +8059,32 @@ async function undoTask(id) {
|
|
|
7943
8059
|
if (els.fileTasks) els.fileTasks.addEventListener('click', () => toggleTasksPanel());
|
|
7944
8060
|
|
|
7945
8061
|
$('#filePreview').addEventListener('click', async () => {
|
|
7946
|
-
|
|
7947
|
-
|
|
7948
|
-
|
|
7949
|
-
|
|
8062
|
+
if (!ideModeOn()) await setIdeMode(true);
|
|
8063
|
+
/* proje tipi algıla: statik site ajan gerektirmez, dev-server projelerinde
|
|
8064
|
+
HER PROJE FARKLI KOMUTLA çalışır — komutu ajan package.json'a bakıp seçer */
|
|
8065
|
+
const info = await beast.ideProjInfo().catch(() => null);
|
|
8066
|
+
const kind = (info && info.kind) || 'unknown';
|
|
8067
|
+
if (kind === 'static') {
|
|
8068
|
+
const r = await beast.idePreview().catch(() => null);
|
|
8069
|
+
if (r && r.ok) return;
|
|
7950
8070
|
toast((r && r.error) || 'preview açılamadı');
|
|
8071
|
+
return;
|
|
8072
|
+
}
|
|
8073
|
+
const ask =
|
|
8074
|
+
kind === 'expo'
|
|
8075
|
+
? 'Preview aç — bu klasör bir Expo/React Native projesi (app.json var). Web önizlemeyi arka planda başlat: package.json scripts.web varsa `npm run web`, yoksa `npx expo start --web`. Sunucu kalkınca çalışan http://localhost:PORT adresini raporda yaz.'
|
|
8076
|
+
: kind === 'react-native'
|
|
8077
|
+
? 'Preview aç — bu klasör bir React Native projesi. Metro sunucusunu arka planda başlat: package.json scripts.start varsa `npm start`, yoksa `npx react-native start`. Sunucu kalkınca çalışan http://localhost:PORT adresini raporda yaz.'
|
|
8078
|
+
: kind === 'web'
|
|
8079
|
+
? 'Preview aç — bu proje dev-server ister. Doğru komutu package.json scripts\'ından seç (dev/start/serve — `npm run dev` vb.) ve arka planda başlat. Sunucu kalkınca çalışan http://localhost:PORT adresini raporda yaz.'
|
|
8080
|
+
: 'Preview aç — bu projenin nasıl çalıştığını package.json / konfigürasyon dosyalarından anla, doğru dev komutunu arka planda başlat ve çalışan http://localhost:PORT adresini raporda yaz.';
|
|
8081
|
+
if (els.bcInput) {
|
|
8082
|
+
els.bcInput.value = ask;
|
|
8083
|
+
bcInputResize();
|
|
8084
|
+
bcRunCurrent();
|
|
8085
|
+
toast('Ajan preview görevini aldı');
|
|
8086
|
+
} else {
|
|
8087
|
+
toast('Beast Code paneli yok');
|
|
7951
8088
|
}
|
|
7952
8089
|
});
|
|
7953
8090
|
if (els.codeSave) els.codeSave.addEventListener('click', codeSave);
|
|
@@ -8028,8 +8165,9 @@ function fileCtxShow(e, rel, isDir) {
|
|
|
8028
8165
|
const menu = els.fileCtxMenu;
|
|
8029
8166
|
if (!menu || !rel) return;
|
|
8030
8167
|
e.preventDefault();
|
|
8168
|
+
const sbx = sbModeOn();
|
|
8031
8169
|
const studio = studioModeOn();
|
|
8032
|
-
const st = studio ? studioState : ideState;
|
|
8170
|
+
const st = sbx ? sbTreeState : studio ? studioState : ideState;
|
|
8033
8171
|
const isMedia = MEDIA_FILE_RE.test(rel.split('/').pop() || '');
|
|
8034
8172
|
const items = [];
|
|
8035
8173
|
if (isDir) {
|
|
@@ -8041,6 +8179,22 @@ function fileCtxShow(e, rel, isDir) {
|
|
|
8041
8179
|
renderFileTree();
|
|
8042
8180
|
},
|
|
8043
8181
|
});
|
|
8182
|
+
} else if (sbx) {
|
|
8183
|
+
/* Sandbox: dosya düzenleme Code moduna aittir — chate bağlam bırak/aç */
|
|
8184
|
+
items.push({
|
|
8185
|
+
label: 'Chate ekle (şu dosyaya bak)',
|
|
8186
|
+
fn: () => {
|
|
8187
|
+
if (els.sbInput) {
|
|
8188
|
+
els.sbInput.value = 'Şu dosyayı incele: ' + rel;
|
|
8189
|
+
els.sbInput.focus();
|
|
8190
|
+
sbInputResize();
|
|
8191
|
+
}
|
|
8192
|
+
},
|
|
8193
|
+
});
|
|
8194
|
+
items.push({
|
|
8195
|
+
label: 'Dış uygulamada aç',
|
|
8196
|
+
fn: () => beast.openPath((sbTreeState.path || '') + '\\' + rel.replace(/\//g, '\\')).catch(() => {}),
|
|
8197
|
+
});
|
|
8044
8198
|
} else if (studio && isMedia) {
|
|
8045
8199
|
items.push({ label: 'Oynat', fn: () => stVideoPlay(rel) });
|
|
8046
8200
|
} else if (studio) {
|
|
@@ -8695,6 +8849,10 @@ function bcIngest(ev) {
|
|
|
8695
8849
|
/* iş bitince üretilen site/app dahili tarayıcıda CANLI açılır */
|
|
8696
8850
|
bcAutoPreview(ev.url);
|
|
8697
8851
|
break;
|
|
8852
|
+
case 'bc-exp-qr':
|
|
8853
|
+
/* Expo dev server exp:// adresi → telefonda Expo Go için QR kart */
|
|
8854
|
+
bcQrShow(ev.qr, ev.url);
|
|
8855
|
+
break;
|
|
8698
8856
|
case 'bc-mode':
|
|
8699
8857
|
/* OpenCode disiplini çalışma modu: başlıkta rozet + panelde bilgi satırı */
|
|
8700
8858
|
if (els.bcTitle) {
|
|
@@ -8822,6 +8980,33 @@ if (els.bcClear) els.bcClear.addEventListener('click', () => {
|
|
|
8822
8980
|
bcHideTodos();
|
|
8823
8981
|
bcFlushStream();
|
|
8824
8982
|
});
|
|
8983
|
+
|
|
8984
|
+
/* ---------- Expo Go QR kartı (yalnız Beast Code) ---------- */
|
|
8985
|
+
function bcQrShow(qr, url) {
|
|
8986
|
+
if (!els.bcQrCard || !ideModeOn() || !qr) return;
|
|
8987
|
+
if (els.bcQrImg) els.bcQrImg.src = qr;
|
|
8988
|
+
if (els.bcQrUrl) {
|
|
8989
|
+
els.bcQrUrl.textContent = url || '';
|
|
8990
|
+
els.bcQrUrl.title = url || '';
|
|
8991
|
+
}
|
|
8992
|
+
if (els.bcQrBtn) els.bcQrBtn.hidden = false;
|
|
8993
|
+
els.bcQrCard.hidden = false;
|
|
8994
|
+
}
|
|
8995
|
+
if (els.bcQrBtn) els.bcQrBtn.addEventListener('click', () => {
|
|
8996
|
+
if (!els.bcQrCard) return;
|
|
8997
|
+
if (els.bcQrCard.hidden) {
|
|
8998
|
+
beast.ideExpQr().then((r) => {
|
|
8999
|
+
if (r && r.ok && r.qr) bcQrShow(r.qr, r.url);
|
|
9000
|
+
else toast('QR henüz yok — ajan expo start çalıştırınca çıkar');
|
|
9001
|
+
}).catch(() => {});
|
|
9002
|
+
} else {
|
|
9003
|
+
els.bcQrCard.hidden = true;
|
|
9004
|
+
}
|
|
9005
|
+
});
|
|
9006
|
+
if (els.bcQrCard) {
|
|
9007
|
+
const qclose = els.bcQrCard.querySelector('#bcQrClose');
|
|
9008
|
+
if (qclose) qclose.addEventListener('click', () => { els.bcQrCard.hidden = true; });
|
|
9009
|
+
}
|
|
8825
9010
|
if (els.bcNew) els.bcNew.addEventListener('click', async () => {
|
|
8826
9011
|
if (bcRunning) { toast('Mesaj sürüyor — önce ■ ile durdur'); return; }
|
|
8827
9012
|
const r = await beast.beastcodeNew().catch(() => null);
|
|
@@ -9247,3 +9432,463 @@ if (els.stNew) els.stNew.addEventListener('click', async () => {
|
|
|
9247
9432
|
});
|
|
9248
9433
|
/* Uygulama her açılışta agent (chat) modunda başlar — IDE modu yalnız
|
|
9249
9434
|
kullanıcı butona basınca girilir (oturumluk). */
|
|
9435
|
+
|
|
9436
|
+
/* ================= BEAST SANDBOX =================
|
|
9437
|
+
GitHub reposu indir (git clone) + repo klasöründe ajanla çalış.
|
|
9438
|
+
Sağ dock — ana chat solda yerinde kalır; Code/Studio'dan tamamen ayrı. */
|
|
9439
|
+
|
|
9440
|
+
let sbSessionId = '';
|
|
9441
|
+
let sbFolder = '';
|
|
9442
|
+
let sbBusy = false;
|
|
9443
|
+
let sbItems = [];
|
|
9444
|
+
let sbStreamEl = null;
|
|
9445
|
+
let sbStreamRaw = '';
|
|
9446
|
+
let sbCloning = false;
|
|
9447
|
+
/* sol dosya konsolu (repo ağacı) + sağ çalıştırıcı durumu */
|
|
9448
|
+
const sbTreeState = { cache: new Map(), open: new Set(['']), path: '' };
|
|
9449
|
+
let sbRunUrl = '';
|
|
9450
|
+
let sbRunRunning = false;
|
|
9451
|
+
|
|
9452
|
+
function sbModeOn() {
|
|
9453
|
+
return document.body.classList.contains('sandbox-mode');
|
|
9454
|
+
}
|
|
9455
|
+
|
|
9456
|
+
function sbLine(cls, text) {
|
|
9457
|
+
if (!els.sbOut) return null;
|
|
9458
|
+
const div = document.createElement('div');
|
|
9459
|
+
div.className = cls || 't-out';
|
|
9460
|
+
div.textContent = String(text || '');
|
|
9461
|
+
els.sbOut.appendChild(div);
|
|
9462
|
+
els.sbOut.scrollTop = els.sbOut.scrollHeight;
|
|
9463
|
+
return div;
|
|
9464
|
+
}
|
|
9465
|
+
|
|
9466
|
+
function sbStreamDelta(delta) {
|
|
9467
|
+
if (!els.sbOut) return;
|
|
9468
|
+
if (!sbStreamEl) {
|
|
9469
|
+
sbStreamEl = sbLine('t-out', '');
|
|
9470
|
+
}
|
|
9471
|
+
sbStreamRaw += String(delta || '');
|
|
9472
|
+
sbStreamEl.textContent = sbStreamRaw;
|
|
9473
|
+
els.sbOut.scrollTop = els.sbOut.scrollHeight;
|
|
9474
|
+
}
|
|
9475
|
+
|
|
9476
|
+
function sbFlushStream() {
|
|
9477
|
+
sbStreamEl = null;
|
|
9478
|
+
sbStreamRaw = '';
|
|
9479
|
+
}
|
|
9480
|
+
|
|
9481
|
+
function sbMsgText(content) {
|
|
9482
|
+
const t = Array.isArray(content)
|
|
9483
|
+
? content.filter((p) => p && p.type === 'text').map((p) => String(p.text || '')).join('\n')
|
|
9484
|
+
: String(content || '');
|
|
9485
|
+
return t.replace(/\s+/g, ' ').trim();
|
|
9486
|
+
}
|
|
9487
|
+
|
|
9488
|
+
function sbArgsSummary(args) {
|
|
9489
|
+
try {
|
|
9490
|
+
const j = typeof args === 'string' ? JSON.parse(args) : args || {};
|
|
9491
|
+
return String(j.command || j.path || j.url || j.query || j.pattern || '').replace(/\s+/g, ' ').slice(0, 90);
|
|
9492
|
+
} catch {
|
|
9493
|
+
return '';
|
|
9494
|
+
}
|
|
9495
|
+
}
|
|
9496
|
+
|
|
9497
|
+
function sbSetBusy(b) {
|
|
9498
|
+
sbBusy = !!b;
|
|
9499
|
+
if (els.sbStop) els.sbStop.hidden = !sbBusy;
|
|
9500
|
+
}
|
|
9501
|
+
|
|
9502
|
+
function sbStatusShow(text) {
|
|
9503
|
+
if (els.sbStatus) {
|
|
9504
|
+
els.sbStatus.hidden = false;
|
|
9505
|
+
els.sbStatus.textContent = text;
|
|
9506
|
+
}
|
|
9507
|
+
}
|
|
9508
|
+
function sbStatusHide() {
|
|
9509
|
+
if (els.sbStatus) els.sbStatus.hidden = true;
|
|
9510
|
+
}
|
|
9511
|
+
|
|
9512
|
+
/* Sandbox oturumunun engine olayları → panel (bcIngest'in minimal karşılığı) */
|
|
9513
|
+
function sbIngest(ev) {
|
|
9514
|
+
if (!sbSessionId || ev.sessionId !== sbSessionId) return;
|
|
9515
|
+
switch (ev.type) {
|
|
9516
|
+
case 'token':
|
|
9517
|
+
sbStreamDelta(ev.delta);
|
|
9518
|
+
break;
|
|
9519
|
+
case 'message': {
|
|
9520
|
+
const m = ev.message;
|
|
9521
|
+
if (!m) break;
|
|
9522
|
+
/* KULLANICI ECHO BASILMAZ — gönderirken zaten 'sen>' satırı düştü
|
|
9523
|
+
(Beast Code paneliyle aynı disiplin; yoksa mesaj ÇİFT görünür) */
|
|
9524
|
+
if (m.role === 'assistant') {
|
|
9525
|
+
sbFlushStream();
|
|
9526
|
+
const hasTools = Array.isArray(m.tool_calls) && m.tool_calls.length > 0;
|
|
9527
|
+
const txt = typeof m.content === 'string' ? m.content.trim() : '';
|
|
9528
|
+
if (txt && !hasTools) sbLine('t-out', txt);
|
|
9529
|
+
}
|
|
9530
|
+
break;
|
|
9531
|
+
}
|
|
9532
|
+
case 'tool-start':
|
|
9533
|
+
sbSetBusy(true);
|
|
9534
|
+
sbLine('t-dim', '\u2692 ' + (ev.name || '?') + (sbArgsSummary(ev.args) ? ' \u00B7 ' + sbArgsSummary(ev.args) : ''));
|
|
9535
|
+
break;
|
|
9536
|
+
case 'tool-end': {
|
|
9537
|
+
const ok = ev.ok !== false;
|
|
9538
|
+
sbLine(ok ? 't-dim' : 't-err', (ok ? ' \u2713 ' : ' \u2717 ') + String(ev.result || '').replace(/\s+/g, ' ').slice(0, 160));
|
|
9539
|
+
/* ajan dosya yazarsa/editlerse soldaki repo ağacı canlı tazelenir */
|
|
9540
|
+
if (ev.name === 'write_file' || ev.name === 'edit_file' || ev.name === 'run_command') ideRefreshTree();
|
|
9541
|
+
break;
|
|
9542
|
+
}
|
|
9543
|
+
case 'status':
|
|
9544
|
+
if (ev.status === 'idle') {
|
|
9545
|
+
sbSetBusy(false);
|
|
9546
|
+
sbStatusHide();
|
|
9547
|
+
} else {
|
|
9548
|
+
sbSetBusy(true);
|
|
9549
|
+
sbStatusShow(ev.status === 'thinking' ? 'düşünüyor…' : String(ev.status || ''));
|
|
9550
|
+
}
|
|
9551
|
+
break;
|
|
9552
|
+
case 'done':
|
|
9553
|
+
sbFlushStream();
|
|
9554
|
+
sbSetBusy(false);
|
|
9555
|
+
sbStatusHide();
|
|
9556
|
+
sbLine('t-dim', ev.aborted ? '[durduruldu' + (ev.reason ? ' — ' + ev.reason : '') + ']' : '(tamamlandı)');
|
|
9557
|
+
break;
|
|
9558
|
+
case 'error':
|
|
9559
|
+
sbFlushStream();
|
|
9560
|
+
sbSetBusy(false);
|
|
9561
|
+
sbStatusHide();
|
|
9562
|
+
sbLine('t-err', '[hata] ' + (ev.error || ''));
|
|
9563
|
+
break;
|
|
9564
|
+
}
|
|
9565
|
+
}
|
|
9566
|
+
|
|
9567
|
+
async function loadSandboxList() {
|
|
9568
|
+
const r = await beast.sandboxList().catch(() => ({ ok: false }));
|
|
9569
|
+
sbItems = (r && r.items) || [];
|
|
9570
|
+
const sel = els.sbRepo;
|
|
9571
|
+
if (!sel) return;
|
|
9572
|
+
sel.innerHTML = '';
|
|
9573
|
+
if (!sbItems.length) {
|
|
9574
|
+
const o = document.createElement('option');
|
|
9575
|
+
o.value = '';
|
|
9576
|
+
o.textContent = 'Repo yok, indir';
|
|
9577
|
+
sel.appendChild(o);
|
|
9578
|
+
}
|
|
9579
|
+
for (const it of sbItems) {
|
|
9580
|
+
const o = document.createElement('option');
|
|
9581
|
+
o.value = it.folder;
|
|
9582
|
+
o.textContent = it.name + (it.busy ? ' ●' : '');
|
|
9583
|
+
sel.appendChild(o);
|
|
9584
|
+
}
|
|
9585
|
+
if (sbFolder && sbItems.some((x) => x.folder === sbFolder)) sel.value = sbFolder;
|
|
9586
|
+
else if (sbItems.length) {
|
|
9587
|
+
sel.value = sbItems[0].folder;
|
|
9588
|
+
sbFolder = sel.value;
|
|
9589
|
+
} else {
|
|
9590
|
+
sbFolder = '';
|
|
9591
|
+
}
|
|
9592
|
+
await sbSelectCurrent();
|
|
9593
|
+
}
|
|
9594
|
+
|
|
9595
|
+
async function sbSelectCurrent() {
|
|
9596
|
+
sbFolder = els.sbRepo ? String(els.sbRepo.value || '') : '';
|
|
9597
|
+
if (els.sbOut) els.sbOut.innerHTML = '';
|
|
9598
|
+
sbSessionId = '';
|
|
9599
|
+
sbStreamEl = null;
|
|
9600
|
+
sbStreamRaw = '';
|
|
9601
|
+
sbSetBusy(false);
|
|
9602
|
+
sbStatusHide();
|
|
9603
|
+
/* çalıştırıcı + ağaç yeni repoya döner */
|
|
9604
|
+
sbRunUrl = '';
|
|
9605
|
+
sbRunRunning = false;
|
|
9606
|
+
if (els.sbRunOpen) els.sbRunOpen.disabled = true;
|
|
9607
|
+
if (els.sbRunUrl) els.sbRunUrl.textContent = '';
|
|
9608
|
+
if (els.sbRunOut) els.sbRunOut.innerHTML = '';
|
|
9609
|
+
sbTreeState.cache.clear();
|
|
9610
|
+
sbTreeState.open = new Set(['']);
|
|
9611
|
+
if (sbModeOn()) renderFileTree().catch(() => {});
|
|
9612
|
+
if (!sbFolder) {
|
|
9613
|
+
sbLine('t-dim', 'Repo indir: kutuya github.com/owner/repo yaz → İndir. Ya da 🔍 ile GitHub\u2019da ara.');
|
|
9614
|
+
return;
|
|
9615
|
+
}
|
|
9616
|
+
const r = await beast.sandboxOpen({ folder: sbFolder }).catch(() => null);
|
|
9617
|
+
if (r && r.ok) {
|
|
9618
|
+
sbSessionId = r.sessionId;
|
|
9619
|
+
for (const m of r.messages || []) {
|
|
9620
|
+
sbLine(m.role === 'assistant' ? 't-out' : 't-cmd', (m.role === 'assistant' ? '' : 'sen> ') + m.text);
|
|
9621
|
+
}
|
|
9622
|
+
sbLine('t-dim', 'Oturum yüklendi');
|
|
9623
|
+
} else {
|
|
9624
|
+
sbLine('t-err', (r && r.error) || 'oturum açılamadı');
|
|
9625
|
+
}
|
|
9626
|
+
sbSetBusy(!!(r && r.busy));
|
|
9627
|
+
/* sol konsol: seçilen reponun klasörü — oturum açıldıktan sonra da garanti tazele */
|
|
9628
|
+
sbTreeState.cache.clear();
|
|
9629
|
+
if (sbModeOn()) renderFileTree().catch(() => {});
|
|
9630
|
+
}
|
|
9631
|
+
|
|
9632
|
+
function sbInputResize() {
|
|
9633
|
+
const ta = els.sbInput;
|
|
9634
|
+
if (!ta) return;
|
|
9635
|
+
ta.style.height = 'auto';
|
|
9636
|
+
ta.style.height = Math.min(ta.scrollHeight, 140) + 'px';
|
|
9637
|
+
ta.classList.toggle('expand', ta.scrollHeight > 140);
|
|
9638
|
+
}
|
|
9639
|
+
|
|
9640
|
+
function sbRunCurrent() {
|
|
9641
|
+
const msg = els.sbInput.value.trim();
|
|
9642
|
+
if (!msg || !sbFolder || sbCloning) return;
|
|
9643
|
+
els.sbInput.value = '';
|
|
9644
|
+
sbInputResize();
|
|
9645
|
+
sbLine('t-cmd', 'sen> ' + msg);
|
|
9646
|
+
sbSetBusy(true);
|
|
9647
|
+
beast.sandboxSend({ folder: sbFolder, msg }).then((r) => {
|
|
9648
|
+
if (r && r.ok) {
|
|
9649
|
+
if (r.sessionId) sbSessionId = r.sessionId;
|
|
9650
|
+
if (r.queued) sbLine('t-dim', '⏳ kuyrukta (' + r.count + ') — iş bitince gönderilir');
|
|
9651
|
+
} else {
|
|
9652
|
+
sbSetBusy(false);
|
|
9653
|
+
sbLine('t-err', (r && r.error) || 'gönderilemedi');
|
|
9654
|
+
}
|
|
9655
|
+
}).catch((e) => {
|
|
9656
|
+
sbSetBusy(false);
|
|
9657
|
+
sbLine('t-err', String((e && e.message) || e));
|
|
9658
|
+
});
|
|
9659
|
+
}
|
|
9660
|
+
|
|
9661
|
+
let sbCloneLine = null;
|
|
9662
|
+
function sbCloneProgress(pct, text, done) {
|
|
9663
|
+
/* buton etiketi: %34 · İndir */
|
|
9664
|
+
const label = document.getElementById('sbCloneLabel');
|
|
9665
|
+
if (label) label.textContent = pct != null ? '%' + pct : 'İndir';
|
|
9666
|
+
if (!els.sbOut) return;
|
|
9667
|
+
if (done) {
|
|
9668
|
+
if (sbCloneLine && sbCloneLine.isConnected) sbCloneLine.remove();
|
|
9669
|
+
sbCloneLine = null;
|
|
9670
|
+
return;
|
|
9671
|
+
}
|
|
9672
|
+
if (!sbCloneLine || !sbCloneLine.isConnected) {
|
|
9673
|
+
sbCloneLine = sbLine('t-dim', '');
|
|
9674
|
+
}
|
|
9675
|
+
if (sbCloneLine) {
|
|
9676
|
+
sbCloneLine.textContent = (pct != null ? '⬇ %' + pct : '⬇ klonlanıyor') + (text ? ' · ' + text : '');
|
|
9677
|
+
els.sbOut.scrollTop = els.sbOut.scrollHeight;
|
|
9678
|
+
}
|
|
9679
|
+
}
|
|
9680
|
+
|
|
9681
|
+
async function sbClone(input) {
|
|
9682
|
+
if (sbCloning) return;
|
|
9683
|
+
const src = String(input || '').trim();
|
|
9684
|
+
if (!src) {
|
|
9685
|
+
toast('Repo adresi gir: github.com/owner/repo');
|
|
9686
|
+
return;
|
|
9687
|
+
}
|
|
9688
|
+
sbCloning = true;
|
|
9689
|
+
if (els.sbCloneBtn) els.sbCloneBtn.disabled = true;
|
|
9690
|
+
sbCloneLine = null;
|
|
9691
|
+
sbLine('t-dim', '⬇ klonlanıyor: ' + src + ' — (büyük repolar sürebilir…)');
|
|
9692
|
+
const r = await beast.sandboxClone(src).catch((e) => ({ ok: false, error: String((e && e.message) || e) }));
|
|
9693
|
+
sbCloning = false;
|
|
9694
|
+
if (els.sbCloneBtn) els.sbCloneBtn.disabled = false;
|
|
9695
|
+
sbCloneProgress(null, '', true); /* progress satırını temizle + etiketi geri koy */
|
|
9696
|
+
if (r && r.ok) {
|
|
9697
|
+
sbLine('t-dim', '✓ indirildi: ' + r.name);
|
|
9698
|
+
if (els.sbCloneInput) els.sbCloneInput.value = '';
|
|
9699
|
+
sbFolder = r.folder;
|
|
9700
|
+
await loadSandboxList();
|
|
9701
|
+
if (els.sbInput) els.sbInput.focus();
|
|
9702
|
+
} else {
|
|
9703
|
+
sbLine('t-err', '[klonlama] ' + ((r && r.error) || 'başarısız'));
|
|
9704
|
+
}
|
|
9705
|
+
}
|
|
9706
|
+
|
|
9707
|
+
function setSandboxMode(on) {
|
|
9708
|
+
if (on && ideModeOn()) { setIdeMode(false); }
|
|
9709
|
+
if (on && studioModeOn()) { setStudioMode(false); }
|
|
9710
|
+
document.body.classList.toggle('sandbox-mode', !!on);
|
|
9711
|
+
if (els.sbBtn) els.sbBtn.classList.toggle('on', !!on);
|
|
9712
|
+
/* marka + sol konsol başlığı: moduna göre BEAST Agent/Code/Studio/Sandbox */
|
|
9713
|
+
const brandSub = document.querySelector('#brand .brand-sub');
|
|
9714
|
+
if (brandSub) brandSub.textContent = on ? 'Sandbox' : 'Agent';
|
|
9715
|
+
const ftp = document.getElementById('filePanelTitle');
|
|
9716
|
+
if (ftp && on) ftp.textContent = 'REPO DOSYALARI';
|
|
9717
|
+
if (on) {
|
|
9718
|
+
loadSandboxList();
|
|
9719
|
+
sbTreeState.cache.clear();
|
|
9720
|
+
renderFileTree().catch(() => {});
|
|
9721
|
+
} else if (!ideModeOn() && !studioModeOn()) {
|
|
9722
|
+
/* agent moduna dönüş: ağaç eski köküne döner */
|
|
9723
|
+
ideState.cache.clear();
|
|
9724
|
+
renderFileTree().catch(() => {});
|
|
9725
|
+
}
|
|
9726
|
+
}
|
|
9727
|
+
|
|
9728
|
+
/* ---------- ÇALIŞTIRICI: butonlar KOMUT DEĞİL AJANA TALİMATTIR ----------
|
|
9729
|
+
Her proje farklı çalışır; komutu kullanıcı bilemez, AJAN bilir:
|
|
9730
|
+
paket bildirim dosyasına + README'ye bakıp doğru komutu bulur, uzun süreli
|
|
9731
|
+
süreci panel_run aracıyla ÇALIŞTIR panelinde (turu kilitlemeden) başlatır. */
|
|
9732
|
+
function sbInstruct(text) {
|
|
9733
|
+
if (!sbFolder) { toast('Önce repo indir ya da seç'); return; }
|
|
9734
|
+
sbLine('t-cmd', 'sen> ' + text);
|
|
9735
|
+
sbSetBusy(true);
|
|
9736
|
+
beast.sandboxSend({ folder: sbFolder, msg: text }).then((r) => {
|
|
9737
|
+
if (r && r.ok) {
|
|
9738
|
+
if (r.sessionId) sbSessionId = r.sessionId;
|
|
9739
|
+
if (r.queued) sbLine('t-dim', '⏳ kuyrukta (' + r.count + ') — iş bitince gönderilir');
|
|
9740
|
+
} else {
|
|
9741
|
+
sbSetBusy(false);
|
|
9742
|
+
sbLine('t-err', (r && r.error) || 'gönderilemedi');
|
|
9743
|
+
}
|
|
9744
|
+
}).catch((e) => {
|
|
9745
|
+
sbSetBusy(false);
|
|
9746
|
+
sbLine('t-err', String((e && e.message) || e));
|
|
9747
|
+
});
|
|
9748
|
+
}
|
|
9749
|
+
|
|
9750
|
+
function sbRunLine(text, cls) {
|
|
9751
|
+
if (!els.sbRunOut) return null;
|
|
9752
|
+
const div = document.createElement('div');
|
|
9753
|
+
div.className = cls || 't-out';
|
|
9754
|
+
div.textContent = String(text || '');
|
|
9755
|
+
els.sbRunOut.appendChild(div);
|
|
9756
|
+
els.sbRunOut.scrollTop = els.sbRunOut.scrollHeight;
|
|
9757
|
+
return div;
|
|
9758
|
+
}
|
|
9759
|
+
|
|
9760
|
+
/* süreç çıktısı akışı: sessionId'siz global olaylar — en üstte yönlendirilir */
|
|
9761
|
+
function sbRunIngest(ev) {
|
|
9762
|
+
if (ev.type === 'sb-run') {
|
|
9763
|
+
sbRunLine(ev.data);
|
|
9764
|
+
return;
|
|
9765
|
+
}
|
|
9766
|
+
if (ev.type === 'sb-run-url') {
|
|
9767
|
+
sbRunUrl = String(ev.url || '');
|
|
9768
|
+
sbRunLine('🌐 dev server: ' + sbRunUrl, 't-dim');
|
|
9769
|
+
if (els.sbRunOpen) els.sbRunOpen.disabled = !sbRunUrl;
|
|
9770
|
+
if (els.sbRunUrl) els.sbRunUrl.textContent = sbRunUrl;
|
|
9771
|
+
return;
|
|
9772
|
+
}
|
|
9773
|
+
if (ev.type === 'sb-run-end') {
|
|
9774
|
+
sbRunRunning = false;
|
|
9775
|
+
if (els.sbRunStop) els.sbRunStop.hidden = true;
|
|
9776
|
+
}
|
|
9777
|
+
}
|
|
9778
|
+
|
|
9779
|
+
function sbRunExec(cmd) {
|
|
9780
|
+
if (!sbFolder) { toast('Önce repo indir ya da seç'); return; }
|
|
9781
|
+
if (sbRunRunning) { toast('Zaten çalışıyor — önce ■ ile durdur'); return; }
|
|
9782
|
+
sbRunRunning = true;
|
|
9783
|
+
if (els.sbRunStop) els.sbRunStop.hidden = false;
|
|
9784
|
+
beast.sandboxRun({ folder: sbFolder, cmd }).then((r) => {
|
|
9785
|
+
if (!r || !r.ok) {
|
|
9786
|
+
sbRunRunning = false;
|
|
9787
|
+
if (els.sbRunStop) els.sbRunStop.hidden = true;
|
|
9788
|
+
sbRunLine('[hata] ' + ((r && r.error) || 'çalıştırılamadı'), 't-err');
|
|
9789
|
+
}
|
|
9790
|
+
}).catch((e) => {
|
|
9791
|
+
sbRunRunning = false;
|
|
9792
|
+
if (els.sbRunStop) els.sbRunStop.hidden = true;
|
|
9793
|
+
sbRunLine('[hata] ' + String((e && e.message) || e), 't-err');
|
|
9794
|
+
});
|
|
9795
|
+
}
|
|
9796
|
+
|
|
9797
|
+
/* topbar + dock olay bağlama */
|
|
9798
|
+
if (els.sbBtn) els.sbBtn.addEventListener('click', () => setSandboxMode(!sbModeOn()));
|
|
9799
|
+
if (els.sbRepo) els.sbRepo.addEventListener('change', sbSelectCurrent);
|
|
9800
|
+
if (els.sbCloneBtn) els.sbCloneBtn.addEventListener('click', () => sbClone(els.sbCloneInput.value));
|
|
9801
|
+
if (els.sbCloneInput) {
|
|
9802
|
+
els.sbCloneInput.addEventListener('keydown', (e) => {
|
|
9803
|
+
if (e.key === 'Enter') {
|
|
9804
|
+
e.preventDefault();
|
|
9805
|
+
sbClone(els.sbCloneInput.value);
|
|
9806
|
+
}
|
|
9807
|
+
});
|
|
9808
|
+
}
|
|
9809
|
+
if (els.sbGhBtn) els.sbGhBtn.addEventListener('click', () => openGit());
|
|
9810
|
+
if (els.sbNew) els.sbNew.addEventListener('click', async () => {
|
|
9811
|
+
if (sbBusy) { toast('Mesaj sürüyor — önce ■ ile durdur'); return; }
|
|
9812
|
+
if (!sbFolder) return;
|
|
9813
|
+
const r = await beast.sandboxNew({ folder: sbFolder }).catch(() => null);
|
|
9814
|
+
if (r && r.ok) {
|
|
9815
|
+
sbSessionId = '';
|
|
9816
|
+
await sbSelectCurrent();
|
|
9817
|
+
sbLine('t-sys', 'yeni oturum — taze başlar');
|
|
9818
|
+
}
|
|
9819
|
+
});
|
|
9820
|
+
if (els.sbRemove) els.sbRemove.addEventListener('click', async () => {
|
|
9821
|
+
if (!sbFolder) { toast('Önce repo seç'); return; }
|
|
9822
|
+
const name = (sbItems.find((x) => x.folder === sbFolder) || {}).name || 'repo';
|
|
9823
|
+
const ok = await uiConfirm('"' + name + '" reposunu diskten silmek istiyor musun? (klasör + sohbet)', 'Sil');
|
|
9824
|
+
if (!ok) return;
|
|
9825
|
+
const r = await beast.sandboxRemove({ folder: sbFolder }).catch(() => null);
|
|
9826
|
+
if (r && r.ok) {
|
|
9827
|
+
sbFolder = '';
|
|
9828
|
+
sbSessionId = '';
|
|
9829
|
+
await loadSandboxList();
|
|
9830
|
+
} else {
|
|
9831
|
+
toast((r && r.error) || 'silinemedi');
|
|
9832
|
+
}
|
|
9833
|
+
});
|
|
9834
|
+
if (els.sbReveal) els.sbReveal.addEventListener('click', () => {
|
|
9835
|
+
if (sbFolder) beast.sandboxReveal({ folder: sbFolder }).catch(() => {});
|
|
9836
|
+
});
|
|
9837
|
+
if (els.sbInput) {
|
|
9838
|
+
els.sbInput.addEventListener('input', sbInputResize);
|
|
9839
|
+
els.sbInput.addEventListener('keydown', (e) => {
|
|
9840
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
9841
|
+
e.preventDefault();
|
|
9842
|
+
sbRunCurrent();
|
|
9843
|
+
}
|
|
9844
|
+
});
|
|
9845
|
+
}
|
|
9846
|
+
if (els.sbStop) {
|
|
9847
|
+
els.sbStop.addEventListener('click', () => {
|
|
9848
|
+
beast.sandboxStop({ folder: sbFolder }).then((r) => {
|
|
9849
|
+
if (r && r.ok && r.wasBusy === false) {
|
|
9850
|
+
sbSetBusy(false);
|
|
9851
|
+
sbStatusHide();
|
|
9852
|
+
}
|
|
9853
|
+
}).catch(() => {});
|
|
9854
|
+
});
|
|
9855
|
+
}
|
|
9856
|
+
/* ÇALIŞTIRICI butonları — KOMUT DEĞİL AJANA TALİMAT (komutu ajan bulur):
|
|
9857
|
+
uzun süreli süreci panel_run ile ÇALIŞTIR paneline bırakır, tur kilitlenmez */
|
|
9858
|
+
if (els.sbRunInstall) els.sbRunInstall.addEventListener('click', () =>
|
|
9859
|
+
sbInstruct('Bu projeyi KUR — paket bildirim dosyasına (package.json, requirements.txt, Cargo.toml, go.mod, pom.xml vb.) göre doğru kurulum komutunu bul ve çalıştır (run_command); sonucu 1-2 satırla raporla.')
|
|
9860
|
+
);
|
|
9861
|
+
if (els.sbRunStart) els.sbRunStart.addEventListener('click', () =>
|
|
9862
|
+
sbInstruct('Bu projeyi ÇALIŞTIR — README/package.json scripts\u2019e göre doğru başlatma komutunu bul; uzun süreli sunucu/süreçse panel_run ile ÇALIŞTIR panelinde başlat (tur kilitleme), adresini/çalıştığını kullanıcıya bildir.')
|
|
9863
|
+
);
|
|
9864
|
+
if (els.sbRunDev) els.sbRunDev.addEventListener('click', () =>
|
|
9865
|
+
sbInstruct('Bu projeyi GELİŞTİRME modunda başlat — package.json scripts\u2019e bak (npm run dev, vite, expo start, ng serve vb. hangisi varsa) ve panel_run ile ÇALIŞTIR panelinde başlat; adresini kullanıcıya bildir.')
|
|
9866
|
+
);
|
|
9867
|
+
if (els.sbRunGo) els.sbRunGo.addEventListener('click', () => {
|
|
9868
|
+
const c = els.sbRunCmd.value.trim();
|
|
9869
|
+
if (!c) { toast('Komut yaz'); return; }
|
|
9870
|
+
sbRunExec(c);
|
|
9871
|
+
});
|
|
9872
|
+
if (els.sbRunCmd) {
|
|
9873
|
+
els.sbRunCmd.addEventListener('keydown', (e) => {
|
|
9874
|
+
if (e.key === 'Enter') {
|
|
9875
|
+
e.preventDefault();
|
|
9876
|
+
const c = els.sbRunCmd.value.trim();
|
|
9877
|
+
if (c) sbRunExec(c);
|
|
9878
|
+
}
|
|
9879
|
+
});
|
|
9880
|
+
}
|
|
9881
|
+
if (els.sbRunStop) {
|
|
9882
|
+
els.sbRunStop.addEventListener('click', () => {
|
|
9883
|
+
beast.sandboxRunStop().then((r) => {
|
|
9884
|
+
if (r && r.ok) sbRunLine('⏹ durduruldu', 't-dim');
|
|
9885
|
+
}).catch(() => {});
|
|
9886
|
+
});
|
|
9887
|
+
}
|
|
9888
|
+
if (els.sbRunOpen) {
|
|
9889
|
+
els.sbRunOpen.addEventListener('click', () => {
|
|
9890
|
+
/* Tarayıcıda aç da AJANA TALİMAT: ajan çalışma adresini bulup kendi
|
|
9891
|
+
browser_open aracıyla dahili tarayıcıda açar */
|
|
9892
|
+
sbInstruct('Bu projenin web arayüzü çalışıyorsa adresini tespit et (çıktılar/README/port taraması) ve browser_open aracıyla DAHİLİ TARAYICIDA aç.')
|
|
9893
|
+
});
|
|
9894
|
+
}
|