beast-agent 2.30.4 → 2.30.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "beast-agent",
3
3
  "productName": "Beast Agent",
4
- "version": "2.30.4",
4
+ "version": "2.30.6",
5
5
  "description": "Ultra-fast local agent shell for Windows.",
6
6
  "author": "algokodcom (AlgoKod)",
7
7
  "license": "MIT",
@@ -327,6 +327,7 @@ class Engine {
327
327
  boyunca "always" desenlerini kural olarak taşır (opencode birebir). */
328
328
  this._perm = new AskService((ev) => this.emit(ev));
329
329
  this.bcAskApprovals = opts.approvals ? true : false; // onay ayarı → opencode user konfigi gibi "ask" üretir
330
+ this._perm.autoAllow = !this.bcAskApprovals; // güvenlik kapalı: BeastCode/Sandbox izin SORMAZ (deny yine geçerli)
330
331
  /* opencode reminders.ts: bu oturumda daha önce plan ajanı koştu mu?
331
332
  plan→build geçişinde build-switch.txt synthetic part'ı buna bağlanır */
332
333
  this._bcWasPlan = new Map(); // sessionId -> bool
@@ -1608,11 +1609,13 @@ class Engine {
1608
1609
  ? 'plan'
1609
1610
  : 'build';
1610
1611
  const ws = (session && session.workspace) || this.workspace;
1611
- const user = this.bcAskApprovals ? { bash: 'ask', edit: { '*': 'ask' } } : {};
1612
- const info = opencode.agents.get(name, { worktree: ws, promptExplore: opencode.PROMPT_EXPLORE, user });
1612
+ /* BeastCode/Sandbox onayı ARIZİ değil: güvenlik açıkken yalnız SİLME
1613
+ işlemleri _perm.ask ile sorulur (aşağıda _isDeleteOp) — bash/edit'in
1614
+ tamamına asks koymak "her işlemde sor" demekti, kaldırıldı. */
1615
+ const info = opencode.agents.get(name, { worktree: ws, promptExplore: opencode.PROMPT_EXPLORE });
1613
1616
  if (info) return info;
1614
1617
  const fallbackName = session.sbSandbox ? 'sandbox' : 'build';
1615
- return opencode.agents.get(fallbackName, { worktree: ws, promptExplore: opencode.PROMPT_EXPLORE, user });
1618
+ return opencode.agents.get(fallbackName, { worktree: ws, promptExplore: opencode.PROMPT_EXPLORE });
1616
1619
  }
1617
1620
 
1618
1621
  /* opencode opencode ajan değişimi: /plan /build — oturumun ajanı döner,
@@ -1638,6 +1641,21 @@ class Engine {
1638
1641
  }
1639
1642
  }
1640
1643
 
1644
+ /* Güvenlik ayarı canlı değişimi (Ayarlar → Güvenlik):
1645
+ - kapalı → BeastCode/Sandbox dahil açık izin akışı hiç sormaz (autoAllow)
1646
+ - açık → riskli araçlarda onay ister (approvals köprüsü + bash/edit user kuralı)
1647
+ Bekleyen istekler serbest bırakılır (kapı kalktı; araç devam eder). */
1648
+ setApprovals(on) {
1649
+ this.bcAskApprovals = !!on;
1650
+ this._perm.autoAllow = !this.bcAskApprovals;
1651
+ if (!this.bcAskApprovals) {
1652
+ try {
1653
+ for (const req of this._perm.list()) this._perm.reply(req.id, 'once');
1654
+ } catch {}
1655
+ }
1656
+ return { bcAskApprovals: this.bcAskApprovals, autoAllow: this._perm.autoAllow };
1657
+ }
1658
+
1641
1659
  /* ---------- Supermemory (lokal) bellek köprüsü ---------- */
1642
1660
 
1643
1661
  _smConfig() {
@@ -1894,16 +1912,16 @@ class Engine {
1894
1912
  macro:
1895
1913
  'ROL: MAKRO AJANI 🌍 — büyük resim uzmanısın, İşlem AÇMAZSIN (mt5_trade/mt5_pending/mt5_close KULLANMA). Her turda web_search ile güncel makro manşetleri + ekonomik takvim riskleri (faiz, CPI, jeopolitik); DXY/altın/petrol bağıntılarını odak sembollere çevir; sembol başına yön eğilimi + TEMKİN/BEKLE notu ver.',
1896
1914
  })[String((session && session.financeRole) || '')] || '';
1897
- /* ROL → SKILL eşleştirmesi (ayarlar modalı): rolün okuması gereken skill'ler
1898
- prompta gömülür; ayar boşsa satır eklenmez. Skill adları kurulu katalogdan
1899
- seçilir — yeni skill eklendiğinde modalda görünür ve buraya yansır. */
1915
+ /* ROL → SKILL eşleştirmesi (ayarlar modalı): TAMAMEN İSTEĞE BAĞLI — boşsa
1916
+ satır eklenmez ve ajan skill'i göreve göre kendi seçer (SKILLS kataloğu).
1917
+ Doluysa rol için öncelikli skill'ler hatırlatılır. */
1900
1918
  const roleSkills = Array.isArray(session && session.financeRoleSkills)
1901
1919
  ? session.financeRoleSkills.map((s) => String(s || '').trim()).filter(Boolean).slice(0, 8)
1902
1920
  : [];
1903
1921
  const roleBlockFull = roleBlock
1904
1922
  ? roleBlock +
1905
1923
  (roleSkills.length
1906
- ? ` ÖNCE şu skill'leri skill aracıyla oku ve prosedürüne göre uygula: ${roleSkills.map((n) => `skill("${n}")`).join(', ')}.`
1924
+ ? ` Bu rol için isteğe bağlı öncelikli skill'ler: ${roleSkills.map((n) => `skill("${n}")`).join(', ')} — görev gerektiriyorsa skill aracıyla oku ve prosedürüne göre uygula.`
1907
1925
  : '')
1908
1926
  : '';
1909
1927
  /* FİNANS EKİBİ: tüm finance ajanları tek DM grubundadır — sohbet grup
@@ -4126,15 +4144,23 @@ class Engine {
4126
4144
  if (dups >= DOOM_LOOP_THRESHOLD) {
4127
4145
  if (bcAgent) {
4128
4146
  try {
4129
- await this._perm.ask({
4130
- sessionId: sid,
4131
- ruleset: bcAgent.permission,
4132
- permission: 'doom_loop',
4133
- patterns: [name],
4134
- always: [name],
4135
- metadata: { callCount: DOOM_LOOP_THRESHOLD, arguments: (tc.function && tc.function.arguments) || '' },
4136
- tool: { name, args },
4137
- });
4147
+ /* doom_loop bir SİLME değil: onay kartıyla kullanıcıyı yorma —
4148
+ kural değerlendirmesi (deny) işler, ask otomatik geçer */
4149
+ const prevAuto = this._perm.autoAllow;
4150
+ this._perm.autoAllow = true;
4151
+ try {
4152
+ await this._perm.ask({
4153
+ sessionId: sid,
4154
+ ruleset: bcAgent.permission,
4155
+ permission: 'doom_loop',
4156
+ patterns: [name],
4157
+ always: [name],
4158
+ metadata: { callCount: DOOM_LOOP_THRESHOLD, arguments: (tc.function && tc.function.arguments) || '' },
4159
+ tool: { name, args },
4160
+ });
4161
+ } finally {
4162
+ this._perm.autoAllow = prevAuto;
4163
+ }
4138
4164
  out = await this._execTool(name, args, ctrl.signal, sid);
4139
4165
  } catch (permErr) {
4140
4166
  out = JSON.stringify({
@@ -4883,6 +4909,33 @@ const skills = require('./skills');
4883
4909
  opencode'da edit+write aynı "edit" iznine takılır — burada da ikisi birlikte */
4884
4910
  static RISKY_TOOLS = new Set(['run_command', 'write_file', 'edit_file', 'python_run', 'email_send', 'watcher_add', 'git_commit', 'git_pr_create', 'xlsx_write', 'xlsx_edit']);
4885
4911
 
4912
+ /* SİLME desenleri — güvenlik AÇIKken onay kapısı YALNIZCA silmelerde sorar
4913
+ (kullanıcı isteği: her işlem değil, sadece silmeler). */
4914
+ static DELETE_RE =
4915
+ /(remove-item|\bri\s|\bdel\s|\bdel\b|\brd\b|\brmdir\b|\berase\b|\brm\s|\bunlink|shutil\s*\.\s*rmtree|os\s*\.\s*(remove|unlink|rmdir)|\brmtree\b|\.unlink\s*\(|fs\s*\.\s*(rm|unlink|rmdir)|rimraf|clear-content|\breg\s+delete|git\s+clean)/i;
4916
+
4917
+ /* Bu araç çağrısı bir SİLME mi? (komut/betik içeriği + araç adı deseni) */
4918
+ _isDeleteOp(name, args) {
4919
+ const n = String(name || '');
4920
+ const a = args || {};
4921
+ if (n === 'run_command' || n === 'panel_run') return Engine.DELETE_RE.test(String(a.command || ''));
4922
+ if (n === 'python_run') return Engine.DELETE_RE.test(String(a.code || ''));
4923
+ return /(delete|remove|unlink|rmdir|rmtree)/i.test(n);
4924
+ }
4925
+
4926
+ /* "Bir daha sorma" anahtarı: aynı silme işlemi için tekrar sorulmaz */
4927
+ _deleteKey(name, args) {
4928
+ const a = args || {};
4929
+ const raw =
4930
+ name === 'run_command' || name === 'panel_run'
4931
+ ? String(a.command || '')
4932
+ : name === 'python_run'
4933
+ ? String(a.code || '')
4934
+ : String(name || '');
4935
+ const s = raw.replace(/\s+/g, ' ').trim();
4936
+ return (s.length > 200 ? s.slice(0, 200) + '…' : s) || '*';
4937
+ }
4938
+
4886
4939
  /* ANA KOD KİLİDİ: yıkıcı işlem desenleri (korumalı yol + bu desen = engel) */
4887
4940
  static DESTRUCTIVE_RE =
4888
4941
  /(remove-item|\bri\s|\bdel\s|\bdel\b|\brd\b|\brmdir\b|\berase\b|set-content|out-file|add-content|new-item|clear-content|move-item|rename-item|\bren\s|\bcopy-item|\bmove\b|\bmv\s|\bcp\s|>>|[^|]>\s|\bicacls|\btakeown|\bformat\b|\bfsutil|\breg\s+(add|delete)|schtasks|stop-process|\btaskkill|\bkill\b|\brm\s|\bunlink|shutil|os\.remove|os\.unlink|open\([^)]*['"][wa]['"]\)|write_text|to_csv\(|savefig\(|\.write\()/i;
@@ -4975,13 +5028,18 @@ const skills = require('./skills');
4975
5028
  }
4976
5029
  if (isBc) {
4977
5030
  /* opencode permission akışı (tool/external-directory.ts + her aracın
4978
- ctx.ask'ı): önce workspace DIŞI erişim izni, sonra araç izni.
4979
- deny anında hata döner (asla sorulmaz), allow sessiz geçer,
4980
- ask UI'ya 'permission.asked' eventi ile sorulur */
5031
+ ctx.ask'ı): deny anında hata döner (asla sorulmaz), allow sessiz geçer.
5032
+ GÜVENLİK AÇIKken yalnız SİLME işlemleri 'permission.asked' ile sorulur;
5033
+ diğer ask kuralları otomatik serbesttir (deny yine geçerlidir). */
4981
5034
  const ws = this._sessionWorkspace(sessionId);
4982
5035
  const bcAgent = this._bcAgentInfo(bcSess);
4983
5036
  const ruleset = bcAgent ? bcAgent.permission : [];
5037
+ const isDel = this.bcAskApprovals && this._isDeleteOp(name, args);
5038
+ const prevAuto = this._perm.autoAllow;
4984
5039
  try {
5040
+ /* 1) deny kuralları her durumda işler; ask'ler silme dışında otomatik
5041
+ geçer (güvenlik açıkken kullanıcıyı yormama) */
5042
+ this._perm.autoAllow = true;
4985
5043
  const ext = this._bcExternalCheck(name, args, ws);
4986
5044
  if (ext) {
4987
5045
  await this._perm.ask({ sessionId, ruleset, ...ext, metadata: { tool: name, args: args || {} } });
@@ -4996,19 +5054,34 @@ const skills = require('./skills');
4996
5054
  metadata: { args: args || {} },
4997
5055
  tool: { name, args: args || {} },
4998
5056
  });
5057
+ /* 2) güvenlik AÇIK + SİLME → onay sorusu (tek gerçek ask) */
5058
+ if (isDel) {
5059
+ this._perm.autoAllow = false;
5060
+ const key = this._deleteKey(name, args);
5061
+ await this._perm.ask({
5062
+ sessionId,
5063
+ ruleset: [{ permission: 'delete', pattern: '*', action: 'ask' }],
5064
+ permission: 'delete',
5065
+ patterns: [key],
5066
+ always: [key],
5067
+ metadata: { tool: name, args: args || {} },
5068
+ tool: { name, args: args || {} },
5069
+ });
5070
+ }
4999
5071
  } catch (permErr) {
5000
5072
  return JSON.stringify({ ok: false, error: AskService.errorText(permErr) });
5073
+ } finally {
5074
+ this._perm.autoAllow = prevAuto;
5001
5075
  }
5002
5076
  } else {
5003
- /* onay kapısı: riskli araçta dış onay bekle; reddedilirse araç çalışmaz.
5004
- "always" onaylı araçlar doğrudan geçer. (BC dışı oturumlar — opencode
5005
- izin sistemi yalnız Beast Code oturumlarında koşar) */
5077
+ /* onay kapısı: güvenlik açıkken YALNIZCA SİLME işlemlerinde dış onay
5078
+ beklenir; reddedilirse araç çalışmaz. "always" onaylılar doğrudan
5079
+ geçer. (BC dışı oturumlar — opencode izin sistemi Beast Code'da koşar) */
5006
5080
  if (
5007
- (Engine.RISKY_TOOLS.has(name) ||
5008
- String(name).startsWith('mcp__') ||
5009
- String(name).startsWith('tool__')) && /* kişisel tool = kullanıcı kodu koşturur */
5081
+ this.approvals &&
5082
+ typeof this.approvals.request === 'function' &&
5010
5083
  !this.alwaysAllowTools.has(name) &&
5011
- this.approvals && typeof this.approvals.request === 'function'
5084
+ this._isDeleteOp(name, args)
5012
5085
  ) {
5013
5086
  emitSafe(this, sessionId, { type: 'status', status: `onay bekleniyor: ${name}` });
5014
5087
  let ok = false;
@@ -28,6 +28,9 @@ class AskService {
28
28
  this.emit = typeof emitFn === 'function' ? emitFn : () => {};
29
29
  this.pending = new Map(); // id -> { info, resolve, reject }
30
30
  this.approved = []; // oturumlar arası paylaşılan kural listesi (engine'e aşılanır)
31
+ /* Güvenlik ayarı KAPALI: 'ask' kuralı yine de sorulmaz — deny korunur,
32
+ ask otomatik serbesttir (tüm yetki ajanda). Engine ayarlar ile günceller. */
33
+ this.autoAllow = false;
31
34
  }
32
35
 
33
36
  /* opencode Permission.ask — throws: { kind:'denied'|'rejected'|'corrected', feedback? } */
@@ -40,6 +43,7 @@ class AskService {
40
43
  throw { kind: 'denied', permission, pattern };
41
44
  }
42
45
  if (rule.action === 'allow') continue;
46
+ if (this.autoAllow) continue; /* güvenlik kapalı: sorma, geç */
43
47
  needsAsk = true;
44
48
  }
45
49
  if (!needsAsk) return Promise.resolve();
@@ -60,12 +64,14 @@ class AskService {
60
64
  this.emit({ type: 'permission.asked', sessionId: info.sessionID, request: info });
61
65
  } catch {}
62
66
  /* güvenlik: emit kanalı koptuysa pending asılı kalmasın */
63
- setTimeout(() => {
67
+ const timer = setTimeout(() => {
64
68
  if (this.pending.has(id)) {
65
69
  this.pending.delete(id);
66
70
  reject({ kind: 'rejected' });
67
71
  }
68
72
  }, 5 * 60 * 1000);
73
+ /* bekleyen onay süreci/prosesi canlı tutmasın (özellikle test/çıkış) */
74
+ if (timer && typeof timer.unref === 'function') timer.unref();
69
75
  });
70
76
  }
71
77
 
package/src/main.js CHANGED
@@ -6206,6 +6206,8 @@ ipcMain.handle('sec:set', (_e, cfg) => {
6206
6206
  if (engine) {
6207
6207
  engine.approvals = settings.security.approvals ? approvalsBridge : null;
6208
6208
  engine.alwaysAllowTools = new Set(settings.security.alwaysAllow);
6209
+ /* BeastCode + Sandbox izin akışı CANLI güncellenir: kapalıyken hiç sorulmaz */
6210
+ if (typeof engine.setApprovals === 'function') engine.setApprovals(settings.security.approvals);
6209
6211
  }
6210
6212
  log.info('sec', `güvenlik: onay kapısı ${settings.security.approvals ? 'AÇIK' : 'KAPALI (her şey serbest)'}`);
6211
6213
  return { approvals: settings.security.approvals, alwaysAllow: settings.security.alwaysAllow };
@@ -8329,10 +8331,17 @@ function finCfg() {
8329
8331
  f.analysisAuto = true;
8330
8332
  if (!Number.isFinite(Number(f.analysisCount))) f.analysisCount = 2;
8331
8333
  f.analysisCount = Math.max(0, Math.min(FIN_ROLES_AUTO.length, Math.round(Number(f.analysisCount) || 0)));
8332
- /* ROL → SKILL eşleştirmesi: rol başına en fazla 8 skill adı */
8334
+ /* ROL → SKILL eşleştirmesi: VARSAYILAN BOŞ — ajan göreve göre skill'i kendi
8335
+ seçer (SKILLS kataloğu promptta). İstenirse ⚙ modalından rol başına
8336
+ sabitlenir; skill adları kurulu katalogdan gelir. Eski sürümün otomatik
8337
+ doldurduğu varsayılanlar bir kez temizlenir. */
8338
+ if (f.roleSkillsDefaultsCleared !== true) {
8339
+ f.roleSkills = {};
8340
+ f.roleSkillsDefaultsCleared = true;
8341
+ }
8333
8342
  if (!f.roleSkills || typeof f.roleSkills !== 'object') f.roleSkills = {};
8334
8343
  for (const d of FIN_ROLES) {
8335
- const cur = Array.isArray(f.roleSkills[d.id]) ? f.roleSkills[d.id] : ROLE_SKILL_DEFAULTS[d.id] || [];
8344
+ const cur = Array.isArray(f.roleSkills[d.id]) ? f.roleSkills[d.id] : [];
8336
8345
  f.roleSkills[d.id] = cur.map((s) => String(s || '').trim()).filter(Boolean).slice(0, 8);
8337
8346
  }
8338
8347
  if (!Number(f.intervalSec)) f.intervalSec = 120;
@@ -8351,14 +8360,6 @@ const FIN_ROLES = [
8351
8360
  { id: 'macro', label: 'Haber / Makro', desc: 'haber akışı + ekonomik takvim, DXY/emtia bağıntıları, yön eğilimi' },
8352
8361
  ];
8353
8362
  const FIN_ROLES_AUTO = ['technic', 'risk', 'macro'];
8354
- /* ROL → SKILL varsayılanları: her rolün tur başında okuması gereken skill'ler.
8355
- TRADE AJANI kartındaki ⚙ modalından değiştirilebilir; liste kurulu skill
8356
- kataloğundan beslenir, yeni skill eklenince modalda otomatik görünür. */
8357
- const ROLE_SKILL_DEFAULTS = {
8358
- technic: ['price-action'],
8359
- risk: ['risk-yonetimi'],
8360
- macro: ['haber-duygu'],
8361
- };
8362
8363
  function finRolesValid(list) {
8363
8364
  return (Array.isArray(list) ? list : [])
8364
8365
  .map((r) => String(r || '').trim())
@@ -435,14 +435,14 @@
435
435
  security_h2: 'Güvenlik',
436
436
  st_open: 'Aç',
437
437
  st_del: 'Sil',
438
- sec_toggle: 'Tehlikeli işlemlerde onay iste (silme, değiştirme, komut çalıştırma, mail gönderme…)',
439
- sec_sub: 'Kapalıyken her şey serbesttir (varsayım). Açıkken ajan riskli bir araç çağırmadan önce onay ister: sohbette onay kartı + WhatsApp\u2019a mesaj gider.',
438
+ sec_toggle: 'İzin iste: yalnızca silme işlemlerinde onay sor (Beast Code, Sandbox dahil)',
439
+ sec_sub: 'Kapalıyken (varsayılan) HİÇBİR yerde izin istenmez — Beast Code, Sandbox ve tüm araçlar serbest; tüm yetki ajandadır. Açıkken YALNIZCA SİLME işlemlerinde onay istenir: sohbette onay kartı + WhatsApp\u2019a mesaj gider. Diğer işlemler (yazma, düzenleme, komut çalıştırma, mail…) sorulmaz.',
440
440
  sec_note: 'Onay: sohbet kartındaki butonlar ya da /approve · Bu araç için bir daha sorma: /approve always · Reddet: /deny',
441
441
  sec_always_h2: 'Bir Daha Sorulmayan Araçlar',
442
442
  sec_always_empty: 'Henüz "always" onaylı araç yok.',
443
443
  sec_clear_always: 'Listeyi Temizle',
444
- sec_on_toast: 'Onay kapısı AÇIK — riskli işlemlerde ajan sorar',
445
- sec_off_toast: 'Onay kapısı KAPALI — her şey serbest',
444
+ sec_on_toast: 'Onay açık — yalnızca silme işlemlerinde ajan sorar',
445
+ sec_off_toast: 'Onay kapalı — hiçbir yerde sorulmaz, her şey serbest',
446
446
  sec_ok: 'Onayla',
447
447
  sec_always: 'Her zaman',
448
448
  sec_no: 'Reddet',
@@ -1147,14 +1147,14 @@
1147
1147
  security_h2: 'Security',
1148
1148
  st_open: 'Open',
1149
1149
  st_del: 'Delete',
1150
- sec_toggle: 'Ask approval for dangerous actions (delete, modify, run commands, send mail…)',
1151
- sec_sub: 'When off, everything is free (default). When on, the agent asks approval before a risky tool call: an approval card in chat + a WhatsApp message.',
1150
+ sec_toggle: 'Ask permission: only for deletions (including Beast Code and Sandbox)',
1151
+ sec_sub: 'When off (default) NOTHING asks for permission anywhere — Beast Code, Sandbox and all tools are free; the agent has full authority. When on, approval is asked ONLY for deletions: an approval card in chat + a WhatsApp message. Other actions (write, edit, run commands, mail…) never ask.',
1152
1152
  sec_note: 'Approve: chat card buttons or /approve · Never ask again for this tool: /approve always · Deny: /deny',
1153
1153
  sec_always_h2: 'Tools Never Asked Again',
1154
1154
  sec_always_empty: 'No "always" approved tools yet.',
1155
1155
  sec_clear_always: 'Clear List',
1156
- sec_on_toast: 'Approval gate ON — the agent asks before risky actions',
1157
- sec_off_toast: 'Approval gate OFF — everything free',
1156
+ sec_on_toast: 'Approval ON — the agent asks only for deletions',
1157
+ sec_off_toast: 'Approval OFF — nothing asks, everything free',
1158
1158
  sec_ok: 'Approve',
1159
1159
  sec_always: 'Always',
1160
1160
  sec_no: 'Deny',
@@ -656,7 +656,7 @@
656
656
  </div>
657
657
  <div class="mini-body">
658
658
  <div id="finSkillsList" class="mini-list"></div>
659
- <div class="fin-sym-hint">Her rolün okuması gereken skill'leri seç — liste kurulu katalogdan gelir; yeni skill eklersen burada otomatik görünür.</div>
659
+ <div class="fin-sym-hint">İsteğe bağlı: rol başına skill sabitle. Boş bırakırsan ajan göreve göre skill'i kendi seçer — liste kurulu katalogdan gelir, yeni skill eklenince otomatik görünür.</div>
660
660
  </div>
661
661
  </div>
662
662
  </div>