beast-agent 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/scripts/release.js +21 -34
- package/src/agent/bots.js +495 -0
- package/src/agent/engine.js +3486 -3118
- package/src/agent/memory.js +419 -383
- package/src/agent/mqueue.js +124 -0
- package/src/agent/skills.js +523 -522
- package/src/agent/store.js +378 -0
- package/src/agent/watext.js +76 -75
- package/src/main.js +4948 -3951
- package/src/preload.js +159 -128
- package/src/renderer/i18n.js +1093 -795
- package/src/renderer/index.html +332 -231
- package/src/renderer/renderer.js +5095 -3340
- package/src/renderer/style.css +2353 -1312
- package/store/skills.json +5 -0
- package/tests/bg-jobs.test.js +4 -3
package/package.json
CHANGED
package/scripts/release.js
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/* Beast Agent — Dağıtım / Senkron Sistemi
|
|
4
|
-
Tek komutla tam sürüm
|
|
5
|
-
npm run release → otomatik patch bump (0.
|
|
6
|
-
npm run release -- minor → 0.
|
|
7
|
-
npm release -- 0.
|
|
4
|
+
Tek komutla tam sürüm akışı (EXE/INSTALLER YOK — npm + kaynak dağıtımı):
|
|
5
|
+
npm run release → otomatik patch bump (0.20.0 → 0.20.1)
|
|
6
|
+
npm run release -- minor → 0.21.0
|
|
7
|
+
npm run release -- 0.22.0 → belirli sürüm
|
|
8
8
|
|
|
9
9
|
Adımlar:
|
|
10
10
|
1) package.json sürümü yükselt
|
|
11
11
|
2) commit + tag + push (main + tag)
|
|
12
|
-
3)
|
|
13
|
-
4)
|
|
14
|
-
5)
|
|
15
|
-
6) OneDrive yedek klasörüne kaynak kopyası (beast-v< sürüm >)
|
|
12
|
+
3) GitHub Release (yalnız kaynak — exe/asset yüklenmez)
|
|
13
|
+
4) npm publish (NPM_TOKEN env var ise; yoksa atlar ve uyarır)
|
|
14
|
+
5) OneDrive yedek klasörüne kaynak kopyası (beast-v< sürüm >)
|
|
16
15
|
*/
|
|
17
16
|
|
|
18
17
|
const fs = require('fs');
|
|
@@ -29,7 +28,8 @@ const warn = (msg) => console.log(' \x1b[33m!\x1b[0m ' + msg);
|
|
|
29
28
|
const fail = (msg) => { console.error(' \x1b[31m✗ ' + msg + '\x1b[0m'); process.exit(1); };
|
|
30
29
|
|
|
31
30
|
function run(cmd, opts = {}) {
|
|
32
|
-
|
|
31
|
+
/* stdio:'inherit' iken execSync null döner — trim patlamasın */
|
|
32
|
+
return String(execSync(cmd, { cwd: ROOT, stdio: opts.inherit ? 'inherit' : 'pipe', encoding: 'utf8', ...opts }) ?? '').trim();
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
function bump(version, kind) {
|
|
@@ -51,13 +51,13 @@ const tag = 'v' + next;
|
|
|
51
51
|
console.log(`\x1b[1mBeast Agent release: ${current} → ${next}\x1b[0m`);
|
|
52
52
|
|
|
53
53
|
/* ---------- 1) sürüm bump ---------- */
|
|
54
|
-
step('1/
|
|
54
|
+
step('1/5 sürüm yükselt: ' + current + ' → ' + next);
|
|
55
55
|
pkg.version = next;
|
|
56
56
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 4) + '\n');
|
|
57
57
|
ok('package.json → ' + next);
|
|
58
58
|
|
|
59
59
|
/* ---------- 2) commit + push ---------- */
|
|
60
|
-
step('2/
|
|
60
|
+
step('2/5 git: commit + tag + push');
|
|
61
61
|
try {
|
|
62
62
|
run('git add -A');
|
|
63
63
|
run(`git commit -m "v${next}"`);
|
|
@@ -67,43 +67,30 @@ run('git push origin main');
|
|
|
67
67
|
run(`git push origin ${tag}`);
|
|
68
68
|
ok('pushed: main + ' + tag);
|
|
69
69
|
|
|
70
|
-
/* ---------- 3)
|
|
71
|
-
step('3/
|
|
72
|
-
run('npm run dist', { inherit: true });
|
|
73
|
-
const setupExe = path.join(ROOT, 'dist', `BeastAgent-Setup-${next}.exe`);
|
|
74
|
-
const portableExe = path.join(ROOT, 'dist', 'BeastAgent.exe');
|
|
75
|
-
if (!fs.existsSync(setupExe)) fail('setup exe bulunamadı: ' + setupExe);
|
|
76
|
-
if (!fs.existsSync(portableExe)) fail('portable exe bulunamadı: ' + portableExe);
|
|
77
|
-
ok('dist hazır: Setup + Portable');
|
|
78
|
-
|
|
79
|
-
/* ---------- 4) GitHub release ---------- */
|
|
80
|
-
step('4/6 GitHub Release ' + tag);
|
|
70
|
+
/* ---------- 3) GitHub Release (kaynak — exe yok) ---------- */
|
|
71
|
+
step('3/5 GitHub Release ' + tag);
|
|
81
72
|
const gh = process.env.GH || 'gh';
|
|
82
73
|
try {
|
|
83
74
|
const notes = [
|
|
84
75
|
`## Beast Agent ${tag}`,
|
|
85
76
|
'',
|
|
86
|
-
'-
|
|
87
|
-
'- \`BeastAgent.exe\` — portable',
|
|
88
|
-
'- \`npm i -g beast-agent\` — npm üzerinden',
|
|
77
|
+
'- \`npm i -g beast-agent@\`' + next,
|
|
89
78
|
'',
|
|
79
|
+
'Dağıtım npm üzerinden yapılır — exe/installer sürümü kaldırıldı.',
|
|
90
80
|
'Tam değişiklik listesi: commit geçmişi.',
|
|
91
81
|
].join('\n');
|
|
92
82
|
const notesFile = path.join(ROOT, 'dist', 'release-notes.md');
|
|
83
|
+
fs.mkdirSync(path.dirname(notesFile), { recursive: true });
|
|
93
84
|
fs.writeFileSync(notesFile, notes);
|
|
94
|
-
const assets = [setupExe, setupExe + '.blockmap', portableExe, path.join(ROOT, 'dist', 'latest.yml')]
|
|
95
|
-
.filter((f) => fs.existsSync(f))
|
|
96
|
-
.map((f) => `"${f}"`)
|
|
97
|
-
.join(' ');
|
|
98
85
|
try { run(`${gh} release delete ${tag} --yes --cleanup-tag`); } catch {}
|
|
99
|
-
run(`${gh} release create ${tag}
|
|
86
|
+
run(`${gh} release create ${tag} --title "Beast Agent ${tag}" --notes-file "${notesFile}"`, { inherit: true });
|
|
100
87
|
ok('release yayında: https://github.com/algokodcom/beast-agent/releases/tag/' + tag);
|
|
101
88
|
} catch (e) {
|
|
102
89
|
fail('GitHub release: ' + String(e));
|
|
103
90
|
}
|
|
104
91
|
|
|
105
|
-
/* ----------
|
|
106
|
-
step('5
|
|
92
|
+
/* ---------- 4) npm publish ---------- */
|
|
93
|
+
step('4/5 npm publish');
|
|
107
94
|
if (process.env.NPM_TOKEN) {
|
|
108
95
|
try {
|
|
109
96
|
run(`npm publish --//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}`, { inherit: true });
|
|
@@ -116,8 +103,8 @@ if (process.env.NPM_TOKEN) {
|
|
|
116
103
|
warn('Elle: set NPM_TOKEN=<token> && npm publish');
|
|
117
104
|
}
|
|
118
105
|
|
|
119
|
-
/* ----------
|
|
120
|
-
step('
|
|
106
|
+
/* ---------- 5) OneDrive kaynak yedeği ---------- */
|
|
107
|
+
step('5/5 OneDrive yedek (beast-v' + next + ')');
|
|
121
108
|
try {
|
|
122
109
|
const dest = path.join(ONE_DRIVE_DIR, 'beast-v' + next);
|
|
123
110
|
fs.mkdirSync(dest, { recursive: true });
|
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/* Beast Bot Sistemi (BÖLÜM 2 / 3 / 6 / 7)
|
|
4
|
+
- İlk bot hep "Beast" (admin, silinemez). Toplam MAX 5 bot (1 admin + 4 müşteri).
|
|
5
|
+
- Her bot izole klasörde yaşar: bots/<id>/
|
|
6
|
+
config.json → botun temel ayarı (ayna)
|
|
7
|
+
memory.md → botun KENDİ hafızası (diğer botlar göremez)
|
|
8
|
+
yetkiler.json → görebildiği botlar + skill/plugin/tarayıcı yetkileri
|
|
9
|
+
logs/changes.log → yetki/ayar değişiklik günlüğü (her değişiklik loglanır)
|
|
10
|
+
chat/ plugins/ watchers/ → botun izole çalışma alanları
|
|
11
|
+
- WhatsApp numaraları bot_id ile eşlenir; registry bots.json'da durur.
|
|
12
|
+
whitelist.json aynası main tarafında senkronlanır. */
|
|
13
|
+
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const os = require('os');
|
|
17
|
+
const memory = require('./memory'); // tokenize/scoreEntry yeniden kullanılır (döngü yok)
|
|
18
|
+
|
|
19
|
+
const MAX_BOTS = 5;
|
|
20
|
+
|
|
21
|
+
const ICONS = ['🦁', '🚀', '💎', '⭐', '🔥', '🧮', '📊', '🤖', '🦊', '🐼', '🎯', '🛠️'];
|
|
22
|
+
|
|
23
|
+
/* Her botta varsayılan AÇIK gelen skill'ler (yetki sadece admin tarafından değişir) */
|
|
24
|
+
const DEFAULT_SKILLS = {
|
|
25
|
+
email: true,
|
|
26
|
+
browser: true, // dahili tarayıcı varsayılan TÜM botlarda aktif
|
|
27
|
+
web_search: true,
|
|
28
|
+
run_command: false,
|
|
29
|
+
memory: true,
|
|
30
|
+
kb: true,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const SKILL_LIST = [
|
|
34
|
+
['email', 'E-posta (okuma/gönderme)'],
|
|
35
|
+
['browser', 'Dahili tarayıcı (panel)'],
|
|
36
|
+
['web_search', 'Web arama + sayfa okuma'],
|
|
37
|
+
['run_command', 'Terminal / dosya / ekran'],
|
|
38
|
+
['memory', 'Kendi hafızası (yazma/arama)'],
|
|
39
|
+
['kb', 'Bilgi bankası (arama/ekleme)'],
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
const PLUGIN_LIST = ['fatura_okuyucu', 'crm_plugin', 'rapor_uretici', 'stok_takip', 'toplanti_ozet'];
|
|
43
|
+
|
|
44
|
+
function beastRoot() {
|
|
45
|
+
if (process.env.BEAST_DATA) return process.env.BEAST_DATA;
|
|
46
|
+
return process.env.APPDATA
|
|
47
|
+
? path.join(process.env.APPDATA, 'beast')
|
|
48
|
+
: path.join(os.homedir(), 'AppData', 'Roaming', 'beast');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function registryFile() {
|
|
52
|
+
return path.join(beastRoot(), 'bots.json');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function botDir(id) {
|
|
56
|
+
return path.join(beastRoot(), 'bots', String(id || '').replace(/[^a-z0-9_-]/gi, ''));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function nowIso() {
|
|
60
|
+
return new Date().toISOString();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function uid() {
|
|
64
|
+
return Date.now().toString(36) + Math.random().toString(36).slice(2, 7);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function foldTr(s) {
|
|
68
|
+
return String(s || '')
|
|
69
|
+
.toLowerCase()
|
|
70
|
+
.replace(/[çğıöşüâîû]/g, (ch) => ({ ç: 'c', ğ: 'g', ı: 'i', ö: 'o', ş: 's', ü: 'u', â: 'a', î: 'i', û: 'u' }[ch] || ch));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function slugify(name) {
|
|
74
|
+
const base = foldTr(String(name || 'bot'))
|
|
75
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
76
|
+
.replace(/^-+|-+$/g, '')
|
|
77
|
+
.slice(0, 18);
|
|
78
|
+
return base || 'bot';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function adminBot() {
|
|
82
|
+
return {
|
|
83
|
+
id: 'beast',
|
|
84
|
+
name: 'Beast',
|
|
85
|
+
icon: '🦁',
|
|
86
|
+
admin: true,
|
|
87
|
+
prompt: '',
|
|
88
|
+
perm: 'all',
|
|
89
|
+
skills: { ...DEFAULT_SKILLS, run_command: true },
|
|
90
|
+
seeBots: [], // admin her şeyi görür
|
|
91
|
+
extBrowser: true, // dış tarayıcı yetkisi
|
|
92
|
+
browserDefault: 'dahili',
|
|
93
|
+
extCommand: '',
|
|
94
|
+
plugins: [],
|
|
95
|
+
createdAt: nowIso(),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* ---------- registry ---------- */
|
|
100
|
+
|
|
101
|
+
let REG = null;
|
|
102
|
+
|
|
103
|
+
function loadRegistry() {
|
|
104
|
+
if (REG) return REG;
|
|
105
|
+
try {
|
|
106
|
+
REG = JSON.parse(fs.readFileSync(registryFile(), 'utf8'));
|
|
107
|
+
} catch {
|
|
108
|
+
REG = null;
|
|
109
|
+
}
|
|
110
|
+
if (!REG || !Array.isArray(REG.bots)) REG = { bots: [adminBot()] };
|
|
111
|
+
/* beast her zaman ilk ve admin */
|
|
112
|
+
const beast = REG.bots.find((b) => b && b.id === 'beast');
|
|
113
|
+
if (!beast) REG.bots.unshift(adminBot());
|
|
114
|
+
else Object.assign(beast, { ...adminBot(), ...beast, id: 'beast', admin: true, name: beast.name || 'Beast' });
|
|
115
|
+
saveRegistry();
|
|
116
|
+
ensureDirs();
|
|
117
|
+
return REG;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function saveRegistry() {
|
|
121
|
+
try {
|
|
122
|
+
fs.mkdirSync(beastRoot(), { recursive: true });
|
|
123
|
+
fs.writeFileSync(registryFile(), JSON.stringify(REG, null, 2));
|
|
124
|
+
} catch {}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function ensureDirs() {
|
|
128
|
+
for (const b of REG.bots) {
|
|
129
|
+
const d = botDir(b.id);
|
|
130
|
+
try {
|
|
131
|
+
for (const sub of ['logs', 'chat', 'plugins', 'watchers']) fs.mkdirSync(path.join(d, sub), { recursive: true });
|
|
132
|
+
const cfgP = path.join(d, 'config.json');
|
|
133
|
+
if (!fs.existsSync(cfgP)) fs.writeFileSync(cfgP, JSON.stringify(botConfigOf(b), null, 2));
|
|
134
|
+
const yetP = path.join(d, 'yetkiler.json');
|
|
135
|
+
if (!fs.existsSync(yetP)) fs.writeFileSync(yetP, JSON.stringify(botPermsOf(b), null, 2));
|
|
136
|
+
/* bot hafızası ayarlardaki yapıyla aynı: SOUL.md + MEMORY.md + USER.md
|
|
137
|
+
(eski memory.md varsa içeriği MEMORY.md'ye taşınır) */
|
|
138
|
+
const legacyP = path.join(d, 'memory.md');
|
|
139
|
+
const legacy = fs.existsSync(legacyP) ? fs.readFileSync(legacyP, 'utf8') : '';
|
|
140
|
+
const memP = path.join(d, 'MEMORY.md');
|
|
141
|
+
if (!fs.existsSync(memP)) fs.writeFileSync(memP, legacy || '');
|
|
142
|
+
for (const f of ['SOUL.md', 'USER.md']) {
|
|
143
|
+
const p = path.join(d, f);
|
|
144
|
+
if (!fs.existsSync(p)) fs.writeFileSync(p, '');
|
|
145
|
+
}
|
|
146
|
+
} catch {}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function botConfigOf(b) {
|
|
151
|
+
return {
|
|
152
|
+
id: b.id,
|
|
153
|
+
name: b.name,
|
|
154
|
+
icon: b.icon,
|
|
155
|
+
admin: !!b.admin,
|
|
156
|
+
prompt: b.prompt || '',
|
|
157
|
+
browser: { default: b.browserDefault || 'dahili', extCommand: b.extCommand || '' },
|
|
158
|
+
plugins: b.plugins || [],
|
|
159
|
+
createdAt: b.createdAt,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function botPermsOf(b) {
|
|
164
|
+
return {
|
|
165
|
+
id: b.id,
|
|
166
|
+
perm: b.perm || 'all',
|
|
167
|
+
skills: { ...DEFAULT_SKILLS, ...(b.skills || {}) },
|
|
168
|
+
seeBots: b.seeBots || [],
|
|
169
|
+
extBrowser: b.extBrowser !== false,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* ---------- log ---------- */
|
|
174
|
+
|
|
175
|
+
function logChange(id, text) {
|
|
176
|
+
try {
|
|
177
|
+
const d = botDir(id);
|
|
178
|
+
fs.mkdirSync(path.join(d, 'logs'), { recursive: true });
|
|
179
|
+
fs.appendFileSync(path.join(d, 'logs', 'changes.log'), `[${new Date().toISOString()}] ${text}\n`);
|
|
180
|
+
} catch {}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/* ---------- public API ---------- */
|
|
184
|
+
|
|
185
|
+
function list() {
|
|
186
|
+
loadRegistry();
|
|
187
|
+
return REG.bots.map((b) => ({ ...b, skills: { ...DEFAULT_SKILLS, ...(b.skills || {}) } }));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function get(id) {
|
|
191
|
+
loadRegistry();
|
|
192
|
+
return REG.bots.find((b) => b.id === String(id || '')) || null;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function add({ name, icon, prompt }) {
|
|
196
|
+
loadRegistry();
|
|
197
|
+
const n = String(name || '').trim().slice(0, 40);
|
|
198
|
+
if (!n) return { ok: false, error: 'bot adı zorunlu' };
|
|
199
|
+
if (REG.bots.length >= MAX_BOTS) return { ok: false, error: `en fazla ${MAX_BOTS} bot olabilir (1 admin + ${MAX_BOTS - 1} müşteri)` };
|
|
200
|
+
let id = slugify(n);
|
|
201
|
+
while (get(id)) id = slugify(n) + '-' + uid().slice(-4);
|
|
202
|
+
const bot = {
|
|
203
|
+
id,
|
|
204
|
+
name: n,
|
|
205
|
+
icon: ICONS.includes(icon) ? icon : '🤖',
|
|
206
|
+
admin: false,
|
|
207
|
+
prompt: String(prompt || '').slice(0, 4000),
|
|
208
|
+
perm: 'all',
|
|
209
|
+
skills: { ...DEFAULT_SKILLS },
|
|
210
|
+
seeBots: [], // varsayılan: hiçbir bot baka botu göremez
|
|
211
|
+
extBrowser: false, // dış tarayıcı sadece yetkilide
|
|
212
|
+
browserDefault: 'dahili',
|
|
213
|
+
extCommand: '',
|
|
214
|
+
plugins: [],
|
|
215
|
+
createdAt: nowIso(),
|
|
216
|
+
};
|
|
217
|
+
REG.bots.push(bot);
|
|
218
|
+
saveRegistry();
|
|
219
|
+
ensureDirs();
|
|
220
|
+
logChange(id, `bot oluşturuldu (name="${n}", icon=${bot.icon})`);
|
|
221
|
+
return { ok: true, bot: { ...bot } };
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function update(id, patch) {
|
|
225
|
+
loadRegistry();
|
|
226
|
+
const b = get(id);
|
|
227
|
+
if (!b) return { ok: false, error: 'bot yok' };
|
|
228
|
+
const changes = [];
|
|
229
|
+
if (patch && typeof patch === 'object') {
|
|
230
|
+
if (typeof patch.name === 'string' && patch.name.trim() && patch.name.trim() !== b.name) {
|
|
231
|
+
changes.push(`name: "${b.name}" → "${patch.name.trim().slice(0, 40)}"`);
|
|
232
|
+
b.name = patch.name.trim().slice(0, 40);
|
|
233
|
+
}
|
|
234
|
+
if (typeof patch.icon === 'string' && ICONS.includes(patch.icon) && patch.icon !== b.icon) {
|
|
235
|
+
changes.push(`icon: ${b.icon} → ${patch.icon}`);
|
|
236
|
+
b.icon = patch.icon;
|
|
237
|
+
}
|
|
238
|
+
if (typeof patch.prompt === 'string' && patch.prompt !== b.prompt) {
|
|
239
|
+
changes.push('prompt güncellendi');
|
|
240
|
+
b.prompt = String(patch.prompt).slice(0, 4000);
|
|
241
|
+
}
|
|
242
|
+
if (['all', 'web', 'read', 'chat'].includes(patch.perm) && patch.perm !== b.perm) {
|
|
243
|
+
changes.push(`perm: ${b.perm} → ${patch.perm}`);
|
|
244
|
+
b.perm = patch.perm;
|
|
245
|
+
}
|
|
246
|
+
if (patch.skills && typeof patch.skills === 'object') {
|
|
247
|
+
const merged = { ...DEFAULT_SKILLS, ...(b.skills || {}) };
|
|
248
|
+
for (const k of Object.keys(DEFAULT_SKILLS)) {
|
|
249
|
+
if (typeof patch.skills[k] === 'boolean' && patch.skills[k] !== merged[k]) {
|
|
250
|
+
changes.push(`skill ${k}: ${merged[k]} → ${patch.skills[k]}`);
|
|
251
|
+
merged[k] = patch.skills[k];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
b.skills = merged;
|
|
255
|
+
}
|
|
256
|
+
if (Array.isArray(patch.seeBots)) {
|
|
257
|
+
const valid = patch.seeBots.map(String).filter((x) => x !== b.id && get(x));
|
|
258
|
+
const next = [...new Set(valid)];
|
|
259
|
+
if (JSON.stringify(next) !== JSON.stringify(b.seeBots || [])) {
|
|
260
|
+
changes.push(`görebilir: [${(b.seeBots || []).join(', ') || '—'}] → [${next.join(', ') || '—'}]`);
|
|
261
|
+
b.seeBots = next;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (typeof patch.extBrowser === 'boolean' && patch.extBrowser !== b.extBrowser) {
|
|
265
|
+
changes.push(`dış tarayıcı yetkisi: ${b.extBrowser} → ${patch.extBrowser}`);
|
|
266
|
+
b.extBrowser = patch.extBrowser;
|
|
267
|
+
}
|
|
268
|
+
if (['dahili', 'dis'].includes(patch.browserDefault) && patch.browserDefault !== b.browserDefault) {
|
|
269
|
+
changes.push(`varsayılan tarayıcı: ${b.browserDefault} → ${patch.browserDefault}`);
|
|
270
|
+
b.browserDefault = patch.browserDefault;
|
|
271
|
+
}
|
|
272
|
+
if (typeof patch.extCommand === 'string' && patch.extCommand !== b.extCommand) {
|
|
273
|
+
changes.push('dış tarayıcı komutu güncellendi');
|
|
274
|
+
b.extCommand = String(patch.extCommand).slice(0, 200);
|
|
275
|
+
}
|
|
276
|
+
if (Array.isArray(patch.plugins)) {
|
|
277
|
+
const next = [...new Set(patch.plugins.map((p) => String(p).slice(0, 40)).filter((p) => PLUGIN_LIST.includes(p)))];
|
|
278
|
+
if (JSON.stringify(next) !== JSON.stringify(b.plugins || [])) {
|
|
279
|
+
changes.push(`pluginler: [${(b.plugins || []).join(', ') || '—'}] → [${next.join(', ') || '—'}]`);
|
|
280
|
+
b.plugins = next;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
saveRegistry();
|
|
285
|
+
ensureDirs();
|
|
286
|
+
try {
|
|
287
|
+
const d = botDir(b.id);
|
|
288
|
+
fs.writeFileSync(path.join(d, 'config.json'), JSON.stringify(botConfigOf(b), null, 2));
|
|
289
|
+
fs.writeFileSync(path.join(d, 'yetkiler.json'), JSON.stringify(botPermsOf(b), null, 2));
|
|
290
|
+
} catch {}
|
|
291
|
+
for (const c of changes) logChange(b.id, `yetki/ayar değişikliği (admin): ${c}`);
|
|
292
|
+
return { ok: true, bot: { ...b }, changed: changes.length };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function remove(id) {
|
|
296
|
+
loadRegistry();
|
|
297
|
+
const b = get(id);
|
|
298
|
+
if (!b) return { ok: false, error: 'bot yok' };
|
|
299
|
+
if (b.admin) return { ok: false, error: 'admin bot silinemez' };
|
|
300
|
+
REG.bots = REG.bots.filter((x) => x.id !== b.id);
|
|
301
|
+
saveRegistry();
|
|
302
|
+
logChange(b.id, `bot SİLİNDİ — bağlı numaralar botsuz duruma düştü (beast'e yönlendirilir)`);
|
|
303
|
+
/* klasör arşivlenir — veri kaybı olmasın */
|
|
304
|
+
try {
|
|
305
|
+
const d = botDir(b.id);
|
|
306
|
+
if (fs.existsSync(d)) fs.renameSync(d, d + '-arsiv-' + Date.now().toString(36));
|
|
307
|
+
} catch {}
|
|
308
|
+
return { ok: true };
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/* viewer botun target botu görüp göremeyeceği */
|
|
312
|
+
function canSee(viewerId, targetId) {
|
|
313
|
+
const v = get(viewerId);
|
|
314
|
+
if (!v) return false;
|
|
315
|
+
if (v.admin) return true; // admin her şeyi görür
|
|
316
|
+
if (viewerId === targetId) return true;
|
|
317
|
+
return (v.seeBots || []).includes(String(targetId));
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/* botun hafıza dosyaları — ayarlardaki SOUL/USER/MEMORY üçlüsünün bot izole hali */
|
|
321
|
+
const BOT_MEM_FILES = ['SOUL.md', 'MEMORY.md', 'USER.md'];
|
|
322
|
+
|
|
323
|
+
/* botun MEMORY.md'si (persona bloğuna giden kısım) */
|
|
324
|
+
function readMemory(id, cap = 2000) {
|
|
325
|
+
try {
|
|
326
|
+
return fs.readFileSync(path.join(botDir(id), 'MEMORY.md'), 'utf8').slice(0, cap).trim();
|
|
327
|
+
} catch {
|
|
328
|
+
return '';
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function readMemoryFiles(id) {
|
|
333
|
+
const d = botDir(id);
|
|
334
|
+
const out = { soul: '', memory: '', user: '' };
|
|
335
|
+
try { out.soul = fs.readFileSync(path.join(d, 'SOUL.md'), 'utf8'); } catch {}
|
|
336
|
+
try { out.memory = fs.readFileSync(path.join(d, 'MEMORY.md'), 'utf8'); } catch {}
|
|
337
|
+
try { out.user = fs.readFileSync(path.join(d, 'USER.md'), 'utf8'); } catch {}
|
|
338
|
+
return out;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function writeMemoryFile(id, file, content) {
|
|
342
|
+
const b = get(id);
|
|
343
|
+
if (!b) return { ok: false, error: 'bot yok' };
|
|
344
|
+
if (!BOT_MEM_FILES.includes(file)) return { ok: false, error: 'geçersiz dosya' };
|
|
345
|
+
try {
|
|
346
|
+
const d = botDir(id);
|
|
347
|
+
fs.mkdirSync(d, { recursive: true });
|
|
348
|
+
fs.writeFileSync(path.join(d, file), String(content ?? ''), 'utf8');
|
|
349
|
+
logChange(id, `${file} admin tarafından güncellendi`);
|
|
350
|
+
return { ok: true };
|
|
351
|
+
} catch (e) {
|
|
352
|
+
return { ok: false, error: String((e && e.message) || e) };
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/* ---------- BOT OTURUMU hafıza operasyonları ----------
|
|
357
|
+
Bot oturumlarında memory_write/memory_search GLOBAL Beast hafızasına DEĞİL,
|
|
358
|
+
botun kendi SOUL/USER/MEMORY dosyalarına gider (tam izolasyon). */
|
|
359
|
+
|
|
360
|
+
function readMem(id, f) {
|
|
361
|
+
if (!BOT_MEM_FILES.includes(f)) return '';
|
|
362
|
+
try {
|
|
363
|
+
return fs.readFileSync(path.join(botDir(id), f), 'utf8');
|
|
364
|
+
} catch {
|
|
365
|
+
return '';
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function memEntries(id) {
|
|
370
|
+
return readMem(id, 'MEMORY.md')
|
|
371
|
+
.split('\n')
|
|
372
|
+
.map((l) => l.replace(/^[-*]\s*/, '').trim())
|
|
373
|
+
.filter(Boolean);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function appendMem(id, text) {
|
|
377
|
+
const t = String(text || '').replace(/\s+/g, ' ').trim().slice(0, 500);
|
|
378
|
+
if (!t) return { ok: false, error: 'empty' };
|
|
379
|
+
const list = memEntries(id);
|
|
380
|
+
const key = foldTr(t).replace(/[^a-z0-9]+/g, ' ').trim();
|
|
381
|
+
if (list.some((l) => foldTr(l).replace(/[^a-z0-9]+/g, ' ').trim() === key)) {
|
|
382
|
+
return { ok: true, duplicate: true };
|
|
383
|
+
}
|
|
384
|
+
try {
|
|
385
|
+
fs.mkdirSync(botDir(id), { recursive: true });
|
|
386
|
+
fs.appendFileSync(path.join(botDir(id), 'MEMORY.md'), '- ' + t + '\n');
|
|
387
|
+
return { ok: true };
|
|
388
|
+
} catch (e) {
|
|
389
|
+
return { ok: false, error: String((e && e.message) || e) };
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/* botun USER.md'si: bota özel kullanıcı profili (aynı dedup/yenile mantığı) */
|
|
394
|
+
function appendUserMem(id, text) {
|
|
395
|
+
const t = String(text || '').replace(/\s+/g, ' ').trim().slice(0, 300);
|
|
396
|
+
if (!t) return { ok: false, error: 'empty' };
|
|
397
|
+
try {
|
|
398
|
+
const p = path.join(botDir(id), 'USER.md');
|
|
399
|
+
fs.mkdirSync(botDir(id), { recursive: true });
|
|
400
|
+
const lines = readMem(id, 'USER.md')
|
|
401
|
+
.split('\n')
|
|
402
|
+
.map((l) => l.replace(/^[-*]\s*/, '').trim())
|
|
403
|
+
.filter(Boolean);
|
|
404
|
+
/* profil anahtarı: "Konu: ..." satırlarında Konu — değişiklikte güncelle */
|
|
405
|
+
const topicOf = (s) => {
|
|
406
|
+
const c = foldTr(s).indexOf(':');
|
|
407
|
+
return (c > 0 ? foldTr(s).slice(0, c) : foldTr(s)).replace(/[^a-z0-9]+/g, ' ').trim();
|
|
408
|
+
};
|
|
409
|
+
const topic = topicOf(t);
|
|
410
|
+
const idx = lines.findIndex((l) => topicOf(l) === topic);
|
|
411
|
+
if (idx >= 0) {
|
|
412
|
+
if (lines[idx] === t) return { ok: true, duplicate: true };
|
|
413
|
+
lines[idx] = t;
|
|
414
|
+
} else {
|
|
415
|
+
lines.push(t);
|
|
416
|
+
}
|
|
417
|
+
while (lines.length > 60) lines.shift();
|
|
418
|
+
fs.writeFileSync(p, lines.map((l) => '- ' + l).join('\n') + '\n');
|
|
419
|
+
return { ok: true, updated: idx >= 0 };
|
|
420
|
+
} catch (e) {
|
|
421
|
+
return { ok: false, error: String((e && e.message) || e) };
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function searchMem(id, query, limit = 8) {
|
|
426
|
+
const list = memEntries(id);
|
|
427
|
+
if (!list.length) return [];
|
|
428
|
+
const qTokens = memory.tokenize(query);
|
|
429
|
+
let rows;
|
|
430
|
+
if (!qTokens.length) {
|
|
431
|
+
rows = list.map((text, i) => ({ text, score: 0, i })).slice(-limit).reverse();
|
|
432
|
+
} else {
|
|
433
|
+
rows = list
|
|
434
|
+
.map((text, i) => ({ text, i, score: Number(memory.scoreEntry(text, qTokens).toFixed(3)) }))
|
|
435
|
+
.filter((r) => r.score > 0)
|
|
436
|
+
.sort((a, b) => b.score - a.score)
|
|
437
|
+
.slice(0, limit);
|
|
438
|
+
}
|
|
439
|
+
return rows.map(({ text, score }) => ({ score, text }));
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function relevantMem(id, query, { maxRelevant = 6, maxRecent = 4, charCap = 2400 } = {}) {
|
|
443
|
+
const list = memEntries(id);
|
|
444
|
+
if (!list.length) return '';
|
|
445
|
+
const qTokens = memory.tokenize(query);
|
|
446
|
+
const picked = new Set();
|
|
447
|
+
if (qTokens.length) {
|
|
448
|
+
list
|
|
449
|
+
.map((text, i) => ({ i, score: memory.scoreEntry(text, qTokens) }))
|
|
450
|
+
.filter((r) => r.score > 0)
|
|
451
|
+
.sort((a, b) => b.score - a.score)
|
|
452
|
+
.slice(0, maxRelevant)
|
|
453
|
+
.forEach((r) => picked.add(r.i));
|
|
454
|
+
}
|
|
455
|
+
for (let i = list.length - 1; i >= 0 && picked.size < maxRelevant + maxRecent; i--) picked.add(i);
|
|
456
|
+
let out = '';
|
|
457
|
+
for (const i of [...picked].sort((a, b) => a - b)) {
|
|
458
|
+
const line = '- ' + list[i];
|
|
459
|
+
if (out.length + line.length > charCap) break;
|
|
460
|
+
out += (out ? '\n' : '') + line;
|
|
461
|
+
}
|
|
462
|
+
return out;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function readLog(id, cap = 20000) {
|
|
466
|
+
try {
|
|
467
|
+
return fs.readFileSync(path.join(botDir(id), 'logs', 'changes.log'), 'utf8').slice(-cap);
|
|
468
|
+
} catch {
|
|
469
|
+
return '';
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
module.exports = {
|
|
474
|
+
MAX_BOTS,
|
|
475
|
+
ICONS,
|
|
476
|
+
SKILL_LIST,
|
|
477
|
+
PLUGIN_LIST,
|
|
478
|
+
beastRoot,
|
|
479
|
+
botDir,
|
|
480
|
+
list,
|
|
481
|
+
get,
|
|
482
|
+
add,
|
|
483
|
+
update,
|
|
484
|
+
remove,
|
|
485
|
+
canSee,
|
|
486
|
+
readMemory,
|
|
487
|
+
readMemoryFiles,
|
|
488
|
+
writeMemoryFile,
|
|
489
|
+
readMem,
|
|
490
|
+
appendMem,
|
|
491
|
+
appendUserMem,
|
|
492
|
+
searchMem,
|
|
493
|
+
relevantMem,
|
|
494
|
+
readLog,
|
|
495
|
+
};
|