beast-agent 0.16.1 → 0.18.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/bin/beast-agent.js +27 -6
- package/package.json +1 -1
- package/src/main.js +170 -33
- package/src/preload.js +3 -1
- package/src/renderer/i18n.js +4 -2
- package/src/renderer/index.html +2 -0
- package/src/renderer/renderer.js +20 -12
- package/src/renderer/style.css +27 -5
package/bin/beast-agent.js
CHANGED
|
@@ -8,13 +8,34 @@
|
|
|
8
8
|
const { spawn, spawnSync } = require('child_process');
|
|
9
9
|
const path = require('path');
|
|
10
10
|
|
|
11
|
-
/* güncelleme modu:
|
|
11
|
+
/* güncelleme modu: çalışan Beast'i kapat (dosya kilidi EBUSY vermesin) → npm güncelle → yeniden başlat */
|
|
12
12
|
if (process.argv[2] === 'update') {
|
|
13
|
-
const
|
|
14
|
-
console.log(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
const isWin = process.platform === 'win32';
|
|
14
|
+
console.log('\u27F3 beast-agent g\u00FCncelleniyor\u2026');
|
|
15
|
+
if (isWin) {
|
|
16
|
+
try {
|
|
17
|
+
spawnSync('powershell.exe', ['-NoProfile', '-Command',
|
|
18
|
+
"Get-Process electron -ErrorAction SilentlyContinue | Where-Object { $_.Path -like '*node_modules*beast-agent*' } | Stop-Process -Force"],
|
|
19
|
+
{ stdio: 'ignore' });
|
|
20
|
+
console.log('\u2022 \u00E7al\u0131\u015Fan Beast kapat\u0131ld\u0131 (varsa)');
|
|
21
|
+
spawnSync('powershell.exe', ['-NoProfile', '-Command', 'Start-Sleep -Seconds 2'], { stdio: 'ignore' });
|
|
22
|
+
} catch {}
|
|
23
|
+
} else {
|
|
24
|
+
try { spawnSync('pkill', ['-f', 'node_modules/beast-agent'], { stdio: 'ignore' }); } catch {}
|
|
25
|
+
}
|
|
26
|
+
const r = spawnSync('npm', ['install', '-g', 'beast-agent@latest'], { stdio: 'inherit', shell: isWin });
|
|
27
|
+
if (r.status !== 0) {
|
|
28
|
+
console.log('\n\u2717 g\u00FCncelleme ba\u015Far\u0131s\u0131z \u2014 elle: npm install -g beast-agent@latest');
|
|
29
|
+
process.exit(r.status || 1);
|
|
30
|
+
}
|
|
31
|
+
console.log('\n\u2713 beast-agent g\u00FCncellendi \u2014 uygulama ba\u015Flat\u0131l\u0131yor\u2026');
|
|
32
|
+
try {
|
|
33
|
+
const electron = require('electron');
|
|
34
|
+
if (typeof electron === 'string') {
|
|
35
|
+
spawn(electron, [path.resolve(__dirname, '..')], { stdio: 'ignore', detached: true }).unref();
|
|
36
|
+
}
|
|
37
|
+
} catch {}
|
|
38
|
+
process.exit(0);
|
|
18
39
|
}
|
|
19
40
|
|
|
20
41
|
const electron = require('electron');
|
package/package.json
CHANGED
package/src/main.js
CHANGED
|
@@ -30,6 +30,33 @@ function isNpmMode() {
|
|
|
30
30
|
return !app.isPackaged && /node_modules[\\/]beast-agent/i.test(String(app.getAppPath()));
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/* npm registry'den en son sürüm (10 dk cache) — Update sekmesi + otomatik kontrol */
|
|
34
|
+
let npmLatestCache = { version: null, at: 0 };
|
|
35
|
+
|
|
36
|
+
function isNewerVersion(a, b) {
|
|
37
|
+
const pa = String(a).split('.').map(Number);
|
|
38
|
+
const pb = String(b).split('.').map(Number);
|
|
39
|
+
for (let i = 0; i < 3; i++) {
|
|
40
|
+
const d = (pa[i] || 0) - (pb[i] || 0);
|
|
41
|
+
if (d) return d > 0;
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function getNpmLatest(force) {
|
|
47
|
+
const now = Date.now();
|
|
48
|
+
if (!force && npmLatestCache.version && now - npmLatestCache.at < 10 * 60 * 1000) return npmLatestCache.version;
|
|
49
|
+
try {
|
|
50
|
+
const res = await fetch('https://registry.npmjs.org/beast-agent/latest', { signal: AbortSignal.timeout(15000) });
|
|
51
|
+
if (res.ok) {
|
|
52
|
+
const j = await res.json();
|
|
53
|
+
const v = String(j.version || '').trim();
|
|
54
|
+
if (v) npmLatestCache = { version: v, at: now };
|
|
55
|
+
}
|
|
56
|
+
} catch {}
|
|
57
|
+
return npmLatestCache.version;
|
|
58
|
+
}
|
|
59
|
+
|
|
33
60
|
function emitUpdateEvent() {
|
|
34
61
|
try {
|
|
35
62
|
if (win && !win.isDestroyed()) {
|
|
@@ -99,6 +126,24 @@ function startAutoUpdater() {
|
|
|
99
126
|
}
|
|
100
127
|
} catch {}
|
|
101
128
|
}
|
|
129
|
+
|
|
130
|
+
/* npm kurulumu için otomatik sürüm kontrolü (registry üzerinden, 6 saatte bir) */
|
|
131
|
+
function startNpmUpdateWatch() {
|
|
132
|
+
if (!isNpmMode() || settings.autoCheckUpdate === false) return;
|
|
133
|
+
const check = async () => {
|
|
134
|
+
try {
|
|
135
|
+
const v = await getNpmLatest();
|
|
136
|
+
if (v && isNewerVersion(v, app.getVersion()) && !updateState.available) {
|
|
137
|
+
updateState.available = true;
|
|
138
|
+
updateState.version = v;
|
|
139
|
+
emitUpdateEvent();
|
|
140
|
+
log.info('main', `npm: yeni sürüm var ${v} (mevcut ${app.getVersion()})`);
|
|
141
|
+
}
|
|
142
|
+
} catch {}
|
|
143
|
+
};
|
|
144
|
+
check();
|
|
145
|
+
setInterval(check, 6 * 60 * 60 * 1000);
|
|
146
|
+
}
|
|
102
147
|
const { htmlToText, setExaKey, setTinyfishKey } = require('./agent/tools');
|
|
103
148
|
const { waToolLine } = require('./agent/watext');
|
|
104
149
|
|
|
@@ -460,12 +505,17 @@ function decodeAudioToPcm16k(buf) {
|
|
|
460
505
|
});
|
|
461
506
|
}
|
|
462
507
|
|
|
463
|
-
async function transcribeAudio(buf /*
|
|
508
|
+
async function transcribeAudio(buf, langOverride /* 'tr' | 'en' | 'auto' */) {
|
|
464
509
|
try {
|
|
465
510
|
const audio = await decodeAudioToPcm16k(buf);
|
|
466
511
|
if (!audio || !audio.length) return null;
|
|
467
512
|
const asr = await ensureStt();
|
|
468
|
-
|
|
513
|
+
/* dil: arayüz diline bağlı — UI Türkçe ise Türkçe, İngilizce ise İngilizce algılar */
|
|
514
|
+
const lang = langOverride || settings.sttLang || 'tr';
|
|
515
|
+
const opts = { task: 'transcribe', chunk_length_s: 30, stride_length_s: 5 };
|
|
516
|
+
if (lang === 'en') opts.language = 'english';
|
|
517
|
+
else if (lang === 'tr') opts.language = 'turkish';
|
|
518
|
+
const out = await asr(audio, opts);
|
|
469
519
|
return String((out && out.text) || '').trim() || null;
|
|
470
520
|
} catch (e) {
|
|
471
521
|
waLog('stt hata: ' + String((e && e.message) || e));
|
|
@@ -907,9 +957,11 @@ async function tryWaSlash(jid, rawText, senderNum) {
|
|
|
907
957
|
? `*${cmd === 'deny' ? 'Reddedildi' : 'Onaylandı'}:* ${r.tool}${always ? ' — bu araç için bir daha sorulmayacak' : ''}`
|
|
908
958
|
: 'Bekleyen onay yok.';
|
|
909
959
|
} else if (cmd === 'update') {
|
|
910
|
-
/* /update — sürüm kontrol; /update now — indirileni kur */
|
|
960
|
+
/* /update — sürüm kontrol; /update now — indirileni kur (npm modunda kendini günceller) */
|
|
911
961
|
if (String(arg || '').toLowerCase() === 'now') {
|
|
912
|
-
if (
|
|
962
|
+
if (isNpmMode()) {
|
|
963
|
+
npmUpdateNow(async (text) => { out = text; });
|
|
964
|
+
} else if (updateState.downloaded && autoUpdater) {
|
|
913
965
|
out = `*v${updateState.version} kuruluyor* — uygulama yeniden başlayacak.`;
|
|
914
966
|
setTimeout(() => { try { autoUpdater.quitAndInstall(); } catch {} }, 1200);
|
|
915
967
|
} else {
|
|
@@ -1740,6 +1792,7 @@ app.whenReady().then(() => {
|
|
|
1740
1792
|
maybeRunWhereWasI();
|
|
1741
1793
|
falloutResume();
|
|
1742
1794
|
startAutoUpdater(); // #3 sessiz güncelleme
|
|
1795
|
+
startNpmUpdateWatch(); // npm kurulumunda registry üzerinden otomatik sürüm kontrolü
|
|
1743
1796
|
|
|
1744
1797
|
// #12 STT prefetch: whisper modelini arka planda hazırla (ilk sesli mesajda bekleme olmasın)
|
|
1745
1798
|
if (settings.sttPrefetch !== false) {
|
|
@@ -2614,7 +2667,9 @@ ipcMain.handle('agent:send', (_e, { sessionId, text }) => {
|
|
|
2614
2667
|
const a = t.slice(7).trim().toLowerCase();
|
|
2615
2668
|
updateReplies.sids.add(String(sessionId || ''));
|
|
2616
2669
|
if (a === 'now') {
|
|
2617
|
-
if (
|
|
2670
|
+
if (isNpmMode()) {
|
|
2671
|
+
npmUpdateNow((text) => desktopEcho(sessionId, t, text));
|
|
2672
|
+
} else if (updateState.downloaded && autoUpdater) {
|
|
2618
2673
|
desktopEcho(sessionId, t, `*v${updateState.version} kuruluyor* — uygulama yeniden başlayacak.`);
|
|
2619
2674
|
setTimeout(() => { try { autoUpdater.quitAndInstall(); } catch {} }, 1200);
|
|
2620
2675
|
} else {
|
|
@@ -3135,29 +3190,75 @@ ipcMain.handle('sec:set', (_e, cfg) => {
|
|
|
3135
3190
|
ipcMain.handle('approval:respond', (_e, { id, ok, always }) => resolveApproval(id, ok, always));
|
|
3136
3191
|
|
|
3137
3192
|
/* ---------------- #Update IPC ---------------- */
|
|
3138
|
-
ipcMain.handle('update:status', () =>
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
ipcMain.handle('update:check', async (_e, viaCommand) => {
|
|
3148
|
-
if (isNpmMode()) return { ok: false, npm: true, error: 'npm kurulumu — güncelleme: beast-agent update' };
|
|
3149
|
-
if (!autoUpdater) return { ok: false, error: 'updater kullanılamıyor (taşınabilir/geliştirme modu)' };
|
|
3193
|
+
ipcMain.handle('update:status', async () => {
|
|
3194
|
+
const st = {
|
|
3195
|
+
current: app.getVersion(),
|
|
3196
|
+
packaged: app.isPackaged,
|
|
3197
|
+
npm: isNpmMode(),
|
|
3198
|
+
...updateState,
|
|
3199
|
+
autoCheck: settings.autoCheckUpdate !== false,
|
|
3200
|
+
autoDownload: settings.autoDownloadUpdate !== false,
|
|
3201
|
+
};
|
|
3150
3202
|
try {
|
|
3151
|
-
|
|
3152
|
-
const v =
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3203
|
+
/* npm registry'den güncel sürüm — updater ne yaparsa yapsın "En son sürüm" kartı dolu olsun */
|
|
3204
|
+
const v = await getNpmLatest();
|
|
3205
|
+
if (v) {
|
|
3206
|
+
st.npmLatest = v;
|
|
3207
|
+
if (!st.version) st.version = v;
|
|
3208
|
+
if (isNewerVersion(v, app.getVersion())) st.available = true;
|
|
3209
|
+
}
|
|
3210
|
+
} catch {}
|
|
3211
|
+
return st;
|
|
3212
|
+
});
|
|
3213
|
+
|
|
3214
|
+
ipcMain.handle('update:check', async () => {
|
|
3215
|
+
const current = app.getVersion();
|
|
3216
|
+
/* her modda npm registry'den taze kontrol (cache bypass) */
|
|
3217
|
+
const v = await getNpmLatest(true);
|
|
3218
|
+
const out = { ok: true, npm: isNpmMode(), version: v || undefined, available: v ? isNewerVersion(v, current) : false };
|
|
3219
|
+
if (v) {
|
|
3220
|
+
if (!updateState.version || isNewerVersion(v, updateState.version)) updateState.version = v;
|
|
3221
|
+
if (isNewerVersion(v, current)) updateState.available = true;
|
|
3156
3222
|
}
|
|
3223
|
+
/* packaged + updater: GitHub Releases kontrolü de çalışsın */
|
|
3224
|
+
if (!isNpmMode() && autoUpdater) {
|
|
3225
|
+
try {
|
|
3226
|
+
const r = await autoUpdater.checkForUpdates();
|
|
3227
|
+
const uv = r && r.update && r.update.version;
|
|
3228
|
+
if (uv) { out.version = uv; out.available = uv !== current; }
|
|
3229
|
+
} catch (e) {
|
|
3230
|
+
if (!v) return { ok: false, error: String((e && e.message) || e) };
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
emitUpdateEvent();
|
|
3234
|
+
return out;
|
|
3157
3235
|
});
|
|
3158
3236
|
|
|
3237
|
+
/* npm kurulumunda KENDİ KENDİNİ GÜNCELLEME:
|
|
3238
|
+
detached helper bırakır (uygulama çıkınca npm install + yeniden başlatma), sonra app.quit() */
|
|
3239
|
+
function npmSelfUpdate() {
|
|
3240
|
+
try {
|
|
3241
|
+
const electronExe = process.execPath;
|
|
3242
|
+
const appPath = app.getAppPath();
|
|
3243
|
+
if (process.platform === 'win32') {
|
|
3244
|
+
const ps =
|
|
3245
|
+
'Start-Sleep -Seconds 3;' +
|
|
3246
|
+
'npm install -g beast-agent@latest;' +
|
|
3247
|
+
'Start-Sleep -Seconds 1;' +
|
|
3248
|
+
`Start-Process -FilePath '${electronExe}' -ArgumentList '\"${appPath}\"'`;
|
|
3249
|
+
spawn('powershell.exe', ['-NoProfile', '-Command', ps], { detached: true, stdio: 'ignore', windowsHide: true }).unref();
|
|
3250
|
+
} else {
|
|
3251
|
+
const sh = `sleep 3; npm install -g beast-agent@latest; sleep 1; '${electronExe}' '${appPath}' &`;
|
|
3252
|
+
spawn('sh', ['-c', sh], { detached: true, stdio: 'ignore' }).unref();
|
|
3253
|
+
}
|
|
3254
|
+
log.info('main', 'npm self-update: helper bırakıldı, uygulama kapatılıyor');
|
|
3255
|
+
} catch {}
|
|
3256
|
+
setTimeout(() => { try { app.quit(); } catch {} }, 400);
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3159
3259
|
ipcMain.handle('update:install', () => {
|
|
3160
|
-
if (isNpmMode()
|
|
3260
|
+
if (isNpmMode()) { npmSelfUpdate(); return { ok: true, npm: true }; }
|
|
3261
|
+
if (!autoUpdater) return { ok: false, error: 'updater kullanılamıyor' };
|
|
3161
3262
|
if (!updateState.downloaded) return { ok: false, error: 'indirilmiş sürüm yok — önce /update' };
|
|
3162
3263
|
try { autoUpdater.quitAndInstall(); return { ok: true }; } catch (e) {
|
|
3163
3264
|
return { ok: false, error: String((e && e.message) || e) };
|
|
@@ -3175,33 +3276,69 @@ ipcMain.handle('update:setAuto', (_e, cfg) => {
|
|
|
3175
3276
|
});
|
|
3176
3277
|
|
|
3177
3278
|
/* /update komutu (masaüstü + WA): hedefi kaydet, kontrol başlat */
|
|
3279
|
+
/* npm modunda güncelle-şimdi: sürüm kontrolü + numaralarıyla bildir + kendi kendini güncelle */
|
|
3280
|
+
function npmUpdateNow(reply /* fn(text) */) {
|
|
3281
|
+
const current = app.getVersion();
|
|
3282
|
+
getNpmLatest(true).then((v) => {
|
|
3283
|
+
if (v && isNewerVersion(v, current)) {
|
|
3284
|
+
updateState.available = true;
|
|
3285
|
+
updateState.version = v;
|
|
3286
|
+
reply(`🔄 *Güncelleniyor*\nMevcut: v${current}\nYeni: v${v}\nKapanıp yeniden açılıyorum…`);
|
|
3287
|
+
setTimeout(() => npmSelfUpdate(), 1500);
|
|
3288
|
+
} else {
|
|
3289
|
+
reply(`✅ *Güncelsin* — v${current} zaten en son sürüm.`);
|
|
3290
|
+
}
|
|
3291
|
+
}).catch(() => reply('Sürüm kontrol edilemedi — bağlantıyı kontrol et.'));
|
|
3292
|
+
}
|
|
3293
|
+
|
|
3178
3294
|
async function runUpdateCommand(reply /* fn(text) */) {
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
return;
|
|
3182
|
-
}
|
|
3295
|
+
const current = app.getVersion();
|
|
3296
|
+
if (isNpmMode()) return npmUpdateNow(reply);
|
|
3183
3297
|
if (!autoUpdater) {
|
|
3184
|
-
reply('Updater bu modda kullanılamıyor
|
|
3298
|
+
reply('Updater bu modda kullanılamıyor. Yeni sürüm: github.com/algokodcom/beast-agent/releases');
|
|
3185
3299
|
return;
|
|
3186
3300
|
}
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3301
|
+
/* önce npm registry'den sürüm bilgisi — kullanıcıya numaraları söyle */
|
|
3302
|
+
const v = await getNpmLatest(true);
|
|
3303
|
+
if (v && isNewerVersion(v, current)) {
|
|
3304
|
+
updateState.available = true;
|
|
3305
|
+
updateState.version = v;
|
|
3306
|
+
emitUpdateEvent();
|
|
3307
|
+
reply(`🔄 *Yeni sürüm bulundu*\nMevcut: v${current}\nYeni: v${v}\nİndiriliyor… (kurulum için: /update now)`);
|
|
3308
|
+
try { await autoUpdater.checkForUpdates(); } catch (e) {
|
|
3309
|
+
reply('İndirme başlatılamadı: ' + String((e && e.message) || e));
|
|
3310
|
+
}
|
|
3311
|
+
} else if (v) {
|
|
3312
|
+
reply(`✅ *Güncelsin* — v${current} en son sürüm.`);
|
|
3313
|
+
} else {
|
|
3314
|
+
reply(`🔍 Kontrol ediliyor (mevcut sürüm v${current})…`);
|
|
3315
|
+
try { await autoUpdater.checkForUpdates(); } catch (e) {
|
|
3316
|
+
reply('Kontrol başarısız: ' + String((e && e.message) || e));
|
|
3317
|
+
}
|
|
3190
3318
|
}
|
|
3191
3319
|
}
|
|
3192
3320
|
|
|
3193
3321
|
/* #STT: sohbet mikrofonu — MediaRecorder sesini (webm/opus) yerel whisper'a çevir */
|
|
3194
|
-
|
|
3322
|
+
/* #STT: sohbet mikrofonu — MediaRecorder sesini (webm/opus) yerel whisper'a çevir */
|
|
3323
|
+
ipcMain.handle('stt:transcribe', async (_e, b64, lang) => {
|
|
3195
3324
|
try {
|
|
3196
3325
|
const buf = Buffer.from(String(b64 || '').split(',').pop() || '', 'base64');
|
|
3197
3326
|
if (!buf.length) return { ok: false, error: 'boş ses kaydı' };
|
|
3198
|
-
const text = await transcribeAudio(buf);
|
|
3327
|
+
const text = await transcribeAudio(buf, lang === 'en' || lang === 'auto' ? lang : undefined);
|
|
3199
3328
|
return text ? { ok: true, text } : { ok: false, error: 'konuşma algılanamadı' };
|
|
3200
3329
|
} catch (e) {
|
|
3201
3330
|
return { ok: false, error: String((e && e.message) || e) };
|
|
3202
3331
|
}
|
|
3203
3332
|
});
|
|
3204
3333
|
|
|
3334
|
+
ipcMain.handle('stt:lang:get', () => settings.sttLang || 'tr');
|
|
3335
|
+
ipcMain.handle('stt:lang:set', (_e, lang) => {
|
|
3336
|
+
const v = ['auto', 'tr', 'en'].includes(String(lang)) ? String(lang) : 'tr';
|
|
3337
|
+
settings.sttLang = v;
|
|
3338
|
+
saveSettings();
|
|
3339
|
+
return v;
|
|
3340
|
+
});
|
|
3341
|
+
|
|
3205
3342
|
ipcMain.handle('limits:get', () => {
|
|
3206
3343
|
const l = settings.limits || {};
|
|
3207
3344
|
return {
|
package/src/preload.js
CHANGED
|
@@ -44,7 +44,9 @@ contextBridge.exposeInMainWorld('beast', {
|
|
|
44
44
|
secGet: () => ipcRenderer.invoke('sec:get'),
|
|
45
45
|
secSet: (cfg) => ipcRenderer.invoke('sec:set', cfg),
|
|
46
46
|
approvalRespond: (id, ok, always) => ipcRenderer.invoke('approval:respond', { id, ok, always }),
|
|
47
|
-
sttTranscribe: (b64) => ipcRenderer.invoke('stt:transcribe', b64),
|
|
47
|
+
sttTranscribe: (b64, lang) => ipcRenderer.invoke('stt:transcribe', b64, lang),
|
|
48
|
+
sttLangGet: () => ipcRenderer.invoke('stt:lang:get'),
|
|
49
|
+
sttLangSet: (lang) => ipcRenderer.invoke('stt:lang:set', lang),
|
|
48
50
|
updateStatus: () => ipcRenderer.invoke('update:status'),
|
|
49
51
|
updateCheck: () => ipcRenderer.invoke('update:check'),
|
|
50
52
|
updateInstall: () => ipcRenderer.invoke('update:install'),
|
package/src/renderer/i18n.js
CHANGED
|
@@ -72,7 +72,8 @@
|
|
|
72
72
|
up_uptodate: 'Güncel',
|
|
73
73
|
up_downloading: 'İndiriliyor…',
|
|
74
74
|
up_downloaded: 'İndirildi — kurulum için hazır',
|
|
75
|
-
up_npm_mode: 'npm kurulumu —
|
|
75
|
+
up_npm_mode: 'npm kurulumu — güncellemeler otomatik kontrol edilir',
|
|
76
|
+
up_npm_note: 'Yeni sürüm algılanınca buton aktifleşir: uygulama kapanır, güncellenir ve kendiliğinden yeniden açılır. Terminal komutu: beast-agent update',
|
|
76
77
|
up_auto_check: 'Otomatik sürüm kontrolü (açılış + 6 saatte bir)',
|
|
77
78
|
up_auto_dl: 'Yeni sürümü otomatik indir (kapanışta kurulur)',
|
|
78
79
|
up_check_now: 'Şimdi Kontrol Et',
|
|
@@ -422,7 +423,8 @@
|
|
|
422
423
|
up_uptodate: 'Up to date',
|
|
423
424
|
up_downloading: 'Downloading…',
|
|
424
425
|
up_downloaded: 'Downloaded — ready to install',
|
|
425
|
-
up_npm_mode: 'npm install —
|
|
426
|
+
up_npm_mode: 'npm install — updates are checked automatically',
|
|
427
|
+
up_npm_note: 'The button activates when a new version is detected: the app closes, updates and relaunches by itself. Terminal command: beast-agent update',
|
|
426
428
|
up_auto_check: 'Automatic version check (on startup + every 6 hours)',
|
|
427
429
|
up_auto_dl: 'Auto-download new versions (installed on quit)',
|
|
428
430
|
up_check_now: 'Check Now',
|
package/src/renderer/index.html
CHANGED
|
@@ -93,6 +93,7 @@
|
|
|
93
93
|
<div id="settingsDialog">
|
|
94
94
|
<aside id="setTabs">
|
|
95
95
|
<div class="set-tabs-title" data-i18n="set_title">AYARLAR</div>
|
|
96
|
+
<nav class="set-tabs-list">
|
|
96
97
|
<button class="tab active" data-tab="provider" data-i18n="tab_provider">Provider</button>
|
|
97
98
|
<button class="tab" data-tab="fallout" data-i18n="tab_fallout">Fallout</button>
|
|
98
99
|
<button class="tab" data-tab="memory" data-i18n="tab_memory">Memory</button>
|
|
@@ -110,6 +111,7 @@
|
|
|
110
111
|
<button class="tab" data-tab="limits" data-i18n="tab_limits">Limit</button>
|
|
111
112
|
<button class="tab" data-tab="sec" data-i18n="tab_security">Güvenlik</button>
|
|
112
113
|
<button class="tab" data-tab="update" data-i18n="tab_update">Güncelleme</button>
|
|
114
|
+
</nav>
|
|
113
115
|
<div class="set-tabs-foot">
|
|
114
116
|
<div id="beastCodeBox" class="beast-code" data-i18n-title="bc_label" title="Beast Kodu">
|
|
115
117
|
<div class="bc-row">
|
package/src/renderer/renderer.js
CHANGED
|
@@ -1550,16 +1550,16 @@ let updatePaneTimer = null;
|
|
|
1550
1550
|
|
|
1551
1551
|
function renderUpdateStateHtml(st) {
|
|
1552
1552
|
let status;
|
|
1553
|
-
if (st.
|
|
1554
|
-
else if (st.error) status = '⚠ ' + st.error;
|
|
1553
|
+
if (st.error) status = '\u26A0\uFE0E ' + st.error;
|
|
1555
1554
|
else if (st.downloaded) status = _t('up_downloaded') + ' (v' + (st.version || '?') + ')';
|
|
1556
1555
|
else if (st.progress) status = _t('up_downloading') + ' %' + st.progress.percent;
|
|
1557
1556
|
else if (st.checking) status = _t('up_checking');
|
|
1558
1557
|
else if (st.available) status = _t('up_available') + ' (v' + (st.version || '?') + ')';
|
|
1558
|
+
else if (st.npm) status = _t('up_npm_mode');
|
|
1559
1559
|
else if (st.available === false) status = _t('up_uptodate');
|
|
1560
1560
|
else status = '—';
|
|
1561
1561
|
|
|
1562
|
-
return `<div class="usage-stat"
|
|
1562
|
+
return `<div class="usage-stat" id="upStatusBox"><div class="us-label">${_t('up_status')}</div><div class="us-value" style="font-size:14px">${escapeHtml(status)}</div></div>`;
|
|
1563
1563
|
}
|
|
1564
1564
|
|
|
1565
1565
|
async function renderUpdatePane() {
|
|
@@ -1582,8 +1582,10 @@ async function renderUpdatePane() {
|
|
|
1582
1582
|
<label class="lock-row"><input type="checkbox" id="upAutoDl" ${st.autoDownload ? 'checked' : ''}/><span>${_t('up_auto_dl')}</span></label>
|
|
1583
1583
|
</div>` +
|
|
1584
1584
|
(st.npm
|
|
1585
|
-
? `<div class="
|
|
1586
|
-
|
|
1585
|
+
? `<div class="form-grid" style="grid-template-columns:auto auto;gap:8px;margin-top:12px">
|
|
1586
|
+
<button id="upInstall" class="btn ghost" ${st.available ? '' : 'disabled style="opacity:.45;cursor:default"'}>${_t('up_install_now')}</button>
|
|
1587
|
+
</div>
|
|
1588
|
+
<div class="sub" style="margin-top:8px">${_t('up_npm_note')}</div>`
|
|
1587
1589
|
: `<div class="form-grid" style="grid-template-columns:auto auto;gap:8px;margin-top:12px">
|
|
1588
1590
|
<button id="upCheck" class="btn ghost">${_t('up_check_now')}</button>
|
|
1589
1591
|
<button id="upInstall" class="btn ghost" ${st.downloaded ? '' : 'disabled style="opacity:.45;cursor:default"'}>${_t('up_install_now')}</button>
|
|
@@ -1599,7 +1601,9 @@ beast-agent update</pre></div>`
|
|
|
1599
1601
|
if (btnCheck) btnCheck.addEventListener('click', async () => {
|
|
1600
1602
|
btnCheck.disabled = true;
|
|
1601
1603
|
const r = await beast.updateCheck().catch(() => ({ ok: false, error: 'ipc' }));
|
|
1604
|
+
btnCheck.disabled = false;
|
|
1602
1605
|
if (!r.ok && r.error) toast(r.error);
|
|
1606
|
+
renderUpdatePane();
|
|
1603
1607
|
});
|
|
1604
1608
|
const btnInstall = pane.querySelector('#upInstall');
|
|
1605
1609
|
if (btnInstall) btnInstall.addEventListener('click', async () => {
|
|
@@ -1607,16 +1611,13 @@ beast-agent update</pre></div>`
|
|
|
1607
1611
|
if (!r.ok && r.error) toast(r.error);
|
|
1608
1612
|
});
|
|
1609
1613
|
|
|
1610
|
-
/* indirme ilerlemesi için sekme açıkken canlı tazele */
|
|
1614
|
+
/* indirme ilerlemesi için sekme açıkken canlı tazele — YALNIZ durum kutusu */
|
|
1611
1615
|
updatePaneTimer = setInterval(() => {
|
|
1612
1616
|
if ($('#tab-update').hidden || els.settingsOverlay.hidden) { clearInterval(updatePaneTimer); return; }
|
|
1613
1617
|
beast.updateStatus().then((s) => {
|
|
1614
1618
|
if (!s) return;
|
|
1615
|
-
const box = pane.querySelector('
|
|
1616
|
-
if (box)
|
|
1617
|
-
const wrap = pane.querySelector('.usage-stat');
|
|
1618
|
-
if (wrap) wrap.outerHTML = renderUpdateStateHtml(s);
|
|
1619
|
-
}
|
|
1619
|
+
const box = pane.querySelector('#upStatusBox');
|
|
1620
|
+
if (box) box.outerHTML = renderUpdateStateHtml(s);
|
|
1620
1621
|
}).catch(() => {});
|
|
1621
1622
|
}, 1000);
|
|
1622
1623
|
}
|
|
@@ -2194,6 +2195,7 @@ function onEvent(ev) {
|
|
|
2194
2195
|
}
|
|
2195
2196
|
if (ev.type === 'update') {
|
|
2196
2197
|
if (ev.downloaded) toast(_t('up_downloaded') + ' (v' + (ev.version || '?') + ') — /update now');
|
|
2198
|
+
else if (ev.available && ev.version && ev.version !== ev.current) toast(_t('up_available') + ' (v' + ev.version + ')');
|
|
2197
2199
|
if (!els.settingsOverlay.hidden && setTab === 'update') renderUpdatePane();
|
|
2198
2200
|
return;
|
|
2199
2201
|
}
|
|
@@ -3051,6 +3053,10 @@ async function init() {
|
|
|
3051
3053
|
});
|
|
3052
3054
|
document.addEventListener('langchange', syncLangBtn);
|
|
3053
3055
|
document.addEventListener('langchange', renderActiveSettingsTab);
|
|
3056
|
+
/* Whisper STT dili arayüz dilini izler (WA sesli notları da) */
|
|
3057
|
+
const syncSttLang = () => { try { beast.sttLangSet((window.I18N && window.I18N.lang) || 'tr'); } catch {} };
|
|
3058
|
+
syncSttLang();
|
|
3059
|
+
document.addEventListener('langchange', syncSttLang);
|
|
3054
3060
|
}
|
|
3055
3061
|
|
|
3056
3062
|
els.attachBtn.addEventListener('click', () => els.fileInput.click());
|
|
@@ -3091,7 +3097,9 @@ async function init() {
|
|
|
3091
3097
|
if (!blob.size) return;
|
|
3092
3098
|
toast(_t('mic_transcribing'));
|
|
3093
3099
|
const b64 = await blobToDataUrl(blob);
|
|
3094
|
-
|
|
3100
|
+
/* arayüz dili = Whisper dili: TR ise Türkçe, EN ise İngilizce algılar */
|
|
3101
|
+
const uiLang = (window.I18N && window.I18N.lang) || 'tr';
|
|
3102
|
+
const r = await beast.sttTranscribe(b64, uiLang).catch(() => ({ ok: false, error: 'ipc' }));
|
|
3095
3103
|
if (r && r.ok && r.text) {
|
|
3096
3104
|
els.input.value = (els.input.value ? els.input.value.replace(/\s+$/, '') + ' ' : '') + r.text;
|
|
3097
3105
|
els.input.focus();
|
package/src/renderer/style.css
CHANGED
|
@@ -1096,11 +1096,33 @@ body.browser-open #toast { left: calc((100vw - var(--bw, 480px)) / 2); }
|
|
|
1096
1096
|
flex-direction: column;
|
|
1097
1097
|
padding: 16px 10px 12px;
|
|
1098
1098
|
}
|
|
1099
|
-
.set-tabs-title {
|
|
1100
|
-
font-size: 11px;
|
|
1101
|
-
letter-spacing: 2px;
|
|
1102
|
-
color: var(--muted);
|
|
1103
|
-
padding: 0 12px 10px;
|
|
1099
|
+
.set-tabs-title {
|
|
1100
|
+
font-size: 11px;
|
|
1101
|
+
letter-spacing: 2px;
|
|
1102
|
+
color: var(--muted);
|
|
1103
|
+
padding: 0 12px 10px;
|
|
1104
|
+
}
|
|
1105
|
+
/* sekme listesi: küçük ekranda taşarsa içeride kayar — alt kısım (Beast Kodu + Kapat) sabit kalır */
|
|
1106
|
+
.set-tabs-list {
|
|
1107
|
+
display: flex;
|
|
1108
|
+
flex-direction: column;
|
|
1109
|
+
align-items: stretch;
|
|
1110
|
+
flex: 1 1 auto;
|
|
1111
|
+
min-height: 0;
|
|
1112
|
+
overflow-y: auto;
|
|
1113
|
+
padding-right: 2px;
|
|
1114
|
+
margin: 0 -2px;
|
|
1115
|
+
scrollbar-width: thin;
|
|
1116
|
+
scrollbar-color: var(--border) transparent;
|
|
1117
|
+
}
|
|
1118
|
+
.set-tabs-list::-webkit-scrollbar { width: 8px; }
|
|
1119
|
+
.set-tabs-list::-webkit-scrollbar-thumb { background: var(--border); border-radius: 8px; }
|
|
1120
|
+
.set-tabs-list::-webkit-scrollbar-thumb:hover { background: var(--muted); }
|
|
1121
|
+
.set-tabs-list::-webkit-scrollbar-track { background: transparent; }
|
|
1122
|
+
@media (max-height: 860px) {
|
|
1123
|
+
#setTabs { padding: 10px 8px; }
|
|
1124
|
+
.set-tabs-title { padding: 0 12px 6px; }
|
|
1125
|
+
#setTabs .tab { padding: 6px 12px; font-size: 12.5px; margin-bottom: 1px; }
|
|
1104
1126
|
}
|
|
1105
1127
|
#setTabs .tab {
|
|
1106
1128
|
text-align: left;
|