telegram-claude-mcp 2.0.7 → 3.0.1

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,118 @@
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
+ # Check for required dependencies
17
+ if ! command -v tmux &> /dev/null; then
18
+ echo "Error: tmux is required but not installed."
19
+ echo ""
20
+ echo "Install it with:"
21
+ echo " macOS: brew install tmux"
22
+ echo " Ubuntu/Debian: sudo apt install tmux"
23
+ echo " Fedora: sudo dnf install tmux"
24
+ exit 1
25
+ fi
26
+
27
+ if ! command -v claude &> /dev/null; then
28
+ echo "Error: claude CLI is required but not installed."
29
+ echo ""
30
+ echo "Install Claude Code from: https://claude.ai/code"
31
+ exit 1
32
+ fi
33
+
34
+ # Configuration
35
+ PROFILE="corporate"
36
+ CONFIG_DIR="$HOME/.claude"
37
+ BRIDGE_PORT="${BRIDGE_PORT:-3334}"
38
+ BRIDGE_URL="http://localhost:$BRIDGE_PORT"
39
+
40
+ # Project name from current directory
41
+ PROJECT_NAME="${PWD##*/}"
42
+ SESSION_NAME="${PROFILE}:${PROJECT_NAME}"
43
+ TMUX_SESSION="claude-${PROJECT_NAME}"
44
+
45
+ # Colors
46
+ RED='\033[0;31m'
47
+ GREEN='\033[0;32m'
48
+ YELLOW='\033[1;33m'
49
+ NC='\033[0m' # No Color
50
+
51
+ # Check if bridge is running
52
+ check_bridge() {
53
+ if ! curl -s "$BRIDGE_URL/health" > /dev/null 2>&1; then
54
+ echo -e "${YELLOW}Warning: Bridge daemon not running${NC}"
55
+ echo "Start it with: telegram-claude-bridge"
56
+ echo ""
57
+ echo "Starting Claude without Telegram integration..."
58
+ echo ""
59
+ return 1
60
+ fi
61
+ return 0
62
+ }
63
+
64
+ # Register session with bridge
65
+ register_session() {
66
+ curl -s -X POST "$BRIDGE_URL/register" \
67
+ -H "Content-Type: application/json" \
68
+ -d "{
69
+ \"profile\": \"$PROFILE\",
70
+ \"projectName\": \"$PROJECT_NAME\",
71
+ \"tmuxSession\": \"$TMUX_SESSION\",
72
+ \"cwd\": \"$PWD\"
73
+ }" > /dev/null 2>&1 || true
74
+ }
75
+
76
+ # Unregister session from bridge
77
+ unregister_session() {
78
+ curl -s -X POST "$BRIDGE_URL/unregister" \
79
+ -H "Content-Type: application/json" \
80
+ -d "{\"sessionName\": \"$SESSION_NAME\"}" > /dev/null 2>&1 || true
81
+ }
82
+
83
+ # Cleanup on exit
84
+ cleanup() {
85
+ unregister_session
86
+ echo -e "\n${GREEN}Session ended: $SESSION_NAME${NC}"
87
+ }
88
+
89
+ # Main
90
+ main() {
91
+ echo -e "${GREEN}Claude TG${NC} - Corporate Profile"
92
+ echo "Project: $PROJECT_NAME"
93
+ echo ""
94
+
95
+ # Check if tmux session already exists
96
+ if tmux has-session -t "$TMUX_SESSION" 2>/dev/null; then
97
+ echo "Attaching to existing session: $TMUX_SESSION"
98
+ else
99
+ echo "Creating new session: $TMUX_SESSION"
100
+ # Start Claude in a new tmux session
101
+ tmux new-session -d -s "$TMUX_SESSION" -c "$PWD" \
102
+ "CLAUDE_CONFIG_DIR=$CONFIG_DIR claude $*; echo 'Press Enter to close...'; read"
103
+ fi
104
+
105
+ # Register with bridge if running
106
+ if check_bridge; then
107
+ register_session
108
+ trap cleanup EXIT
109
+ echo -e "${GREEN}Connected to Telegram bridge${NC}"
110
+ fi
111
+
112
+ echo ""
113
+
114
+ # Attach to the session
115
+ tmux attach -t "$TMUX_SESSION"
116
+ }
117
+
118
+ main "$@"
package/bin/pclaude-tg ADDED
@@ -0,0 +1,126 @@
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
+ # Check for required dependencies
17
+ if ! command -v tmux &> /dev/null; then
18
+ echo "Error: tmux is required but not installed."
19
+ echo ""
20
+ echo "Install it with:"
21
+ echo " macOS: brew install tmux"
22
+ echo " Ubuntu/Debian: sudo apt install tmux"
23
+ echo " Fedora: sudo dnf install tmux"
24
+ exit 1
25
+ fi
26
+
27
+ if ! command -v claude &> /dev/null; then
28
+ echo "Error: claude CLI is required but not installed."
29
+ echo ""
30
+ echo "Install Claude Code from: https://claude.ai/code"
31
+ exit 1
32
+ fi
33
+
34
+ # Configuration
35
+ PROFILE="personal"
36
+ CONFIG_DIR="$HOME/.claude-personal"
37
+ BRIDGE_PORT="${BRIDGE_PORT:-3334}"
38
+ BRIDGE_URL="http://localhost:$BRIDGE_PORT"
39
+
40
+ # Project name from current directory
41
+ PROJECT_NAME="${PWD##*/}"
42
+ SESSION_NAME="${PROFILE}:${PROJECT_NAME}"
43
+ TMUX_SESSION="pclaude-${PROJECT_NAME}"
44
+
45
+ # Colors
46
+ RED='\033[0;31m'
47
+ GREEN='\033[0;32m'
48
+ YELLOW='\033[1;33m'
49
+ BLUE='\033[0;34m'
50
+ NC='\033[0m' # No Color
51
+
52
+ # Check if bridge is running
53
+ check_bridge() {
54
+ if ! curl -s "$BRIDGE_URL/health" > /dev/null 2>&1; then
55
+ echo -e "${YELLOW}Warning: Bridge daemon not running${NC}"
56
+ echo "Start it with: telegram-claude-bridge"
57
+ echo ""
58
+ echo "Starting Claude without Telegram integration..."
59
+ echo ""
60
+ return 1
61
+ fi
62
+ return 0
63
+ }
64
+
65
+ # Register session with bridge
66
+ register_session() {
67
+ curl -s -X POST "$BRIDGE_URL/register" \
68
+ -H "Content-Type: application/json" \
69
+ -d "{
70
+ \"profile\": \"$PROFILE\",
71
+ \"projectName\": \"$PROJECT_NAME\",
72
+ \"tmuxSession\": \"$TMUX_SESSION\",
73
+ \"cwd\": \"$PWD\"
74
+ }" > /dev/null 2>&1 || true
75
+ }
76
+
77
+ # Unregister session from bridge
78
+ unregister_session() {
79
+ curl -s -X POST "$BRIDGE_URL/unregister" \
80
+ -H "Content-Type: application/json" \
81
+ -d "{\"sessionName\": \"$SESSION_NAME\"}" > /dev/null 2>&1 || true
82
+ }
83
+
84
+ # Cleanup on exit
85
+ cleanup() {
86
+ unregister_session
87
+ echo -e "\n${GREEN}Session ended: $SESSION_NAME${NC}"
88
+ }
89
+
90
+ # Main
91
+ main() {
92
+ echo -e "${BLUE}Claude TG${NC} - Personal Profile"
93
+ echo "Project: $PROJECT_NAME"
94
+ echo ""
95
+
96
+ # Check if personal config exists
97
+ if [ ! -d "$CONFIG_DIR" ]; then
98
+ echo -e "${YELLOW}Warning: $CONFIG_DIR does not exist${NC}"
99
+ echo "Using default Claude config instead"
100
+ CONFIG_DIR="$HOME/.claude"
101
+ fi
102
+
103
+ # Check if tmux session already exists
104
+ if tmux has-session -t "$TMUX_SESSION" 2>/dev/null; then
105
+ echo "Attaching to existing session: $TMUX_SESSION"
106
+ else
107
+ echo "Creating new session: $TMUX_SESSION"
108
+ # Start Claude in a new tmux session
109
+ tmux new-session -d -s "$TMUX_SESSION" -c "$PWD" \
110
+ "CLAUDE_CONFIG_DIR=$CONFIG_DIR claude $*; echo 'Press Enter to close...'; read"
111
+ fi
112
+
113
+ # Register with bridge if running
114
+ if check_bridge; then
115
+ register_session
116
+ trap cleanup EXIT
117
+ echo -e "${GREEN}Connected to Telegram bridge${NC}"
118
+ fi
119
+
120
+ echo ""
121
+
122
+ # Attach to the session
123
+ tmux attach -t "$TMUX_SESSION"
124
+ }
125
+
126
+ 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.7",
4
- "description": "MCP server that lets Claude message you on Telegram with hooks support",
3
+ "version": "3.0.1",
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
+ });