beast-agent 0.21.0 → 0.22.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/README.md +1 -1
- package/bin/beast-agent.js +16 -6
- package/package.json +3 -2
- package/src/agent/bots.js +17 -3
- package/src/agent/engine.js +35 -17
- package/src/main.js +100 -17
- package/src/renderer/i18n.js +8 -2
- package/src/renderer/index.html +1 -0
- package/src/renderer/renderer.js +59 -8
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ Then start it:
|
|
|
37
37
|
beast-agent
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
That's it — the app window opens. On first launch Beast also creates a **desktop shortcut** and registers itself to **start with Windows** (lives in the tray). Later updates: close the app and run `beast-agent update
|
|
40
|
+
That's it — the app window opens. On first launch Beast also creates a **desktop shortcut** and registers itself to **start with Windows** (lives in the tray). Later updates: close the app and run `beast update` (or `beast-agent update`).
|
|
41
41
|
|
|
42
42
|
## ⚙️ Configuration
|
|
43
43
|
|
package/bin/beast-agent.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
/* Beast Agent global npm
|
|
5
|
-
`beast-agent`
|
|
6
|
-
`beast
|
|
4
|
+
/* Beast Agent global npm başlatıcısı (`beast` kısa adı da aynı scripte bağlı):
|
|
5
|
+
`beast` / `beast-agent` → uygulamayı detached başlatır, terminali hemen serbest bırakır
|
|
6
|
+
`beast update` → npm'den en son sürümü yükler (uygulama kapalıyken çalıştır) */
|
|
7
7
|
|
|
8
8
|
const { spawn, spawnSync } = require('child_process');
|
|
9
9
|
const path = require('path');
|
|
@@ -62,10 +62,20 @@ if (process.argv[2] === 'update') {
|
|
|
62
62
|
} else {
|
|
63
63
|
try { spawnSync('pkill', ['-f', 'node_modules/beast-agent'], { stdio: 'ignore' }); } catch {}
|
|
64
64
|
}
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
/* dosya kilidi (EBUSY) bazen ilk denemede patlar — 5 deneme hakkı */
|
|
66
|
+
let ok = false;
|
|
67
|
+
for (let i = 1; i <= 5 && !ok; i++) {
|
|
68
|
+
const r = spawnSync('npm', ['install', '-g', 'beast-agent@latest'], { stdio: 'inherit', shell: isWin });
|
|
69
|
+
ok = r.status === 0;
|
|
70
|
+
if (!ok && i < 5) {
|
|
71
|
+
console.log(` \u2022 deneme ${i}/5 ba\u015Far\u0131s\u0131z (dosya kilidi olabilir) \u2014 3 sn sonra tekrar\u2026`);
|
|
72
|
+
if (isWin) spawnSync('powershell.exe', ['-NoProfile', '-Command', 'Start-Sleep -Seconds 3'], { stdio: 'ignore' });
|
|
73
|
+
else spawnSync('sleep', ['3']);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (!ok) {
|
|
67
77
|
console.log('\n\u2717 g\u00FCncelleme ba\u015Far\u0131s\u0131z \u2014 elle: npm install -g beast-agent@latest');
|
|
68
|
-
process.exit(
|
|
78
|
+
process.exit(1);
|
|
69
79
|
}
|
|
70
80
|
console.log('\n\u2713 beast-agent g\u00FCncellendi \u2014 uygulama ba\u015Flat\u0131l\u0131yor\u2026');
|
|
71
81
|
try {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "beast-agent",
|
|
3
3
|
"productName": "Beast Agent",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.22.0",
|
|
5
5
|
"description": "Ultra-fast local agent shell for Windows.",
|
|
6
6
|
"author": "algokodcom (AlgoKod)",
|
|
7
7
|
"license": "MIT",
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
],
|
|
26
26
|
"main": "src/main.js",
|
|
27
27
|
"bin": {
|
|
28
|
-
"beast-agent": "bin/beast-agent.js"
|
|
28
|
+
"beast-agent": "bin/beast-agent.js",
|
|
29
|
+
"beast": "bin/beast-agent.js"
|
|
29
30
|
},
|
|
30
31
|
"scripts": {
|
|
31
32
|
"start": "electron .",
|
package/src/agent/bots.js
CHANGED
|
@@ -239,9 +239,23 @@ function update(id, patch) {
|
|
|
239
239
|
changes.push('prompt güncellendi');
|
|
240
240
|
b.prompt = String(patch.prompt).slice(0, 4000);
|
|
241
241
|
}
|
|
242
|
-
if (
|
|
243
|
-
|
|
244
|
-
|
|
242
|
+
if (patch.perm !== undefined) {
|
|
243
|
+
/* 'all' tek başına tüm araçları verir; web/read/chat çoklu seçilebilir
|
|
244
|
+
(['web','read'] gibi dizi ya da 'web,read' gibi string kabul edilir) */
|
|
245
|
+
const PERMS_ALL = ['all', 'web', 'read', 'chat'];
|
|
246
|
+
let nextPerm = null;
|
|
247
|
+
if (Array.isArray(patch.perm)) {
|
|
248
|
+
const picked = [...new Set(patch.perm.map((x) => String(x).trim()).filter((x) => PERMS_ALL.includes(x)))];
|
|
249
|
+
nextPerm = picked.includes('all') ? 'all' : (picked.length ? picked : 'chat');
|
|
250
|
+
} else if (typeof patch.perm === 'string') {
|
|
251
|
+
const arr = patch.perm.split(',').map((x) => x.trim()).filter((x) => PERMS_ALL.includes(x));
|
|
252
|
+
if (arr.length) nextPerm = arr.includes('all') ? 'all' : (arr.length === 1 ? arr[0] : arr);
|
|
253
|
+
}
|
|
254
|
+
if (nextPerm !== null && JSON.stringify(nextPerm) !== JSON.stringify(b.perm)) {
|
|
255
|
+
const fp = (p) => (Array.isArray(p) ? '[' + p.join('+') + ']' : String(p));
|
|
256
|
+
changes.push(`perm: ${fp(b.perm)} → ${fp(nextPerm)}`);
|
|
257
|
+
b.perm = nextPerm;
|
|
258
|
+
}
|
|
245
259
|
}
|
|
246
260
|
if (patch.skills && typeof patch.skills === 'object') {
|
|
247
261
|
const merged = { ...DEFAULT_SKILLS, ...(b.skills || {}) };
|
package/src/agent/engine.js
CHANGED
|
@@ -83,6 +83,16 @@ const PERM_TOOL_SETS = {
|
|
|
83
83
|
};
|
|
84
84
|
const PERM_LEVELS = ['all', 'web', 'read', 'chat'];
|
|
85
85
|
|
|
86
|
+
/* İzin değerini normalize eder: 'all' → ['all'], 'web' → ['web'],
|
|
87
|
+
'web,read' / ['web','read'] → ['web','read'] (sıra PERM_LEVELS'e göre dizilir).
|
|
88
|
+
Geçersiz değerler atılır; hiçbiri kalmazsa boş dizi döner. */
|
|
89
|
+
function normalizePerms(p) {
|
|
90
|
+
const arr = Array.isArray(p) ? p.map(String) : String(p == null ? '' : p).split(',');
|
|
91
|
+
const picked = arr.map((s) => s.trim()).filter((s) => PERM_LEVELS.includes(s));
|
|
92
|
+
if (picked.includes('all')) return ['all'];
|
|
93
|
+
return PERM_LEVELS.filter((k) => picked.includes(k));
|
|
94
|
+
}
|
|
95
|
+
|
|
86
96
|
/* CEO modu: ana (konuşma) oturumunun KULLANAMAYACAĞI uygulayıcı araçlar.
|
|
87
97
|
Bunların hepsi run_background ile paralel ajana devredilir — CEO sadece
|
|
88
98
|
konuşur, planlar, emir verir ve takip eder. */
|
|
@@ -190,7 +200,7 @@ class Engine {
|
|
|
190
200
|
this.sel = this._resolve(opts.modelOverride) || this.cfg.defaultSelection || null;
|
|
191
201
|
this.roleModels = opts.roleModels || {}; // { vision?, terminal?, coding?, subagent? } // providerId::model string
|
|
192
202
|
this.lockdown = !!opts.lockdown; // varsayılan kısıt (oturum bazlı override edilmezse)
|
|
193
|
-
this.sessionPerm = new Map(); // sessionId -> 'web'|'read'|'chat' (kişi bazlı izin)
|
|
203
|
+
this.sessionPerm = new Map(); // sessionId -> ['web'] | ['web','read'] | ['chat'] (kişi/bot bazlı izin)
|
|
194
204
|
this.sessionTools = new Map(); // sessionId -> Set(araç adları) — bot skill kısıtı
|
|
195
205
|
this.resolveBot = opts.resolveBot || null; // botId -> bot bilgisi (main enjekte eder)
|
|
196
206
|
/* bot oturumu hafıza köprüsü: botun kendi SOUL/USER/MEMORY dosyaları */
|
|
@@ -285,12 +295,13 @@ class Engine {
|
|
|
285
295
|
this.lockdown = !!v;
|
|
286
296
|
}
|
|
287
297
|
|
|
288
|
-
/* Kişi bazlı granül izin — WhatsApp oturumları için.
|
|
298
|
+
/* Kişi/bot bazlı granül izin — WhatsApp oturumları için.
|
|
299
|
+
Tek seviye ('web') ya da çoklu (['web','read']) verilebilir; 'all' kaydı siler. */
|
|
289
300
|
setSessionPerm(sessionId, perm) {
|
|
290
301
|
const id = String(sessionId || '');
|
|
291
302
|
if (!id) return;
|
|
292
|
-
const
|
|
293
|
-
if (
|
|
303
|
+
const arr = normalizePerms(perm);
|
|
304
|
+
if (arr.length && !arr.includes('all')) this.sessionPerm.set(id, arr);
|
|
294
305
|
else this.sessionPerm.delete(id);
|
|
295
306
|
}
|
|
296
307
|
|
|
@@ -347,8 +358,8 @@ class Engine {
|
|
|
347
358
|
|
|
348
359
|
sessionPermFor(sessionId) {
|
|
349
360
|
const p = this.sessionPerm.get(String(sessionId || ''));
|
|
350
|
-
if (p) return p;
|
|
351
|
-
return this.lockdown ? 'chat' : 'all';
|
|
361
|
+
if (p && p.length) return p;
|
|
362
|
+
return this.lockdown ? ['chat'] : ['all'];
|
|
352
363
|
}
|
|
353
364
|
|
|
354
365
|
setRoleModels(map) {
|
|
@@ -929,7 +940,7 @@ class Engine {
|
|
|
929
940
|
for (const v of this.listSessions()) {
|
|
930
941
|
const s = this._load(v.id);
|
|
931
942
|
if (s && s.notes && String(s.notes).trim()) {
|
|
932
|
-
out.push({ id: s.id, code: s.code || '', title: v.title, updatedAt: v.updatedAt, count: v.count, notes: String(s.notes) });
|
|
943
|
+
out.push({ id: s.id, code: s.code || '', title: v.title, updatedAt: v.updatedAt, count: v.count, notes: String(s.notes), botId: s.botId || '' });
|
|
933
944
|
}
|
|
934
945
|
}
|
|
935
946
|
return out;
|
|
@@ -2063,9 +2074,14 @@ class Engine {
|
|
|
2063
2074
|
: session.bcCode
|
|
2064
2075
|
? this.buildBcSystem(session)
|
|
2065
2076
|
: this.buildSystem(promptText, session);
|
|
2066
|
-
// Granül izin: oturumun yetki seviyesine göre araç seti daraltılır
|
|
2067
|
-
|
|
2068
|
-
const
|
|
2077
|
+
// Granül izin: oturumun yetki seviyesine göre araç seti daraltılır.
|
|
2078
|
+
// Çoklu izin (ör. web+read) seçiliyse kümeler BİRLEŞİR — hepsinin araçları açık olur.
|
|
2079
|
+
const perms = this.sessionPermFor(session.id);
|
|
2080
|
+
let allowedSet = null;
|
|
2081
|
+
if (!perms.includes('all')) {
|
|
2082
|
+
allowedSet = new Set();
|
|
2083
|
+
for (const p of perms) for (const t of PERM_TOOL_SETS[p] || []) allowedSet.add(t);
|
|
2084
|
+
}
|
|
2069
2085
|
let activeTools = allowedSet ? toolsList.filter((t) => allowedSet.has(t.function.name)) : toolsList;
|
|
2070
2086
|
/* bot skill kısıtı: bota verilen yetkiye göre araç seti daraltılır */
|
|
2071
2087
|
const toolLimit = this.sessionTools.get(String(session.id));
|
|
@@ -2077,17 +2093,16 @@ class Engine {
|
|
|
2077
2093
|
/* CEO: uygulayıcı araçlar kapalı — her şey paralel ajana devredilir */
|
|
2078
2094
|
activeTools = activeTools.filter((t) => !CEO_EXEC_TOOLS.has(t.function.name));
|
|
2079
2095
|
}
|
|
2080
|
-
if (
|
|
2096
|
+
if (perms.length === 1 && perms[0] === 'chat') {
|
|
2081
2097
|
system +=
|
|
2082
2098
|
'\n\n# KISITLI MOD\nTüm araçların (komut, dosya, web, tarayıcı, hafıza) kapalı. Sadece yazarak cevap ver. ' +
|
|
2083
2099
|
'Bilgisayarla ilgili bir işlem istenirse bu modda yapamayacağını kibarca söyle.';
|
|
2084
|
-
} else if (
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
} else if (perm === 'read') {
|
|
2100
|
+
} else if (!perms.includes('all')) {
|
|
2101
|
+
const bits = [];
|
|
2102
|
+
if (perms.includes('web')) bits.push('web ve tarayıcı araçlarına erişimin var');
|
|
2103
|
+
if (perms.includes('read')) bits.push('bilgisayarı SADECE OKUYABİLİRSİN (klasör listeleme, dosya okuma) + web/tarayıcı');
|
|
2089
2104
|
system +=
|
|
2090
|
-
'\n\n# SINIRLI
|
|
2105
|
+
'\n\n# SINIRLI YETKİ\n' + bits.join('; ') + '. ' +
|
|
2091
2106
|
'Dosya yazma, silme ve komut çalıştırma YOK; istenirse yapamayacağını söyle.';
|
|
2092
2107
|
}
|
|
2093
2108
|
/* bot kimliği: bota bağlı oturumlarda kişilik + izolasyon kuralları */
|
|
@@ -3484,3 +3499,6 @@ module.exports.sanitizeTodoItems = sanitizeTodoItems;
|
|
|
3484
3499
|
module.exports.parseReflectionJson = parseReflectionJson;
|
|
3485
3500
|
module.exports.CEO_EXEC_TOOLS = CEO_EXEC_TOOLS;
|
|
3486
3501
|
module.exports.BG_HIDDEN_TOOLS = BG_HIDDEN_TOOLS;
|
|
3502
|
+
module.exports.PERM_TOOL_SETS = PERM_TOOL_SETS;
|
|
3503
|
+
module.exports.PERM_LEVELS = PERM_LEVELS;
|
|
3504
|
+
module.exports.normalizePerms = normalizePerms;
|
package/src/main.js
CHANGED
|
@@ -193,6 +193,7 @@ const BUILTIN_PROVIDERS = [
|
|
|
193
193
|
{ id: 'gemini', name: 'Google Gemini', baseUrl: 'https://generativelanguage.googleapis.com/v1beta/openai', hint: 'aistudio.google.com/apikey' },
|
|
194
194
|
{ id: 'zhipu', name: 'Zhipu AI', baseUrl: 'https://api.z.ai/api/paas/v4', hint: 'z.ai model konsolu' },
|
|
195
195
|
{ id: 'groq', name: 'Groq', baseUrl: 'https://api.groq.com/openai/v1', hint: 'console.groq.com/keys' },
|
|
196
|
+
{ id: 'nvidia', name: 'NVIDIA NIM', baseUrl: 'https://integrate.api.nvidia.com/v1', hint: 'build.nvidia.com — ücretsiz kredi veriyor, talep yüksek' },
|
|
196
197
|
];
|
|
197
198
|
const SESSIONS_DIR = path.join(APP_DIR, 'sessions');
|
|
198
199
|
const SETTINGS_FILE = path.join(APP_DIR, 'settings.json');
|
|
@@ -1333,13 +1334,37 @@ function scheduleReminder({ when, message, sessionId, repeat }) {
|
|
|
1333
1334
|
/* ---------------- BOT SİSTEMİ yardımcıları ----------------
|
|
1334
1335
|
Bot eşleştirme, izolasyon, whitelist.json aynası ve bot istatistikleri. */
|
|
1335
1336
|
|
|
1336
|
-
|
|
1337
|
+
/* İzin değerini araç kümesine çevirir; null = tüm araçlar ('all').
|
|
1338
|
+
'web' / ['web','read'] / 'web,read' biçimlerini kabul eder. */
|
|
1339
|
+
function permToToolSet(p) {
|
|
1340
|
+
const { PERM_TOOL_SETS } = require('./agent/engine');
|
|
1341
|
+
const set = new Set();
|
|
1342
|
+
for (const raw of Array.isArray(p) ? p : String(p == null ? 'all' : p).split(',')) {
|
|
1343
|
+
const k = String(raw).trim() || 'all';
|
|
1344
|
+
if (k === 'all' || !PERM_TOOL_SETS[k]) return null;
|
|
1345
|
+
for (const t of PERM_TOOL_SETS[k]) set.add(t);
|
|
1346
|
+
}
|
|
1347
|
+
return set;
|
|
1348
|
+
}
|
|
1337
1349
|
|
|
1350
|
+
/* Hangi izin daha kısıtlıysa o kazanır. Dizi (çoklu bot izni) destekler:
|
|
1351
|
+
araç kümesi diğerinin alt kümesiyse o geçer; ikisi de alt küme değilse
|
|
1352
|
+
daha küçük küme kazanır (eşitse kişi yetkisi). */
|
|
1338
1353
|
function moreRestrictivePerm(a, b) {
|
|
1339
|
-
const
|
|
1340
|
-
const
|
|
1341
|
-
|
|
1342
|
-
|
|
1354
|
+
const sa = permToToolSet(a);
|
|
1355
|
+
const sb = permToToolSet(b);
|
|
1356
|
+
if (sa === null && sb === null) return 'all';
|
|
1357
|
+
if (sa === null) return b; // b kısıtlı
|
|
1358
|
+
if (sb === null) return a; // a kısıtlı
|
|
1359
|
+
const aSubB = [...sa].every((t) => sb.has(t));
|
|
1360
|
+
const bSubA = [...sb].every((t) => sa.has(t));
|
|
1361
|
+
if (aSubB && !bSubA) return a;
|
|
1362
|
+
if (bSubA && !aSubB) return b;
|
|
1363
|
+
return sa.size <= sb.size ? a : b;
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
function fmtPerm(p) {
|
|
1367
|
+
return Array.isArray(p) ? '[' + p.join('+') + ']' : String(p);
|
|
1343
1368
|
}
|
|
1344
1369
|
|
|
1345
1370
|
/* Bot skill checkbox'ları → oturumun görebileceği araç adları.
|
|
@@ -1623,7 +1648,7 @@ async function processWaMessage(jid, payload, senderNum, requeues = 0) {
|
|
|
1623
1648
|
} else {
|
|
1624
1649
|
engine.setSessionTools(sid, null);
|
|
1625
1650
|
}
|
|
1626
|
-
waLog(`perm=${perm} bot=${botId} sid=${sid}`);
|
|
1651
|
+
waLog(`perm=${fmtPerm(perm)} bot=${botId} sid=${sid}`);
|
|
1627
1652
|
|
|
1628
1653
|
const participantName = payload.participant ? '+' + String(payload.participant).split('@')[0].split(':')[0] : '';
|
|
1629
1654
|
/* #v13.1 rol: SAHİP vs MİSAFİR — ajan kime konuştuğunu net bilsin */
|
|
@@ -3585,24 +3610,82 @@ ipcMain.handle('update:check', async () => {
|
|
|
3585
3610
|
});
|
|
3586
3611
|
|
|
3587
3612
|
/* npm kurulumunda KENDİ KENDİNİ GÜNCELLEME:
|
|
3588
|
-
|
|
3613
|
+
helper script %APPDATA%\beast'a yazılır (paket dizini değişse de yaşar) ve
|
|
3614
|
+
detached çalışır: 1) uygulama PID'i tamamen çıkana kadar bekler (en çok 30 sn,
|
|
3615
|
+
sonra zorla kapatır — EBUSY dosya kilidinin numarası), 2) npm install -g
|
|
3616
|
+
beast-agent@latest — kilide karşı 5 deneme, 3) tüm çıktı update.log'a yazılır,
|
|
3617
|
+
4) beast-agent komut shim'i üzerinden yeniden başlatır (electron sürümü
|
|
3618
|
+
değişse de yol bozulmaz). Sonra app.quit(). */
|
|
3589
3619
|
function npmSelfUpdate() {
|
|
3590
3620
|
try {
|
|
3591
|
-
|
|
3592
|
-
const
|
|
3621
|
+
fs.mkdirSync(APP_DIR, { recursive: true });
|
|
3622
|
+
const pid = String(process.pid);
|
|
3593
3623
|
if (process.platform === 'win32') {
|
|
3594
|
-
const ps =
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3624
|
+
const ps = [
|
|
3625
|
+
"param([int]$ProcId = 0)",
|
|
3626
|
+
"$ErrorActionPreference = 'Continue'",
|
|
3627
|
+
"$Log = Join-Path $env:APPDATA 'beast\\update.log'",
|
|
3628
|
+
"function L([string]$m) { try { Add-Content -LiteralPath $Log -Value (\"[\" + (Get-Date -Format 'yyyy-MM-dd HH:mm:ss') + \"] \" + $m) } catch {} }",
|
|
3629
|
+
"L \"=== self-update basladi (app pid: $ProcId) ===\"",
|
|
3630
|
+
"if ($ProcId -gt 0) {",
|
|
3631
|
+
" $deadline = (Get-Date).AddSeconds(30)",
|
|
3632
|
+
" while ((Get-Date) -lt $deadline) {",
|
|
3633
|
+
" if (-not (Get-Process -Id $ProcId -ErrorAction SilentlyContinue)) { break }",
|
|
3634
|
+
" Start-Sleep -Milliseconds 500",
|
|
3635
|
+
" }",
|
|
3636
|
+
" if (Get-Process -Id $ProcId -ErrorAction SilentlyContinue) {",
|
|
3637
|
+
" L 'uygulama hala acik - zorla kapatiliyor'",
|
|
3638
|
+
" try { Stop-Process -Id $ProcId -Force } catch {}",
|
|
3639
|
+
" Start-Sleep -Seconds 2",
|
|
3640
|
+
" }",
|
|
3641
|
+
"}",
|
|
3642
|
+
"L 'uygulama kapandi, npm install basliyor'",
|
|
3643
|
+
"$npmCmd = (Get-Command 'npm.cmd' -ErrorAction SilentlyContinue).Source",
|
|
3644
|
+
"if (-not $npmCmd) { $npmCmd = Join-Path $env:APPDATA 'npm\\npm.cmd' }",
|
|
3645
|
+
"$ok = $false",
|
|
3646
|
+
"for ($i = 1; $i -le 5; $i++) {",
|
|
3647
|
+
" if ($ok) { break }",
|
|
3648
|
+
" L \"npm install -g beast-agent@latest (deneme $i)\"",
|
|
3649
|
+
" $out = & $npmCmd install -g beast-agent@latest 2>&1",
|
|
3650
|
+
" $code = $LASTEXITCODE",
|
|
3651
|
+
" foreach ($line in @($out)) { L \" npm: $line\" }",
|
|
3652
|
+
" if ($code -eq 0) { $ok = $true } else { Start-Sleep -Seconds 3 }",
|
|
3653
|
+
"}",
|
|
3654
|
+
"if (-not $ok) {",
|
|
3655
|
+
" L 'HATA: npm install 5 denemede basarisiz - uygulama yeniden baslatilmiyor'",
|
|
3656
|
+
" exit 1",
|
|
3657
|
+
"}",
|
|
3658
|
+
"L 'npm install tamam, yeniden baslatma'",
|
|
3659
|
+
"$shim = Get-Command 'beast-agent.cmd' -ErrorAction SilentlyContinue",
|
|
3660
|
+
"if ($shim) {",
|
|
3661
|
+
" L \"shim uzerinden: $($shim.Source)\"",
|
|
3662
|
+
" Start-Process -FilePath $shim.Source -WindowStyle Hidden",
|
|
3663
|
+
"} else {",
|
|
3664
|
+
" $prefix = (& $npmCmd prefix -g 2>$null)",
|
|
3665
|
+
" if (-not $prefix) { $prefix = Join-Path $env:APPDATA 'npm' }",
|
|
3666
|
+
" $exe = Join-Path $prefix 'node_modules\\electron\\dist\\electron.exe'",
|
|
3667
|
+
" if (-not (Test-Path $exe)) { $exe = Join-Path $prefix 'node_modules\\beast-agent\\node_modules\\electron\\dist\\electron.exe' }",
|
|
3668
|
+
" $appDir = Join-Path $prefix 'node_modules\\beast-agent'",
|
|
3669
|
+
" L \"shim bulunamadi - dogrudan: $exe\"",
|
|
3670
|
+
" Start-Process -FilePath $exe -ArgumentList \"`\"$appDir`\"\" -WindowStyle Hidden",
|
|
3671
|
+
"}",
|
|
3672
|
+
"L '=== self-update bitti ==='",
|
|
3673
|
+
].join('\r\n');
|
|
3674
|
+
const psFile = path.join(APP_DIR, 'update-helper.ps1');
|
|
3675
|
+
fs.writeFileSync(psFile, ps, 'utf8');
|
|
3676
|
+
spawn('powershell.exe', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', psFile, '-ProcId', pid],
|
|
3677
|
+
{ detached: true, stdio: 'ignore', windowsHide: true }).unref();
|
|
3600
3678
|
} else {
|
|
3601
|
-
const sh =
|
|
3679
|
+
const sh =
|
|
3680
|
+
`i=0; while [ $i -lt 60 ] && kill -0 ${pid} 2>/dev/null; do i=$((i+1)); sleep 0.5; done; ` +
|
|
3681
|
+
'ok=0; for n in 1 2 3 4 5; do npm install -g beast-agent@latest && ok=1 && break; sleep 3; done; ' +
|
|
3682
|
+
'if [ $ok -eq 1 ]; then nohup beast-agent >/dev/null 2>&1 & fi';
|
|
3602
3683
|
spawn('sh', ['-c', sh], { detached: true, stdio: 'ignore' }).unref();
|
|
3603
3684
|
}
|
|
3604
3685
|
log.info('main', 'npm self-update: helper bırakıldı, uygulama kapatılıyor');
|
|
3605
|
-
} catch {
|
|
3686
|
+
} catch (e) {
|
|
3687
|
+
log.error('main', 'npm self-update hatası: ' + String((e && e.message) || e));
|
|
3688
|
+
}
|
|
3606
3689
|
setTimeout(() => { try { app.quit(); } catch {} }, 400);
|
|
3607
3690
|
}
|
|
3608
3691
|
|
package/src/renderer/i18n.js
CHANGED
|
@@ -73,7 +73,8 @@
|
|
|
73
73
|
up_downloading: 'İndiriliyor…',
|
|
74
74
|
up_downloaded: 'İndirildi — kurulum için hazır',
|
|
75
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
|
|
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 update',
|
|
77
|
+
up_npm_started: 'Güncelleme başladı — uygulama kapanacak, en son sürüm kurulup kendiliğinden açılacak…',
|
|
77
78
|
up_dev_note: 'Geliştirme modu — güncelleme buradan yapılmaz; dağıtım npm ve GitHub Releases üzerinden. Kaynak kod için: git pull',
|
|
78
79
|
up_auto_check: 'Otomatik sürüm kontrolü (açılış + 6 saatte bir)',
|
|
79
80
|
up_auto_dl: 'Yeni sürümü otomatik indir (kapanışta kurulur)',
|
|
@@ -374,6 +375,7 @@
|
|
|
374
375
|
bot_tab_plugin: 'Plugin',
|
|
375
376
|
bot_tab_watcher: 'Watcher',
|
|
376
377
|
bot_tab_stats: 'İstatistik',
|
|
378
|
+
bot_tab_notes: 'Notlar',
|
|
377
379
|
bot_name: 'Bot adı',
|
|
378
380
|
bot_icon: 'İkon',
|
|
379
381
|
bot_prompt: 'System prompt (kişilik/görev)',
|
|
@@ -396,6 +398,7 @@
|
|
|
396
398
|
bot_see: 'Görebilir (diğer botlar)',
|
|
397
399
|
bot_no_other: 'Başka bot yok.',
|
|
398
400
|
bot_perm: 'Yetki seviyesi',
|
|
401
|
+
bot_perm_note: 'all tek başına tüm araçları açar (özel). Web / Okuma / Sohbet birden fazla seçilebilir — seçilenlerin araçları birleşir.',
|
|
399
402
|
bot_skills: 'Skill erişimi',
|
|
400
403
|
bot_browser: 'Tarayıcı ayarları',
|
|
401
404
|
bot_ext_browser: 'Dış tarayıcı yetkisi (kullanıcı isterse)',
|
|
@@ -571,7 +574,8 @@
|
|
|
571
574
|
up_downloading: 'Downloading…',
|
|
572
575
|
up_downloaded: 'Downloaded — ready to install',
|
|
573
576
|
up_npm_mode: 'npm install — updates are checked automatically',
|
|
574
|
-
up_npm_note: 'The button activates when a new version is detected: the app closes, updates and relaunches by itself. Terminal command: beast
|
|
577
|
+
up_npm_note: 'The button activates when a new version is detected: the app closes, updates and relaunches by itself. Terminal command: beast update',
|
|
578
|
+
up_npm_started: 'Update started — the app will close, install the latest version and relaunch…',
|
|
575
579
|
up_dev_note: 'Development mode — updates are distributed via npm and GitHub Releases. For source code: git pull',
|
|
576
580
|
up_auto_check: 'Automatic version check (on startup + every 6 hours)',
|
|
577
581
|
up_auto_dl: 'Auto-download new versions (installed on quit)',
|
|
@@ -930,6 +934,7 @@
|
|
|
930
934
|
bot_tab_plugin: 'Plugin',
|
|
931
935
|
bot_tab_watcher: 'Watcher',
|
|
932
936
|
bot_tab_stats: 'Stats',
|
|
937
|
+
bot_tab_notes: 'Notes',
|
|
933
938
|
bot_name: 'Bot name',
|
|
934
939
|
bot_icon: 'Icon',
|
|
935
940
|
bot_prompt: 'System prompt (personality/task)',
|
|
@@ -952,6 +957,7 @@
|
|
|
952
957
|
bot_see: 'Can see (other bots)',
|
|
953
958
|
bot_no_other: 'No other bots.',
|
|
954
959
|
bot_perm: 'Permission level',
|
|
960
|
+
bot_perm_note: 'all alone grants every tool (exclusive). Web / Read / Chat can be multi-selected — their tool sets are combined.',
|
|
955
961
|
bot_skills: 'Skill access',
|
|
956
962
|
bot_browser: 'Browser settings',
|
|
957
963
|
bot_ext_browser: 'External browser permission (when user asks)',
|
package/src/renderer/index.html
CHANGED
|
@@ -240,6 +240,7 @@
|
|
|
240
240
|
<button class="btab" data-btab="log" data-i18n="bot_tab_log">Log</button>
|
|
241
241
|
<button class="btab" data-btab="watcher" data-i18n="bot_tab_watcher">Watcher</button>
|
|
242
242
|
<button class="btab" data-btab="stats" data-i18n="bot_tab_stats">İstatistik</button>
|
|
243
|
+
<button class="btab" data-btab="notes" data-i18n="bot_tab_notes">Notlar</button>
|
|
243
244
|
</nav>
|
|
244
245
|
<div id="botPane"></div>
|
|
245
246
|
</div>
|
package/src/renderer/renderer.js
CHANGED
|
@@ -1719,7 +1719,8 @@ async function renderUpdatePane(autoCheck) {
|
|
|
1719
1719
|
const btnInstall = pane.querySelector('#upInstall');
|
|
1720
1720
|
if (btnInstall) btnInstall.addEventListener('click', async () => {
|
|
1721
1721
|
const r = await beast.updateInstall().catch(() => ({ ok: false, error: 'ipc' }));
|
|
1722
|
-
if (
|
|
1722
|
+
if (r.ok && r.npm) toast(_t('up_npm_started'));
|
|
1723
|
+
else if (!r.ok && r.error) toast(r.error);
|
|
1723
1724
|
});
|
|
1724
1725
|
|
|
1725
1726
|
/* indirme ilerlemesi için sekme açıkken canlı tazele — YALNIZ durum kutusu */
|
|
@@ -2224,9 +2225,44 @@ function renderBotPage() {
|
|
|
2224
2225
|
else if (tab === 'log') renderBotLog(pane, b);
|
|
2225
2226
|
else if (tab === 'watcher') renderBotWatcher(pane, b);
|
|
2226
2227
|
else if (tab === 'stats') renderBotStats(pane, b);
|
|
2228
|
+
else if (tab === 'notes') renderBotNotes(pane, b);
|
|
2227
2229
|
renderBotChats(b);
|
|
2228
2230
|
}
|
|
2229
2231
|
|
|
2232
|
+
/* --- Notlar sekmesi: oturum notları — konuşma kodu, başlık, tarih ve özet metni.
|
|
2233
|
+
Admin bot (beast) tüm oturumları görür; müşteri botu yalnız kendi oturumlarını. --- */
|
|
2234
|
+
async function renderBotNotes(pane, b) {
|
|
2235
|
+
pane.innerHTML = `<h2>${_t('notes_h2')}</h2><div class="sub">${_t('notes_sub')}</div>`;
|
|
2236
|
+
let all = [];
|
|
2237
|
+
try { all = await beast.listNotes(); } catch {}
|
|
2238
|
+
const list = (b.admin ? all : all.filter((n) => (n.botId || 'beast') === b.id))
|
|
2239
|
+
.slice()
|
|
2240
|
+
.sort((x, y) => String(y.updatedAt).localeCompare(String(x.updatedAt)));
|
|
2241
|
+
if (!list.length) {
|
|
2242
|
+
pane.insertAdjacentHTML('beforeend', `<div class="mini-empty">${_t('notes_empty')}</div>`);
|
|
2243
|
+
return;
|
|
2244
|
+
}
|
|
2245
|
+
const f = document.createElement('div');
|
|
2246
|
+
f.className = 'bot-form';
|
|
2247
|
+
for (const n of list) {
|
|
2248
|
+
const when = n.updatedAt ? new Date(n.updatedAt).toLocaleString('tr-TR', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' }) : '';
|
|
2249
|
+
const card = document.createElement('div');
|
|
2250
|
+
card.className = 'notes-card';
|
|
2251
|
+
card.innerHTML =
|
|
2252
|
+
`<div class="notes-head"><div class="skill-name">${escapeHtml((b.icon || '') + ' ' + (n.code || '?'))} — ${escapeHtml(n.title || '')}</div>` +
|
|
2253
|
+
`<div class="notes-meta">${escapeHtml(when)} · ${n.count || 0} ${_t('bot_stat_msgs')}</div></div>` +
|
|
2254
|
+
`<div class="notes-body">${escapeHtml(String(n.notes || '').slice(0, 4000))}</div>` +
|
|
2255
|
+
`<div style="margin-top:8px"><button class="btn ghost notes-del">${_t('notes_del')}</button></div>`;
|
|
2256
|
+
card.querySelector('.notes-del').addEventListener('click', async () => {
|
|
2257
|
+
await beast.clearNotes(n.id).catch(() => {});
|
|
2258
|
+
toast(_t('deleted'));
|
|
2259
|
+
renderBotNotes(pane, b);
|
|
2260
|
+
});
|
|
2261
|
+
f.appendChild(card);
|
|
2262
|
+
}
|
|
2263
|
+
pane.appendChild(f);
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2230
2266
|
function renderBotOverview(pane) {
|
|
2231
2267
|
pane.innerHTML = `<h2>${_t('bot_overview')}</h2><div class="sub">${_t('bot_overview_sub')}</div>`;
|
|
2232
2268
|
const totals = { numbers: 0, sessions: 0, msgs: 0 };
|
|
@@ -2313,6 +2349,12 @@ function renderBotSettings(pane, b) {
|
|
|
2313
2349
|
const skillChecks = BOT_SKILLS
|
|
2314
2350
|
.map(([k, lbl]) => `<label><input type="checkbox" data-skill="${k}" ${(b.skills || {})[k] ? 'checked' : ''}/> ${lbl}</label>`)
|
|
2315
2351
|
.join('');
|
|
2352
|
+
/* Yetki: 'all' tek başına tüm araçları verir (özel); web/read/chat çoklu seçilebilir */
|
|
2353
|
+
const PERM_OPTS = [['all', _t('wa_perm_all')], ['web', 'Web'], ['read', _t('wa_perm_read')], ['chat', _t('wa_perm_chat')]];
|
|
2354
|
+
const curPerms = Array.isArray(b.perm) ? b.perm : [b.perm || 'all'];
|
|
2355
|
+
const permChecks = PERM_OPTS
|
|
2356
|
+
.map(([k, lbl]) => `<label><input type="checkbox" data-perm="${k}" ${curPerms.includes(k) ? 'checked' : ''}/> ${lbl}</label>`)
|
|
2357
|
+
.join('');
|
|
2316
2358
|
const numRows = (b.numbers || [])
|
|
2317
2359
|
.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>`)
|
|
2318
2360
|
.join('');
|
|
@@ -2334,12 +2376,8 @@ function renderBotSettings(pane, b) {
|
|
|
2334
2376
|
<div class="bot-checks" id="bSee">${seeChecks}</div>
|
|
2335
2377
|
${b.admin ? '' : `
|
|
2336
2378
|
<label class="mem-label">${_t('bot_perm')}</label>
|
|
2337
|
-
<
|
|
2338
|
-
|
|
2339
|
-
<option value="web" ${b.perm === 'web' ? 'selected' : ''}>web</option>
|
|
2340
|
-
<option value="read" ${b.perm === 'read' ? 'selected' : ''}>${_t('wa_perm_read')}</option>
|
|
2341
|
-
<option value="chat" ${b.perm === 'chat' ? 'selected' : ''}>${_t('wa_perm_chat')}</option>
|
|
2342
|
-
</select>
|
|
2379
|
+
<div class="bot-checks" id="bPerm">${permChecks}</div>
|
|
2380
|
+
<div class="sub" style="margin-top:4px">${_t('bot_perm_note')}</div>
|
|
2343
2381
|
<label class="mem-label">${_t('bot_skills')}</label>
|
|
2344
2382
|
<div class="bot-checks" id="bSkills">${skillChecks}</div>`}
|
|
2345
2383
|
<label class="mem-label">${_t('bot_browser')}</label>
|
|
@@ -2387,6 +2425,18 @@ function renderBotSettings(pane, b) {
|
|
|
2387
2425
|
if (bb) renderBotSettings(pane, bb);
|
|
2388
2426
|
})
|
|
2389
2427
|
);
|
|
2428
|
+
/* 'all' hariç diğer izinler çoklu seçilebilir; 'all' işaretlenince diğerleri kapanır */
|
|
2429
|
+
f.querySelectorAll('#bPerm input').forEach((c) =>
|
|
2430
|
+
c.addEventListener('change', () => {
|
|
2431
|
+
if (c.dataset.perm === 'all' && c.checked) {
|
|
2432
|
+
f.querySelectorAll('#bPerm input').forEach((x) => { if (x !== c) x.checked = false; });
|
|
2433
|
+
} else if (c.checked) {
|
|
2434
|
+
const all = f.querySelector('#bPerm input[data-perm="all"]');
|
|
2435
|
+
if (all) all.checked = false;
|
|
2436
|
+
}
|
|
2437
|
+
if (![...f.querySelectorAll('#bPerm input')].some((x) => x.checked)) c.checked = true; // en az biri seçili kalsın
|
|
2438
|
+
})
|
|
2439
|
+
);
|
|
2390
2440
|
$('#bSave').addEventListener('click', async () => {
|
|
2391
2441
|
const patch = {
|
|
2392
2442
|
name: $('#bName').value.trim(),
|
|
@@ -2399,7 +2449,8 @@ function renderBotSettings(pane, b) {
|
|
|
2399
2449
|
numbers: (b.numbers || []).map((n) => n.num),
|
|
2400
2450
|
};
|
|
2401
2451
|
if (!b.admin) {
|
|
2402
|
-
|
|
2452
|
+
const selPerms = [...f.querySelectorAll('#bPerm input:checked')].map((c) => c.dataset.perm);
|
|
2453
|
+
patch.perm = selPerms.includes('all') ? 'all' : selPerms;
|
|
2403
2454
|
const sk = {};
|
|
2404
2455
|
f.querySelectorAll('#bSkills input').forEach((c) => { sk[c.dataset.skill] = c.checked; });
|
|
2405
2456
|
patch.skills = sk;
|