beast-agent 2.76.5 → 2.77.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/src/agent/bots.js +669 -664
- package/src/agent/customtools.js +6 -19
- package/src/agent/engine.js +55 -307
- package/src/agent/seeds/tool-yazma/SKILL.md +13 -16
- package/src/agent/skills.js +14 -35
- package/src/agent/supertonic.js +622 -0
- package/src/agent/tools.js +3 -7
- package/src/main.js +77 -6068
- package/src/preload.js +2 -17
- package/src/renderer/i18n.js +14 -8
- package/src/renderer/index.html +0 -297
- package/src/renderer/renderer.js +142 -2280
- package/src/renderer/style.css +3 -825
- package/src/agent/defaulttools/mt5_barlar2/run.js +0 -188
- package/src/agent/defaulttools/mt5_barlar2/tool.json +0 -23
- package/src/agent/defaulttools/mt5_bekleyen/run.js +0 -105
- package/src/agent/defaulttools/mt5_bekleyen/tool.json +0 -18
- package/src/agent/defaulttools/mt5_durum/run.js +0 -93
- package/src/agent/defaulttools/mt5_durum/tool.json +0 -10
- package/src/agent/defaulttools/mt5_emir/run.js +0 -98
- package/src/agent/defaulttools/mt5_emir/tool.json +0 -17
- package/src/agent/defaulttools/mt5_emir_iptal/run.js +0 -90
- package/src/agent/defaulttools/mt5_emir_iptal/tool.json +0 -12
- package/src/agent/defaulttools/mt5_fiyat/run.js +0 -87
- package/src/agent/defaulttools/mt5_fiyat/tool.json +0 -16
- package/src/agent/defaulttools/mt5_gecmis/run.js +0 -87
- package/src/agent/defaulttools/mt5_gecmis/tool.json +0 -12
- package/src/agent/defaulttools/mt5_kapat/run.js +0 -108
- package/src/agent/defaulttools/mt5_kapat/tool.json +0 -15
- package/src/agent/defaulttools/mt5_m15_m5/m15m5.py +0 -60
- package/src/agent/defaulttools/mt5_m15_m5/run.js +0 -73
- package/src/agent/defaulttools/mt5_m15_m5/tool.json +0 -10
- package/src/agent/defaulttools/mt5_pozisyon_gecmis/run.js +0 -144
- package/src/agent/defaulttools/mt5_pozisyon_gecmis/tool.json +0 -12
- package/src/agent/defaulttools/mt5_shot/run.js +0 -649
- package/src/agent/defaulttools/mt5_shot/stitch.js +0 -151
- package/src/agent/defaulttools/mt5_shot/tool.json +0 -25
- package/src/agent/defaulttools/mt5_sltp/run.js +0 -92
- package/src/agent/defaulttools/mt5_sltp/tool.json +0 -14
- package/src/agent/financetools.js +0 -1025
- package/src/agent/finindicators.js +0 -254
- package/src/agent/finrisk.js +0 -289
- package/src/agent/finstats.js +0 -239
- package/src/agent/finwatch.js +0 -302
- package/src/agent/mt5/BeastFinance.mq5 +0 -498
- package/src/agent/mt5/BeastShot.tpl +0 -0
- package/src/agent/mt5setup.js +0 -542
- package/src/agent/scripts/mt5_bridge.py +0 -575
- package/src/agent/seeds/haber-duygu/SKILL.md +0 -49
- package/src/agent/seeds/mql5/SKILL.md +0 -154
- package/src/agent/seeds/price-action/SKILL.md +0 -60
- package/src/agent/seeds/risk-yonetimi/SKILL.md +0 -52
- package/src/mt5bridge.js +0 -215
package/src/agent/bots.js
CHANGED
|
@@ -1,664 +1,669 @@
|
|
|
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
|
-
code: '', // 5 haneli benzersiz bot kodu (ensureBotCodes atar)
|
|
88
|
-
prompt: '',
|
|
89
|
-
perm: 'all',
|
|
90
|
-
vis: true, // sohbet görünürlüğü: ana sohbete davet edilebilir
|
|
91
|
-
skills: { ...DEFAULT_SKILLS, run_command: true },
|
|
92
|
-
seeBots: [], // admin her şeyi görür
|
|
93
|
-
extBrowser: true, // dış tarayıcı yetkisi
|
|
94
|
-
browserDefault: 'dahili',
|
|
95
|
-
extCommand: '',
|
|
96
|
-
plugins: [],
|
|
97
|
-
createdAt: nowIso(),
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/* ZORUNLU VARSAYILAN BOTLAR: Beast (admin) +
|
|
102
|
-
Eksik olanlar OTOMATİK açılır — Tool botunun TEK görevi tool yazmaktır;
|
|
103
|
-
diğer ajanlar/botlar tool_request ile ona devreder (cephane mantığı). */
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
function
|
|
278
|
-
loadRegistry();
|
|
279
|
-
return REG.bots.
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function
|
|
283
|
-
loadRegistry();
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
loadRegistry();
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
if (patch && typeof patch === '
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
b.
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
b.
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
b.
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
b.
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
b.
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
/*
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
return { ok: true };
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
const
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
const
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
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
|
+
code: '', // 5 haneli benzersiz bot kodu (ensureBotCodes atar)
|
|
88
|
+
prompt: '',
|
|
89
|
+
perm: 'all',
|
|
90
|
+
vis: true, // sohbet görünürlüğü: ana sohbete davet edilebilir
|
|
91
|
+
skills: { ...DEFAULT_SKILLS, run_command: true },
|
|
92
|
+
seeBots: [], // admin her şeyi görür
|
|
93
|
+
extBrowser: true, // dış tarayıcı yetkisi
|
|
94
|
+
browserDefault: 'dahili',
|
|
95
|
+
extCommand: '',
|
|
96
|
+
plugins: [],
|
|
97
|
+
createdAt: nowIso(),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* ZORUNLU VARSAYILAN BOTLAR: Beast (admin) + Coder + Tool.
|
|
102
|
+
Eksik olanlar OTOMATİK açılır — Tool botunun TEK görevi tool yazmaktır;
|
|
103
|
+
diğer ajanlar/botlar tool_request ile ona devreder (cephane mantığı). */
|
|
104
|
+
const RETIRED_TRADER_PROMPT = "Sen BEAST Trader botsun: disiplinli bir trading analisti. Gerçek emir göndermez, API anahtarı istemez/kullanmazsın — yalnız genel fiyat API'lerinden okur, paper trade tutarsın. Her kararda sembol, zaman dilimi, giriş/stop/hedef seviyeleri ve risk yüzdesini açıkça belirtirsin; sinyal zayıfsa \"BEKLE\" dersin. İzleyici (watcher) kurarak sürekli izlersin. Grafik doğrulaması: tool__mt5_shot ile MT5 grafiğinden GERÇEK PNG al ve grafiği gör (timeframes:[\"M1\",\"M15\"] ile çoklu periyot, symbols:[\"GOLD\",\"EURUSD\"] ile çoklu sembol TEK karede; yoksa computer_look; metin-model isen ocr_read source:\"screen\"/\"browser\"); web grafiklerinde browser_screenshot kullan. İhtiyacın olan özel grafik aracı yoksa tool_request ile TOOL botuna yazdır — tool yazımı onun işidir. Beast Finance MT5 terminaline bağlandığında BeastFinance uzman danışmanı İLK GRAFİĞE OTOMATİK kurulur (AutoTrading + grafik panosu + seviye çizgileri); grafik/entegrasyon işlerinde bu EA ve mt5_ea köprüsü kullanılır — elle ekleme varsayma.";
|
|
105
|
+
|
|
106
|
+
const DEFAULT_BOT_SEEDS = [
|
|
107
|
+
{
|
|
108
|
+
id: 'coder',
|
|
109
|
+
name: 'Coder',
|
|
110
|
+
icon: '🤖',
|
|
111
|
+
prompt:
|
|
112
|
+
'Sen BEAST Coder botsun: disiplinli bir yazılım mühendisi. Küçük adımlarla plan çıkarır (todo), uygular, doğrularsın. Dosya düzenler, komut çalıştırır ve kısa net açıklamalar yaparsın; gereksiz konuşmazsın.',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: 'tool',
|
|
116
|
+
name: 'Tool',
|
|
117
|
+
icon: '🛠️',
|
|
118
|
+
prompt:
|
|
119
|
+
'Sen BEAST TOOL botusun — TEK görevin TOOL YAZMAK. Başka hiçbir iş yapmazsın: analiz, genel sohbet, araştırma, kod projesi YOK; yalnız eksik/bozuk araçları yazar ve onarırsın. Her istek bir araç ihtiyacıdır. ÖNCE skill aracıyla "tool-yazma" skill\'ini oku ve sözleşmeye BİREBİR uy: araç %APPDATA%\\beast\\tools\\<slug>\\ klasöründe tool.json (tanım) + run.js (kod) olarak yaşar; slug a-z0-9_- 2-24 karakter. Sözleşme: stdin JSON argüman → stdout SADECE JSON sonuç; {ok:true,...} ya da {ok:false,error:"sebep"}; günlük/teşhis metnini console.error\'a yaz. Var olan aracı silip baştan yazma — edit_file ile GÜNCELLE. Yazdıktan sonra run_command ile TEST DÖNGÜSÜ işlet (echo \'{"mesaj":"test"}\' | node "%APPDATA%\\beast\\tools\\<slug>\\run.js"): çıktı JSON ve ok:true DEĞİLSE stderr\'i/hatayı oku → edit_file ile düzelt → YENİDEN test et; en fazla 5 deneme. Ancak test GEÇİNCE "YAYINDA" de; geçmeyen aracı yayınlama, raporda BAŞARISIZ + kök hatayı yaz. Ağ çağrılarında timeout kullan; şifre/API anahtarını ASLA loglama/yazma. İstek eksikse tek cümlelik varsayım yazıp çalışan aracı üret. Cevabın TEK paragraf: tool adı (tool__<slug>), ne yaptığı, adımlar (yazıldı → test → düzeltme → YAYINDA/BAŞARISIZ), doğrulama sonucu ve tek satır çağrı örneği. Başka ajanlara iş devretme — tool yazımı senin işin. TÜM ajanlar (Beast, müşteri botları) tool_request ya da bot DM ile sana istek atar; her isteği araç ihtiyacı say ve sözleşmeye uygun yaz.',
|
|
120
|
+
},
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
/* Eksik varsayılan botları oluştur (id sabit — tool_request 'tool' id'sini arar) */
|
|
124
|
+
function ensureDefaultBots() {
|
|
125
|
+
loadRegistry();
|
|
126
|
+
let created = false;
|
|
127
|
+
/* TEMİZLİK: kaldırılan varsayılan "Trader" botu — yalnız HİÇ düzenlenmemişse sil
|
|
128
|
+
(kullanıcı promptunu değiştirdiyse dokunulmaz). */
|
|
129
|
+
{
|
|
130
|
+
const i = REG.bots.findIndex((b) => b && b.id === 'trader' && String(b.prompt || '') === RETIRED_TRADER_PROMPT);
|
|
131
|
+
if (i >= 0) {
|
|
132
|
+
try { fs.rmSync(path.join(beastRoot(), 'bots', 'trader'), { recursive: true, force: true }); } catch {}
|
|
133
|
+
REG.bots.splice(i, 1);
|
|
134
|
+
created = true;
|
|
135
|
+
logChange('trader', 'varsayılan Trader botu kaldırıldı (Beast Finance ayrıldı)');
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
for (const def of DEFAULT_BOT_SEEDS) {
|
|
139
|
+
const existing = REG.bots.find((b) => b && b.id === def.id);
|
|
140
|
+
if (existing) {
|
|
141
|
+
/* VARSAYILAN PROMPT GÜNCELLEMESİ (tek seferlik ek): eski sürümde
|
|
142
|
+
oluşmuş Tool botunun promptunda mql5/edit_file/skill vurgusu yoksa
|
|
143
|
+
eksik parçalar EKLENİR — kullanıcı düzenlemesi ezilmez. */
|
|
144
|
+
if (def.id === 'tool') {
|
|
145
|
+
const p = String(existing.prompt || '');
|
|
146
|
+
const add = [];
|
|
147
|
+
if (!/edit_file/.test(p)) add.push('Var olan dosyayı edit_file ile GÜNCELLE; yeniyi write_file ile yaz; içerik aramada grep, dosya adı aramada glob kullan.');
|
|
148
|
+
if (!/skill\(["']tool-yazma["']\)/.test(p)) add.push('Tool yazmadan önce skill("tool-yazma") oku ve sözleşmeye birebir uy.');
|
|
149
|
+
if (add.length) {
|
|
150
|
+
existing.prompt = (p ? p + ' ' : '') + add.join(' ');
|
|
151
|
+
created = true;
|
|
152
|
+
logChange(def.id, 'varsayılan prompt ekleri eklendi (edit_file/skill)');
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (REG.bots.length >= MAX_BOTS) break;
|
|
158
|
+
const bot = {
|
|
159
|
+
id: def.id,
|
|
160
|
+
name: def.name,
|
|
161
|
+
icon: ICONS.includes(def.icon) ? def.icon : '🤖',
|
|
162
|
+
admin: false,
|
|
163
|
+
code: '',
|
|
164
|
+
prompt: String(def.prompt || '').slice(0, 4000),
|
|
165
|
+
perm: 'all',
|
|
166
|
+
vis: true,
|
|
167
|
+
/* Tool botu araç yazıp doğrulayabilmeli: run_command/read/write açık */
|
|
168
|
+
skills: { ...DEFAULT_SKILLS, run_command: def.id === 'tool' },
|
|
169
|
+
seeBots: [],
|
|
170
|
+
extBrowser: false,
|
|
171
|
+
browserDefault: 'dahili',
|
|
172
|
+
extCommand: '',
|
|
173
|
+
plugins: [],
|
|
174
|
+
createdAt: nowIso(),
|
|
175
|
+
};
|
|
176
|
+
REG.bots.push(bot);
|
|
177
|
+
created = true;
|
|
178
|
+
logChange(def.id, `varsayılan bot otomatik oluşturuldu (name="${def.name}")`);
|
|
179
|
+
}
|
|
180
|
+
if (created) {
|
|
181
|
+
ensureBotCodes();
|
|
182
|
+
saveRegistry();
|
|
183
|
+
ensureDirs();
|
|
184
|
+
}
|
|
185
|
+
return created;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* ---------- registry ---------- */
|
|
189
|
+
|
|
190
|
+
let REG = null;
|
|
191
|
+
|
|
192
|
+
function loadRegistry() {
|
|
193
|
+
if (REG) return REG;
|
|
194
|
+
try {
|
|
195
|
+
REG = JSON.parse(fs.readFileSync(registryFile(), 'utf8'));
|
|
196
|
+
} catch {
|
|
197
|
+
REG = null;
|
|
198
|
+
}
|
|
199
|
+
if (!REG || !Array.isArray(REG.bots)) REG = { bots: [adminBot()] };
|
|
200
|
+
/* beast her zaman ilk ve admin */
|
|
201
|
+
const beast = REG.bots.find((b) => b && b.id === 'beast');
|
|
202
|
+
if (!beast) REG.bots.unshift(adminBot());
|
|
203
|
+
else Object.assign(beast, { ...adminBot(), ...beast, id: 'beast', admin: true, name: beast.name || 'Beast' });
|
|
204
|
+
/* ZORUNLU bot seti: Beast + Coder + Tool (eksikler otomatik açılır) */
|
|
205
|
+
ensureDefaultBots();
|
|
206
|
+
saveRegistry();
|
|
207
|
+
ensureDirs();
|
|
208
|
+
return REG;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function saveRegistry() {
|
|
212
|
+
try {
|
|
213
|
+
fs.mkdirSync(beastRoot(), { recursive: true });
|
|
214
|
+
fs.writeFileSync(registryFile(), JSON.stringify(REG, null, 2));
|
|
215
|
+
} catch {}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function ensureDirs() {
|
|
219
|
+
for (const b of REG.bots) {
|
|
220
|
+
const d = botDir(b.id);
|
|
221
|
+
try {
|
|
222
|
+
for (const sub of ['logs', 'chat', 'plugins', 'watchers']) fs.mkdirSync(path.join(d, sub), { recursive: true });
|
|
223
|
+
const cfgP = path.join(d, 'config.json');
|
|
224
|
+
if (!fs.existsSync(cfgP)) fs.writeFileSync(cfgP, JSON.stringify(botConfigOf(b), null, 2));
|
|
225
|
+
const yetP = path.join(d, 'yetkiler.json');
|
|
226
|
+
if (!fs.existsSync(yetP)) fs.writeFileSync(yetP, JSON.stringify(botPermsOf(b), null, 2));
|
|
227
|
+
/* bot hafızası ayarlardaki yapıyla aynı: SOUL.md + MEMORY.md + USER.md
|
|
228
|
+
(eski memory.md varsa içeriği MEMORY.md'ye taşınır) */
|
|
229
|
+
const legacyP = path.join(d, 'memory.md');
|
|
230
|
+
const legacy = fs.existsSync(legacyP) ? fs.readFileSync(legacyP, 'utf8') : '';
|
|
231
|
+
const memP = path.join(d, 'MEMORY.md');
|
|
232
|
+
if (!fs.existsSync(memP)) fs.writeFileSync(memP, legacy || '');
|
|
233
|
+
for (const f of ['SOUL.md', 'USER.md']) {
|
|
234
|
+
const p = path.join(d, f);
|
|
235
|
+
if (!fs.existsSync(p)) fs.writeFileSync(p, '');
|
|
236
|
+
}
|
|
237
|
+
} catch {}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function botConfigOf(b) {
|
|
242
|
+
return {
|
|
243
|
+
id: b.id,
|
|
244
|
+
name: b.name,
|
|
245
|
+
icon: b.icon,
|
|
246
|
+
admin: !!b.admin,
|
|
247
|
+
code: b.code || '',
|
|
248
|
+
prompt: b.prompt || '',
|
|
249
|
+
browser: { default: b.browserDefault || 'dahili', extCommand: b.extCommand || '' },
|
|
250
|
+
plugins: b.plugins || [],
|
|
251
|
+
createdAt: b.createdAt,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function botPermsOf(b) {
|
|
256
|
+
return {
|
|
257
|
+
id: b.id,
|
|
258
|
+
perm: b.perm || 'all',
|
|
259
|
+
skills: { ...DEFAULT_SKILLS, ...(b.skills || {}) },
|
|
260
|
+
seeBots: b.seeBots || [],
|
|
261
|
+
extBrowser: b.extBrowser !== false,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/* ---------- log ---------- */
|
|
266
|
+
|
|
267
|
+
function logChange(id, text) {
|
|
268
|
+
try {
|
|
269
|
+
const d = botDir(id);
|
|
270
|
+
fs.mkdirSync(path.join(d, 'logs'), { recursive: true });
|
|
271
|
+
fs.appendFileSync(path.join(d, 'logs', 'changes.log'), `[${new Date().toISOString()}] ${text}\n`);
|
|
272
|
+
} catch {}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/* ---------- public API ---------- */
|
|
276
|
+
|
|
277
|
+
function list() {
|
|
278
|
+
loadRegistry();
|
|
279
|
+
return REG.bots.map((b) => ({ ...b, skills: { ...DEFAULT_SKILLS, ...(b.skills || {}) } }));
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function get(id) {
|
|
283
|
+
loadRegistry();
|
|
284
|
+
return REG.bots.find((b) => b.id === String(id || '')) || null;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function add({ name, icon, prompt }) {
|
|
288
|
+
loadRegistry();
|
|
289
|
+
const n = String(name || '').trim().slice(0, 40);
|
|
290
|
+
if (!n) return { ok: false, error: 'bot adı zorunlu' };
|
|
291
|
+
/* İLK HARF ZORUNLU: bot adı harf karakteriyle başlamalı */
|
|
292
|
+
if (!/^\p{L}/u.test(n)) return { ok: false, error: 'bot adı harf ile başlamalı — ilk karakter harf olmalı' };
|
|
293
|
+
if (REG.bots.length >= MAX_BOTS) return { ok: false, error: `en fazla ${MAX_BOTS} bot olabilir (1 admin + ${MAX_BOTS - 1} müşteri)` };
|
|
294
|
+
let id = slugify(n);
|
|
295
|
+
while (get(id)) id = slugify(n) + '-' + uid().slice(-4);
|
|
296
|
+
const bot = {
|
|
297
|
+
id,
|
|
298
|
+
name: n,
|
|
299
|
+
icon: ICONS.includes(icon) ? icon : '🤖',
|
|
300
|
+
admin: false,
|
|
301
|
+
code: '', // ensureBotCodes hemen altında benzersiz 5 hane atar
|
|
302
|
+
prompt: String(prompt || '').slice(0, 4000),
|
|
303
|
+
perm: 'all',
|
|
304
|
+
vis: true, // sohbet görünürlüğü (admin matristen kapatır)
|
|
305
|
+
skills: { ...DEFAULT_SKILLS },
|
|
306
|
+
seeBots: [], // varsayılan: hiçbir bot baka botu göremez
|
|
307
|
+
extBrowser: false, // dış tarayıcı sadece yetkilide
|
|
308
|
+
browserDefault: 'dahili',
|
|
309
|
+
extCommand: '',
|
|
310
|
+
plugins: [],
|
|
311
|
+
createdAt: nowIso(),
|
|
312
|
+
};
|
|
313
|
+
REG.bots.push(bot);
|
|
314
|
+
ensureBotCodes();
|
|
315
|
+
saveRegistry();
|
|
316
|
+
ensureDirs();
|
|
317
|
+
logChange(id, `bot oluşturuldu (name="${n}", icon=${bot.icon}, code=${bot.code})`);
|
|
318
|
+
return { ok: true, bot: { ...bot } };
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/* ---------- 5 HANELİ BENZERSİZ BOT KODU ----------
|
|
322
|
+
Her bot oluşurken 10000-99999 arası rastgele kod alır; duplicate kontrolü
|
|
323
|
+
zorunlu (tüm botlara karşı). Açılışta kodu eksik/çakışık botlara da atanır. */
|
|
324
|
+
function ensureBotCodes() {
|
|
325
|
+
loadRegistry();
|
|
326
|
+
let dirty = false;
|
|
327
|
+
const used = () => new Set(REG.bots.map((b) => String(b.code || '')).filter((c) => /^\d{5}$/.test(c)));
|
|
328
|
+
const seen = new Set();
|
|
329
|
+
for (const b of REG.bots) {
|
|
330
|
+
const cur = String(b.code || '');
|
|
331
|
+
if (/^\d{5}$/.test(cur) && !seen.has(cur)) { seen.add(cur); continue; }
|
|
332
|
+
const u = used();
|
|
333
|
+
let c;
|
|
334
|
+
do { c = String(10000 + Math.floor(Math.random() * 90000)); } while (u.has(c));
|
|
335
|
+
logChange(b.id, `bot kodu atandı: ${c}${cur ? ` (eskisi geçersizdi: ${cur})` : ''}`);
|
|
336
|
+
b.code = c;
|
|
337
|
+
seen.add(c);
|
|
338
|
+
dirty = true;
|
|
339
|
+
}
|
|
340
|
+
if (dirty) saveRegistry();
|
|
341
|
+
return dirty;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function byCode(code) {
|
|
345
|
+
const c = String(code || '').replace(/\D/g, '');
|
|
346
|
+
if (!/^\d{5}$/.test(c)) return null;
|
|
347
|
+
loadRegistry();
|
|
348
|
+
return REG.bots.find((b) => String(b.code || '') === c) || null;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function update(id, patch) {
|
|
352
|
+
loadRegistry();
|
|
353
|
+
const b = get(id);
|
|
354
|
+
if (!b) return { ok: false, error: 'bot yok' };
|
|
355
|
+
/* İLK HARF ZORUNLU: ad değişikliği harf karakteriyle başlamalı —
|
|
356
|
+
diğer alanlara dokunmadan reddet */
|
|
357
|
+
if (patch && typeof patch.name === 'string' && patch.name.trim() &&
|
|
358
|
+
!/^\p{L}/u.test(patch.name.trim())) {
|
|
359
|
+
return { ok: false, error: 'bot adı harf ile başlamalı — ilk karakter harf olmalı' };
|
|
360
|
+
}
|
|
361
|
+
const changes = [];
|
|
362
|
+
if (patch && typeof patch === 'object') {
|
|
363
|
+
if (typeof patch.name === 'string' && patch.name.trim() && patch.name.trim() !== b.name) {
|
|
364
|
+
changes.push(`name: "${b.name}" → "${patch.name.trim().slice(0, 40)}"`);
|
|
365
|
+
b.name = patch.name.trim().slice(0, 40);
|
|
366
|
+
}
|
|
367
|
+
if (typeof patch.icon === 'string' && ICONS.includes(patch.icon) && patch.icon !== b.icon) {
|
|
368
|
+
changes.push(`icon: ${b.icon} → ${patch.icon}`);
|
|
369
|
+
b.icon = patch.icon;
|
|
370
|
+
}
|
|
371
|
+
if (typeof patch.prompt === 'string' && patch.prompt !== b.prompt) {
|
|
372
|
+
changes.push('prompt güncellendi');
|
|
373
|
+
b.prompt = String(patch.prompt).slice(0, 4000);
|
|
374
|
+
}
|
|
375
|
+
if (patch.perm !== undefined) {
|
|
376
|
+
/* 'all' tek başına tüm araçları verir; web/read/chat çoklu seçilebilir
|
|
377
|
+
(['web','read'] gibi dizi ya da 'web,read' gibi string kabul edilir) */
|
|
378
|
+
const PERMS_ALL = ['all', 'web', 'read', 'chat'];
|
|
379
|
+
let nextPerm = null;
|
|
380
|
+
if (Array.isArray(patch.perm)) {
|
|
381
|
+
const picked = [...new Set(patch.perm.map((x) => String(x).trim()).filter((x) => PERMS_ALL.includes(x)))];
|
|
382
|
+
nextPerm = picked.includes('all') ? 'all' : (picked.length ? picked : 'chat');
|
|
383
|
+
} else if (typeof patch.perm === 'string') {
|
|
384
|
+
const arr = patch.perm.split(',').map((x) => x.trim()).filter((x) => PERMS_ALL.includes(x));
|
|
385
|
+
if (arr.length) nextPerm = arr.includes('all') ? 'all' : (arr.length === 1 ? arr[0] : arr);
|
|
386
|
+
}
|
|
387
|
+
if (nextPerm !== null && JSON.stringify(nextPerm) !== JSON.stringify(b.perm)) {
|
|
388
|
+
const fp = (p) => (Array.isArray(p) ? '[' + p.join('+') + ']' : String(p));
|
|
389
|
+
changes.push(`perm: ${fp(b.perm)} → ${fp(nextPerm)}`);
|
|
390
|
+
b.perm = nextPerm;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (patch.skills && typeof patch.skills === 'object') {
|
|
394
|
+
const merged = { ...DEFAULT_SKILLS, ...(b.skills || {}) };
|
|
395
|
+
for (const k of Object.keys(DEFAULT_SKILLS)) {
|
|
396
|
+
if (typeof patch.skills[k] === 'boolean' && patch.skills[k] !== merged[k]) {
|
|
397
|
+
changes.push(`skill ${k}: ${merged[k]} → ${patch.skills[k]}`);
|
|
398
|
+
merged[k] = patch.skills[k];
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
b.skills = merged;
|
|
402
|
+
}
|
|
403
|
+
if (Array.isArray(patch.seeBots)) {
|
|
404
|
+
const valid = patch.seeBots.map(String).filter((x) => x !== b.id && get(x));
|
|
405
|
+
const next = [...new Set(valid)];
|
|
406
|
+
if (JSON.stringify(next) !== JSON.stringify(b.seeBots || [])) {
|
|
407
|
+
changes.push(`görebilir: [${(b.seeBots || []).join(', ') || '—'}] → [${next.join(', ') || '—'}]`);
|
|
408
|
+
b.seeBots = next;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
if (typeof patch.extBrowser === 'boolean' && patch.extBrowser !== b.extBrowser) {
|
|
412
|
+
changes.push(`dış tarayıcı yetkisi: ${b.extBrowser} → ${patch.extBrowser}`);
|
|
413
|
+
b.extBrowser = patch.extBrowser;
|
|
414
|
+
}
|
|
415
|
+
if (typeof patch.vis === 'boolean' && patch.vis !== (b.vis !== false)) {
|
|
416
|
+
changes.push(`sohbet görünürlüğü: ${b.vis !== false} → ${patch.vis}`);
|
|
417
|
+
b.vis = patch.vis;
|
|
418
|
+
}
|
|
419
|
+
if (['dahili', 'dis'].includes(patch.browserDefault) && patch.browserDefault !== b.browserDefault) {
|
|
420
|
+
changes.push(`varsayılan tarayıcı: ${b.browserDefault} → ${patch.browserDefault}`);
|
|
421
|
+
b.browserDefault = patch.browserDefault;
|
|
422
|
+
}
|
|
423
|
+
if (typeof patch.extCommand === 'string' && patch.extCommand !== b.extCommand) {
|
|
424
|
+
changes.push('dış tarayıcı komutu güncellendi');
|
|
425
|
+
b.extCommand = String(patch.extCommand).slice(0, 200);
|
|
426
|
+
}
|
|
427
|
+
if (typeof patch.model === 'string') {
|
|
428
|
+
/* bot bazlı model override — boş string = global seçim */
|
|
429
|
+
const next = patch.model.trim().slice(0, 160);
|
|
430
|
+
if (next !== (b.model || '')) {
|
|
431
|
+
changes.push('model güncellendi');
|
|
432
|
+
b.model = next;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
if (Array.isArray(patch.plugins)) {
|
|
436
|
+
const next = [...new Set(patch.plugins.map((p) => String(p).slice(0, 40)).filter((p) => PLUGIN_LIST.includes(p)))];
|
|
437
|
+
if (JSON.stringify(next) !== JSON.stringify(b.plugins || [])) {
|
|
438
|
+
changes.push(`pluginler: [${(b.plugins || []).join(', ') || '—'}] → [${next.join(', ') || '—'}]`);
|
|
439
|
+
b.plugins = next;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
saveRegistry();
|
|
444
|
+
ensureDirs();
|
|
445
|
+
try {
|
|
446
|
+
const d = botDir(b.id);
|
|
447
|
+
fs.writeFileSync(path.join(d, 'config.json'), JSON.stringify(botConfigOf(b), null, 2));
|
|
448
|
+
fs.writeFileSync(path.join(d, 'yetkiler.json'), JSON.stringify(botPermsOf(b), null, 2));
|
|
449
|
+
} catch {}
|
|
450
|
+
for (const c of changes) logChange(b.id, `yetki/ayar değişikliği (admin): ${c}`);
|
|
451
|
+
return { ok: true, bot: { ...b }, changed: changes.length };
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function remove(id) {
|
|
455
|
+
loadRegistry();
|
|
456
|
+
const b = get(id);
|
|
457
|
+
if (!b) return { ok: false, error: 'bot yok' };
|
|
458
|
+
if (b.admin) return { ok: false, error: 'admin bot silinemez' };
|
|
459
|
+
REG.bots = REG.bots.filter((x) => x.id !== b.id);
|
|
460
|
+
saveRegistry();
|
|
461
|
+
logChange(b.id, `bot SİLİNDİ — bağlı numaralar botsuz duruma düştü (beast'e yönlendirilir)`);
|
|
462
|
+
/* klasör arşivlenir — veri kaybı olmasın */
|
|
463
|
+
try {
|
|
464
|
+
const d = botDir(b.id);
|
|
465
|
+
if (fs.existsSync(d)) fs.renameSync(d, d + '-arsiv-' + Date.now().toString(36));
|
|
466
|
+
} catch {}
|
|
467
|
+
return { ok: true };
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/* viewer botun target botu görüp göremeyeceği */
|
|
471
|
+
function canSee(viewerId, targetId) {
|
|
472
|
+
const v = get(viewerId);
|
|
473
|
+
if (!v) return false;
|
|
474
|
+
if (v.admin) return true; // admin her şeyi görür
|
|
475
|
+
if (viewerId === targetId) return true;
|
|
476
|
+
return (v.seeBots || []).includes(String(targetId));
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/* botun hafıza dosyaları — ayarlardaki SOUL/USER/MEMORY üçlüsünün bot izole hali */
|
|
480
|
+
const BOT_MEM_FILES = ['SOUL.md', 'MEMORY.md', 'USER.md'];
|
|
481
|
+
|
|
482
|
+
/* botun MEMORY.md'si (persona bloğuna giden kısım) */
|
|
483
|
+
function readMemory(id, cap = 2000) {
|
|
484
|
+
try {
|
|
485
|
+
return fs.readFileSync(path.join(botDir(id), 'MEMORY.md'), 'utf8').slice(0, cap).trim();
|
|
486
|
+
} catch {
|
|
487
|
+
return '';
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function readMemoryFiles(id) {
|
|
492
|
+
const d = botDir(id);
|
|
493
|
+
const out = { soul: '', memory: '', user: '' };
|
|
494
|
+
try { out.soul = fs.readFileSync(path.join(d, 'SOUL.md'), 'utf8'); } catch {}
|
|
495
|
+
try { out.memory = fs.readFileSync(path.join(d, 'MEMORY.md'), 'utf8'); } catch {}
|
|
496
|
+
try { out.user = fs.readFileSync(path.join(d, 'USER.md'), 'utf8'); } catch {}
|
|
497
|
+
return out;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function writeMemoryFile(id, file, content) {
|
|
501
|
+
const b = get(id);
|
|
502
|
+
if (!b) return { ok: false, error: 'bot yok' };
|
|
503
|
+
if (!BOT_MEM_FILES.includes(file)) return { ok: false, error: 'geçersiz dosya' };
|
|
504
|
+
try {
|
|
505
|
+
const d = botDir(id);
|
|
506
|
+
fs.mkdirSync(d, { recursive: true });
|
|
507
|
+
fs.writeFileSync(path.join(d, file), String(content ?? ''), 'utf8');
|
|
508
|
+
/* admin MEMORY.md'yi elle değiştirdiyse botun mem0 store'unu yeniden kur */
|
|
509
|
+
if (file === 'MEMORY.md') {
|
|
510
|
+
try {
|
|
511
|
+
const mem0 = require('./mem0');
|
|
512
|
+
mem0.reindexFromLines('bot:' + id, String(content ?? '').split('\n').map((l) => l.replace(/^[-*]\s*/, '').trim()).filter(Boolean));
|
|
513
|
+
} catch {}
|
|
514
|
+
}
|
|
515
|
+
logChange(id, `${file} admin tarafından güncellendi`);
|
|
516
|
+
return { ok: true };
|
|
517
|
+
} catch (e) {
|
|
518
|
+
return { ok: false, error: String((e && e.message) || e) };
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/* botun MEMORY.md ayna dosyasının yolu (mem0 syncMirror kullanır) */
|
|
523
|
+
function memPath(id) {
|
|
524
|
+
return path.join(botDir(id), 'MEMORY.md');
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/* ---------- BOT OTURUMU hafıza operasyonları ----------
|
|
528
|
+
Bot oturumlarında memory_write/memory_search GLOBAL Beast hafızasına DEĞİL,
|
|
529
|
+
botun kendi SOUL/USER/MEMORY dosyalarına gider (tam izolasyon). */
|
|
530
|
+
|
|
531
|
+
function readMem(id, f) {
|
|
532
|
+
if (!BOT_MEM_FILES.includes(f)) return '';
|
|
533
|
+
try {
|
|
534
|
+
return fs.readFileSync(path.join(botDir(id), f), 'utf8');
|
|
535
|
+
} catch {
|
|
536
|
+
return '';
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
function memEntries(id) {
|
|
541
|
+
return readMem(id, 'MEMORY.md')
|
|
542
|
+
.split('\n')
|
|
543
|
+
.map((l) => l.replace(/^[-*]\s*/, '').trim())
|
|
544
|
+
.filter(Boolean);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function appendMem(id, text) {
|
|
548
|
+
const t = String(text || '').replace(/\s+/g, ' ').trim().slice(0, 500);
|
|
549
|
+
if (!t) return { ok: false, error: 'empty' };
|
|
550
|
+
const list = memEntries(id);
|
|
551
|
+
const key = foldTr(t).replace(/[^a-z0-9]+/g, ' ').trim();
|
|
552
|
+
if (list.some((l) => foldTr(l).replace(/[^a-z0-9]+/g, ' ').trim() === key)) {
|
|
553
|
+
return { ok: true, duplicate: true };
|
|
554
|
+
}
|
|
555
|
+
try {
|
|
556
|
+
fs.mkdirSync(botDir(id), { recursive: true });
|
|
557
|
+
fs.appendFileSync(path.join(botDir(id), 'MEMORY.md'), '- ' + t + '\n');
|
|
558
|
+
return { ok: true };
|
|
559
|
+
} catch (e) {
|
|
560
|
+
return { ok: false, error: String((e && e.message) || e) };
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/* botun USER.md'si: bota özel kullanıcı profili (aynı dedup/yenile mantığı) */
|
|
565
|
+
function appendUserMem(id, text) {
|
|
566
|
+
const t = String(text || '').replace(/\s+/g, ' ').trim().slice(0, 300);
|
|
567
|
+
if (!t) return { ok: false, error: 'empty' };
|
|
568
|
+
try {
|
|
569
|
+
const p = path.join(botDir(id), 'USER.md');
|
|
570
|
+
fs.mkdirSync(botDir(id), { recursive: true });
|
|
571
|
+
const lines = readMem(id, 'USER.md')
|
|
572
|
+
.split('\n')
|
|
573
|
+
.map((l) => l.replace(/^[-*]\s*/, '').trim())
|
|
574
|
+
.filter(Boolean);
|
|
575
|
+
/* profil anahtarı: "Konu: ..." satırlarında Konu — değişiklikte güncelle */
|
|
576
|
+
const topicOf = (s) => {
|
|
577
|
+
const c = foldTr(s).indexOf(':');
|
|
578
|
+
return (c > 0 ? foldTr(s).slice(0, c) : foldTr(s)).replace(/[^a-z0-9]+/g, ' ').trim();
|
|
579
|
+
};
|
|
580
|
+
const topic = topicOf(t);
|
|
581
|
+
const idx = lines.findIndex((l) => topicOf(l) === topic);
|
|
582
|
+
if (idx >= 0) {
|
|
583
|
+
if (lines[idx] === t) return { ok: true, duplicate: true };
|
|
584
|
+
lines[idx] = t;
|
|
585
|
+
} else {
|
|
586
|
+
lines.push(t);
|
|
587
|
+
}
|
|
588
|
+
while (lines.length > 60) lines.shift();
|
|
589
|
+
fs.writeFileSync(p, lines.map((l) => '- ' + l).join('\n') + '\n');
|
|
590
|
+
return { ok: true, updated: idx >= 0 };
|
|
591
|
+
} catch (e) {
|
|
592
|
+
return { ok: false, error: String((e && e.message) || e) };
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function searchMem(id, query, limit = 8) {
|
|
597
|
+
const list = memEntries(id);
|
|
598
|
+
if (!list.length) return [];
|
|
599
|
+
const qTokens = memory.tokenize(query);
|
|
600
|
+
let rows;
|
|
601
|
+
if (!qTokens.length) {
|
|
602
|
+
rows = list.map((text, i) => ({ text, score: 0, i })).slice(-limit).reverse();
|
|
603
|
+
} else {
|
|
604
|
+
rows = list
|
|
605
|
+
.map((text, i) => ({ text, i, score: Number(memory.scoreEntry(text, qTokens).toFixed(3)) }))
|
|
606
|
+
.filter((r) => r.score > 0)
|
|
607
|
+
.sort((a, b) => b.score - a.score)
|
|
608
|
+
.slice(0, limit);
|
|
609
|
+
}
|
|
610
|
+
return rows.map(({ text, score }) => ({ score, text }));
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function relevantMem(id, query, { maxRelevant = 6, maxRecent = 4, charCap = 2400 } = {}) {
|
|
614
|
+
const list = memEntries(id);
|
|
615
|
+
if (!list.length) return '';
|
|
616
|
+
const qTokens = memory.tokenize(query);
|
|
617
|
+
const picked = new Set();
|
|
618
|
+
if (qTokens.length) {
|
|
619
|
+
list
|
|
620
|
+
.map((text, i) => ({ i, score: memory.scoreEntry(text, qTokens) }))
|
|
621
|
+
.filter((r) => r.score > 0)
|
|
622
|
+
.sort((a, b) => b.score - a.score)
|
|
623
|
+
.slice(0, maxRelevant)
|
|
624
|
+
.forEach((r) => picked.add(r.i));
|
|
625
|
+
}
|
|
626
|
+
for (let i = list.length - 1; i >= 0 && picked.size < maxRelevant + maxRecent; i--) picked.add(i);
|
|
627
|
+
let out = '';
|
|
628
|
+
for (const i of [...picked].sort((a, b) => a - b)) {
|
|
629
|
+
const line = '- ' + list[i];
|
|
630
|
+
if (out.length + line.length > charCap) break;
|
|
631
|
+
out += (out ? '\n' : '') + line;
|
|
632
|
+
}
|
|
633
|
+
return out;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function readLog(id, cap = 20000) {
|
|
637
|
+
try {
|
|
638
|
+
return fs.readFileSync(path.join(botDir(id), 'logs', 'changes.log'), 'utf8').slice(-cap);
|
|
639
|
+
} catch {
|
|
640
|
+
return '';
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
module.exports = {
|
|
645
|
+
MAX_BOTS,
|
|
646
|
+
ICONS,
|
|
647
|
+
SKILL_LIST,
|
|
648
|
+
PLUGIN_LIST,
|
|
649
|
+
beastRoot,
|
|
650
|
+
botDir,
|
|
651
|
+
list,
|
|
652
|
+
get,
|
|
653
|
+
add,
|
|
654
|
+
update,
|
|
655
|
+
remove,
|
|
656
|
+
canSee,
|
|
657
|
+
ensureBotCodes,
|
|
658
|
+
byCode,
|
|
659
|
+
readMemory,
|
|
660
|
+
readMemoryFiles,
|
|
661
|
+
writeMemoryFile,
|
|
662
|
+
readMem,
|
|
663
|
+
memPath,
|
|
664
|
+
appendMem,
|
|
665
|
+
appendUserMem,
|
|
666
|
+
searchMem,
|
|
667
|
+
relevantMem,
|
|
668
|
+
readLog,
|
|
669
|
+
};
|