apexbot 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ApexBot Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,307 @@
1
+ # 🦊 ApexBot — Your Free, Private AI Assistant
2
+
3
+ <div align="center">
4
+
5
+ ```
6
+ ___ ____ _______ ______ ____ ______
7
+ / | / __ \/ ____/ |/ / __ )/ __ \/_ __/
8
+ / /| | / /_/ / __/ | / __ / / / / / /
9
+ / ___ |/ ____/ /___ / / /_/ / /_/ / / /
10
+ /_/ |_/_/ /_____//_/|_/_____/\____/ /_/
11
+
12
+ 🦊 Your Free AI Assistant 🦊
13
+ ```
14
+
15
+ [![CI](https://github.com/YOUR_USERNAME/apexbot/actions/workflows/ci.yml/badge.svg)](https://github.com/YOUR_USERNAME/apexbot/actions)
16
+ [![npm version](https://badge.fury.io/js/apexbot.svg)](https://www.npmjs.com/package/apexbot)
17
+ [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
18
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0-blue.svg)](https://www.typescriptlang.org/)
19
+
20
+ **100% Free • Open Source • Private • Self-Hosted**
21
+
22
+ [Installation](#-installation) • [Features](#-features) • [Quick Start](#-quick-start) • [Commands](#-commands) • [Contributing](#-contributing)
23
+
24
+ </div>
25
+
26
+ ---
27
+
28
+ ## ⚡ Installation
29
+
30
+ ### One-Line Install
31
+
32
+ **Windows (PowerShell):**
33
+ ```powershell
34
+ iwr -useb https://raw.githubusercontent.com/YOUR_USERNAME/apexbot/main/scripts/install.ps1 | iex
35
+ ```
36
+
37
+ **macOS/Linux:**
38
+ ```bash
39
+ curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/apexbot/main/scripts/install.sh | bash
40
+ ```
41
+
42
+ **npm (global):**
43
+ ```bash
44
+ npm install -g apexbot
45
+ apexbot onboard
46
+ ```
47
+
48
+ ### Manual Install
49
+
50
+ ```bash
51
+ # Clone repository
52
+ git clone https://github.com/YOUR_USERNAME/apexbot.git
53
+ cd apexbot
54
+ npm install
55
+ npm run build
56
+
57
+ # Run setup wizard
58
+ npm run onboard
59
+ ```
60
+
61
+ ---
62
+
63
+ ## ✨ Features
64
+
65
+ ### 🤖 100% Free AI with Ollama
66
+ - **No API keys needed** — runs completely locally
67
+ - **No cloud costs** — your hardware, your AI
68
+ - **Private** — conversations never leave your machine
69
+ - **Multiple models** — llama3.2, mistral, codellama, qwen2.5
70
+
71
+ ### 📱 Multi-Channel Support
72
+ | Channel | Status | Description |
73
+ |---------|--------|-------------|
74
+ | **Telegram** | ✅ Ready | Full bot integration |
75
+ | **Discord** | ✅ Ready | Guilds and DMs |
76
+ | **WebChat** | ✅ Ready | Built-in web dashboard |
77
+ | **WhatsApp** | 🚧 Soon | Via Baileys |
78
+
79
+ ### 🧠 AI Providers
80
+ | Provider | Cost | Description |
81
+ |----------|------|-------------|
82
+ | **Ollama** | **FREE** | Local AI (recommended!) |
83
+ | Google Gemini | Free tier | Cloud AI |
84
+ | Anthropic Claude | Paid | Cloud AI |
85
+ | OpenAI GPT | Paid | Cloud AI |
86
+
87
+ ### 🛡️ Self-Hosted & Private
88
+ - Your data stays with you
89
+ - No telemetry or tracking
90
+ - Full control over your bot
91
+
92
+ ---
93
+
94
+ ## 🚀 Quick Start
95
+
96
+ ### 1. Install Ollama (for free AI)
97
+
98
+ **Windows:**
99
+ ```powershell
100
+ winget install Ollama.Ollama
101
+ ```
102
+
103
+ **macOS:**
104
+ ```bash
105
+ brew install ollama
106
+ ```
107
+
108
+ **Linux:**
109
+ ```bash
110
+ curl -fsSL https://ollama.com/install.sh | sh
111
+ ```
112
+
113
+ ### 2. Pull a model
114
+
115
+ ```bash
116
+ ollama pull llama3.2
117
+ ollama serve # Keep running in background
118
+ ```
119
+
120
+ ### 3. Install ApexBot
121
+
122
+ ```bash
123
+ npm install -g apexbot
124
+ ```
125
+
126
+ ### 4. Run setup wizard
127
+
128
+ ```bash
129
+ apexbot onboard
130
+ ```
131
+
132
+ The wizard will guide you through:
133
+ - Choosing AI provider (Ollama recommended!)
134
+ - Setting up Telegram/Discord
135
+ - Configuring your bot
136
+
137
+ ### 5. Start your bot
138
+
139
+ ```bash
140
+ apexbot daemon start
141
+ ```
142
+
143
+ Done! 🎉 Your bot is now running.
144
+
145
+ ---
146
+
147
+ ## 🎮 Commands
148
+
149
+ ### CLI Commands
150
+
151
+ ```bash
152
+ # Setup & Configuration
153
+ apexbot onboard # Interactive setup wizard
154
+ apexbot config # Show configuration
155
+ apexbot config --reset # Reset configuration
156
+
157
+ # Daemon (background service)
158
+ apexbot daemon start # Start in background
159
+ apexbot daemon stop # Stop daemon
160
+ apexbot daemon restart # Restart daemon
161
+ apexbot daemon status # Check status
162
+
163
+ # Gateway (foreground)
164
+ apexbot gateway # Start gateway server
165
+ apexbot gateway --verbose # With debug logs
166
+
167
+ # Other
168
+ apexbot status # Show status
169
+ apexbot models # Manage Ollama models
170
+ ```
171
+
172
+ ### Chat Commands
173
+
174
+ | Command | Description |
175
+ |---------|-------------|
176
+ | `/help` | Show available commands |
177
+ | `/status` | Show session info |
178
+ | `/new` | Start new conversation |
179
+ | `/model <name>` | Switch AI model |
180
+
181
+ ---
182
+
183
+ ## 🏗️ Architecture
184
+
185
+ ```
186
+ ┌─────────────────────────────────────────────────────────────┐
187
+ │ Messaging Channels │
188
+ │ Telegram │ Discord │ WebChat │ WhatsApp │
189
+ └────────────┬─────────┬─────────┬─────────┬──────────────────┘
190
+ │ │ │ │
191
+ ▼ ▼ ▼ ▼
192
+ ┌─────────────────────────────────────────────────────────────┐
193
+ │ Gateway Server │
194
+ │ (HTTP + WebSocket on port 18789) │
195
+ ├─────────────────────────────────────────────────────────────┤
196
+ │ Sessions Manager │ Event Bus │ Rate Limiter │
197
+ └────────────────────┼─────────────┼──────────────────────────┘
198
+ │ │
199
+ ▼ ▼
200
+ ┌─────────────────────────────────────────────────────────────┐
201
+ │ AI Agent Manager │
202
+ │ Ollama │ Gemini │ Claude │ OpenAI │
203
+ └─────────────────────────────────────────────────────────────┘
204
+ ```
205
+
206
+ ---
207
+
208
+ ## 🆚 ApexBot vs Clawdbot
209
+
210
+ | Feature | Clawdbot | ApexBot |
211
+ |---------|----------|---------|
212
+ | **Cost** | Cloud APIs (paid) | **100% FREE with Ollama** |
213
+ | **Privacy** | Cloud-dependent | **Fully local & private** |
214
+ | **Channels** | WhatsApp, Telegram, Discord, iMessage | Telegram, Discord, WebChat |
215
+ | **AI** | Claude, GPT | **Ollama (free!)**, Gemini, Claude, GPT |
216
+ | **Setup** | Complex | **Simple wizard** |
217
+ | **License** | Proprietary | **MIT (Open Source)** |
218
+
219
+ ---
220
+
221
+ ## 📁 Project Structure
222
+
223
+ ```
224
+ apexbot/
225
+ ├── src/
226
+ │ ├── cli/ # Command-line interface
227
+ │ ├── gateway/ # HTTP/WebSocket server & dashboard
228
+ │ ├── channels/ # Telegram, Discord, WebChat
229
+ │ ├── agent/ # AI provider integrations
230
+ │ ├── sessions/ # Conversation management
231
+ │ └── core/ # Event bus, utilities
232
+ ├── scripts/
233
+ │ ├── install.ps1 # Windows installer
234
+ │ └── install.sh # macOS/Linux installer
235
+ ├── package.json
236
+ └── README.md
237
+ ```
238
+
239
+ ---
240
+
241
+ ## 🔧 Configuration
242
+
243
+ Configuration is stored in `~/.apexbot/config.json`:
244
+
245
+ ```json
246
+ {
247
+ "gateway": {
248
+ "port": 18789
249
+ },
250
+ "agent": {
251
+ "provider": "ollama",
252
+ "apiUrl": "http://localhost:11434",
253
+ "model": "llama3.2"
254
+ },
255
+ "channels": {
256
+ "telegram": {
257
+ "token": "your-bot-token"
258
+ }
259
+ }
260
+ }
261
+ ```
262
+
263
+ Or use environment variables:
264
+
265
+ ```bash
266
+ export OLLAMA_URL=http://localhost:11434
267
+ export OLLAMA_MODEL=llama3.2
268
+ export TELEGRAM_BOT_TOKEN=your-token
269
+ ```
270
+
271
+ ---
272
+
273
+ ## 🤝 Contributing
274
+
275
+ Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
276
+
277
+ ```bash
278
+ # Development
279
+ git clone https://github.com/YOUR_USERNAME/apexbot.git
280
+ cd apexbot
281
+ npm install
282
+ npm run dev # Start with hot-reload
283
+ ```
284
+
285
+ ---
286
+
287
+ ## 📄 License
288
+
289
+ MIT License — see [LICENSE](LICENSE) for details.
290
+
291
+ ---
292
+
293
+ ## 🙏 Acknowledgments
294
+
295
+ - Inspired by [Clawdbot](https://github.com/clawdbot/clawdbot)
296
+ - Powered by [Ollama](https://ollama.com) for free local AI
297
+ - Built with TypeScript, grammY, discord.js
298
+
299
+ ---
300
+
301
+ <div align="center">
302
+
303
+ **Made with ❤️ by the ApexBot community**
304
+
305
+ ⭐ Star this repo if you find it useful!
306
+
307
+ </div>
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ManifoldAdapter = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const ws_1 = __importDefault(require("ws"));
9
+ const eventBus_1 = require("../eventBus");
10
+ const rateLimiter_1 = __importDefault(require("../rateLimiter"));
11
+ class ManifoldAdapter {
12
+ http;
13
+ ws = null;
14
+ cfg;
15
+ limiter;
16
+ reconnectAttempts = 0;
17
+ maxReconnectAttempts = 10;
18
+ subscribedMarkets = new Set();
19
+ constructor(cfg) {
20
+ this.cfg = {
21
+ baseUrl: 'https://api.manifold.markets/v0',
22
+ wsUrl: 'wss://api.manifold.markets/ws',
23
+ ...cfg,
24
+ };
25
+ this.http = axios_1.default.create({
26
+ baseURL: this.cfg.baseUrl,
27
+ headers: cfg.apiKey ? { Authorization: `Key ${cfg.apiKey}` } : {},
28
+ });
29
+ // Manifold: ~1000 req/min → ~16/sec; be conservative
30
+ this.limiter = new rateLimiter_1.default(20, 10);
31
+ }
32
+ // ─────────────────────────────────────────────────────────────────
33
+ // REST API Methods
34
+ // ─────────────────────────────────────────────────────────────────
35
+ async request(method, path, data) {
36
+ // Rate limit check
37
+ const waitTime = this.limiter.timeUntil(1);
38
+ if (waitTime > 0) {
39
+ await new Promise((r) => setTimeout(r, waitTime * 1000));
40
+ }
41
+ this.limiter.tryRemove(1);
42
+ const res = await this.http.request({ method, url: path, data });
43
+ return res.data;
44
+ }
45
+ async getMarkets(limit = 100) {
46
+ return this.request('get', `/markets?limit=${limit}`);
47
+ }
48
+ async getMarket(id) {
49
+ return this.request('get', `/market/${id}`);
50
+ }
51
+ async searchMarkets(term, limit = 50) {
52
+ return this.request('get', `/search-markets?term=${encodeURIComponent(term)}&limit=${limit}`);
53
+ }
54
+ async getMarketBySlug(slug) {
55
+ return this.request('get', `/slug/${slug}`);
56
+ }
57
+ async getMyBets(limit = 100) {
58
+ return this.request('get', `/bets?limit=${limit}`);
59
+ }
60
+ async getMe() {
61
+ return this.request('get', '/me');
62
+ }
63
+ /**
64
+ * Place a bet on a market.
65
+ * @param marketId Market ID
66
+ * @param amount Amount in Mana (M$)
67
+ * @param outcome 'YES' or 'NO'
68
+ * @param limitProb Optional limit probability (0..1)
69
+ */
70
+ async placeBet(marketId, amount, outcome, limitProb) {
71
+ const payload = { contractId: marketId, amount, outcome };
72
+ if (limitProb !== undefined) {
73
+ payload.limitProb = limitProb;
74
+ }
75
+ const bet = await this.request('post', '/bet', payload);
76
+ (0, eventBus_1.emit)('order:placed', { marketId, side: outcome === 'YES' ? 'buy' : 'sell', stake: amount, betId: bet.id });
77
+ return bet;
78
+ }
79
+ async cancelBet(betId) {
80
+ await this.request('post', `/bet/cancel/${betId}`);
81
+ }
82
+ // ─────────────────────────────────────────────────────────────────
83
+ // WebSocket for real-time updates
84
+ // ─────────────────────────────────────────────────────────────────
85
+ connectWebSocket() {
86
+ if (this.ws) {
87
+ this.ws.close();
88
+ }
89
+ console.log('📡 Connecting to Manifold WebSocket...');
90
+ this.ws = new ws_1.default(this.cfg.wsUrl);
91
+ this.ws.on('open', () => {
92
+ console.log('✅ Manifold WebSocket connected');
93
+ this.reconnectAttempts = 0;
94
+ // Re-subscribe to markets
95
+ for (const marketId of this.subscribedMarkets) {
96
+ this.subscribeMarket(marketId);
97
+ }
98
+ });
99
+ this.ws.on('message', (data) => {
100
+ try {
101
+ const msg = JSON.parse(data.toString());
102
+ this.handleWsMessage(msg);
103
+ }
104
+ catch (e) {
105
+ console.error('WS parse error:', e);
106
+ }
107
+ });
108
+ this.ws.on('close', () => {
109
+ console.log('🔌 Manifold WebSocket closed');
110
+ this.scheduleReconnect();
111
+ });
112
+ this.ws.on('error', (err) => {
113
+ console.error('WS error:', err);
114
+ });
115
+ }
116
+ scheduleReconnect() {
117
+ if (this.reconnectAttempts >= this.maxReconnectAttempts) {
118
+ (0, eventBus_1.emit)('strategy:alert', 'ws:max_reconnect_exceeded');
119
+ return;
120
+ }
121
+ const delay = Math.min(1000 * 2 ** this.reconnectAttempts, 30000);
122
+ this.reconnectAttempts++;
123
+ console.log(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})...`);
124
+ setTimeout(() => this.connectWebSocket(), delay);
125
+ }
126
+ handleWsMessage(msg) {
127
+ // Manifold WS message types: 'market', 'bet', etc.
128
+ switch (msg.type) {
129
+ case 'market':
130
+ (0, eventBus_1.emit)('market:update', {
131
+ marketId: msg.market?.id,
132
+ price: msg.market?.probability,
133
+ description: msg.market?.question,
134
+ timestamp: Date.now(),
135
+ });
136
+ break;
137
+ case 'bet':
138
+ // Someone placed a bet
139
+ (0, eventBus_1.emit)('market:bet', msg.bet);
140
+ break;
141
+ default:
142
+ // Unknown message type
143
+ break;
144
+ }
145
+ }
146
+ subscribeMarket(marketId) {
147
+ this.subscribedMarkets.add(marketId);
148
+ if (this.ws && this.ws.readyState === ws_1.default.OPEN) {
149
+ this.ws.send(JSON.stringify({ type: 'subscribe', marketId }));
150
+ }
151
+ }
152
+ unsubscribeMarket(marketId) {
153
+ this.subscribedMarkets.delete(marketId);
154
+ if (this.ws && this.ws.readyState === ws_1.default.OPEN) {
155
+ this.ws.send(JSON.stringify({ type: 'unsubscribe', marketId }));
156
+ }
157
+ }
158
+ disconnect() {
159
+ if (this.ws) {
160
+ this.ws.close();
161
+ this.ws = null;
162
+ }
163
+ }
164
+ }
165
+ exports.ManifoldAdapter = ManifoldAdapter;
166
+ exports.default = ManifoldAdapter;
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TelegramAdapter = void 0;
4
+ const grammy_1 = require("grammy");
5
+ const eventBus_1 = require("../eventBus");
6
+ class TelegramAdapter {
7
+ bot;
8
+ cfg;
9
+ constructor(cfg) {
10
+ this.cfg = cfg;
11
+ this.bot = new grammy_1.Bot(cfg.botToken);
12
+ this.setupHandlers();
13
+ this.setupEventListeners();
14
+ }
15
+ isAllowed(ctx) {
16
+ const userId = ctx.from?.id;
17
+ console.log(`[TG] User ID: ${userId}, Allowed: ${this.cfg.allowedUserIds}`);
18
+ if (!userId)
19
+ return false;
20
+ // Allow if list is empty (no restrictions) or user is in the list
21
+ if (this.cfg.allowedUserIds.length === 0)
22
+ return true;
23
+ return this.cfg.allowedUserIds.includes(userId);
24
+ }
25
+ setupHandlers() {
26
+ // Command: /start
27
+ this.bot.command('start', async (ctx) => {
28
+ console.log(`[TG] /start from ${ctx.from?.id}`);
29
+ if (!this.isAllowed(ctx)) {
30
+ await ctx.reply('⛔ Brak dostępu. Twoje ID: ' + ctx.from?.id);
31
+ return;
32
+ }
33
+ await ctx.reply('🤖 *ApexBot* uruchomiony!\n\n' +
34
+ 'Komendy:\n' +
35
+ '/status - stan bota i bankroll\n' +
36
+ '/markets - aktywne rynki\n' +
37
+ '/stop - zatrzymaj trading\n' +
38
+ '/start_trading - wznów trading\n' +
39
+ '/set_risk <0.1-1.0> - ustaw mnożnik ryzyka Kelly', { parse_mode: 'Markdown' });
40
+ });
41
+ // Command: /status
42
+ this.bot.command('status', async (ctx) => {
43
+ if (!this.isAllowed(ctx))
44
+ return;
45
+ (0, eventBus_1.emit)('telegram:status_request', { chatId: ctx.chat.id });
46
+ });
47
+ // Command: /markets
48
+ this.bot.command('markets', async (ctx) => {
49
+ if (!this.isAllowed(ctx))
50
+ return;
51
+ (0, eventBus_1.emit)('telegram:markets_request', { chatId: ctx.chat.id });
52
+ });
53
+ // Command: /stop
54
+ this.bot.command('stop', async (ctx) => {
55
+ if (!this.isAllowed(ctx))
56
+ return;
57
+ (0, eventBus_1.emit)('telegram:stop_trading', { chatId: ctx.chat.id });
58
+ await ctx.reply('🛑 Trading zatrzymany.');
59
+ });
60
+ // Command: /start_trading
61
+ this.bot.command('start_trading', async (ctx) => {
62
+ if (!this.isAllowed(ctx))
63
+ return;
64
+ (0, eventBus_1.emit)('telegram:start_trading', { chatId: ctx.chat.id });
65
+ await ctx.reply('▶️ Trading wznowiony.');
66
+ });
67
+ // Command: /set_risk <value>
68
+ this.bot.command('set_risk', async (ctx) => {
69
+ if (!this.isAllowed(ctx))
70
+ return;
71
+ const arg = ctx.message?.text?.split(' ')[1];
72
+ const value = parseFloat(arg || '');
73
+ if (isNaN(value) || value < 0.05 || value > 1.0) {
74
+ await ctx.reply('❌ Użycie: /set_risk <0.05-1.0>');
75
+ return;
76
+ }
77
+ (0, eventBus_1.emit)('telegram:set_risk', { chatId: ctx.chat.id, riskMultiplier: value });
78
+ await ctx.reply(`✅ Risk multiplier ustawiony na ${value}`);
79
+ });
80
+ // Handle text messages (future: natural language commands)
81
+ this.bot.on('message:text', async (ctx) => {
82
+ if (!this.isAllowed(ctx))
83
+ return;
84
+ // Echo for now; could integrate LLM here
85
+ await ctx.reply(`Otrzymałem: ${ctx.message.text}`);
86
+ });
87
+ }
88
+ setupEventListeners() {
89
+ // Listen for events from decision engine and send notifications
90
+ (0, eventBus_1.on)('order:placed', (order) => {
91
+ this.broadcast(`📈 *Order placed*\nMarket: \`${order.marketId}\`\nSide: ${order.side}\nStake: M$${order.stake.toFixed(2)}`);
92
+ });
93
+ (0, eventBus_1.on)('order:filled', (fill) => {
94
+ this.broadcast(`✅ *Order filled*\nMarket: \`${fill.marketId}\`\nPnL: M$${fill.pnl?.toFixed(2) || '?'}`);
95
+ });
96
+ (0, eventBus_1.on)('strategy:alert', (msg) => {
97
+ // Filter important alerts
98
+ if (msg.startsWith('failsafe:') || msg.startsWith('arb:')) {
99
+ this.broadcast(`⚠️ *Alert*: ${msg}`);
100
+ }
101
+ });
102
+ (0, eventBus_1.on)('arb:opportunity', (arb) => {
103
+ this.broadcast(`🔥 *Arbitrage opportunity*\n` +
104
+ `Markets: ${arb.markets.join(', ')}\n` +
105
+ `Expected profit: M$${arb.expectedProfit.toFixed(2)}`);
106
+ });
107
+ (0, eventBus_1.on)('safety:warning', (warn) => {
108
+ this.broadcast(`🚨 *Safety warning*\nMarket: \`${warn.marketId}\`\nReason: ${warn.reason}`);
109
+ });
110
+ }
111
+ async broadcast(message) {
112
+ for (const userId of this.cfg.allowedUserIds) {
113
+ try {
114
+ await this.bot.api.sendMessage(userId, message, { parse_mode: 'Markdown' });
115
+ }
116
+ catch (e) {
117
+ console.error(`Failed to send to ${userId}:`, e);
118
+ }
119
+ }
120
+ }
121
+ async sendTo(chatId, message) {
122
+ await this.bot.api.sendMessage(chatId, message, { parse_mode: 'Markdown' });
123
+ }
124
+ async start() {
125
+ console.log('🤖 Telegram bot starting...');
126
+ await this.bot.start();
127
+ }
128
+ stop() {
129
+ this.bot.stop();
130
+ }
131
+ }
132
+ exports.TelegramAdapter = TelegramAdapter;
133
+ exports.default = TelegramAdapter;