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 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": "2.0.6",
4
- "description": "MCP server that lets Claude message you on Telegram with hooks support",
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
+ });