beast-agent 0.26.0 → 0.26.2
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/bin/beast-agent.js +34 -17
- package/package.json +2 -2
- package/scripts/fix-electron.js +126 -0
- package/src/agent/bots.js +8 -0
- package/src/agent/discord.js +268 -0
- package/src/agent/engine.js +135 -77
- package/src/agent/llm.js +46 -17
- package/src/agent/research.js +133 -0
- package/src/agent/skills.js +8 -1
- package/src/agent/tools.js +53 -14
- package/src/agent/watext.js +4 -0
- package/src/main.js +534 -351
- package/src/preload.js +8 -5
- package/src/renderer/i18n.js +19 -55
- package/src/renderer/index.html +1 -3
- package/src/renderer/renderer.js +336 -155
- package/src/renderer/style.css +1 -60
- package/tests/bg-jobs.test.js +5 -10
- package/tests/llm.test.js +81 -1
- package/tests/python.test.js +3 -2
- package/tests/research.test.js +116 -0
package/src/renderer/renderer.js
CHANGED
|
@@ -471,7 +471,9 @@ async function renderSessions(list) {
|
|
|
471
471
|
tgSet = new Set(await beast.tgListSessions());
|
|
472
472
|
} catch {}
|
|
473
473
|
els.sessList.innerHTML = '';
|
|
474
|
-
/* aktif botun oturumları — botlar arası geçişte liste de o bota göre değişir
|
|
474
|
+
/* aktif botun oturumları — botlar arası geçişte liste de o bota göre değişir.
|
|
475
|
+
KATI KURAL: her oturum yalnız BAĞLI OLDUĞU botun listesinde görünür;
|
|
476
|
+
bot kaydı olmayan (eski) oturumlar Beast (varsayılan sahip) altında görünür. */
|
|
475
477
|
for (const s of list) {
|
|
476
478
|
if ((s.botId || 'beast') !== activeBotId) continue;
|
|
477
479
|
const row = document.createElement('div');
|
|
@@ -635,7 +637,7 @@ function switchTab(name) {
|
|
|
635
637
|
document.querySelectorAll('#setTabs .tab').forEach((b) =>
|
|
636
638
|
b.classList.toggle('active', b.dataset.tab === name)
|
|
637
639
|
);
|
|
638
|
-
for (const p of ['provider', 'fallout', 'skills', 'agents', 'tts', 'email', 'integrations', 'websearch', 'events', 'cron', 'usage', 'logs', 'dash', 'limits', 'sec', '
|
|
640
|
+
for (const p of ['provider', 'fallout', 'skills', 'agents', 'tts', 'email', 'integrations', 'websearch', 'events', 'cron', 'usage', 'logs', 'dash', 'limits', 'sec', 'update']) {
|
|
639
641
|
const el = $('#tab-' + p);
|
|
640
642
|
if (el) el.hidden = p !== name; // guard: eksik pane tüm sekmeleri kilitlemesin
|
|
641
643
|
}
|
|
@@ -646,7 +648,6 @@ function switchTab(name) {
|
|
|
646
648
|
if (name === 'dash') renderDashboardPane();
|
|
647
649
|
if (name === 'limits') renderLimitsPane();
|
|
648
650
|
if (name === 'sec') renderSecurityPane();
|
|
649
|
-
if (name === 'proxy') renderProxyPane();
|
|
650
651
|
if (name === 'update') renderUpdatePane(true);
|
|
651
652
|
if (name === 'agents') refreshAgentsPane();
|
|
652
653
|
if (name === 'websearch') renderWebSearchPane();
|
|
@@ -816,7 +817,7 @@ async function renderProviderPane() {
|
|
|
816
817
|
|
|
817
818
|
for (const m of state.models || []) {
|
|
818
819
|
const row = document.createElement('div');
|
|
819
|
-
row.className = 'prov-row' + (
|
|
820
|
+
row.className = 'prov-row' + (effectiveModelSel() === m.sel ? ' active' : '');
|
|
820
821
|
row.innerHTML =
|
|
821
822
|
`<span class="prov-name">${escapeHtml(m.providerName)}</span>` +
|
|
822
823
|
`<span class="prov-model">${escapeHtml(m.model)}</span>` +
|
|
@@ -824,6 +825,7 @@ async function renderProviderPane() {
|
|
|
824
825
|
`<button class="prov-del" title="${_t('p_del_title')}">✕</button>`;
|
|
825
826
|
row.addEventListener('click', async () => {
|
|
826
827
|
state = await beast.setModel(m.sel);
|
|
828
|
+
await refreshBots().catch(() => {});
|
|
827
829
|
applyState();
|
|
828
830
|
renderProviderPane();
|
|
829
831
|
toast(_t('p_model_toast') + m.providerName + ' · ' + m.model);
|
|
@@ -1536,6 +1538,35 @@ async function renderIntegrationsPane() {
|
|
|
1536
1538
|
<button id="tgAllowAdd" class="btn ghost" style="margin-top:6px">${_t('it_add')}</button>
|
|
1537
1539
|
</div>
|
|
1538
1540
|
<div class="sub" style="margin-top:8px">${_t('it_tg_note')}</div>
|
|
1541
|
+
</div>
|
|
1542
|
+
|
|
1543
|
+
<div class="wa-card" style="margin-top:14px">
|
|
1544
|
+
<div class="wa-head">
|
|
1545
|
+
<div class="wa-logo tg">D</div>
|
|
1546
|
+
<div>
|
|
1547
|
+
<div class="wa-title">Discord</div>
|
|
1548
|
+
<div class="wa-sub">${_t('it_dc_sub')}</div>
|
|
1549
|
+
</div>
|
|
1550
|
+
</div>
|
|
1551
|
+
<div class="wa-status"><span id="dcDot" class="wa-dot"></span><span id="dcStatText">—</span></div>
|
|
1552
|
+
<div id="dcUser" class="wa-user" hidden></div>
|
|
1553
|
+
<div class="form-grid" style="grid-template-columns:1fr auto;align-items:center">
|
|
1554
|
+
<input id="dcTokenInp" class="inp" type="password" style="margin:6px 0 0" placeholder="${_t('it_dc_token_ph')}" autocomplete="off" />
|
|
1555
|
+
<button id="dcSaveBtn" class="btn" style="margin-top:6px">${_t('it_tg_save')}</button>
|
|
1556
|
+
</div>
|
|
1557
|
+
<div class="wa-actions" style="margin-top:6px">
|
|
1558
|
+
<button id="dcStopBtn" class="btn ghost">${_t('it_disconnect')}</button>
|
|
1559
|
+
</div>
|
|
1560
|
+
<div class="divider"></div>
|
|
1561
|
+
<label class="mem-label" style="margin-top:0">${_t('it_allow_label')} — Discord</label>
|
|
1562
|
+
<div id="dcAllowChips" class="chips-inline"></div>
|
|
1563
|
+
<div class="form-grid" style="grid-template-columns:1.2fr 1fr 1fr auto;align-items:center">
|
|
1564
|
+
<input id="dcAllowNameInp" class="inp" style="margin:6px 0 0" placeholder="${_t('it_name_ph')}" autocomplete="off" />
|
|
1565
|
+
<input id="dcAllowIdInp" class="inp" style="margin:6px 0 0" placeholder="${_t('it_dc_id_ph')}" autocomplete="off" />
|
|
1566
|
+
<select id="dcAllowBotSel" class="perm-select" style="margin:6px 0 0;min-width:105px" title="${_t('bot_bind_title')}"></select>
|
|
1567
|
+
<button id="dcAllowAdd" class="btn ghost" style="margin-top:6px">${_t('it_add')}</button>
|
|
1568
|
+
</div>
|
|
1569
|
+
<div class="sub" style="margin-top:8px">${_t('it_dc_note')}</div>
|
|
1539
1570
|
</div>`;
|
|
1540
1571
|
|
|
1541
1572
|
const waGroupsOn = $('#waGroupsOn');
|
|
@@ -1598,6 +1629,29 @@ async function renderIntegrationsPane() {
|
|
|
1598
1629
|
tgUI.user = ts.user || null;
|
|
1599
1630
|
updateTgPane();
|
|
1600
1631
|
} catch {}
|
|
1632
|
+
|
|
1633
|
+
/* DISCORD: token + allow list + durum */
|
|
1634
|
+
$('#dcSaveBtn').addEventListener('click', async () => {
|
|
1635
|
+
const tok = $('#dcTokenInp').value.trim();
|
|
1636
|
+
if (!tok) { toast(_t('it_dc_token_ph')); return; }
|
|
1637
|
+
toast(_t('it_dc_connecting'));
|
|
1638
|
+
const r = await beast.dcSetToken(tok).catch((e) => ({ status: 'error', error: String(e) }));
|
|
1639
|
+
$('#dcTokenInp').value = '';
|
|
1640
|
+
updateDcPane();
|
|
1641
|
+
toast(r.status === 'connected' ? 'Discord bağlı: ' + (r.user || '') : r.status === 'error' ? _t('it_dc_token_bad') : _t('it_dc_connecting'));
|
|
1642
|
+
});
|
|
1643
|
+
$('#dcStopBtn').addEventListener('click', async () => {
|
|
1644
|
+
await beast.dcStop().catch(() => {});
|
|
1645
|
+
updateDcPane();
|
|
1646
|
+
toast('Kesildi');
|
|
1647
|
+
});
|
|
1648
|
+
await renderDcAllow();
|
|
1649
|
+
try {
|
|
1650
|
+
const ds = await beast.dcGetStatus();
|
|
1651
|
+
dcUI.status = ds.status || 'disconnected';
|
|
1652
|
+
dcUI.user = ds.user || null;
|
|
1653
|
+
updateDcPane();
|
|
1654
|
+
} catch {}
|
|
1601
1655
|
}
|
|
1602
1656
|
|
|
1603
1657
|
/* ---------------- Olay Merkezi (ayrı sekme) ---------------- */
|
|
@@ -1791,134 +1845,8 @@ async function renderSecurityPane() {
|
|
|
1791
1845
|
}
|
|
1792
1846
|
}
|
|
1793
1847
|
|
|
1794
|
-
/* ---------------- Proxy sekmesi ----------------
|
|
1795
|
-
Kullanıcı yalnız IP/port/kullanıcı/şifre alanlarını doldurur; URL'i biz kurarız.
|
|
1796
|
-
Eklenen her satır bir proxy — çoklu satır = Node tarafında round-robin rotasyon. */
|
|
1797
|
-
let proxyDraft = null; // { enabled, items:[line,...] } — sekme açıkken çalışma kopyası
|
|
1798
|
-
|
|
1799
|
-
function parseProxyLine(line) {
|
|
1800
|
-
const m = String(line || '').trim().match(/^(https?|socks5):\/\/(?:([^:@/]+):([^@/]*)@)?([^:/]+):(\d+)$/i);
|
|
1801
|
-
if (!m) return null;
|
|
1802
|
-
return { proto: m[1].toLowerCase(), user: decodeURIComponent(m[2] || ''), pass: decodeURIComponent(m[3] || ''), host: m[4], port: m[5] };
|
|
1803
|
-
}
|
|
1804
|
-
|
|
1805
|
-
function proxyLineDisplay(line) {
|
|
1806
|
-
const p = parseProxyLine(line);
|
|
1807
|
-
if (!p) return escapeHtml(line);
|
|
1808
|
-
const creds = p.user ? p.user + ':' + (p.pass ? '•••' : '') + '@' : '';
|
|
1809
|
-
return `${p.proto}://${escapeHtml(creds)}${escapeHtml(p.host)}:${p.port}`;
|
|
1810
|
-
}
|
|
1811
|
-
|
|
1812
|
-
async function renderProxyPane() {
|
|
1813
|
-
const pane = $('#tab-proxy');
|
|
1814
|
-
if (!pane) return;
|
|
1815
|
-
if (!proxyDraft) {
|
|
1816
|
-
const [cfg, ws] = await Promise.all([
|
|
1817
|
-
beast.proxyGet().catch(() => ({ enabled: false, urls: '' })),
|
|
1818
|
-
beast.warpGet().catch(() => ({ enabled: false, running: false, installed: false })),
|
|
1819
|
-
]);
|
|
1820
|
-
proxyDraft = {
|
|
1821
|
-
enabled: !!cfg.enabled,
|
|
1822
|
-
items: String(cfg.urls || '').split(/[\n,;]+/).map((s) => s.trim()).filter(Boolean),
|
|
1823
|
-
warp: ws || {},
|
|
1824
|
-
};
|
|
1825
|
-
}
|
|
1826
|
-
const warp = proxyDraft.warp || {};
|
|
1827
|
-
const warpState = warp.enabled ? (warp.running ? _t('warp_state_on') : _t('warp_state_starting')) : _t('warp_state_off');
|
|
1828
|
-
|
|
1829
|
-
const listHtml = proxyDraft.items.length
|
|
1830
|
-
? proxyDraft.items.map((line, i) =>
|
|
1831
|
-
`<div class="px-row"><code>${proxyLineDisplay(line)}</code><button class="px-del" data-i="${i}" title="${_t('proxy_remove')}">✕</button></div>`
|
|
1832
|
-
).join('')
|
|
1833
|
-
: `<div class="gh-empty" style="padding:10px">${_t('proxy_none')}</div>`;
|
|
1834
|
-
|
|
1835
|
-
pane.innerHTML =
|
|
1836
|
-
'<h2>' + _t('proxy_h2') + '</h2>' +
|
|
1837
|
-
'<div class="sub">' + _t('proxy_sub') + '</div>' +
|
|
1838
|
-
'<div class="warp-card">' +
|
|
1839
|
-
`<div class="warp-head"><span>☁ Cloudflare WARP</span><span class="warp-state">${escapeHtml(warpState)}</span></div>` +
|
|
1840
|
-
`<button id="pxWarp" class="btn ${warp.enabled ? 'ghost' : ''}">${warp.enabled ? _t('warp_off') : _t('warp_on')}</button>` +
|
|
1841
|
-
`<div class="sub" style="margin-top:6px">${_t('warp_note')}</div>` +
|
|
1842
|
-
'</div>' +
|
|
1843
|
-
'<div class="fo-toggles" style="margin-top:12px">' +
|
|
1844
|
-
`<label class="lock-row"><input type="checkbox" id="pxOn" ${proxyDraft.enabled ? 'checked' : ''}/><span>${_t('proxy_enabled')}</span></label>` +
|
|
1845
|
-
'</div>' +
|
|
1846
|
-
`<label class="mem-label">${_t('proxy_urls')}</label>` +
|
|
1847
|
-
`<div id="pxList">${listHtml}</div>` +
|
|
1848
|
-
'<div class="px-add-row">' +
|
|
1849
|
-
`<select id="pxProto"><option value="http">http</option><option value="socks5">socks5</option></select>` +
|
|
1850
|
-
`<input id="pxHost" placeholder="${_t('proxy_host')}" spellcheck="false"/>` +
|
|
1851
|
-
`<input id="pxPort" placeholder="${_t('proxy_port')}" inputmode="numeric"/>` +
|
|
1852
|
-
`<input id="pxUser" placeholder="${_t('proxy_user')}" autocomplete="off" spellcheck="false"/>` +
|
|
1853
|
-
`<input id="pxPass" placeholder="${_t('proxy_pass')}" type="password" autocomplete="off"/>` +
|
|
1854
|
-
`<button id="pxAdd" class="btn" style="margin-top:0">${_t('proxy_add')}</button>` +
|
|
1855
|
-
'</div>' +
|
|
1856
|
-
'<div class="form-grid" style="grid-template-columns:auto auto;gap:8px;margin-top:10px">' +
|
|
1857
|
-
`<button id="pxSave" class="btn">${_t('proxy_save')}</button>` +
|
|
1858
|
-
`<button id="pxTest" class="btn ghost">${_t('proxy_test')}</button>` +
|
|
1859
|
-
'</div>' +
|
|
1860
|
-
`<div id="pxTestOut" class="sub" style="margin-top:8px"></div>` +
|
|
1861
|
-
'<div class="sub" style="margin-top:10px">' + _t('proxy_note') + '</div>';
|
|
1862
|
-
|
|
1863
|
-
pane.querySelector('#pxOn').addEventListener('change', (e) => { proxyDraft.enabled = e.target.checked; });
|
|
1864
|
-
|
|
1865
|
-
pane.querySelector('#pxWarp').addEventListener('click', async () => {
|
|
1866
|
-
const btn = pane.querySelector('#pxWarp');
|
|
1867
|
-
const st = pane.querySelector('#pxWarpState');
|
|
1868
|
-
const want = !warp.enabled;
|
|
1869
|
-
btn.disabled = true;
|
|
1870
|
-
st.textContent = want ? '⏳ ' + _t('warp_state_starting') : '⏳ ' + _t('warp_state_off');
|
|
1871
|
-
const r = await beast.warpSet(want).catch((e) => ({ ok: false, error: String(e) }));
|
|
1872
|
-
if (!(r && r.ok)) {
|
|
1873
|
-
btn.disabled = false;
|
|
1874
|
-
st.textContent = '⚠ ' + ((r && r.error) || 'hata');
|
|
1875
|
-
return;
|
|
1876
|
-
}
|
|
1877
|
-
proxyDraft = null; // listeyi (socks satırı eklenmiş/çıkarılmış) tazele
|
|
1878
|
-
renderProxyPane();
|
|
1879
|
-
});
|
|
1880
|
-
|
|
1881
|
-
const collect = () => {
|
|
1882
|
-
const host = pane.querySelector('#pxHost').value.trim();
|
|
1883
|
-
const port = pane.querySelector('#pxPort').value.trim();
|
|
1884
|
-
const user = pane.querySelector('#pxUser').value.trim();
|
|
1885
|
-
const pass = pane.querySelector('#pxPass').value;
|
|
1886
|
-
const proto = pane.querySelector('#pxProto').value || 'http';
|
|
1887
|
-
if (!host || !/^\d{1,5}$/.test(port)) { toast(_t('proxy_invalid')); return null; }
|
|
1888
|
-
const creds = user ? encodeURIComponent(user) + (pass ? ':' + encodeURIComponent(pass) : '') + '@' : '';
|
|
1889
|
-
return `${proto}://${creds}${host}:${port}`;
|
|
1890
|
-
};
|
|
1891
|
-
pane.querySelector('#pxAdd').addEventListener('click', () => {
|
|
1892
|
-
const line = collect();
|
|
1893
|
-
if (!line) return;
|
|
1894
|
-
if (proxyDraft.items.includes(line)) { toast(_t('proxy_dup')); return; }
|
|
1895
|
-
proxyDraft.items.push(line);
|
|
1896
|
-
renderProxyPane();
|
|
1897
|
-
});
|
|
1898
|
-
pane.querySelectorAll('.px-del').forEach((b) =>
|
|
1899
|
-
b.addEventListener('click', () => {
|
|
1900
|
-
proxyDraft.items.splice(Number(b.dataset.i), 1);
|
|
1901
|
-
renderProxyPane();
|
|
1902
|
-
})
|
|
1903
|
-
);
|
|
1904
|
-
|
|
1905
|
-
pane.querySelector('#pxSave').addEventListener('click', async () => {
|
|
1906
|
-
const r = await beast.proxySet({ enabled: proxyDraft.enabled, urls: proxyDraft.items.join('\n') }).catch(() => null);
|
|
1907
|
-
if (r && r.ok) toast(_t('proxy_saved'));
|
|
1908
|
-
else toast((r && r.error) || 'hata');
|
|
1909
|
-
});
|
|
1910
|
-
pane.querySelector('#pxTest').addEventListener('click', async () => {
|
|
1911
|
-
const out = pane.querySelector('#pxTestOut');
|
|
1912
|
-
out.textContent = '⏳ ' + _t('proxy_testing');
|
|
1913
|
-
/* önce kaydet — test, kayıtlı ayarla çalışır */
|
|
1914
|
-
await beast.proxySet({ enabled: proxyDraft.enabled, urls: proxyDraft.items.join('\n') }).catch(() => null);
|
|
1915
|
-
const r = await beast.proxyTest().catch((e) => ({ ok: false, error: String(e) }));
|
|
1916
|
-
if (r && r.ok) out.innerHTML = `✅ ${_t('proxy_test_ok')} <b>${escapeHtml(r.ip || '?')}</b> · ${escapeHtml(r.proxy || '')} · ${r.ms || '?'}ms`;
|
|
1917
|
-
else out.innerHTML = `⚠ ${_t('proxy_test_fail')} ${escapeHtml((r && r.error) || '?')}`;
|
|
1918
|
-
});
|
|
1919
|
-
}
|
|
1920
|
-
|
|
1921
1848
|
/* ---------------- Update: sürüm kontrol + otomatik güncelleme ---------------- */
|
|
1849
|
+
|
|
1922
1850
|
let updatePaneTimer = null;
|
|
1923
1851
|
|
|
1924
1852
|
function renderUpdateStateHtml(st) {
|
|
@@ -2566,6 +2494,199 @@ async function renderTgAllow() {
|
|
|
2566
2494
|
}
|
|
2567
2495
|
}
|
|
2568
2496
|
|
|
2497
|
+
/* ---------------- Discord izin listesi + durum — TG ile aynı mantık ---------------- */
|
|
2498
|
+
|
|
2499
|
+
const dcUI = { status: 'disconnected', user: null };
|
|
2500
|
+
const DC_STATUS_TEXT = {
|
|
2501
|
+
disconnected: 'Bağlı değil',
|
|
2502
|
+
connecting: 'Bağlanıyor…',
|
|
2503
|
+
connected: 'Bağlı',
|
|
2504
|
+
error: 'Hata — tokenı kontrol et',
|
|
2505
|
+
};
|
|
2506
|
+
|
|
2507
|
+
function onDcEvent(ev) {
|
|
2508
|
+
if (ev.type !== 'status') return;
|
|
2509
|
+
dcUI.status = ev.status;
|
|
2510
|
+
if (ev.user) dcUI.user = ev.user;
|
|
2511
|
+
updateDcPane();
|
|
2512
|
+
}
|
|
2513
|
+
|
|
2514
|
+
function updateDcPane() {
|
|
2515
|
+
const pane = $('#tab-integrations');
|
|
2516
|
+
const dot = pane && pane.querySelector('#dcDot');
|
|
2517
|
+
if (!dot) return;
|
|
2518
|
+
dot.className = 'wa-dot' + (dcUI.status === 'connected' ? ' on' : dcUI.status === 'error' ? ' qr' : '');
|
|
2519
|
+
pane.querySelector('#dcStatText').textContent = DC_STATUS_TEXT[dcUI.status] || dcUI.status;
|
|
2520
|
+
const u = pane.querySelector('#dcUser');
|
|
2521
|
+
u.hidden = !(dcUI.status === 'connected' && dcUI.user);
|
|
2522
|
+
u.textContent = dcUI.user ? '🤖 ' + dcUI.user : '';
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
async function renderDcAllow() {
|
|
2526
|
+
const wrap = $('#dcAllowChips');
|
|
2527
|
+
if (!wrap) return;
|
|
2528
|
+
const list = await beast.dcGetAllow();
|
|
2529
|
+
let botChoices = [];
|
|
2530
|
+
try { botChoices = (await beast.botsList()) || []; } catch {}
|
|
2531
|
+
const dcLabel = (e) => {
|
|
2532
|
+
if (e === '*') return '* herkes';
|
|
2533
|
+
if (typeof e === 'string') return e;
|
|
2534
|
+
const name = String((e && e.name) || '').trim();
|
|
2535
|
+
const id = String((e && e.id) || '');
|
|
2536
|
+
const bot = e && e.bot_id ? botChoices.find((bb) => bb.id === e.bot_id) : null;
|
|
2537
|
+
return (name ? name + ' ' : '') + id + (bot ? ' → ' + bot.name : '');
|
|
2538
|
+
};
|
|
2539
|
+
wrap.innerHTML = '';
|
|
2540
|
+
if (!list.length) wrap.innerHTML = '<span class="sub">— boş —</span>';
|
|
2541
|
+
list.forEach((entry, idx) => {
|
|
2542
|
+
const curPerm = (typeof entry === 'object' && entry.perm) || (entry && entry.lockdown ? 'chat' : 'all');
|
|
2543
|
+
const c = document.createElement('span');
|
|
2544
|
+
c.className = 'chip';
|
|
2545
|
+
c.style.margin = '0 6px 6px 0';
|
|
2546
|
+
const txt = document.createElement('span');
|
|
2547
|
+
txt.className = 'chip-txt';
|
|
2548
|
+
txt.textContent = dcLabel(entry);
|
|
2549
|
+
c.appendChild(txt);
|
|
2550
|
+
if (entry !== '*') {
|
|
2551
|
+
const selP = document.createElement('select');
|
|
2552
|
+
selP.className = 'perm-select';
|
|
2553
|
+
selP.title = _t('wa_perm_title');
|
|
2554
|
+
const PERMS = [
|
|
2555
|
+
['all', _t('wa_perm_all')],
|
|
2556
|
+
['web', 'web'],
|
|
2557
|
+
['read', _t('wa_perm_read')],
|
|
2558
|
+
['chat', _t('wa_perm_chat')],
|
|
2559
|
+
];
|
|
2560
|
+
for (const [v, lbl] of PERMS) {
|
|
2561
|
+
const o = document.createElement('option');
|
|
2562
|
+
o.value = v;
|
|
2563
|
+
o.textContent = lbl;
|
|
2564
|
+
if (curPerm === v) o.selected = true;
|
|
2565
|
+
selP.appendChild(o);
|
|
2566
|
+
}
|
|
2567
|
+
selP.addEventListener('change', async () => {
|
|
2568
|
+
const cur = await beast.dcGetAllow();
|
|
2569
|
+
const next = cur.map((e, i) => {
|
|
2570
|
+
if (i !== idx) return e;
|
|
2571
|
+
const base = typeof e === 'string' ? { id: e, name: '' } : { ...e };
|
|
2572
|
+
base.lockdown = selP.value === 'chat';
|
|
2573
|
+
base.perm = selP.value;
|
|
2574
|
+
return base;
|
|
2575
|
+
});
|
|
2576
|
+
await beast.dcSetAllow(next);
|
|
2577
|
+
renderDcAllow();
|
|
2578
|
+
toast(dcLabel(entry) + ': ' + selP.selectedOptions[0].textContent);
|
|
2579
|
+
});
|
|
2580
|
+
c.appendChild(selP);
|
|
2581
|
+
|
|
2582
|
+
if (botChoices.length) {
|
|
2583
|
+
const sel = document.createElement('select');
|
|
2584
|
+
sel.className = 'perm-select';
|
|
2585
|
+
sel.title = _t('bot_bind_title');
|
|
2586
|
+
const empty = document.createElement('option');
|
|
2587
|
+
empty.value = '';
|
|
2588
|
+
empty.textContent = _t('bot_sel_empty');
|
|
2589
|
+
sel.appendChild(empty);
|
|
2590
|
+
for (const bb of botChoices) {
|
|
2591
|
+
const o = document.createElement('option');
|
|
2592
|
+
o.value = bb.id;
|
|
2593
|
+
o.textContent = `${bb.icon} ${bb.name}`;
|
|
2594
|
+
if ((typeof entry === 'object' && entry.bot_id) === bb.id) o.selected = true;
|
|
2595
|
+
sel.appendChild(o);
|
|
2596
|
+
}
|
|
2597
|
+
sel.addEventListener('change', async () => {
|
|
2598
|
+
const cur = await beast.dcGetAllow();
|
|
2599
|
+
const next = cur.map((e, i) => {
|
|
2600
|
+
if (i !== idx) return e;
|
|
2601
|
+
const base = typeof e === 'string' ? { id: e, name: '' } : { ...e };
|
|
2602
|
+
base.bot_id = sel.value || undefined;
|
|
2603
|
+
return base;
|
|
2604
|
+
});
|
|
2605
|
+
await beast.dcSetAllow(next);
|
|
2606
|
+
renderDcAllow();
|
|
2607
|
+
const bt = botChoices.find((bb) => bb.id === sel.value);
|
|
2608
|
+
toast(dcLabel(entry) + ' → ' + (bt ? bt.name : '?'));
|
|
2609
|
+
});
|
|
2610
|
+
c.appendChild(sel);
|
|
2611
|
+
}
|
|
2612
|
+
|
|
2613
|
+
const isOwnerEntry = typeof entry === 'object' && !!entry.owner;
|
|
2614
|
+
const ownerBtn = document.createElement('span');
|
|
2615
|
+
ownerBtn.className = 'lk';
|
|
2616
|
+
ownerBtn.style.cssText = 'font-size:11px;padding:1px 6px;' + (isOwnerEntry ? 'color:#c9a227;font-weight:800' : '');
|
|
2617
|
+
ownerBtn.title = isOwnerEntry ? _t('wa_owner_title_on') : _t('wa_owner_title_off');
|
|
2618
|
+
ownerBtn.textContent = isOwnerEntry ? _t('wa_owner_on') : _t('wa_owner_off');
|
|
2619
|
+
ownerBtn.addEventListener('click', async () => {
|
|
2620
|
+
if (isOwnerEntry) return;
|
|
2621
|
+
const cur = await beast.dcGetAllow();
|
|
2622
|
+
const next = cur.map((e, i) => {
|
|
2623
|
+
if (typeof e === 'object' && e && e.owner) return { ...e, owner: false };
|
|
2624
|
+
if (i === idx) {
|
|
2625
|
+
const obj = typeof e === 'string' ? { id: e, name: '' } : { ...e };
|
|
2626
|
+
obj.owner = true;
|
|
2627
|
+
return obj;
|
|
2628
|
+
}
|
|
2629
|
+
return e;
|
|
2630
|
+
});
|
|
2631
|
+
const tgt = next[idx];
|
|
2632
|
+
await beast.dcSetAllow(next);
|
|
2633
|
+
renderDcAllow();
|
|
2634
|
+
toast('Sahip: ' + dcLabel(tgt));
|
|
2635
|
+
});
|
|
2636
|
+
c.appendChild(ownerBtn);
|
|
2637
|
+
}
|
|
2638
|
+
const x = document.createElement('span');
|
|
2639
|
+
x.className = 'x';
|
|
2640
|
+
x.textContent = '×';
|
|
2641
|
+
x.addEventListener('click', async () => {
|
|
2642
|
+
const next = (await beast.dcGetAllow()).filter((_v, i) => i !== idx);
|
|
2643
|
+
await beast.dcSetAllow(next);
|
|
2644
|
+
renderDcAllow();
|
|
2645
|
+
toast('Kaldırıldı: ' + dcLabel(entry));
|
|
2646
|
+
});
|
|
2647
|
+
c.appendChild(x);
|
|
2648
|
+
wrap.appendChild(c);
|
|
2649
|
+
});
|
|
2650
|
+
|
|
2651
|
+
const inp = $('#dcAllowIdInp');
|
|
2652
|
+
const nameInp = $('#dcAllowNameInp');
|
|
2653
|
+
const add = $('#dcAllowAdd');
|
|
2654
|
+
const botSel = $('#dcAllowBotSel');
|
|
2655
|
+
if (botSel) {
|
|
2656
|
+
const prev = botSel.value;
|
|
2657
|
+
botSel.innerHTML =
|
|
2658
|
+
`<option value="">${_t('bot_sel_empty')}</option>` +
|
|
2659
|
+
botChoices
|
|
2660
|
+
.map((bb) => `<option value="${bb.id}">${bb.icon} ${escapeHtml(bb.name)}${bb.admin ? ' (admin)' : ''}</option>`)
|
|
2661
|
+
.join('');
|
|
2662
|
+
if (prev) botSel.value = prev;
|
|
2663
|
+
}
|
|
2664
|
+
if (!add.dataset.bound) {
|
|
2665
|
+
add.dataset.bound = '1';
|
|
2666
|
+
const addEntry = async () => {
|
|
2667
|
+
let v = inp.value.trim();
|
|
2668
|
+
if (!v) return;
|
|
2669
|
+
const name = nameInp.value.trim().slice(0, 40);
|
|
2670
|
+
if (!name) { toast('İsim zorunlu — kimin yazdığını bilmek için'); nameInp.focus(); return; }
|
|
2671
|
+
v = v.startsWith('@') ? '@' + v.slice(1).replace(/[^\w]/g, '') : v.replace(/[^\d]/g, '');
|
|
2672
|
+
if (!v) { toast(_t('it_dc_id_ph')); return; }
|
|
2673
|
+
const botId = botSel && botSel.value ? { bot_id: botSel.value } : {};
|
|
2674
|
+
const next = [...(await beast.dcGetAllow()), { id: v, name, ...botId }];
|
|
2675
|
+
if (!next.some((e) => e && typeof e === 'object' && e.owner)) {
|
|
2676
|
+
if (next.length && typeof next[0] === 'object') next[0].owner = true;
|
|
2677
|
+
}
|
|
2678
|
+
await beast.dcSetAllow(next);
|
|
2679
|
+
inp.value = '';
|
|
2680
|
+
nameInp.value = '';
|
|
2681
|
+
renderDcAllow();
|
|
2682
|
+
toast('Eklendi: ' + name);
|
|
2683
|
+
};
|
|
2684
|
+
add.addEventListener('click', addEntry);
|
|
2685
|
+
inp.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); addEntry(); } });
|
|
2686
|
+
nameInp.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); addEntry(); } });
|
|
2687
|
+
}
|
|
2688
|
+
}
|
|
2689
|
+
|
|
2569
2690
|
/* ---------------- BOT SİSTEMİ (BÖLÜM 2-3-4) ----------------
|
|
2570
2691
|
Sol panel altında bot kartları; her bot için sohbet geçmişi + sekmeli yönetim.
|
|
2571
2692
|
İlk bot hep Beast (admin, silinemez). Max 5 bot. */
|
|
@@ -2601,6 +2722,8 @@ async function refreshBots() {
|
|
|
2601
2722
|
/* BOT PICKER SENKRONU: liste her yenilendiğinde üstteki rozet de aktif bota
|
|
2602
2723
|
ayarlanır — startup yarışında (liste boşken çizilen) eski rozet düzelir */
|
|
2603
2724
|
updateBotChip();
|
|
2725
|
+
/* model picker da aktif botun kendi modelini göstersin */
|
|
2726
|
+
if (state) applyState();
|
|
2604
2727
|
if (!$('#botOverlay').hidden) renderBotPage();
|
|
2605
2728
|
}
|
|
2606
2729
|
|
|
@@ -2664,6 +2787,8 @@ async function switchBot(id) {
|
|
|
2664
2787
|
if (list.length) await openSession(list[0].id);
|
|
2665
2788
|
else { const v = await beast.createSession(); await openSession(v.id); }
|
|
2666
2789
|
} catch {}
|
|
2790
|
+
/* picker, aktif botun kendi modelini göstersin */
|
|
2791
|
+
applyState();
|
|
2667
2792
|
toast((b.icon || '🤖') + ' ' + b.name + (b.admin ? '' : ' — ' + _t('bot_switched')));
|
|
2668
2793
|
}
|
|
2669
2794
|
|
|
@@ -2894,6 +3019,15 @@ function renderBotSettings(pane, b) {
|
|
|
2894
3019
|
const numRows = (b.numbers || [])
|
|
2895
3020
|
.map((n) => `<div class="bot-num-row" data-num="${n.num}"><span class="n">+${escapeHtml(n.num)}${n.name ? ' · ' + escapeHtml(n.name) : ''}</span><span class="x" title="${_t('bot_num_del')}">×</span></div>`)
|
|
2896
3021
|
.join('');
|
|
3022
|
+
/* bot bazlı model seçenekleri: ana picker'daki listeyle aynı (state.models) */
|
|
3023
|
+
const modelOpts = ['<option value="">' + escapeHtml(_t('bot_model_global')) + '</option>']
|
|
3024
|
+
.concat(
|
|
3025
|
+
(state.models || []).map((m) => {
|
|
3026
|
+
const s = m.sel || (m.providerId || '') + '::' + (m.model || '');
|
|
3027
|
+
return `<option value="${escapeHtml(s)}" ${b.model === s ? 'selected' : ''}>${escapeHtml(m.providerName || m.providerId || '')} · ${escapeHtml(m.model || '')}</option>`;
|
|
3028
|
+
})
|
|
3029
|
+
)
|
|
3030
|
+
.join('');
|
|
2897
3031
|
/* Numara ekleme KALDIRILDI — girişler yalnız Ayarlar → Entegrasyonlar (WhatsApp
|
|
2898
3032
|
izin listesi) üzerinden yapılır. Bu bölüm salt-okunur bağlı-numara listesidir. */
|
|
2899
3033
|
f.innerHTML = `
|
|
@@ -2916,7 +3050,10 @@ function renderBotSettings(pane, b) {
|
|
|
2916
3050
|
<div class="bot-checks" id="bPerm">${permChecks}</div>
|
|
2917
3051
|
<div class="sub" style="margin-top:4px">${_t('bot_perm_note')}</div>
|
|
2918
3052
|
<label class="mem-label">${_t('bot_skills')}</label>
|
|
2919
|
-
<div class="bot-checks" id="bSkills">${skillChecks}</div
|
|
3053
|
+
<div class="bot-checks" id="bSkills">${skillChecks}</div>
|
|
3054
|
+
<label class="mem-label">${_t('bot_model')}</label>
|
|
3055
|
+
<select id="bModel" class="inp">${modelOpts}</select>
|
|
3056
|
+
<div class="sub" style="margin-top:4px">${_t('bot_model_note')}</div>`}
|
|
2920
3057
|
<label class="mem-label">${_t('bot_browser')}</label>
|
|
2921
3058
|
<div class="bot-checks" style="margin-bottom:6px">
|
|
2922
3059
|
<label><input type="checkbox" id="bExtBrowser" ${b.extBrowser ? 'checked' : ''}/> ${_t('bot_ext_browser')}</label>
|
|
@@ -2991,6 +3128,8 @@ function renderBotSettings(pane, b) {
|
|
|
2991
3128
|
const sk = {};
|
|
2992
3129
|
f.querySelectorAll('#bSkills input').forEach((c) => { sk[c.dataset.skill] = c.checked; });
|
|
2993
3130
|
patch.skills = sk;
|
|
3131
|
+
const bm = $('#bModel');
|
|
3132
|
+
if (bm) patch.model = bm.value;
|
|
2994
3133
|
}
|
|
2995
3134
|
const r = await beast.botsUpdate(b.id, patch);
|
|
2996
3135
|
if (r.ok) { toast(_t('bot_saved')); await refreshBots(); renderBotPage(); }
|
|
@@ -3214,6 +3353,39 @@ function fmtAgo(iso) {
|
|
|
3214
3353
|
return s >= 60 ? Math.floor(s / 60) + 'dk' : s + 'sn';
|
|
3215
3354
|
}
|
|
3216
3355
|
|
|
3356
|
+
/* canlı süre sayacı: 0:43 · 2:05 · 1:02:15 biçimi (koşan ajan kartlarında) */
|
|
3357
|
+
function fmtElapsed(ms) {
|
|
3358
|
+
const s = Math.max(0, Math.floor(ms / 1000));
|
|
3359
|
+
const h = Math.floor(s / 3600);
|
|
3360
|
+
const m = Math.floor((s % 3600) / 60);
|
|
3361
|
+
const sec = s % 60;
|
|
3362
|
+
const p = (n) => String(n).padStart(2, '0');
|
|
3363
|
+
return h > 0 ? `${h}:${p(m)}:${p(sec)}` : `${m}:${p(sec)}`;
|
|
3364
|
+
}
|
|
3365
|
+
|
|
3366
|
+
/* koşan ajanların ⏱ sayaçları — saniyede bir yalnızca sayaç span'leri güncellenir
|
|
3367
|
+
(tüm rail yeniden çizilmez). Koşan kart kalmayınca interval kapanır. */
|
|
3368
|
+
let agentTimerInt = null;
|
|
3369
|
+
function ensureAgentTimers() {
|
|
3370
|
+
const any = !!document.querySelector('.agent-timer[data-start]');
|
|
3371
|
+
if (any && !agentTimerInt) {
|
|
3372
|
+
agentTimerInt = setInterval(() => {
|
|
3373
|
+
document.querySelectorAll('.agent-timer[data-start]').forEach((el) => {
|
|
3374
|
+
const t0 = Date.parse(el.dataset.start || '');
|
|
3375
|
+
if (t0) el.textContent = fmtElapsed(Date.now() - t0);
|
|
3376
|
+
});
|
|
3377
|
+
}, 1000);
|
|
3378
|
+
} else if (!any && agentTimerInt) {
|
|
3379
|
+
clearInterval(agentTimerInt);
|
|
3380
|
+
agentTimerInt = null;
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
function agentTimerHtml(startedAt) {
|
|
3384
|
+
const t0 = Date.parse(startedAt || '');
|
|
3385
|
+
const val = t0 ? fmtElapsed(Date.now() - t0) : '0:00';
|
|
3386
|
+
return `<span class="agent-timer" data-start="${escapeHtml(startedAt || '')}">⏱ ${val}</span>`;
|
|
3387
|
+
}
|
|
3388
|
+
|
|
3217
3389
|
/* sağ panel — paralel ajanların arka plan işleri */
|
|
3218
3390
|
function renderAgentRail() {
|
|
3219
3391
|
const list = els.railList;
|
|
@@ -3244,7 +3416,7 @@ function renderAgentRail() {
|
|
|
3244
3416
|
`<span class="ag-dot"></span>` +
|
|
3245
3417
|
`<span class="sess-title">${escapeHtml(j.title)}</span>` +
|
|
3246
3418
|
(j.code ? `<span class="sess-code" title="Oturum kodu">${escapeHtml(j.code)}</span>` : ``) +
|
|
3247
|
-
`<span class="rj-time">${j.status === 'running' ? when + ' · ' + _t('ag_working') : (agStText(j.status) === _t('ag_st_done') ? '\u2713' : (agStText(j.status) || j.status))}</span>` +
|
|
3419
|
+
`<span class="rj-time">${j.status === 'running' ? when + ' · ' + agentTimerHtml(j.startedAt) + ' · ' + _t('ag_working') : (agStText(j.status) === _t('ag_st_done') ? '\u2713' : (agStText(j.status) || j.status))}</span>` +
|
|
3248
3420
|
(j.status === 'running'
|
|
3249
3421
|
? `<button class="rj-cancel" title="${_t('ag_cancel')}">×</button>`
|
|
3250
3422
|
: `<button class="rj-cancel" title="${_t('ag_delete')}"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M10 11v6M14 11v6"/></svg></button>`) +
|
|
@@ -3289,6 +3461,7 @@ function renderAgentRail() {
|
|
|
3289
3461
|
/* açık sohbet dökümünü re-render sonrası GERİ GETİR (kapanma bug'ının fix'i) */
|
|
3290
3462
|
if (open && agentState.chatOpen.has(j.id)) maybeLoadRailChat(j.id);
|
|
3291
3463
|
}
|
|
3464
|
+
ensureAgentTimers();
|
|
3292
3465
|
}
|
|
3293
3466
|
|
|
3294
3467
|
/* re-render storm'da IPC fırtınası olmasın: döküm 2 sn'de bir tazelenir */
|
|
@@ -3374,7 +3547,7 @@ function renderAgentsPane() {
|
|
|
3374
3547
|
`<span class="ag-dot"></span>` +
|
|
3375
3548
|
`<span class="ag-title">${escapeHtml(j.title)}</span>` +
|
|
3376
3549
|
`<span class="ag-st">${agStText(j.status) || j.status}</span>` +
|
|
3377
|
-
`<span class="ag-time">${when}${j.endedAt ? ` · ${fmtAgo(j.endedAt)}` : ''}</span>` +
|
|
3550
|
+
`<span class="ag-time">${when}${j.status === 'running' ? ' · ' + agentTimerHtml(j.startedAt) : j.endedAt ? ` · ${fmtAgo(j.endedAt)}` : ''}</span>` +
|
|
3378
3551
|
(j.status === 'running'
|
|
3379
3552
|
? `<button class="ag-btn cancel" title="${_t('ag_cancel')}">${_t('ag_cancel')}</button>`
|
|
3380
3553
|
: ``) +
|
|
@@ -3412,16 +3585,8 @@ function renderAgentsPane() {
|
|
|
3412
3585
|
list.appendChild(card);
|
|
3413
3586
|
}
|
|
3414
3587
|
|
|
3415
|
-
/* canlı süre sayacı */
|
|
3416
|
-
|
|
3417
|
-
agentState.tick = setInterval(() => {
|
|
3418
|
-
if (setTab !== 'agents') { clearInterval(agentState.tick); return; }
|
|
3419
|
-
for (const el of document.querySelectorAll('.agent-card.st-running .ag-time')) {
|
|
3420
|
-
/* sadece saati yenile */
|
|
3421
|
-
const t = el.textContent.split(' ')[0];
|
|
3422
|
-
el.textContent = `${t} · ${_t('ag_working')}…`;
|
|
3423
|
-
}
|
|
3424
|
-
}, 5000);
|
|
3588
|
+
/* canlı süre sayacı — saniyede bir yalnız ⏱ sayaç span'leri güncellenir */
|
|
3589
|
+
ensureAgentTimers();
|
|
3425
3590
|
}
|
|
3426
3591
|
|
|
3427
3592
|
/* ---------------- events from engine ---------------- */
|
|
@@ -3522,6 +3687,7 @@ function onEvent(ev) {
|
|
|
3522
3687
|
case 'browser': {
|
|
3523
3688
|
/* visible=false → ajan tarayıcıyı GİZLİ kullanıyor: UI yer açmaz */
|
|
3524
3689
|
const shown = !!ev.open && ev.visible !== false;
|
|
3690
|
+
const wasShown = document.body.classList.contains('browser-open');
|
|
3525
3691
|
document.body.classList.toggle('browser-open', shown);
|
|
3526
3692
|
if (shown && ev.width) document.body.style.setProperty('--bw', ev.width + 'px');
|
|
3527
3693
|
els.browserBar.hidden = !shown;
|
|
@@ -3529,11 +3695,13 @@ function onEvent(ev) {
|
|
|
3529
3695
|
/* terminal de sağ dock'u kullanır — tarayıcı açılınca yerini bırak */
|
|
3530
3696
|
if (shown && termOpen) termSetOpen(false);
|
|
3531
3697
|
/* #19 tarayıcı açılınca paralel ajan konsolu (sağ panel) yerini bırakır;
|
|
3532
|
-
kapanınca önceki durumuna döner — istenirse railBtn ile elle açılır
|
|
3698
|
+
kapanınca önceki durumuna döner — istenirse railBtn ile elle açılır.
|
|
3699
|
+
GİZLİ ajan gezinmeleri (shown=false, wasShown=false) rail'e DOKUNMAZ —
|
|
3700
|
+
aksi halde paralel ajan konsolu kendi kendine kapanırdı */
|
|
3533
3701
|
if (shown) {
|
|
3534
3702
|
railPrefBeforeBrowser = !document.body.classList.contains('rail-hidden');
|
|
3535
3703
|
toggleRail(true);
|
|
3536
|
-
} else {
|
|
3704
|
+
} else if (wasShown) {
|
|
3537
3705
|
toggleRail(!railPrefBeforeBrowser);
|
|
3538
3706
|
}
|
|
3539
3707
|
/* IDE modunda tarayıcı açılır/kapanır/genişlik değişirse row yeniden bölünür —
|
|
@@ -3862,15 +4030,26 @@ async function openCronModal() {
|
|
|
3862
4030
|
|
|
3863
4031
|
/* ---------------- state / controls ---------------- */
|
|
3864
4032
|
|
|
4033
|
+
/* AKTİF BOTUN etkili model seçimi: müşteri botun kendi modeli varsa o,
|
|
4034
|
+
yoksa (ve admin bot daysa) global picker seçimi. */
|
|
4035
|
+
function effectiveModelSel() {
|
|
4036
|
+
const b = botsCache.find((x) => x.id === activeBotId);
|
|
4037
|
+
return b && !b.admin && b.model ? b.model : (state.activeModel && state.activeModel.sel) || '';
|
|
4038
|
+
}
|
|
4039
|
+
|
|
3865
4040
|
function applyState() {
|
|
3866
4041
|
if (!state) return;
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
4042
|
+
const botSel = activeBotId && botsCache.length ? effectiveModelSel() : (state.activeModel && state.activeModel.sel);
|
|
4043
|
+
const bm = botSel ? (state.models || []).find((x) => x.sel === botSel) : null;
|
|
4044
|
+
els.modelBtnLabel.textContent = bm
|
|
4045
|
+
? `${bm.providerName} · ${bm.model}`
|
|
4046
|
+
: state.activeModel
|
|
4047
|
+
? `${state.activeModel.providerName} · ${state.activeModel.model}`
|
|
4048
|
+
: 'Model seçilmedi';
|
|
3870
4049
|
els.thinkBtnLabel.innerHTML =
|
|
3871
|
-
'<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.5 2A2.5 2.5 0 0 0 7 4.5v.55A3.5 3.5 0 0 0 4.5 8.5c0 .74.23 1.43.62 2A3.5 3.5 0 0 0 4 13.5 3.5 3.5 0 0 0 7 16.95v.55A2.5 2.5 0 0 0 9.5 20a2.5 2.5 0 0 0 2.5-2.5v-13A2.5 2.5 0 0 0 9.5 2z"/><path d="M14.5 2A2.5 2.5 0 0 1 17 4.5v.55a3.5 3.5 0 0 1 2.5 3.45c0 .74-.23 1.43-.62 2a3.5 3.5 0 0 1
|
|
4050
|
+
'<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.5 2A2.5 2.5 0 0 0 7 4.5v.55A3.5 3.5 0 0 0 4.5 8.5c0 .74.23 1.43.62 2A3.5 3.5 0 0 0 4 13.5 3.5 3.5 0 0 0 7 16.95v.55A2.5 2.5 0 0 0 9.5 20a2.5 2.5 0 0 0 2.5-2.5v-13A2.5 2.5 0 0 0 9.5 2z"/><path d="M14.5 2A2.5 2.5 0 0 1 17 4.5v.55a3.5 3.5 0 0 1 2.5 3.45c0 .74-.23 1.43-.62 2a3.5 3.5 0 0 1-1.12 3 3.5 3.5 0 0 1-3 3.45v.55A2.5 2.5 0 0 1 14.5 20 2.5 2.5 0 0 1 12 17.5v-13A2.5 2.5 0 0 1 14.5 2z"/></svg>';
|
|
3872
4051
|
renderModelMenu();
|
|
3873
|
-
}
|
|
4052
|
+
}
|
|
3874
4053
|
|
|
3875
4054
|
/* düşünme (reasoning) seviyesi picker — gerçek API değerleri */
|
|
3876
4055
|
const THINK_UI_LEVELS = [
|
|
@@ -3927,7 +4106,7 @@ function renderModelMenu() {
|
|
|
3927
4106
|
els.modelList.innerHTML = '';
|
|
3928
4107
|
for (const m of list) {
|
|
3929
4108
|
const item = document.createElement('div');
|
|
3930
|
-
item.className = 'dd-item' + (
|
|
4109
|
+
item.className = 'dd-item' + (effectiveModelSel() && effectiveModelSel() === m.sel ? ' active' : '');
|
|
3931
4110
|
item.innerHTML =
|
|
3932
4111
|
`<span class="dn">${escapeHtml(m.providerName)}</span>` +
|
|
3933
4112
|
`<span class="dm">${escapeHtml(m.model)}</span>` +
|
|
@@ -3935,6 +4114,7 @@ function renderModelMenu() {
|
|
|
3935
4114
|
item.addEventListener('click', async () => {
|
|
3936
4115
|
state = await beast.setModel(m.sel);
|
|
3937
4116
|
closeModelMenu();
|
|
4117
|
+
await refreshBots().catch(() => {}); // bot modeli değiştiyse botsCache tazelensin
|
|
3938
4118
|
applyState();
|
|
3939
4119
|
});
|
|
3940
4120
|
els.modelList.appendChild(item);
|
|
@@ -4386,6 +4566,7 @@ async function init() {
|
|
|
4386
4566
|
|
|
4387
4567
|
beast.onWaEvent(onWaEvent);
|
|
4388
4568
|
beast.onTgEvent(onTgEvent);
|
|
4569
|
+
beast.onDcEvent(onDcEvent);
|
|
4389
4570
|
|
|
4390
4571
|
els.gearBtn.addEventListener('click', openSettings);
|
|
4391
4572
|
els.setClose.addEventListener('click', closeSettings);
|
|
@@ -4588,7 +4769,7 @@ async function init() {
|
|
|
4588
4769
|
if ($('#botOverviewBack')) $('#botOverviewBack').addEventListener('click', () => openBotPage(null));
|
|
4589
4770
|
if ($('#botChip')) $('#botChip').addEventListener('click', () => openBotPage(activeBotId));
|
|
4590
4771
|
/* kalıcı aktif bot: restart sonrası aynı botun UI'ı açılır */
|
|
4591
|
-
beast.botsActiveGet().then((r) => { activeBotId = (r && r.id) || 'beast'; updateBotChip(); renderBotCards(); }).catch(() => {});
|
|
4772
|
+
beast.botsActiveGet().then((r) => { activeBotId = (r && r.id) || 'beast'; updateBotChip(); renderBotCards(); applyState(); }).catch(() => {});
|
|
4592
4773
|
document.querySelectorAll('.btab').forEach((b) =>
|
|
4593
4774
|
b.addEventListener('click', () => {
|
|
4594
4775
|
document.querySelectorAll('.btab').forEach((x) => x.classList.remove('active'));
|
|
@@ -5101,7 +5282,7 @@ function ghCard(repo, isFav) {
|
|
|
5101
5282
|
</div>
|
|
5102
5283
|
${repo.description ? `<div class="gh-desc" title="${escapeHtml(repo.description)}">${escapeHtml(repo.description)}</div>` : ''}
|
|
5103
5284
|
<div class="gh-actions">
|
|
5104
|
-
<button class="gh-fav ${isFav ? 'on' : ''}" data-act="fav">${isFav ? '★
|
|
5285
|
+
<button class="gh-fav ${isFav ? 'on' : ''}" data-act="fav">${isFav ? '★ Favori' : '☆ Favorile'}</button>
|
|
5105
5286
|
<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>
|
|
5106
5287
|
<button data-act="copy">⧉ Kopyala</button>
|
|
5107
5288
|
</div>
|
|
@@ -5191,7 +5372,7 @@ $('#ghSearch').addEventListener('keydown', (e) => {
|
|
|
5191
5372
|
updateGhSub();
|
|
5192
5373
|
loadGhTrend();
|
|
5193
5374
|
});
|
|
5194
|
-
/* sol sekme: Trend
|
|
5375
|
+
/* sol sekme: Trend Repolar ⇄ Tüm Repolar (eşit bölünmüş, ortalanmış) */
|
|
5195
5376
|
document.querySelectorAll('.gh-tab').forEach((b) =>
|
|
5196
5377
|
b.addEventListener('click', () => {
|
|
5197
5378
|
ghState.ghTab = b.dataset.ghtab;
|