feat: add auto-start, AFK mode, and comprehensive cross-platform setup
Major Features: - Auto-start: MCP server now automatically starts Telegram bridge on demand - AFK Mode: Toggle notifications on/off with /afk slash command - New telegram_toggle_afk MCP tool for controlling notification state - Dynamic enable/disable via new /toggle and /status API endpoints MCP Server Improvements: - Auto-detects if bridge is running and starts it automatically - Monitors bridge process health and logs output - Clean shutdown handling for both MCP server and bridge - Process spawning with proper environment variable passing Telegram Bridge Updates: - Runtime toggle for ENABLED state (was previously static) - POST /toggle endpoint to toggle notifications with Telegram confirmation - GET /status endpoint to check current notification state - Telegram messages sent when state changes (🟢/🔴 indicators) Documentation: - Cross-platform setup instructions (Mac, Linux, Windows) - Claude Code CLI setup guide with claude mcp add commands - Global vs project-specific MCP configuration explained - Troubleshooting section for fixing configuration scope issues - Complete AFK mode usage documentation - All new API endpoints documented Slash Commands: - Created /afk command in .claude/commands/afk.md - Available in both InnerVoice and ESO-MCP projects Files Changed: - src/mcp-server.ts: Auto-start logic and telegram_toggle_afk tool - src/index.ts: Dynamic ENABLED toggle and new API endpoints - README.md: Comprehensive setup and troubleshooting guide - mcp-config.json: Updated with correct absolute path - .claude/commands/afk.md: New slash command for AFK mode 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
5
.claude/commands/afk.md
Normal file
5
.claude/commands/afk.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
description: Toggle InnerVoice AFK mode - enable/disable Telegram notifications
|
||||||
|
---
|
||||||
|
|
||||||
|
Use the `telegram_toggle_afk` MCP tool to toggle InnerVoice notifications. This controls whether you receive Telegram messages while away from your system.
|
||||||
168
README.md
168
README.md
@@ -101,23 +101,63 @@ pnpm daemon
|
|||||||
|
|
||||||
### 5. Add MCP Server to Claude
|
### 5. Add MCP Server to Claude
|
||||||
|
|
||||||
#### Option A: Auto-Generate Config (Easiest)
|
> **✨ Auto-Start Feature:** The MCP server now automatically starts the Telegram bridge when needed - no need to run it separately!
|
||||||
|
|
||||||
|
#### Option A: Claude Code CLI (Recommended)
|
||||||
|
|
||||||
|
> **Note:** Using `claude mcp add` automatically adds the server **globally** (available in all projects). This is the recommended approach.
|
||||||
|
|
||||||
|
**For Mac and Linux:**
|
||||||
```bash
|
```bash
|
||||||
cd innervoice
|
# Navigate to the innervoice directory
|
||||||
./scripts/get-mcp-config.sh
|
cd /path/to/innervoice
|
||||||
|
|
||||||
|
# Add the MCP server globally (available in all projects)
|
||||||
|
claude mcp add --transport stdio telegram \
|
||||||
|
--env TELEGRAM_BRIDGE_URL=http://localhost:3456 \
|
||||||
|
-- node "$(pwd)/dist/mcp-server.js"
|
||||||
|
|
||||||
|
# Verify it was added globally
|
||||||
|
claude mcp list
|
||||||
```
|
```
|
||||||
|
|
||||||
Copy the output to your MCP config file.
|
**For Windows (PowerShell):**
|
||||||
|
```powershell
|
||||||
|
# Navigate to the innervoice directory
|
||||||
|
cd C:\path\to\innervoice
|
||||||
|
|
||||||
#### Option B: Manual Setup
|
# Add the MCP server globally
|
||||||
|
claude mcp add --transport stdio telegram `
|
||||||
|
--env TELEGRAM_BRIDGE_URL=http://localhost:3456 `
|
||||||
|
-- node "$((Get-Location).Path)\dist\mcp-server.js"
|
||||||
|
|
||||||
Add to your Claude Code MCP settings (`~/.config/claude-code/settings/mcp.json`):
|
# Verify it was added
|
||||||
|
claude mcp list
|
||||||
|
```
|
||||||
|
|
||||||
|
**For Windows (Command Prompt):**
|
||||||
|
```cmd
|
||||||
|
# Navigate to the innervoice directory
|
||||||
|
cd C:\path\to\innervoice
|
||||||
|
|
||||||
|
# Add the MCP server globally
|
||||||
|
claude mcp add --transport stdio telegram --env TELEGRAM_BRIDGE_URL=http://localhost:3456 -- node "%CD%\dist\mcp-server.js"
|
||||||
|
|
||||||
|
# Verify it was added
|
||||||
|
claude mcp list
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Option B: Manual Config File Setup
|
||||||
|
|
||||||
|
Add to your Claude Code MCP settings:
|
||||||
|
|
||||||
|
**Mac/Linux:** `~/.claude.json`
|
||||||
|
**Windows:** `%USERPROFILE%\.claude.json`
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"innervoice": {
|
"telegram": {
|
||||||
"command": "node",
|
"command": "node",
|
||||||
"args": [
|
"args": [
|
||||||
"/ABSOLUTE/PATH/TO/innervoice/dist/mcp-server.js"
|
"/ABSOLUTE/PATH/TO/innervoice/dist/mcp-server.js"
|
||||||
@@ -130,17 +170,27 @@ Add to your Claude Code MCP settings (`~/.config/claude-code/settings/mcp.json`)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Find your path:**
|
**Find your absolute path:**
|
||||||
|
|
||||||
|
**Mac/Linux:**
|
||||||
```bash
|
```bash
|
||||||
cd innervoice && pwd
|
cd innervoice && pwd
|
||||||
# Use output: <result>/dist/mcp-server.js
|
# Use output: <result>/dist/mcp-server.js
|
||||||
```
|
```
|
||||||
|
|
||||||
#### MCP Config Locations
|
**Windows (PowerShell):**
|
||||||
|
```powershell
|
||||||
|
cd innervoice
|
||||||
|
(Get-Location).Path
|
||||||
|
# Use output: <result>\dist\mcp-server.js
|
||||||
|
```
|
||||||
|
|
||||||
- **Global (all projects):** `~/.config/claude-code/settings/mcp.json`
|
**Windows (Command Prompt):**
|
||||||
- **Per-project:** `your-project/.claude/mcp.json`
|
```cmd
|
||||||
- **VS Code:** `your-project/.vscode/mcp.json`
|
cd innervoice
|
||||||
|
cd
|
||||||
|
# Use output: <result>\dist\mcp-server.js
|
||||||
|
```
|
||||||
|
|
||||||
### 6. Available Tools
|
### 6. Available Tools
|
||||||
|
|
||||||
@@ -150,6 +200,7 @@ Once configured, Claude can automatically use:
|
|||||||
- `telegram_get_messages` - Check for messages from you
|
- `telegram_get_messages` - Check for messages from you
|
||||||
- `telegram_reply` - Reply to your messages
|
- `telegram_reply` - Reply to your messages
|
||||||
- `telegram_check_health` - Check bridge status
|
- `telegram_check_health` - Check bridge status
|
||||||
|
- `telegram_toggle_afk` - Toggle AFK mode (enable/disable notifications)
|
||||||
|
|
||||||
**View detailed tool info:**
|
**View detailed tool info:**
|
||||||
```bash
|
```bash
|
||||||
@@ -158,7 +209,60 @@ pnpm tools
|
|||||||
node scripts/list-tools.js
|
node scripts/list-tools.js
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7. Test It
|
### 7. AFK Mode - Control Your Notifications
|
||||||
|
|
||||||
|
Use the `/afk` slash command to toggle notifications on/off:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# In Claude Code, just type:
|
||||||
|
/afk
|
||||||
|
```
|
||||||
|
|
||||||
|
This is perfect for:
|
||||||
|
- **Enabling** when you step away from your computer (get notified via Telegram)
|
||||||
|
- **Disabling** when you're actively working (no interruptions)
|
||||||
|
|
||||||
|
The toggle state is preserved while the bridge is running, and you'll get a Telegram message confirming each change.
|
||||||
|
|
||||||
|
### 8. Verify Global Setup
|
||||||
|
|
||||||
|
After adding the MCP server, verify it's available globally:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check that telegram appears in the list
|
||||||
|
claude mcp list
|
||||||
|
|
||||||
|
# Should show:
|
||||||
|
# ✓ telegram: Connected
|
||||||
|
```
|
||||||
|
|
||||||
|
**Troubleshooting:** If `telegram` only appears in one project but not others, it was added to a project-specific config instead of globally. To fix:
|
||||||
|
|
||||||
|
1. Open `~/.claude.json` in your editor
|
||||||
|
2. Find the `telegram` server config under `projects` → `your-project-path` → `mcpServers`
|
||||||
|
3. **Move it** to the root-level `mcpServers` section (same level as other global servers)
|
||||||
|
4. Remove the `telegram` entry from the project-specific section
|
||||||
|
|
||||||
|
**Example structure:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"telegram": {
|
||||||
|
"type": "stdio",
|
||||||
|
"command": "node",
|
||||||
|
"args": ["/path/to/innervoice/dist/mcp-server.js"],
|
||||||
|
"env": {"TELEGRAM_BRIDGE_URL": "http://localhost:3456"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"projects": {
|
||||||
|
"/your/project/path": {
|
||||||
|
"mcpServers": {} // Should be empty or not contain telegram
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9. Test It
|
||||||
|
|
||||||
Restart Claude Code, then tell Claude:
|
Restart Claude Code, then tell Claude:
|
||||||
|
|
||||||
@@ -217,6 +321,20 @@ Check if the Telegram bridge is running and healthy.
|
|||||||
> "Let me verify the Telegram bridge is working."
|
> "Let me verify the Telegram bridge is working."
|
||||||
> *Claude uses: `telegram_check_health({})`*
|
> *Claude uses: `telegram_check_health({})`*
|
||||||
|
|
||||||
|
### `telegram_toggle_afk`
|
||||||
|
Toggle AFK (Away From Keyboard) mode - enables or disables Telegram notifications.
|
||||||
|
|
||||||
|
**No parameters required**
|
||||||
|
|
||||||
|
**Example Claude Usage:**
|
||||||
|
> "Toggle AFK mode"
|
||||||
|
> *Claude uses: `telegram_toggle_afk({})`*
|
||||||
|
|
||||||
|
**When to use:**
|
||||||
|
- Enable when stepping away from your computer (get notifications)
|
||||||
|
- Disable when actively working (avoid interruptions)
|
||||||
|
- State is preserved while the bridge is running
|
||||||
|
|
||||||
## Git Setup (For Sharing)
|
## Git Setup (For Sharing)
|
||||||
|
|
||||||
If you want to push this to your own Git repository:
|
If you want to push this to your own Git repository:
|
||||||
@@ -443,6 +561,30 @@ Check service health
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### POST /toggle
|
||||||
|
Toggle notifications on/off (AFK mode)
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"enabled": true,
|
||||||
|
"previousState": false,
|
||||||
|
"message": "🟢 InnerVoice notifications ENABLED - You will receive messages"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### GET /status
|
||||||
|
Get current notification state
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"enabled": true,
|
||||||
|
"message": "Notifications are ON"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Integration with ESO-MCP
|
## Integration with ESO-MCP
|
||||||
|
|
||||||
Add this helper to your ESO-MCP project:
|
Add this helper to your ESO-MCP project:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"telegram": {
|
"telegram": {
|
||||||
"command": "node",
|
"command": "node",
|
||||||
"args": [
|
"args": [
|
||||||
"/ABSOLUTE/PATH/TO/claude-telegram-bridge/dist/mcp-server.js"
|
"/Volumes/PRO-G40/Docker/innervoice/dist/mcp-server.js"
|
||||||
],
|
],
|
||||||
"env": {
|
"env": {
|
||||||
"TELEGRAM_BRIDGE_URL": "http://localhost:3456"
|
"TELEGRAM_BRIDGE_URL": "http://localhost:3456"
|
||||||
|
|||||||
36
src/index.ts
36
src/index.ts
@@ -10,7 +10,7 @@ const bot = new Telegraf(process.env.TELEGRAM_BOT_TOKEN!);
|
|||||||
const app = express();
|
const app = express();
|
||||||
const PORT = parseInt(process.env.PORT || '3456');
|
const PORT = parseInt(process.env.PORT || '3456');
|
||||||
const HOST = process.env.HOST || 'localhost';
|
const HOST = process.env.HOST || 'localhost';
|
||||||
const ENABLED = process.env.ENABLED !== 'false';
|
let ENABLED = process.env.ENABLED !== 'false'; // Now mutable for runtime toggling
|
||||||
|
|
||||||
let chatId: string | null = process.env.TELEGRAM_CHAT_ID || null;
|
let chatId: string | null = process.env.TELEGRAM_CHAT_ID || null;
|
||||||
const envPath = path.join(process.cwd(), '.env');
|
const envPath = path.join(process.cwd(), '.env');
|
||||||
@@ -256,6 +256,40 @@ app.get('/health', (req, res) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Toggle enabled state
|
||||||
|
app.post('/toggle', async (req, res) => {
|
||||||
|
const previousState = ENABLED;
|
||||||
|
ENABLED = !ENABLED;
|
||||||
|
|
||||||
|
const statusMessage = ENABLED
|
||||||
|
? '🟢 InnerVoice notifications ENABLED - You will receive messages'
|
||||||
|
: '🔴 InnerVoice notifications DISABLED - Messages paused';
|
||||||
|
|
||||||
|
// Notify via Telegram if chat ID is set
|
||||||
|
if (chatId) {
|
||||||
|
try {
|
||||||
|
await bot.telegram.sendMessage(chatId, statusMessage, { parse_mode: 'Markdown' });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to send toggle notification:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
enabled: ENABLED,
|
||||||
|
previousState,
|
||||||
|
message: statusMessage
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get current enabled state
|
||||||
|
app.get('/status', (req, res) => {
|
||||||
|
res.json({
|
||||||
|
enabled: ENABLED,
|
||||||
|
message: ENABLED ? 'Notifications are ON' : 'Notifications are OFF (AFK mode)'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Start bot
|
// Start bot
|
||||||
bot.launch().then(() => {
|
bot.launch().then(() => {
|
||||||
console.log('🤖 Telegram bot started');
|
console.log('🤖 Telegram bot started');
|
||||||
|
|||||||
@@ -7,8 +7,93 @@ import {
|
|||||||
ListToolsRequestSchema,
|
ListToolsRequestSchema,
|
||||||
Tool,
|
Tool,
|
||||||
} from '@modelcontextprotocol/sdk/types.js';
|
} from '@modelcontextprotocol/sdk/types.js';
|
||||||
|
import { spawn, ChildProcess } from 'child_process';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import { dirname, join } from 'path';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
const BRIDGE_URL = process.env.TELEGRAM_BRIDGE_URL || 'http://localhost:3456';
|
const BRIDGE_URL = process.env.TELEGRAM_BRIDGE_URL || 'http://localhost:3456';
|
||||||
|
const BRIDGE_PORT = new URL(BRIDGE_URL).port || '3456';
|
||||||
|
const BRIDGE_HOST = new URL(BRIDGE_URL).hostname || 'localhost';
|
||||||
|
|
||||||
|
let bridgeProcess: ChildProcess | null = null;
|
||||||
|
|
||||||
|
// Check if the bridge is running
|
||||||
|
async function isBridgeRunning(): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${BRIDGE_URL}/health`, {
|
||||||
|
signal: AbortSignal.timeout(2000),
|
||||||
|
});
|
||||||
|
return response.ok;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the Telegram bridge
|
||||||
|
async function startBridge(): Promise<void> {
|
||||||
|
console.error('🚀 Starting Telegram bridge...');
|
||||||
|
|
||||||
|
// Find the project root (one level up from dist or src)
|
||||||
|
const projectRoot = join(__dirname, '..');
|
||||||
|
const bridgeScript = join(projectRoot, 'dist', 'index.js');
|
||||||
|
|
||||||
|
// Start the bridge process
|
||||||
|
bridgeProcess = spawn('node', [bridgeScript], {
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
PORT: BRIDGE_PORT,
|
||||||
|
HOST: BRIDGE_HOST,
|
||||||
|
},
|
||||||
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||||||
|
detached: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Log bridge output
|
||||||
|
if (bridgeProcess.stdout) {
|
||||||
|
bridgeProcess.stdout.on('data', (data) => {
|
||||||
|
console.error(`[Bridge] ${data.toString().trim()}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bridgeProcess.stderr) {
|
||||||
|
bridgeProcess.stderr.on('data', (data) => {
|
||||||
|
console.error(`[Bridge] ${data.toString().trim()}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bridgeProcess.on('error', (error) => {
|
||||||
|
console.error('❌ Bridge process error:', error);
|
||||||
|
});
|
||||||
|
|
||||||
|
bridgeProcess.on('exit', (code) => {
|
||||||
|
console.error(`⚠️ Bridge process exited with code ${code}`);
|
||||||
|
bridgeProcess = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for the bridge to be ready
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
|
if (await isBridgeRunning()) {
|
||||||
|
console.error('✅ Telegram bridge is ready');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Bridge failed to start after 5 seconds');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the bridge is running
|
||||||
|
async function ensureBridge(): Promise<void> {
|
||||||
|
if (await isBridgeRunning()) {
|
||||||
|
console.error('✅ Telegram bridge is already running');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await startBridge();
|
||||||
|
}
|
||||||
|
|
||||||
// Define the Telegram bridge tools
|
// Define the Telegram bridge tools
|
||||||
const TOOLS: Tool[] = [
|
const TOOLS: Tool[] = [
|
||||||
@@ -81,6 +166,14 @@ const TOOLS: Tool[] = [
|
|||||||
properties: {},
|
properties: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'telegram_toggle_afk',
|
||||||
|
description: 'Toggle InnerVoice AFK mode - enables or disables Telegram notifications. Use this when going away from the system to enable notifications, or when back to disable them.',
|
||||||
|
inputSchema: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// Create the MCP server
|
// Create the MCP server
|
||||||
@@ -235,6 +328,30 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'telegram_toggle_afk': {
|
||||||
|
const response = await fetch(`${BRIDGE_URL}/toggle`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to toggle AFK mode');
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: any = await response.json();
|
||||||
|
const icon = result.enabled ? '🟢' : '🔴';
|
||||||
|
const status = result.enabled ? 'ENABLED' : 'DISABLED';
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: `${icon} InnerVoice AFK mode toggled: ${status}\n\n${result.message}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unknown tool: ${name}`);
|
throw new Error(`Unknown tool: ${name}`);
|
||||||
}
|
}
|
||||||
@@ -252,8 +369,32 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Cleanup function
|
||||||
|
function cleanup() {
|
||||||
|
console.error('\n👋 Shutting down MCP server...');
|
||||||
|
if (bridgeProcess) {
|
||||||
|
console.error('🛑 Stopping bridge process...');
|
||||||
|
bridgeProcess.kill('SIGTERM');
|
||||||
|
bridgeProcess = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle shutdown signals
|
||||||
|
process.on('SIGINT', () => {
|
||||||
|
cleanup();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('SIGTERM', () => {
|
||||||
|
cleanup();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
// Start the server
|
// Start the server
|
||||||
async function main() {
|
async function main() {
|
||||||
|
// Ensure the bridge is running before starting the MCP server
|
||||||
|
await ensureBridge();
|
||||||
|
|
||||||
const transport = new StdioServerTransport();
|
const transport = new StdioServerTransport();
|
||||||
await server.connect(transport);
|
await server.connect(transport);
|
||||||
console.error('🚀 Telegram MCP server running on stdio');
|
console.error('🚀 Telegram MCP server running on stdio');
|
||||||
@@ -261,5 +402,6 @@ async function main() {
|
|||||||
|
|
||||||
main().catch((error) => {
|
main().catch((error) => {
|
||||||
console.error('Fatal error:', error);
|
console.error('Fatal error:', error);
|
||||||
|
cleanup();
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user