beast-agent 2.3.2 → 2.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "beast-agent",
3
3
  "productName": "Beast Agent",
4
- "version": "2.3.2",
4
+ "version": "2.3.3",
5
5
  "description": "Ultra-fast local agent shell for Windows.",
6
6
  "author": "algokodcom (AlgoKod)",
7
7
  "license": "MIT",
package/src/main.js CHANGED
@@ -3248,6 +3248,15 @@ app.whenReady().then(() => {
3248
3248
  waLog('STT aktif: ' + sttEngineLabel() + ' — yerel model kullanılmayacak');
3249
3249
  }
3250
3250
 
3251
+ /* EMBEDDING modeli (hafıza semantik arama) — açılışta otomatik indir */
3252
+ setTimeout(() => {
3253
+ try {
3254
+ require('./agent/mem0').search('beast', 'warmup')
3255
+ .then(() => waLog('embedding modeli hazır (all-MiniLM-L6-v2)'))
3256
+ .catch(() => {});
3257
+ } catch {}
3258
+ }, 20000);
3259
+
3251
3260
  // WhatsApp köprüsünü otomatik başlat (eşleme varsa direkt bağlanır)
3252
3261
  ensureWa().start().catch((e) => waLog('autostart failed: ' + (e && e.message)));
3253
3262
 
@@ -5825,6 +5834,90 @@ ipcMain.handle('stt:prefetch', () => {
5825
5834
  .catch((e) => waLog('STT prefetch hata: ' + String((e && e.message) || e)));
5826
5835
  return { ok: true, loading: true };
5827
5836
  });
5837
+
5838
+ /* KURULUM SEKMESİ: gerekli bileşenlerin durum taraması */
5839
+ ipcMain.handle('install:status', async () => {
5840
+ const rows = [];
5841
+ const pkgOk = (id) => { try { require.resolve(id); return true; } catch { return false; } };
5842
+ const scanModel = (rel) => {
5843
+ const dir = path.join(APP_DIR, 'models', ...rel.split('/'));
5844
+ let files = [];
5845
+ try {
5846
+ files = fs.readdirSync(dir, { recursive: true, withFileTypes: true })
5847
+ .filter((d) => d.isFile())
5848
+ .map((d) => path.join(d.parentPath || d.path, d.name));
5849
+ } catch {}
5850
+ let bytes = 0, tmp = 0, onnx = 0, hasCfg = false;
5851
+ for (const p of files) {
5852
+ try {
5853
+ bytes += fs.statSync(p).size;
5854
+ if (/\.tmp/i.test(p)) tmp++;
5855
+ else if (/\.onnx$/i.test(p)) onnx++;
5856
+ else if (/config\.json$/i.test(p)) hasCfg = true;
5857
+ } catch {}
5858
+ }
5859
+ return { files, bytes, tmp, onnx, hasCfg };
5860
+ };
5861
+
5862
+ /* 1) STT modeli */
5863
+ if (sttProvider() !== 'local') {
5864
+ rows.push({ id: 'stt', name: 'STT modeli — ' + sttModelName(), state: 'cloud', detail: 'bulut motoru — indirme gerekmez' });
5865
+ } else {
5866
+ const s = scanModel(sttModelName());
5867
+ let state;
5868
+ if (sttPipeline) state = 'ok';
5869
+ else if (sttLoading) state = 'loading';
5870
+ else if (s.hasCfg && s.onnx >= 2 && s.tmp === 0) state = 'downloaded';
5871
+ else if (s.files.length) state = 'partial';
5872
+ else state = 'missing';
5873
+ rows.push({ id: 'stt', name: 'STT modeli — whisper-large-v3-turbo', state, detail: sttEngineLabel(), mb: Math.round(s.bytes / 1048576) });
5874
+ }
5875
+
5876
+ /* 2) Embedding modeli (hafıza semantik arama) */
5877
+ {
5878
+ const s = scanModel('Xenova/all-MiniLM-L6-v2');
5879
+ const state = s.hasCfg && s.onnx >= 1 && s.tmp === 0 ? 'ok' : (s.files.length ? 'partial' : 'missing');
5880
+ rows.push({ id: 'emb', name: 'Embedding modeli — all-MiniLM-L6-v2', state, detail: 'hafıza semantik arama', mb: Math.round(s.bytes / 1048576) });
5881
+ }
5882
+
5883
+ /* 3) ffmpeg */
5884
+ let ffOk = false;
5885
+ try { const p = require('ffmpeg-static'); ffOk = !!p && fs.existsSync(p); } catch {}
5886
+ rows.push({ id: 'ffmpeg', name: 'ffmpeg — ses/video dönüşüm', state: ffOk ? 'ok' : 'missing', detail: ffOk ? 'kurulu' : 'npm paketi eksik' });
5887
+
5888
+ /* 4) çalışma zamanı npm paketleri */
5889
+ rows.push({ id: 'hf', name: 'Transformers.js — STT çalışma zamanı', state: pkgOk('@huggingface/transformers') ? 'ok' : 'missing', detail: 'npm paketi' });
5890
+ rows.push({ id: 'ort', name: 'ONNX Runtime — model motoru', state: pkgOk('onnxruntime-node') ? 'ok' : 'missing', detail: 'npm paketi' });
5891
+
5892
+ /* 5) OCR */
5893
+ rows.push({ id: 'ocr', name: 'OCR — Tesseract (ekran okuma)', state: pkgOk('tesseract.js') ? 'ok' : 'missing', detail: pkgOk('tesseract.js') ? 'kurulu — dil verisi ilk kullanımda iner' : 'npm paketi eksik' });
5894
+
5895
+ /* 6) Python (opsiyonel — betikler) */
5896
+ let pyVer = '';
5897
+ for (const cmd of ['python -c "import sys;print(sys.version.split()[0])"', 'py -3 -c "import sys;print(sys.version.split()[0])"']) {
5898
+ try {
5899
+ pyVer = String(require('child_process').execSync(cmd, { timeout: 4000, stdio: 'pipe', encoding: 'utf8' })).trim();
5900
+ if (pyVer) break;
5901
+ } catch {}
5902
+ }
5903
+ rows.push({ id: 'python', name: 'Python — betikler / web arama', state: pyVer ? 'ok' : 'optional', detail: pyVer ? 'v' + pyVer : 'sistemde bulunamadı — opsiyonel' });
5904
+
5905
+ /* 7) Edge TTS (bulut) */
5906
+ rows.push({ id: 'edge', name: 'Edge TTS — seslendirme', state: 'cloud', detail: 'bulut — kurulum gerekmez' });
5907
+
5908
+ return rows;
5909
+ });
5910
+
5911
+ /* embedding modelini şimdi indir (mem0 arama yolu ısıtılır) */
5912
+ ipcMain.handle('embed:prefetch', () => {
5913
+ try {
5914
+ const mem0 = require('./agent/mem0');
5915
+ mem0.search('beast', 'warmup')
5916
+ .then(() => waLog('embedding modeli hazır'))
5917
+ .catch(() => {});
5918
+ } catch {}
5919
+ return { ok: true, loading: true };
5920
+ });
5828
5921
  ipcMain.handle('stt:lang:set', (_e, lang) => {
5829
5922
  const v = ['auto', 'tr', 'en'].includes(String(lang)) ? String(lang) : 'tr';
5830
5923
  settings.sttLang = v;
package/src/preload.js CHANGED
@@ -55,6 +55,8 @@ contextBridge.exposeInMainWorld('beast', {
55
55
  sttLangGet: () => ipcRenderer.invoke('stt:lang:get'),
56
56
  sttStatus: () => ipcRenderer.invoke('stt:status'),
57
57
  sttPrefetchNow: () => ipcRenderer.invoke('stt:prefetch'),
58
+ installStatus: () => ipcRenderer.invoke('install:status'),
59
+ embedPrefetch: () => ipcRenderer.invoke('embed:prefetch'),
58
60
  sttLangSet: (lang) => ipcRenderer.invoke('stt:lang:set', lang),
59
61
  updateStatus: () => ipcRenderer.invoke('update:status'),
60
62
  updateCheck: () => ipcRenderer.invoke('update:check'),
@@ -69,7 +69,8 @@
69
69
  tab_notes: 'Oturum Notları',
70
70
  tab_history: 'Oturum Geçmişi',
71
71
  tab_agents: 'Paralel Ajanlar',
72
- tab_tts: 'Sesli Yanıt',
72
+ tab_tts: 'Sesli Yanıt',
73
+ tab_install: 'Kurulum',
73
74
  tab_email: 'E-posta',
74
75
  tab_integrations: 'Entegrasyonlar',
75
76
  tab_websearch: 'Web Arama',
@@ -645,7 +646,8 @@
645
646
  tab_notes: 'Session Notes',
646
647
  tab_history: 'Session History',
647
648
  tab_agents: 'Parallel Agents',
648
- tab_tts: 'Voice Reply',
649
+ tab_tts: 'Voice Reply',
650
+ tab_install: 'Setup',
649
651
  tab_email: 'E-mail',
650
652
  tab_integrations: 'Integrations',
651
653
  tab_websearch: 'Web Search',
@@ -233,6 +233,7 @@
233
233
  <button class="tab" data-tab="skills" data-i18n="tab_skills">Skills</button>
234
234
  <button class="tab" data-tab="agents" data-i18n="tab_agents">Paralel Ajanlar</button>
235
235
  <button class="tab" data-tab="tts" data-i18n="tab_tts">Sesli Yanıt</button>
236
+ <button class="tab" data-tab="install" data-i18n="tab_install">Kurulum</button>
236
237
  <button class="tab" data-tab="email" data-i18n="tab_email">E-posta</button>
237
238
  <button class="tab" data-tab="integrations" data-i18n="tab_integrations">Entegrasyonlar</button>
238
239
  <button class="tab" data-tab="websearch" data-i18n="tab_websearch">Web Arama</button>
@@ -257,6 +258,7 @@
257
258
  <div id="tab-skills" class="pane" hidden></div>
258
259
  <div id="tab-agents" class="pane" hidden></div>
259
260
  <div id="tab-tts" class="pane" hidden></div>
261
+ <div id="tab-install" class="pane" hidden></div>
260
262
  <div id="tab-email" class="pane" hidden></div>
261
263
  <div id="tab-integrations" class="pane" hidden></div>
262
264
  <div id="tab-websearch" class="pane" hidden></div>
@@ -1060,6 +1060,7 @@ async function renderActiveSettingsTab() {
1060
1060
  case 'fallout': await refreshFalloutPane(); break;
1061
1061
  case 'skills': await renderSkillsPane(); break;
1062
1062
  case 'tts': await renderTtsPane(); break;
1063
+ case 'install': await renderInstallPane(); break;
1063
1064
  case 'email': await renderEmailPane(); break;
1064
1065
  case 'integrations': await renderIntegrationsPane(); break;
1065
1066
  case 'websearch': await renderWebSearchPane(); break;
@@ -1150,13 +1151,14 @@ function switchTab(name) {
1150
1151
  document.querySelectorAll('#setTabs .tab').forEach((b) =>
1151
1152
  b.classList.toggle('active', b.dataset.tab === name)
1152
1153
  );
1153
- for (const p of ['lang', 'provider', 'fallout', 'skills', 'agents', 'tts', 'email', 'integrations', 'websearch', 'mcp', 'events', 'cron', 'usage', 'logs', 'dash', 'sec', 'update']) {
1154
+ for (const p of ['lang', 'provider', 'fallout', 'skills', 'agents', 'tts', 'install', 'email', 'integrations', 'websearch', 'mcp', 'events', 'cron', 'usage', 'logs', 'dash', 'sec', 'update']) {
1154
1155
  const el = $('#tab-' + p);
1155
1156
  if (el) el.hidden = p !== name; // guard: eksik pane tüm sekmeleri kilitlemesin
1156
1157
  }
1157
1158
  if (name === 'lang') renderLangPane();
1158
1159
  if (name === 'cron') openCron();
1159
1160
  if (name === 'usage') renderUsagePane();
1161
+ if (name === 'install') renderInstallPane();
1160
1162
  if (name === 'events') renderEventsPane();
1161
1163
  if (name === 'logs') renderLogPane();
1162
1164
  if (name === 'dash') renderDashboardPane();
@@ -2097,8 +2099,76 @@ function ttsFlushTail() {
2097
2099
  if (rest) ttsEnqueueSentence(rest);
2098
2100
  else ttsKick();
2099
2101
  }
2100
- async function renderTtsPane() {
2101
- const pane = $('#tab-tts');
2102
+ /* ---------------- KURULUM SEKMESİ: bileşenler OTOMATİK kurulur ----------------
2103
+ Eksik/kısmen inmiş bileşen sekme açılınca kendiliğinden indirilir; kullanıcı
2104
+ hiçbir düğmeye basmaz. Durum canlı güncellenir (4 sn'de bir). */
2105
+ async function renderInstallPane() {
2106
+ const pane = $('#tab-install');
2107
+ if (!pane) return;
2108
+ pane.innerHTML =
2109
+ '<h2>Kurulum</h2><div class="sub">Gerekli bileşenler otomatik indirilir ve kurulur — eksik varsa aşağıda İNİYOR olarak görürsün.</div>' +
2110
+ '<div id="instRows" style="margin-top:10px">Taranıyor…</div>';
2111
+
2112
+ const autoStarted = new Set(); // bu pane oturumunda otomatik başlatılanlar
2113
+ let refreshTimer = null;
2114
+
2115
+ const badge = (st) => {
2116
+ const map = {
2117
+ ok: ['KURULU', 'var(--ok)'],
2118
+ downloaded: ['İNDİRİLDİ', 'var(--ok)'],
2119
+ loading: ['İNİYOR…', '#d9a441'],
2120
+ partial: ['İNİYOR… (devam)', '#d9a441'],
2121
+ missing: ['İNDİRİLİYOR…', '#d9a441'],
2122
+ cloud: ['BULUT', 'var(--muted)'],
2123
+ optional: ['OPSİYONEL', 'var(--muted)'],
2124
+ };
2125
+ const [txt, color] = map[st] || [st, 'var(--muted)'];
2126
+ return '<span style="color:' + color + ';font-weight:700;font-size:11px;flex:none">' + txt + '</span>';
2127
+ };
2128
+
2129
+ /* eksik bileşenleri OTOMATİK başlat (bileşen başına bir kez) */
2130
+ const autoStart = (rows) => {
2131
+ for (const r of rows) {
2132
+ if (autoStarted.has(r.id)) continue;
2133
+ if (r.id === 'stt' && ['missing', 'partial', 'loading'].includes(r.state)) {
2134
+ autoStarted.add('stt');
2135
+ beast.sttPrefetchNow().catch(() => {});
2136
+ }
2137
+ if (r.id === 'emb' && ['missing', 'partial'].includes(r.state)) {
2138
+ autoStarted.add('emb');
2139
+ beast.embedPrefetch().catch(() => {});
2140
+ }
2141
+ }
2142
+ };
2143
+
2144
+ const render = (rows) => {
2145
+ const el = $('#instRows');
2146
+ if (!el) return;
2147
+ if (!rows || !rows.length) { el.innerHTML = '<div class="sub">Durum alınamadı</div>'; return; }
2148
+ autoStart(rows);
2149
+ el.innerHTML = rows.map((r) => (
2150
+ '<div style="display:flex;align-items:center;gap:10px;padding:9px 0;border-bottom:1px solid var(--border)">' +
2151
+ '<div style="flex:1;min-width:0">' +
2152
+ '<div style="font-size:13px">' + escapeHtml(r.name) + '</div>' +
2153
+ '<div class="sub" style="font-size:11px">' + escapeHtml(r.detail || '') + (r.mb ? ' · ' + r.mb + ' MB' : '') + '</div>' +
2154
+ '</div>' +
2155
+ badge(r.state) +
2156
+ '</div>'
2157
+ )).join('');
2158
+ };
2159
+
2160
+ const refresh = async () => {
2161
+ if (pane.hidden) return;
2162
+ const rows = await beast.installStatus().catch(() => []);
2163
+ render(rows);
2164
+ };
2165
+
2166
+ if (refreshTimer) clearInterval(refreshTimer);
2167
+ await refresh();
2168
+ refreshTimer = setInterval(refresh, 4000);
2169
+ }
2170
+
2171
+ async function renderTtsPane() { const pane = $('#tab-tts');
2102
2172
  if (!pane) return;
2103
2173
  /* STT DURUMU: model indirildi mi / iniyor mu / hangi motor */
2104
2174
  let stt = null;