beast-agent 0.24.0 → 0.24.2

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.
@@ -49,11 +49,12 @@ if (process.argv[2] === 'uninstall') {
49
49
  process.exit(ur.status || 0);
50
50
  }
51
51
 
52
- /* güncelleme modu: çalışan Beast'i kapat (dosya kilidi EBUSY vermesin) → npm güncelle → yeniden başlat.
53
- npm install DETACHED çalışır: terminali/uygulamayı kapatmak update'i boğmaz. */
52
+ /* güncelleme modu: çalışan Beast'i kapat (dosya kilidi EBUSY vermesin) → npm güncelle (görünür ilerleme) → yeniden başlat.
53
+ Bu komut güncelleme butonu tarafından GÖRÜNÜR bir cmd penceresi içinde çalıştırılır;
54
+ doğrudan terminalden de çalışır — npm install çıktısı ekranda akar. */
54
55
  if (process.argv[2] === 'update') {
55
56
  const isWin = process.platform === 'win32';
56
- console.log('\u27F3 beast-agent g\u00FCncelleniyor\u2026 (arka planda s\u00FCrer — bu pencereyi kapabilirsin)');
57
+ console.log('\u27F3 beast-agent g\u00FCncelleniyor\u2026');
57
58
  if (isWin) {
58
59
  try {
59
60
  spawnSync('powershell.exe', ['-NoProfile', '-Command',
@@ -61,42 +62,33 @@ if (process.argv[2] === 'update') {
61
62
  { stdio: 'ignore' });
62
63
  console.log('\u2022 \u00E7al\u0131\u015Fan Beast kapat\u0131ld\u0131 (varsa)');
63
64
  } catch {}
64
- /* detached PS helper: npm install (5 deneme) + electron.exe ile yeniden başlatma */
65
- const ps = [
66
- "$ErrorActionPreference = 'Continue'",
67
- "$Log = Join-Path $env:APPDATA 'beast\\update.log'",
68
- "function L([string]$m) { try { Add-Content -LiteralPath $Log -Value (\"[\" + (Get-Date -Format 'yyyy-MM-dd HH:mm:ss') + \"] \" + $m) } catch {} }",
69
- "L '=== beast update (terminal) basladi ==='",
70
- "$ok = $false",
71
- "for ($i = 1; $i -le 5 -and -not $ok; $i++) {",
72
- " L \"npm install -g beast-agent@latest (deneme $i)\"",
73
- " & npm.cmd install -g beast-agent@latest 2>&1 | ForEach-Object { L \" npm: $_\" }",
74
- " if ($LASTEXITCODE -eq 0) { $ok = $true } else { Start-Sleep -Seconds 3 }",
75
- "}",
76
- "if (-not $ok) { L 'HATA: npm install basarisiz'; exit 1 }",
77
- "L 'npm install tamam - yeniden baslatma'",
78
- "$prefix = Join-Path $env:APPDATA 'npm'",
79
- "$appDir = Join-Path $prefix 'node_modules\\beast-agent'",
80
- "$exe = Join-Path $appDir 'node_modules\\electron\\dist\\electron.exe'",
81
- "if (-not (Test-Path $exe)) { $exe = Join-Path $prefix 'node_modules\\electron\\dist\\electron.exe' }",
82
- "Start-Process -FilePath $exe -ArgumentList ('\"' + $appDir + '\"')",
83
- "L '=== beast update bitti ==='",
84
- ].join('\r\n');
85
- const os = require('os');
86
- const psFile = path.join(os.tmpdir(), 'beast-update-helper.ps1');
87
- fs.writeFileSync(psFile, ps, 'utf8');
88
- spawn('powershell.exe', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', psFile],
89
- { detached: true, stdio: 'ignore', windowsHide: true }).unref();
90
- console.log('\u2022 npm install arka planda s\u00FCr\u00FCyor (2-4 dk) \u2014 bitince uygulama kendili\u011Finden a\u00E7\u0131l\u0131r');
91
- console.log(' durum: %APPDATA%\\beast\\update.log');
92
- process.exit(0);
65
+ } else {
66
+ try { spawnSync('pkill', ['-f', 'node_modules/beast-agent'], { stdio: 'ignore' }); } catch {}
67
+ }
68
+ /* dosya kilidi (EBUSY) bazen ilk denemede patlar — 5 deneme hakkı */
69
+ let ok = false;
70
+ for (let i = 1; i <= 5 && !ok; i++) {
71
+ const r = spawnSync('npm', ['install', '-g', 'beast-agent@latest'], { stdio: 'inherit', shell: isWin });
72
+ ok = r.status === 0;
73
+ if (!ok && i < 5) {
74
+ console.log(` \u2022 deneme ${i}/5 ba\u015Far\u0131s\u0131z (dosya kilidi olabilir) \u2014 3 sn sonra tekrar\u2026`);
75
+ if (isWin) spawnSync('powershell.exe', ['-NoProfile', '-Command', 'Start-Sleep -Seconds 3'], { stdio: 'ignore' });
76
+ else spawnSync('sleep', ['3']);
77
+ }
78
+ }
79
+ if (!ok) {
80
+ console.log('\n\u2717 g\u00FCncelleme ba\u015Far\u0131s\u0131z \u2014 elle: npm install -g beast-agent@latest');
81
+ if (isWin) spawnSync('cmd.exe', ['/c', 'pause'], { stdio: 'inherit', shell: false });
82
+ process.exit(1);
93
83
  }
94
- try { spawnSync('pkill', ['-f', 'node_modules/beast-agent'], { stdio: 'ignore' }); } catch {}
95
- const sh =
96
- 'ok=0; for n in 1 2 3 4 5; do npm install -g beast-agent@latest && ok=1 && break; sleep 3; done; ' +
97
- 'if [ $ok -eq 1 ]; then nohup beast-agent >/dev/null 2>&1 & fi';
98
- spawn('sh', ['-c', sh], { detached: true, stdio: 'ignore' }).unref();
99
- console.log('\u2022 arka planda s\u00FCr\u00FCyor \u2014 bitince uygulama a\u00E7\u0131l\u0131r');
84
+ console.log('\n\u2713 beast-agent g\u00FCncellendi \u2014 uygulama ba\u015Flat\u0131l\u0131yor\u2026');
85
+ try {
86
+ const electron = require('electron');
87
+ if (typeof electron === 'string') {
88
+ spawn(electron, [path.resolve(__dirname, '..')], { stdio: 'ignore', detached: true }).unref();
89
+ }
90
+ } catch {}
91
+ if (isWin) spawnSync('cmd.exe', ['/c', 'timeout /t 3'], { stdio: 'ignore' });
100
92
  process.exit(0);
101
93
  }
102
94
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "beast-agent",
3
3
  "productName": "Beast Agent",
4
- "version": "0.24.0",
4
+ "version": "0.24.2",
5
5
  "description": "Ultra-fast local agent shell for Windows.",
6
6
  "author": "algokodcom (AlgoKod)",
7
7
  "license": "MIT",
package/src/main.js CHANGED
@@ -1015,9 +1015,10 @@ async function tryWaSlash(jid, rawText, senderNum) {
1015
1015
  ? `*${cmd === 'deny' ? 'Reddedildi' : 'Onaylandı'}:* ${r.tool}${always ? ' — bu araç için bir daha sorulmayacak' : ''}`
1016
1016
  : 'Bekleyen onay yok.';
1017
1017
  } else if (cmd === 'update') {
1018
- /* /update — sürüm kontrol. TEK DAĞITIM npm: uygulama içi kurulum YOK. */
1018
+ /* /update — sürüm kontrol; /update now görünür cmd'de beast update */
1019
1019
  if (String(arg || '').toLowerCase() === 'now') {
1020
- out = NPM_ONLY_TEXT;
1020
+ updateReplies.jids.add(jid);
1021
+ npmUpdateNow(async (text) => { out = text; });
1021
1022
  } else {
1022
1023
  updateReplies.jids.add(jid);
1023
1024
  await runUpdateCommand(async (text) => { out = text; });
@@ -3325,7 +3326,7 @@ ipcMain.handle('agent:send', (_e, { sessionId, text }) => {
3325
3326
  const a = t.slice(7).trim().toLowerCase();
3326
3327
  updateReplies.sids.add(String(sessionId || ''));
3327
3328
  if (a === 'now') {
3328
- desktopEcho(sessionId, t, NPM_ONLY_TEXT);
3329
+ npmUpdateNow((text) => desktopEcho(sessionId, t, text));
3329
3330
  } else {
3330
3331
  runUpdateCommand((text) => desktopEcho(sessionId, t, text));
3331
3332
  }
@@ -4075,10 +4076,12 @@ ipcMain.handle('update:check', async () => {
4075
4076
  /* TEK DAĞITIM POLİTİKASI: uygulama içi self-update KALDIRILDI (v0.24.0).
4076
4077
  Güncelleme yalnız: uygulamayı kapat → "npm i -g beast-agent@latest" → tekrar aç. */
4077
4078
 
4078
- ipcMain.handle('update:install', () => ({
4079
- ok: false,
4080
- error: NPM_ONLY_TEXT,
4081
- }));
4079
+ ipcMain.handle('update:install', () => {
4080
+ /* TEK DAĞITIM npm: buton → görünür cmd'de "beast update" → kapan → kur → aç */
4081
+ if (!isNpmMode()) return { ok: false, error: NPM_ONLY_TEXT };
4082
+ npmUpdateViaCmd();
4083
+ return { ok: true, npm: true };
4084
+ });
4082
4085
 
4083
4086
  ipcMain.handle('update:setAuto', (_e, cfg) => {
4084
4087
  if (cfg && typeof cfg.autoCheck === 'boolean') settings.autoCheckUpdate = cfg.autoCheck;
@@ -4092,11 +4095,26 @@ ipcMain.handle('update:setAuto', (_e, cfg) => {
4092
4095
 
4093
4096
  /* /update komutu (masaüstü + WA): hedefi kaydet, kontrol başlat */
4094
4097
  /* npm modunda güncelle-şimdi: sürüm kontrolü + numaralarıyla bildir + kendi kendini güncelle */
4095
- /* TEK DAĞITIM POLİTİKASI: exe/installer YOK, uygulama içi self-update YOK.
4096
- Güncelleme yalnız: uygulamayı kapat "npm i -g beast-agent@latest"tekrar aç. */
4098
+ /* TEK DAĞITIM POLİTİKASI: exe/installer YOK.
4099
+ Güncelleme akışı: butongörünür CMD penceresi açılır"beast update"
4100
+ (npm install çıktısı ekranda akar) → uygulama kapanır → kurulum bitince
4101
+ uygulama kendiliğinden yeniden açılır. */
4097
4102
  const NPM_ONLY_TEXT =
4098
- 'Tek dağıtım npm\u2019dir uygulama içi güncelleme yok.\n' +
4099
- 'Güncellemek için:\n1) Uygulamayı kapat\n2) Terminalde: npm i -g beast-agent@latest\n3) Tekrar aç';
4103
+ 'Tek dağıtım npm\u2019dir. Güncellemek için:\n1) Uygulamayı kapat\n2) Terminalde: npm i -g beast-agent@latest\n3) Tekrar aç';
4104
+
4105
+ /* buton akışı: görünür cmd + "beast update" + uygulama kapanışı */
4106
+ function npmUpdateViaCmd() {
4107
+ try {
4108
+ const shim = path.join(process.env.APPDATA || '', 'npm', 'beast-agent.cmd');
4109
+ const cmdLine = fs.existsSync(shim) ? `"${shim}" update` : 'beast update';
4110
+ spawn(
4111
+ 'cmd.exe',
4112
+ ['/c', 'start', 'Beast Guncelleme', 'cmd', '/k', cmdLine],
4113
+ { detached: true, stdio: 'ignore', windowsHide: false }
4114
+ ).unref();
4115
+ } catch {}
4116
+ setTimeout(() => { try { app.quit(); } catch {} }, 600);
4117
+ }
4100
4118
 
4101
4119
  function npmUpdateNow(reply /* fn(text) */) {
4102
4120
  const current = app.getVersion();
@@ -4104,7 +4122,8 @@ function npmUpdateNow(reply /* fn(text) */) {
4104
4122
  if (v && isNewerVersion(v, current)) {
4105
4123
  updateState.available = true;
4106
4124
  updateState.version = v;
4107
- reply(`🔄 *Yeni sürüm var*\nMevcut: v${current}\nYeni: v${v}\n\n${NPM_ONLY_TEXT}`);
4125
+ reply(`🔄 *Yeni sürüm var*\nMevcut: v${current}\nYeni: v${v}\nGüncelleme başlatıldı — cmd penceresinden takip et.`);
4126
+ npmUpdateViaCmd();
4108
4127
  } else {
4109
4128
  reply(`✅ *Güncelsin* — v${current} zaten en son sürüm.`);
4110
4129
  }
@@ -4112,7 +4131,7 @@ function npmUpdateNow(reply /* fn(text) */) {
4112
4131
  }
4113
4132
 
4114
4133
  async function runUpdateCommand(reply /* fn(text) */) {
4115
- /* yalnız KONTROL + yol gösterme — kurulum yapmaz */
4134
+ /* yalnız KONTROL + yol gösterme — kendiliğinden kurulum yapmaz */
4116
4135
  return npmUpdateNow(reply);
4117
4136
  }
4118
4137
 
@@ -165,7 +165,7 @@
165
165
  sk_h2: 'Skills',
166
166
  sk_sub: 'SKILL.md indeksi — tam metin model tarafından okunur',
167
167
  sk_auto: 'Otomatik skill: ajan öğrendiği yeni yöntemleri taslak onayı beklemeden kurar; bir skillin daha kolay/daha iyi yolunu bulursa mevcut skilli kendisi günceller',
168
- up_npm_only: 'Tek dağıtım npm\u2019dir uygulama içi kurulum butonu yoktur. Güncellemek için: uygulamayı kapat terminalde "npm i -g beast-agent@latest" tekrar aç. (İpucu: sohbete "beni güncelle" yazarsan adımları söyler.)',
168
+ up_npm_only: 'Tek dağıtım npm\u2019dir. "Yeniden başlat ve güncelle" butonu: uygulamayı kapatır, GÖRÜNÜR bir cmd penceresinde "beast update" koşturur (npm install çıktısını ekranda görürsün), kurulum bitince uygulama kendiliğinden açılır.İstersen terminalden de: npm i -g beast-agent@latest',
169
169
  sk_rules_h2: 'Kalıcı Kurallar',
170
170
  sk_rules_sub: 'Agent\u2019ın her sohbette uyduğu talimatlar — WA\u2019dan /rule ile de eklenir',
171
171
  sk_no_rule: 'Henüz kural yok.',
@@ -446,6 +446,7 @@
446
446
  bot_sel_empty: '— bot seçme —',
447
447
  bot_code_title: 'Botun benzersiz 5 haneli kodu — botlar arası DM adresi',
448
448
  bot_vis: 'Ana sohbete davet edilebilir (sohbet görünürlüğü)',
449
+ tipGuestBot: 'Konuşmaya bot davet et — davetli botlara ajan bot_dm ile danışır',
449
450
  bot_switch_hint: 'Tıkla: bu botta çalış · ⚙: yönet',
450
451
  bot_switched: 'bottasın — sohbetler bu botun kimliğiyle gider',
451
452
  bot_manage: 'Botu yönet',
@@ -683,7 +684,7 @@
683
684
  sk_h2: 'Skills',
684
685
  sk_sub: 'SKILL.md index — full text is read by the model',
685
686
  sk_auto: 'Auto skills: the agent installs learned procedures without draft approval and updates existing skills when it finds an easier or better way',
686
- up_npm_only: 'npm is the only distribution there is no in-app install button. To update: close the app run "npm i -g beast-agent@latest" in a terminal → reopen.',
687
+ up_npm_only: 'npm is the only distribution. The "Restart & update" button: closes the app, runs "beast update" in a VISIBLE cmd window (npm install output on screen), and reopens the app when done. Or manually: npm i -g beast-agent@latest',
687
688
  sk_rules_h2: 'Persistent Rules',
688
689
  sk_rules_sub: 'Instructions the agent follows in every chat — also addable via /rule on WA',
689
690
  sk_no_rule: 'No rules yet.',
@@ -1022,6 +1023,7 @@
1022
1023
  bot_sel_empty: '— no bot —',
1023
1024
  bot_code_title: "This bot's unique 5-digit code — the inter-bot DM address",
1024
1025
  bot_vis: 'Invitable to the main chat (chat visibility)',
1026
+ tipGuestBot: 'Invite a bot to this chat — the agent consults invited bots via bot_dm',
1025
1027
  bot_switch_hint: 'Click: work as this bot · ⚙: manage',
1026
1028
  bot_switched: 'active — chats run with this bot\u2019s identity',
1027
1029
  bot_manage: 'Manage bot',
@@ -95,16 +95,16 @@
95
95
  <div id="chips" hidden></div>
96
96
  <div id="slashMenu" hidden></div>
97
97
  <div id="composer">
98
- <button id="attachBtn" title="Dosya / resim ekle" data-i18n-title="tipAttach">+</button>
99
- <button id="micBtn" title="Sesli komut konuş, bırakınca yazıya çevirsin" data-i18n-title="tipMic"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="2" width="6" height="12" rx="3"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><path d="M12 19v3"/></svg></button>
98
+ <div id="composerLeft" class="dd">
99
+ <button id="attachBtn" title="Dosya / resim ekle" data-i18n-title="tipAttach">+</button>
100
+ <button id="micBtn" title="Sesli komut — konuş, bırakınca yazıya çevirsin" data-i18n-title="tipMic"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="2" width="6" height="12" rx="3"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><path d="M12 19v3"/></svg></button>
101
+ <button id="guestBotBtn" title="Konuşmaya bot davet et — davetli botlara ajan bot_dm ile danışır" data-i18n-title="tipGuestBot" hidden><span style="filter:grayscale(1)">🤖</span></button>
102
+ <div id="guestBotMenu" class="dd-menu" hidden></div>
103
+ </div>
100
104
  <textarea id="input" rows="1" placeholder="Bir şey sor ya da görev ver… (Enter: gönder · Shift+Enter: satır · /: komutlar)" data-i18n-ph="composerPh"></textarea>
101
105
  <button id="stopBtn" title="Durdur" hidden data-i18n-title="tipStop">■</button>
102
106
  <button id="sendBtn" title="Gönder" data-i18n-title="tipSend">&#x27A4;&#xFE0E;</button>
103
107
  </div>
104
- <div id="guestBotDD" class="dd" style="align-self:center">
105
- <button id="guestBotBtn" class="btn ghost" style="margin-top:6px;padding:4px 12px;font-size:12px" title="Konuşmaya başka bot davet et">🤖 Bot davet et</button>
106
- <div id="guestBotMenu" class="dd-menu" hidden style="left:50%;transform:translateX(-50%)"></div>
107
- </div>
108
108
  </div>
109
109
 
110
110
  <div id="ideRow">
@@ -1813,13 +1813,14 @@ async function renderUpdatePane(autoCheck) {
1813
1813
  if (!st) return;
1814
1814
  clearInterval(updatePaneTimer);
1815
1815
 
1816
- /* mod bazlı butonlar: npm → kontrol, installer kontrol, dev → sadece kontrol.
1817
- TEK DAĞITIM npm uygulama içi kurulum butonu KALDIRILDI. */
1816
+ /* mod bazlı butonlar: npm → kontrol + güncelle-butonu (görünür cmd açar),
1817
+ installer kontrol + not, dev sadece kontrol */
1818
1818
  const isDev = !st.packaged && !st.npm;
1819
1819
  let actions;
1820
1820
  if (st.npm) {
1821
1821
  actions = `<div class="form-grid" style="grid-template-columns:auto auto;gap:8px;margin-top:12px">
1822
1822
  <button id="upCheck" class="btn ghost">${_t('up_check_now')}</button>
1823
+ <button id="upInstall" class="btn">${st.available ? '🔄 ' + _t('up_install_now') : _t('up_install_now')}</button>
1823
1824
  </div>
1824
1825
  <div class="sub" style="margin-top:8px">${_t('up_npm_only')}</div>`;
1825
1826
  } else if (isDev) {
@@ -2463,15 +2464,16 @@ let botPageStats = [];
2463
2464
  let activeBotId = 'beast'; // masaüstü UI'ının şu an hangi botta olduğu (varsayılan: ilk bot/Beast)
2464
2465
  let activeGuests = []; // aktif ana sohbete davetli botlar [{id, code, name}]
2465
2466
 
2466
- /* ANA SOHBETE BOT DAVETİ: yalnız admin bottayken görünür; davetli botlar
2467
- session'a kaydedilir, ajan bot_dm aracıyla onlara danışıp cevapları aktarır */
2467
+ /* ANA SOHBETE BOT DAVETİ: yalnız admin bottayken görünür (composer'daki 🤖 ikonu);
2468
+ davetli botlar session'a kaydedilir, ajan bot_dm aracıyla onlara danışır */
2468
2469
  function renderGuestBotMenu() {
2469
- const wrap = $('#guestBotDD');
2470
+ const btn = $('#guestBotBtn');
2470
2471
  const menu = $('#guestBotMenu');
2471
- if (!wrap || !menu) return;
2472
+ if (!btn || !menu) return;
2472
2473
  const isAdmin = activeBotId === 'beast';
2473
- wrap.style.display = isAdmin && activeId ? '' : 'none';
2474
- if (!isAdmin) return;
2474
+ const show = isAdmin && !!activeId;
2475
+ btn.style.display = show ? '' : 'none';
2476
+ if (!show) { menu.hidden = true; return; }
2475
2477
  const candidates = botsCache.filter((b) => !b.admin && b.vis !== false);
2476
2478
  menu.innerHTML = '';
2477
2479
  if (!candidates.length) {
@@ -998,6 +998,23 @@ body.term-open #settingsOverlay { right: var(--tw, 520px); }
998
998
  }
999
999
  #attachBtn:hover { background: var(--panel); color: var(--accent); }
1000
1000
 
1001
+ /* composer sol grubu: + mikrofon bot-davet — yanyana boşluksuz */
1002
+ #composerLeft { display: flex; align-items: center; gap: 0; flex-shrink: 0; }
1003
+ #guestBotBtn {
1004
+ width: 32px; height: 32px;
1005
+ border-radius: 9px;
1006
+ border: none;
1007
+ cursor: pointer;
1008
+ font-size: 15px;
1009
+ line-height: 1;
1010
+ flex-shrink: 0;
1011
+ background: none;
1012
+ color: var(--muted);
1013
+ padding: 0;
1014
+ }
1015
+ #guestBotBtn:hover { background: var(--panel); color: var(--accent); }
1016
+ #guestBotMenu { width: 260px; left: 0; }
1017
+
1001
1018
  #micBtn {
1002
1019
  width: 32px; height: 32px;
1003
1020
  border-radius: 9px;
@@ -1714,7 +1731,6 @@ body.browser-open #toast { left: calc((100vw - var(--bw, 480px)) / 2); }
1714
1731
  #botList { overflow-y: auto; }
1715
1732
  .bot-card {
1716
1733
  display: flex;
1717
- flex-wrap: wrap;
1718
1734
  align-items: center;
1719
1735
  gap: 8px;
1720
1736
  padding: 6px 8px;
@@ -1726,16 +1742,15 @@ body.browser-open #toast { left: calc((100vw - var(--bw, 480px)) / 2); }
1726
1742
  .bot-card:hover { background: var(--panel2); color: var(--text); }
1727
1743
  .bot-card.active { background: var(--panel2); color: var(--text); box-shadow: inset 2px 0 0 var(--accent); }
1728
1744
  .bot-card .bot-ico { font-size: 16px; line-height: 1; flex-shrink: 0; }
1729
- /* 5 haneli benzersiz bot kodu — satırda ortalanmış */
1745
+ /* 5 haneli benzersiz bot kodu — bot adının yanında */
1730
1746
  .bot-card .bot-code {
1731
- width: 100%;
1732
- text-align: center;
1733
1747
  font-family: ui-monospace, Consolas, monospace;
1734
- font-size: 10.5px;
1748
+ font-size: 10px;
1735
1749
  font-weight: 700;
1736
- letter-spacing: 3px;
1750
+ letter-spacing: 1.5px;
1737
1751
  color: var(--accent);
1738
- opacity: 0.85;
1752
+ opacity: 0.9;
1753
+ margin-left: 2px;
1739
1754
  }
1740
1755
  .bot-card .bot-gear {
1741
1756
  visibility: hidden;