telegram-claude-mcp 2.0.6 → 3.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/bin/bridge.js +28 -0
- package/bin/claude-tg +100 -0
- package/bin/pclaude-tg +108 -0
- package/bin/telegram-claude-bridge +13 -0
- package/package.json +10 -4
- package/src/bridge/index.ts +197 -0
- package/src/bridge/output-parser.ts +238 -0
- package/src/bridge/session-manager.ts +323 -0
- package/src/bridge/telegram-handler.ts +368 -0
- package/src/bridge/tmux-client.ts +138 -0
- package/src/telegram.ts +13 -0
package/bin/bridge.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Telegram Claude Bridge - Launcher
|
|
5
|
+
* Runs the bridge daemon with tsx for TypeScript support
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { spawn } from 'child_process';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import { dirname, join } from 'path';
|
|
11
|
+
|
|
12
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const bridgePath = join(__dirname, '..', 'src', 'bridge', 'index.ts');
|
|
14
|
+
|
|
15
|
+
// Run with tsx
|
|
16
|
+
const child = spawn('node', ['--import', 'tsx', bridgePath], {
|
|
17
|
+
stdio: 'inherit',
|
|
18
|
+
env: process.env,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
child.on('error', (err) => {
|
|
22
|
+
console.error('Failed to start bridge:', err.message);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
child.on('exit', (code) => {
|
|
27
|
+
process.exit(code || 0);
|
|
28
|
+
});
|
package/bin/claude-tg
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# claude-tg - Launch Claude CLI with Telegram bridge (Corporate profile)
|
|
4
|
+
#
|
|
5
|
+
# Usage: claude-tg [claude args...]
|
|
6
|
+
#
|
|
7
|
+
# This script:
|
|
8
|
+
# 1. Starts Claude in a tmux session
|
|
9
|
+
# 2. Registers with the Telegram bridge daemon
|
|
10
|
+
# 3. Attaches to the tmux session
|
|
11
|
+
# 4. Unregisters on exit
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
set -e
|
|
15
|
+
|
|
16
|
+
# Configuration
|
|
17
|
+
PROFILE="corporate"
|
|
18
|
+
CONFIG_DIR="$HOME/.claude"
|
|
19
|
+
BRIDGE_PORT="${BRIDGE_PORT:-3334}"
|
|
20
|
+
BRIDGE_URL="http://localhost:$BRIDGE_PORT"
|
|
21
|
+
|
|
22
|
+
# Project name from current directory
|
|
23
|
+
PROJECT_NAME="${PWD##*/}"
|
|
24
|
+
SESSION_NAME="${PROFILE}:${PROJECT_NAME}"
|
|
25
|
+
TMUX_SESSION="claude-${PROJECT_NAME}"
|
|
26
|
+
|
|
27
|
+
# Colors
|
|
28
|
+
RED='\033[0;31m'
|
|
29
|
+
GREEN='\033[0;32m'
|
|
30
|
+
YELLOW='\033[1;33m'
|
|
31
|
+
NC='\033[0m' # No Color
|
|
32
|
+
|
|
33
|
+
# Check if bridge is running
|
|
34
|
+
check_bridge() {
|
|
35
|
+
if ! curl -s "$BRIDGE_URL/health" > /dev/null 2>&1; then
|
|
36
|
+
echo -e "${YELLOW}Warning: Bridge daemon not running${NC}"
|
|
37
|
+
echo "Start it with: telegram-claude-bridge"
|
|
38
|
+
echo ""
|
|
39
|
+
echo "Starting Claude without Telegram integration..."
|
|
40
|
+
echo ""
|
|
41
|
+
return 1
|
|
42
|
+
fi
|
|
43
|
+
return 0
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# Register session with bridge
|
|
47
|
+
register_session() {
|
|
48
|
+
curl -s -X POST "$BRIDGE_URL/register" \
|
|
49
|
+
-H "Content-Type: application/json" \
|
|
50
|
+
-d "{
|
|
51
|
+
\"profile\": \"$PROFILE\",
|
|
52
|
+
\"projectName\": \"$PROJECT_NAME\",
|
|
53
|
+
\"tmuxSession\": \"$TMUX_SESSION\",
|
|
54
|
+
\"cwd\": \"$PWD\"
|
|
55
|
+
}" > /dev/null 2>&1 || true
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# Unregister session from bridge
|
|
59
|
+
unregister_session() {
|
|
60
|
+
curl -s -X POST "$BRIDGE_URL/unregister" \
|
|
61
|
+
-H "Content-Type: application/json" \
|
|
62
|
+
-d "{\"sessionName\": \"$SESSION_NAME\"}" > /dev/null 2>&1 || true
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# Cleanup on exit
|
|
66
|
+
cleanup() {
|
|
67
|
+
unregister_session
|
|
68
|
+
echo -e "\n${GREEN}Session ended: $SESSION_NAME${NC}"
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# Main
|
|
72
|
+
main() {
|
|
73
|
+
echo -e "${GREEN}Claude TG${NC} - Corporate Profile"
|
|
74
|
+
echo "Project: $PROJECT_NAME"
|
|
75
|
+
echo ""
|
|
76
|
+
|
|
77
|
+
# Check if tmux session already exists
|
|
78
|
+
if tmux has-session -t "$TMUX_SESSION" 2>/dev/null; then
|
|
79
|
+
echo "Attaching to existing session: $TMUX_SESSION"
|
|
80
|
+
else
|
|
81
|
+
echo "Creating new session: $TMUX_SESSION"
|
|
82
|
+
# Start Claude in a new tmux session
|
|
83
|
+
tmux new-session -d -s "$TMUX_SESSION" -c "$PWD" \
|
|
84
|
+
"CLAUDE_CONFIG_DIR=$CONFIG_DIR claude $*; echo 'Press Enter to close...'; read"
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# Register with bridge if running
|
|
88
|
+
if check_bridge; then
|
|
89
|
+
register_session
|
|
90
|
+
trap cleanup EXIT
|
|
91
|
+
echo -e "${GREEN}Connected to Telegram bridge${NC}"
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
echo ""
|
|
95
|
+
|
|
96
|
+
# Attach to the session
|
|
97
|
+
tmux attach -t "$TMUX_SESSION"
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
main "$@"
|
package/bin/pclaude-tg
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# pclaude-tg - Launch Claude CLI with Telegram bridge (Personal profile)
|
|
4
|
+
#
|
|
5
|
+
# Usage: pclaude-tg [claude args...]
|
|
6
|
+
#
|
|
7
|
+
# This script:
|
|
8
|
+
# 1. Starts Claude in a tmux session with personal config
|
|
9
|
+
# 2. Registers with the Telegram bridge daemon
|
|
10
|
+
# 3. Attaches to the tmux session
|
|
11
|
+
# 4. Unregisters on exit
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
set -e
|
|
15
|
+
|
|
16
|
+
# Configuration
|
|
17
|
+
PROFILE="personal"
|
|
18
|
+
CONFIG_DIR="$HOME/.claude-personal"
|
|
19
|
+
BRIDGE_PORT="${BRIDGE_PORT:-3334}"
|
|
20
|
+
BRIDGE_URL="http://localhost:$BRIDGE_PORT"
|
|
21
|
+
|
|
22
|
+
# Project name from current directory
|
|
23
|
+
PROJECT_NAME="${PWD##*/}"
|
|
24
|
+
SESSION_NAME="${PROFILE}:${PROJECT_NAME}"
|
|
25
|
+
TMUX_SESSION="pclaude-${PROJECT_NAME}"
|
|
26
|
+
|
|
27
|
+
# Colors
|
|
28
|
+
RED='\033[0;31m'
|
|
29
|
+
GREEN='\033[0;32m'
|
|
30
|
+
YELLOW='\033[1;33m'
|
|
31
|
+
BLUE='\033[0;34m'
|
|
32
|
+
NC='\033[0m' # No Color
|
|
33
|
+
|
|
34
|
+
# Check if bridge is running
|
|
35
|
+
check_bridge() {
|
|
36
|
+
if ! curl -s "$BRIDGE_URL/health" > /dev/null 2>&1; then
|
|
37
|
+
echo -e "${YELLOW}Warning: Bridge daemon not running${NC}"
|
|
38
|
+
echo "Start it with: telegram-claude-bridge"
|
|
39
|
+
echo ""
|
|
40
|
+
echo "Starting Claude without Telegram integration..."
|
|
41
|
+
echo ""
|
|
42
|
+
return 1
|
|
43
|
+
fi
|
|
44
|
+
return 0
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Register session with bridge
|
|
48
|
+
register_session() {
|
|
49
|
+
curl -s -X POST "$BRIDGE_URL/register" \
|
|
50
|
+
-H "Content-Type: application/json" \
|
|
51
|
+
-d "{
|
|
52
|
+
\"profile\": \"$PROFILE\",
|
|
53
|
+
\"projectName\": \"$PROJECT_NAME\",
|
|
54
|
+
\"tmuxSession\": \"$TMUX_SESSION\",
|
|
55
|
+
\"cwd\": \"$PWD\"
|
|
56
|
+
}" > /dev/null 2>&1 || true
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# Unregister session from bridge
|
|
60
|
+
unregister_session() {
|
|
61
|
+
curl -s -X POST "$BRIDGE_URL/unregister" \
|
|
62
|
+
-H "Content-Type: application/json" \
|
|
63
|
+
-d "{\"sessionName\": \"$SESSION_NAME\"}" > /dev/null 2>&1 || true
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# Cleanup on exit
|
|
67
|
+
cleanup() {
|
|
68
|
+
unregister_session
|
|
69
|
+
echo -e "\n${GREEN}Session ended: $SESSION_NAME${NC}"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# Main
|
|
73
|
+
main() {
|
|
74
|
+
echo -e "${BLUE}Claude TG${NC} - Personal Profile"
|
|
75
|
+
echo "Project: $PROJECT_NAME"
|
|
76
|
+
echo ""
|
|
77
|
+
|
|
78
|
+
# Check if personal config exists
|
|
79
|
+
if [ ! -d "$CONFIG_DIR" ]; then
|
|
80
|
+
echo -e "${YELLOW}Warning: $CONFIG_DIR does not exist${NC}"
|
|
81
|
+
echo "Using default Claude config instead"
|
|
82
|
+
CONFIG_DIR="$HOME/.claude"
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# Check if tmux session already exists
|
|
86
|
+
if tmux has-session -t "$TMUX_SESSION" 2>/dev/null; then
|
|
87
|
+
echo "Attaching to existing session: $TMUX_SESSION"
|
|
88
|
+
else
|
|
89
|
+
echo "Creating new session: $TMUX_SESSION"
|
|
90
|
+
# Start Claude in a new tmux session
|
|
91
|
+
tmux new-session -d -s "$TMUX_SESSION" -c "$PWD" \
|
|
92
|
+
"CLAUDE_CONFIG_DIR=$CONFIG_DIR claude $*; echo 'Press Enter to close...'; read"
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# Register with bridge if running
|
|
96
|
+
if check_bridge; then
|
|
97
|
+
register_session
|
|
98
|
+
trap cleanup EXIT
|
|
99
|
+
echo -e "${GREEN}Connected to Telegram bridge${NC}"
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
echo ""
|
|
103
|
+
|
|
104
|
+
# Attach to the session
|
|
105
|
+
tmux attach -t "$TMUX_SESSION"
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
main "$@"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Telegram Claude Bridge - Launcher
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
import { dirname, join } from 'path';
|
|
9
|
+
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
|
|
12
|
+
// Import and run the bridge
|
|
13
|
+
import(join(__dirname, '..', 'src', 'bridge', 'index.ts'));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "telegram-claude-mcp",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Telegram bridge for Claude CLI - bidirectional communication via tmux",
|
|
5
5
|
"author": "Geravant",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
"messaging",
|
|
18
18
|
"hooks",
|
|
19
19
|
"permissions",
|
|
20
|
-
"daemon"
|
|
20
|
+
"daemon",
|
|
21
|
+
"tmux",
|
|
22
|
+
"bridge"
|
|
21
23
|
],
|
|
22
24
|
"type": "module",
|
|
23
25
|
"main": "src/index.ts",
|
|
@@ -26,7 +28,10 @@
|
|
|
26
28
|
"telegram-claude-setup": "./bin/setup.js",
|
|
27
29
|
"telegram-claude-daemon": "./bin/daemon.js",
|
|
28
30
|
"telegram-claude-proxy": "./bin/proxy.js",
|
|
29
|
-
"telegram-claude-ctl": "./bin/daemon-ctl.js"
|
|
31
|
+
"telegram-claude-ctl": "./bin/daemon-ctl.js",
|
|
32
|
+
"telegram-claude-bridge": "./bin/bridge.js",
|
|
33
|
+
"claude-tg": "./bin/claude-tg",
|
|
34
|
+
"pclaude-tg": "./bin/pclaude-tg"
|
|
30
35
|
},
|
|
31
36
|
"files": [
|
|
32
37
|
"src",
|
|
@@ -41,6 +46,7 @@
|
|
|
41
46
|
"dev": "node --watch --import tsx src/index.ts",
|
|
42
47
|
"daemon": "node --import tsx src/daemon/index.ts",
|
|
43
48
|
"proxy": "node --import tsx src/proxy/index.ts",
|
|
49
|
+
"bridge": "node --import tsx src/bridge/index.ts",
|
|
44
50
|
"daemon:start": "node bin/daemon-ctl.js start",
|
|
45
51
|
"daemon:stop": "node bin/daemon-ctl.js stop",
|
|
46
52
|
"daemon:status": "node bin/daemon-ctl.js status"
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Telegram Bridge - Main Daemon
|
|
3
|
+
*
|
|
4
|
+
* Connects Claude CLI (via tmux) to Telegram for bidirectional communication.
|
|
5
|
+
* Supports multiple simultaneous sessions (corporate and personal).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as http from 'http';
|
|
9
|
+
import { SessionManager, SessionProfile } from './session-manager.js';
|
|
10
|
+
import { TelegramHandler } from './telegram-handler.js';
|
|
11
|
+
|
|
12
|
+
const VERSION = '1.0.0';
|
|
13
|
+
const HTTP_PORT = parseInt(process.env.BRIDGE_PORT || '3334', 10);
|
|
14
|
+
|
|
15
|
+
// Telegram configuration
|
|
16
|
+
const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN;
|
|
17
|
+
const TELEGRAM_CHAT_ID = process.env.TELEGRAM_CHAT_ID;
|
|
18
|
+
|
|
19
|
+
if (!TELEGRAM_BOT_TOKEN || !TELEGRAM_CHAT_ID) {
|
|
20
|
+
console.error('Error: TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID are required');
|
|
21
|
+
console.error('');
|
|
22
|
+
console.error('Set environment variables:');
|
|
23
|
+
console.error(' export TELEGRAM_BOT_TOKEN="your-bot-token"');
|
|
24
|
+
console.error(' export TELEGRAM_CHAT_ID="your-chat-id"');
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Initialize components
|
|
29
|
+
const sessionManager = new SessionManager();
|
|
30
|
+
const telegramHandler = new TelegramHandler(
|
|
31
|
+
{ botToken: TELEGRAM_BOT_TOKEN, chatId: TELEGRAM_CHAT_ID },
|
|
32
|
+
sessionManager
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* HTTP server for session registration
|
|
37
|
+
* Launcher scripts (claude-tg, pclaude-tg) call these endpoints
|
|
38
|
+
*/
|
|
39
|
+
const httpServer = http.createServer(async (req, res) => {
|
|
40
|
+
// CORS headers
|
|
41
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
42
|
+
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
|
|
43
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
44
|
+
|
|
45
|
+
if (req.method === 'OPTIONS') {
|
|
46
|
+
res.writeHead(200);
|
|
47
|
+
res.end();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const url = req.url || '/';
|
|
52
|
+
|
|
53
|
+
// GET endpoints
|
|
54
|
+
if (req.method === 'GET') {
|
|
55
|
+
if (url === '/status') {
|
|
56
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
57
|
+
res.end(JSON.stringify({
|
|
58
|
+
version: VERSION,
|
|
59
|
+
sessions: sessionManager.getAll().map(s => ({
|
|
60
|
+
name: s.name,
|
|
61
|
+
profile: s.profile,
|
|
62
|
+
projectName: s.projectName,
|
|
63
|
+
tmuxSession: s.tmuxSession,
|
|
64
|
+
isWaitingForInput: s.isWaitingForInput,
|
|
65
|
+
lastActivity: s.lastActivity,
|
|
66
|
+
})),
|
|
67
|
+
}));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (url === '/health') {
|
|
72
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
73
|
+
res.end(JSON.stringify({ ok: true, version: VERSION }));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
res.writeHead(404);
|
|
78
|
+
res.end('Not found');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// POST endpoints
|
|
83
|
+
if (req.method === 'POST') {
|
|
84
|
+
let body = '';
|
|
85
|
+
for await (const chunk of req) {
|
|
86
|
+
body += chunk;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
const data = JSON.parse(body);
|
|
91
|
+
|
|
92
|
+
if (url === '/register') {
|
|
93
|
+
const { profile, projectName, tmuxSession, cwd } = data;
|
|
94
|
+
|
|
95
|
+
if (!profile || !projectName || !tmuxSession) {
|
|
96
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
97
|
+
res.end(JSON.stringify({ error: 'Missing required fields: profile, projectName, tmuxSession' }));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const session = await sessionManager.register(
|
|
102
|
+
profile as SessionProfile,
|
|
103
|
+
projectName,
|
|
104
|
+
tmuxSession,
|
|
105
|
+
cwd || process.cwd()
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
109
|
+
res.end(JSON.stringify({ ok: true, session: session.name }));
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (url === '/unregister') {
|
|
114
|
+
const { sessionName } = data;
|
|
115
|
+
|
|
116
|
+
if (!sessionName) {
|
|
117
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
118
|
+
res.end(JSON.stringify({ error: 'Missing sessionName' }));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
await sessionManager.unregister(sessionName);
|
|
123
|
+
|
|
124
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
125
|
+
res.end(JSON.stringify({ ok: true }));
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (url === '/send') {
|
|
130
|
+
const { sessionName, input } = data;
|
|
131
|
+
|
|
132
|
+
if (!sessionName || !input) {
|
|
133
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
134
|
+
res.end(JSON.stringify({ error: 'Missing sessionName or input' }));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const success = await sessionManager.sendInput(sessionName, input);
|
|
139
|
+
|
|
140
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
141
|
+
res.end(JSON.stringify({ ok: success }));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
146
|
+
res.end(JSON.stringify({ error: 'Not found' }));
|
|
147
|
+
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error('[Bridge] HTTP error:', error);
|
|
150
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
151
|
+
res.end(JSON.stringify({ error: 'Internal server error' }));
|
|
152
|
+
}
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
res.writeHead(405);
|
|
157
|
+
res.end('Method not allowed');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Start server
|
|
161
|
+
httpServer.listen(HTTP_PORT, () => {
|
|
162
|
+
console.log(`
|
|
163
|
+
╔═══════════════════════════════════════════════════════════╗
|
|
164
|
+
║ Claude Telegram Bridge v${VERSION} ║
|
|
165
|
+
╠═══════════════════════════════════════════════════════════╣
|
|
166
|
+
║ ║
|
|
167
|
+
║ HTTP API: http://localhost:${HTTP_PORT} ║
|
|
168
|
+
║ Telegram: Connected ║
|
|
169
|
+
║ ║
|
|
170
|
+
║ Start sessions with: ║
|
|
171
|
+
║ claude-tg → Corporate (~/.claude) ║
|
|
172
|
+
║ pclaude-tg → Personal (~/.claude-personal) ║
|
|
173
|
+
║ ║
|
|
174
|
+
╚═══════════════════════════════════════════════════════════╝
|
|
175
|
+
`);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Graceful shutdown
|
|
179
|
+
async function shutdown() {
|
|
180
|
+
console.log('\n[Bridge] Shutting down...');
|
|
181
|
+
await sessionManager.cleanup();
|
|
182
|
+
await telegramHandler.stop();
|
|
183
|
+
httpServer.close();
|
|
184
|
+
process.exit(0);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
process.on('SIGINT', shutdown);
|
|
188
|
+
process.on('SIGTERM', shutdown);
|
|
189
|
+
|
|
190
|
+
// Handle uncaught errors
|
|
191
|
+
process.on('uncaughtException', (error) => {
|
|
192
|
+
console.error('[Bridge] Uncaught exception:', error);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
process.on('unhandledRejection', (reason) => {
|
|
196
|
+
console.error('[Bridge] Unhandled rejection:', reason);
|
|
197
|
+
});
|