telegram-claude-mcp 1.6.0 ā 1.6.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/README.md +127 -58
- package/bin/setup.js +90 -63
- package/package.json +1 -1
- package/src/telegram.ts +19 -2
package/README.md
CHANGED
|
@@ -35,29 +35,29 @@ Create directory `~/.claude/hooks/` and add these scripts:
|
|
|
35
35
|
**~/.claude/hooks/permission-hook.sh**
|
|
36
36
|
```bash
|
|
37
37
|
#!/bin/bash
|
|
38
|
+
# Set SESSION_NAME env var to target a specific session (for multi-session setups)
|
|
38
39
|
SESSION_DIR="/tmp/telegram-claude-sessions"
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
find_session() {
|
|
42
|
+
if [ -n "$SESSION_NAME" ]; then
|
|
43
|
+
local f="$SESSION_DIR/${SESSION_NAME}.info"
|
|
44
|
+
[ -f "$f" ] && { local p=$(jq -r '.pid // empty' "$f" 2>/dev/null); [ -n "$p" ] && kill -0 "$p" 2>/dev/null && echo "$f"; return; }
|
|
45
|
+
return
|
|
46
|
+
fi
|
|
47
|
+
local latest="" latest_time=0
|
|
43
48
|
[ -d "$SESSION_DIR" ] || return
|
|
44
|
-
for
|
|
45
|
-
[ -e "$
|
|
46
|
-
local pid
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if [ "$file_time" -gt "$latest_time" ]; then
|
|
52
|
-
latest_time=$file_time
|
|
53
|
-
latest_file=$info_file
|
|
54
|
-
fi
|
|
55
|
-
fi
|
|
49
|
+
for f in "$SESSION_DIR"/*.info; do
|
|
50
|
+
[ -e "$f" ] || continue
|
|
51
|
+
local p=$(jq -r '.pid // empty' "$f" 2>/dev/null)
|
|
52
|
+
[ -n "$p" ] && kill -0 "$p" 2>/dev/null && {
|
|
53
|
+
local t=$(stat -f %m "$f" 2>/dev/null || stat -c %Y "$f" 2>/dev/null)
|
|
54
|
+
[ "$t" -gt "$latest_time" ] && { latest_time=$t; latest=$f; }
|
|
55
|
+
}
|
|
56
56
|
done
|
|
57
|
-
echo "$
|
|
57
|
+
echo "$latest"
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
INFO_FILE=$(
|
|
60
|
+
INFO_FILE=$(find_session)
|
|
61
61
|
[ -z "$INFO_FILE" ] || [ ! -f "$INFO_FILE" ] && exit 0
|
|
62
62
|
|
|
63
63
|
HOOK_PORT=$(jq -r '.port' "$INFO_FILE")
|
|
@@ -78,33 +78,33 @@ RESPONSE=$(curl -s -X POST "$HOOK_URL" -H "Content-Type: application/json" -d "$
|
|
|
78
78
|
**~/.claude/hooks/stop-hook.sh**
|
|
79
79
|
```bash
|
|
80
80
|
#!/bin/bash
|
|
81
|
+
# Set SESSION_NAME env var to target a specific session (for multi-session setups)
|
|
81
82
|
SESSION_DIR="/tmp/telegram-claude-sessions"
|
|
82
83
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
find_session() {
|
|
85
|
+
if [ -n "$SESSION_NAME" ]; then
|
|
86
|
+
local f="$SESSION_DIR/${SESSION_NAME}.info"
|
|
87
|
+
[ -f "$f" ] && { local p=$(jq -r '.pid // empty' "$f" 2>/dev/null); [ -n "$p" ] && kill -0 "$p" 2>/dev/null && echo "$f"; return; }
|
|
88
|
+
return
|
|
89
|
+
fi
|
|
90
|
+
local latest="" latest_time=0
|
|
86
91
|
[ -d "$SESSION_DIR" ] || return
|
|
87
|
-
for
|
|
88
|
-
[ -e "$
|
|
89
|
-
local pid
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if [ "$file_time" -gt "$latest_time" ]; then
|
|
95
|
-
latest_time=$file_time
|
|
96
|
-
latest_file=$info_file
|
|
97
|
-
fi
|
|
98
|
-
fi
|
|
92
|
+
for f in "$SESSION_DIR"/*.info; do
|
|
93
|
+
[ -e "$f" ] || continue
|
|
94
|
+
local p=$(jq -r '.pid // empty' "$f" 2>/dev/null)
|
|
95
|
+
[ -n "$p" ] && kill -0 "$p" 2>/dev/null && {
|
|
96
|
+
local t=$(stat -f %m "$f" 2>/dev/null || stat -c %Y "$f" 2>/dev/null)
|
|
97
|
+
[ "$t" -gt "$latest_time" ] && { latest_time=$t; latest=$f; }
|
|
98
|
+
}
|
|
99
99
|
done
|
|
100
|
-
echo "$
|
|
100
|
+
echo "$latest"
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
INPUT=$(cat)
|
|
104
104
|
STOP_HOOK_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false')
|
|
105
105
|
[ "$STOP_HOOK_ACTIVE" = "true" ] && exit 0
|
|
106
106
|
|
|
107
|
-
INFO_FILE=$(
|
|
107
|
+
INFO_FILE=$(find_session)
|
|
108
108
|
[ -z "$INFO_FILE" ] || [ ! -f "$INFO_FILE" ] && exit 0
|
|
109
109
|
|
|
110
110
|
HOOK_PORT=$(jq -r '.port' "$INFO_FILE")
|
|
@@ -124,29 +124,29 @@ fi
|
|
|
124
124
|
**~/.claude/hooks/notify-hook.sh**
|
|
125
125
|
```bash
|
|
126
126
|
#!/bin/bash
|
|
127
|
+
# Set SESSION_NAME env var to target a specific session (for multi-session setups)
|
|
127
128
|
SESSION_DIR="/tmp/telegram-claude-sessions"
|
|
128
129
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
find_session() {
|
|
131
|
+
if [ -n "$SESSION_NAME" ]; then
|
|
132
|
+
local f="$SESSION_DIR/${SESSION_NAME}.info"
|
|
133
|
+
[ -f "$f" ] && { local p=$(jq -r '.pid // empty' "$f" 2>/dev/null); [ -n "$p" ] && kill -0 "$p" 2>/dev/null && echo "$f"; return; }
|
|
134
|
+
return
|
|
135
|
+
fi
|
|
136
|
+
local latest="" latest_time=0
|
|
132
137
|
[ -d "$SESSION_DIR" ] || return
|
|
133
|
-
for
|
|
134
|
-
[ -e "$
|
|
135
|
-
local pid
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if [ "$file_time" -gt "$latest_time" ]; then
|
|
141
|
-
latest_time=$file_time
|
|
142
|
-
latest_file=$info_file
|
|
143
|
-
fi
|
|
144
|
-
fi
|
|
138
|
+
for f in "$SESSION_DIR"/*.info; do
|
|
139
|
+
[ -e "$f" ] || continue
|
|
140
|
+
local p=$(jq -r '.pid // empty' "$f" 2>/dev/null)
|
|
141
|
+
[ -n "$p" ] && kill -0 "$p" 2>/dev/null && {
|
|
142
|
+
local t=$(stat -f %m "$f" 2>/dev/null || stat -c %Y "$f" 2>/dev/null)
|
|
143
|
+
[ "$t" -gt "$latest_time" ] && { latest_time=$t; latest=$f; }
|
|
144
|
+
}
|
|
145
145
|
done
|
|
146
|
-
echo "$
|
|
146
|
+
echo "$latest"
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
INFO_FILE=$(
|
|
149
|
+
INFO_FILE=$(find_session)
|
|
150
150
|
[ -z "$INFO_FILE" ] || [ ! -f "$INFO_FILE" ] && exit 0
|
|
151
151
|
|
|
152
152
|
HOOK_PORT=$(jq -r '.port' "$INFO_FILE")
|
|
@@ -175,19 +175,19 @@ Add to `~/.claude/settings.json`:
|
|
|
175
175
|
"PermissionRequest": [
|
|
176
176
|
{
|
|
177
177
|
"matcher": "*",
|
|
178
|
-
"hooks": [{ "type": "command", "command": "~/.claude/hooks/permission-hook.sh" }]
|
|
178
|
+
"hooks": [{ "type": "command", "command": "SESSION_NAME=default ~/.claude/hooks/permission-hook.sh" }]
|
|
179
179
|
}
|
|
180
180
|
],
|
|
181
181
|
"Stop": [
|
|
182
182
|
{
|
|
183
183
|
"matcher": "*",
|
|
184
|
-
"hooks": [{ "type": "command", "command": "~/.claude/hooks/stop-hook.sh" }]
|
|
184
|
+
"hooks": [{ "type": "command", "command": "SESSION_NAME=default ~/.claude/hooks/stop-hook.sh" }]
|
|
185
185
|
}
|
|
186
186
|
],
|
|
187
187
|
"Notification": [
|
|
188
188
|
{
|
|
189
189
|
"matcher": "*",
|
|
190
|
-
"hooks": [{ "type": "command", "command": "~/.claude/hooks/notify-hook.sh" }]
|
|
190
|
+
"hooks": [{ "type": "command", "command": "SESSION_NAME=default ~/.claude/hooks/notify-hook.sh" }]
|
|
191
191
|
}
|
|
192
192
|
]
|
|
193
193
|
},
|
|
@@ -205,6 +205,8 @@ Add to `~/.claude/settings.json`:
|
|
|
205
205
|
}
|
|
206
206
|
```
|
|
207
207
|
|
|
208
|
+
**Important:** The `SESSION_NAME` in hook commands must match the `SESSION_NAME` in the MCP server env.
|
|
209
|
+
|
|
208
210
|
### 3. Create Telegram Bot
|
|
209
211
|
|
|
210
212
|
1. Open Telegram and message [@BotFather](https://t.me/BotFather)
|
|
@@ -257,17 +259,84 @@ Claude Code Hook Scripts telegram-claude-mcp
|
|
|
257
259
|
|
|
258
260
|
## Multiple Sessions
|
|
259
261
|
|
|
260
|
-
Run multiple Claude instances with
|
|
262
|
+
Run multiple Claude Code instances (e.g., `~/.claude` and `~/.claude-personal`) with proper message routing.
|
|
263
|
+
|
|
264
|
+
### Why This Matters
|
|
261
265
|
|
|
266
|
+
Without proper configuration, hooks from one Claude session might route to another session's MCP server. The `SESSION_NAME` environment variable ensures each session connects to its own MCP server.
|
|
267
|
+
|
|
268
|
+
### Configuration
|
|
269
|
+
|
|
270
|
+
Each Claude config needs a unique `SESSION_NAME` in **both** the MCP server env and the hook commands.
|
|
271
|
+
|
|
272
|
+
**~/.claude/settings.json** (main):
|
|
262
273
|
```json
|
|
263
274
|
{
|
|
264
|
-
"
|
|
265
|
-
"
|
|
275
|
+
"hooks": {
|
|
276
|
+
"PermissionRequest": [{
|
|
277
|
+
"matcher": "*",
|
|
278
|
+
"hooks": [{ "type": "command", "command": "SESSION_NAME=main ~/.claude/hooks/permission-hook.sh" }]
|
|
279
|
+
}],
|
|
280
|
+
"Stop": [{
|
|
281
|
+
"matcher": "*",
|
|
282
|
+
"hooks": [{ "type": "command", "command": "SESSION_NAME=main ~/.claude/hooks/stop-hook.sh" }]
|
|
283
|
+
}],
|
|
284
|
+
"Notification": [{
|
|
285
|
+
"matcher": "*",
|
|
286
|
+
"hooks": [{ "type": "command", "command": "SESSION_NAME=main ~/.claude/hooks/notify-hook.sh" }]
|
|
287
|
+
}]
|
|
288
|
+
},
|
|
289
|
+
"mcpServers": {
|
|
290
|
+
"telegram": {
|
|
291
|
+
"command": "npx",
|
|
292
|
+
"args": ["-y", "telegram-claude-mcp"],
|
|
293
|
+
"env": {
|
|
294
|
+
"TELEGRAM_BOT_TOKEN": "YOUR_BOT_TOKEN",
|
|
295
|
+
"TELEGRAM_CHAT_ID": "YOUR_CHAT_ID",
|
|
296
|
+
"SESSION_NAME": "main"
|
|
297
|
+
}
|
|
298
|
+
}
|
|
266
299
|
}
|
|
267
300
|
}
|
|
268
301
|
```
|
|
269
302
|
|
|
270
|
-
|
|
303
|
+
**~/.claude-personal/settings.json** (personal):
|
|
304
|
+
```json
|
|
305
|
+
{
|
|
306
|
+
"hooks": {
|
|
307
|
+
"PermissionRequest": [{
|
|
308
|
+
"matcher": "*",
|
|
309
|
+
"hooks": [{ "type": "command", "command": "SESSION_NAME=personal ~/.claude/hooks/permission-hook.sh" }]
|
|
310
|
+
}],
|
|
311
|
+
"Stop": [{
|
|
312
|
+
"matcher": "*",
|
|
313
|
+
"hooks": [{ "type": "command", "command": "SESSION_NAME=personal ~/.claude/hooks/stop-hook.sh" }]
|
|
314
|
+
}],
|
|
315
|
+
"Notification": [{
|
|
316
|
+
"matcher": "*",
|
|
317
|
+
"hooks": [{ "type": "command", "command": "SESSION_NAME=personal ~/.claude/hooks/notify-hook.sh" }]
|
|
318
|
+
}]
|
|
319
|
+
},
|
|
320
|
+
"mcpServers": {
|
|
321
|
+
"telegram": {
|
|
322
|
+
"command": "npx",
|
|
323
|
+
"args": ["-y", "telegram-claude-mcp"],
|
|
324
|
+
"env": {
|
|
325
|
+
"TELEGRAM_BOT_TOKEN": "YOUR_BOT_TOKEN",
|
|
326
|
+
"TELEGRAM_CHAT_ID": "YOUR_CHAT_ID",
|
|
327
|
+
"SESSION_NAME": "personal"
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Key Points
|
|
335
|
+
|
|
336
|
+
- **SESSION_NAME must match** - The env var in hook commands must match the MCP server's SESSION_NAME
|
|
337
|
+
- **Share hook scripts** - All configs can use the same hook scripts in `~/.claude/hooks/`
|
|
338
|
+
- **Message tagging** - Messages are tagged with `[main]` or `[personal]` so you know the source
|
|
339
|
+
- **Separate ports** - Each MCP server auto-discovers an available port
|
|
271
340
|
|
|
272
341
|
## Troubleshooting
|
|
273
342
|
|
package/bin/setup.js
CHANGED
|
@@ -97,19 +97,31 @@ RESPONSE=$(curl -s -X POST "$HOOK_URL" \\
|
|
|
97
97
|
const STOP_HOOK = `#!/bin/bash
|
|
98
98
|
#
|
|
99
99
|
# Claude Code Interactive Stop Hook - sends stop notification and waits for reply
|
|
100
|
+
# Set SESSION_NAME env var to target a specific session (for multi-session setups)
|
|
100
101
|
#
|
|
101
102
|
|
|
102
103
|
SESSION_DIR="/tmp/telegram-claude-sessions"
|
|
103
104
|
|
|
104
|
-
|
|
105
|
+
find_session() {
|
|
106
|
+
if [ -n "$SESSION_NAME" ]; then
|
|
107
|
+
local specific_file="$SESSION_DIR/\${SESSION_NAME}.info"
|
|
108
|
+
if [ -f "$specific_file" ]; then
|
|
109
|
+
local pid
|
|
110
|
+
pid=$(jq -r '.pid // empty' "$specific_file" 2>/dev/null)
|
|
111
|
+
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
|
112
|
+
echo "$specific_file"
|
|
113
|
+
return
|
|
114
|
+
fi
|
|
115
|
+
fi
|
|
116
|
+
return
|
|
117
|
+
fi
|
|
118
|
+
|
|
105
119
|
local latest_file=""
|
|
106
120
|
local latest_time=0
|
|
107
|
-
|
|
108
121
|
[ -d "$SESSION_DIR" ] || return
|
|
109
122
|
|
|
110
123
|
for info_file in "$SESSION_DIR"/*.info; do
|
|
111
124
|
[ -e "$info_file" ] || continue
|
|
112
|
-
|
|
113
125
|
local pid
|
|
114
126
|
pid=$(jq -r '.pid // empty' "$info_file" 2>/dev/null)
|
|
115
127
|
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
|
@@ -121,22 +133,16 @@ find_active_session() {
|
|
|
121
133
|
fi
|
|
122
134
|
fi
|
|
123
135
|
done
|
|
124
|
-
|
|
125
136
|
echo "$latest_file"
|
|
126
137
|
}
|
|
127
138
|
|
|
128
139
|
INPUT=$(cat)
|
|
129
140
|
|
|
130
141
|
STOP_HOOK_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false')
|
|
131
|
-
|
|
132
|
-
exit 0
|
|
133
|
-
fi
|
|
134
|
-
|
|
135
|
-
INFO_FILE=$(find_active_session)
|
|
142
|
+
[ "$STOP_HOOK_ACTIVE" = "true" ] && exit 0
|
|
136
143
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
fi
|
|
144
|
+
INFO_FILE=$(find_session)
|
|
145
|
+
[ -z "$INFO_FILE" ] || [ ! -f "$INFO_FILE" ] && exit 0
|
|
140
146
|
|
|
141
147
|
HOOK_PORT=$(jq -r '.port' "$INFO_FILE")
|
|
142
148
|
HOOK_HOST=$(jq -r '.host // "localhost"' "$INFO_FILE")
|
|
@@ -156,29 +162,38 @@ RESPONSE=$(curl -s -X POST "$HOOK_URL" \\
|
|
|
156
162
|
if [ $? -eq 0 ]; then
|
|
157
163
|
DECISION=$(echo "$RESPONSE" | jq -r '.decision // empty')
|
|
158
164
|
REASON=$(echo "$RESPONSE" | jq -r '.reason // empty')
|
|
159
|
-
|
|
160
|
-
if [ "$DECISION" = "block" ] && [ -n "$REASON" ]; then
|
|
161
|
-
echo "$RESPONSE"
|
|
162
|
-
fi
|
|
165
|
+
[ "$DECISION" = "block" ] && [ -n "$REASON" ] && echo "$RESPONSE"
|
|
163
166
|
fi
|
|
164
167
|
`;
|
|
165
168
|
|
|
166
169
|
const NOTIFY_HOOK = `#!/bin/bash
|
|
167
170
|
#
|
|
168
171
|
# Claude Code Notification Hook - sends notifications to Telegram
|
|
172
|
+
# Set SESSION_NAME env var to target a specific session (for multi-session setups)
|
|
169
173
|
#
|
|
170
174
|
|
|
171
175
|
SESSION_DIR="/tmp/telegram-claude-sessions"
|
|
172
176
|
|
|
173
|
-
|
|
177
|
+
find_session() {
|
|
178
|
+
if [ -n "$SESSION_NAME" ]; then
|
|
179
|
+
local specific_file="$SESSION_DIR/\${SESSION_NAME}.info"
|
|
180
|
+
if [ -f "$specific_file" ]; then
|
|
181
|
+
local pid
|
|
182
|
+
pid=$(jq -r '.pid // empty' "$specific_file" 2>/dev/null)
|
|
183
|
+
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
|
184
|
+
echo "$specific_file"
|
|
185
|
+
return
|
|
186
|
+
fi
|
|
187
|
+
fi
|
|
188
|
+
return
|
|
189
|
+
fi
|
|
190
|
+
|
|
174
191
|
local latest_file=""
|
|
175
192
|
local latest_time=0
|
|
176
|
-
|
|
177
193
|
[ -d "$SESSION_DIR" ] || return
|
|
178
194
|
|
|
179
195
|
for info_file in "$SESSION_DIR"/*.info; do
|
|
180
196
|
[ -e "$info_file" ] || continue
|
|
181
|
-
|
|
182
197
|
local pid
|
|
183
198
|
pid=$(jq -r '.pid // empty' "$info_file" 2>/dev/null)
|
|
184
199
|
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
|
@@ -190,15 +205,11 @@ find_active_session() {
|
|
|
190
205
|
fi
|
|
191
206
|
fi
|
|
192
207
|
done
|
|
193
|
-
|
|
194
208
|
echo "$latest_file"
|
|
195
209
|
}
|
|
196
210
|
|
|
197
|
-
INFO_FILE=$(
|
|
198
|
-
|
|
199
|
-
if [ -z "$INFO_FILE" ] || [ ! -f "$INFO_FILE" ]; then
|
|
200
|
-
exit 0
|
|
201
|
-
fi
|
|
211
|
+
INFO_FILE=$(find_session)
|
|
212
|
+
[ -z "$INFO_FILE" ] || [ ! -f "$INFO_FILE" ] && exit 0
|
|
202
213
|
|
|
203
214
|
HOOK_PORT=$(jq -r '.port' "$INFO_FILE")
|
|
204
215
|
HOOK_HOST=$(jq -r '.host // "localhost"' "$INFO_FILE")
|
|
@@ -218,42 +229,46 @@ curl -s -X POST "$HOOK_URL" \\
|
|
|
218
229
|
--max-time 10 > /dev/null 2>&1
|
|
219
230
|
`;
|
|
220
231
|
|
|
221
|
-
//
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
232
|
+
// Generate hooks configuration for Claude settings
|
|
233
|
+
// sessionName parameter enables multi-session support
|
|
234
|
+
function generateHooksConfig(sessionName = 'default') {
|
|
235
|
+
const envPrefix = `SESSION_NAME=${sessionName}`;
|
|
236
|
+
return {
|
|
237
|
+
PermissionRequest: [
|
|
238
|
+
{
|
|
239
|
+
matcher: '*',
|
|
240
|
+
hooks: [
|
|
241
|
+
{
|
|
242
|
+
type: 'command',
|
|
243
|
+
command: `${envPrefix} ~/.claude/hooks/permission-hook.sh`
|
|
244
|
+
}
|
|
245
|
+
]
|
|
246
|
+
}
|
|
247
|
+
],
|
|
248
|
+
Stop: [
|
|
249
|
+
{
|
|
250
|
+
matcher: '*',
|
|
251
|
+
hooks: [
|
|
252
|
+
{
|
|
253
|
+
type: 'command',
|
|
254
|
+
command: `${envPrefix} ~/.claude/hooks/stop-hook.sh`
|
|
255
|
+
}
|
|
256
|
+
]
|
|
257
|
+
}
|
|
258
|
+
],
|
|
259
|
+
Notification: [
|
|
260
|
+
{
|
|
261
|
+
matcher: '*',
|
|
262
|
+
hooks: [
|
|
263
|
+
{
|
|
264
|
+
type: 'command',
|
|
265
|
+
command: `${envPrefix} ~/.claude/hooks/notify-hook.sh`
|
|
266
|
+
}
|
|
267
|
+
]
|
|
268
|
+
}
|
|
269
|
+
]
|
|
270
|
+
};
|
|
271
|
+
}
|
|
257
272
|
|
|
258
273
|
function setup() {
|
|
259
274
|
console.log('\nš± telegram-claude-mcp Setup\n');
|
|
@@ -291,8 +306,8 @@ function setup() {
|
|
|
291
306
|
}
|
|
292
307
|
}
|
|
293
308
|
|
|
294
|
-
// Merge hooks config
|
|
295
|
-
settings.hooks = { ...settings.hooks, ...
|
|
309
|
+
// Merge hooks config (default session)
|
|
310
|
+
settings.hooks = { ...settings.hooks, ...generateHooksConfig('default') };
|
|
296
311
|
|
|
297
312
|
// Add MCP server config if not present
|
|
298
313
|
if (!settings.mcpServers) {
|
|
@@ -337,6 +352,18 @@ function setup() {
|
|
|
337
352
|
console.log('4. Restart Claude Code\n');
|
|
338
353
|
|
|
339
354
|
console.log('ā'.repeat(50));
|
|
355
|
+
console.log('\nš Multi-Session Setup (optional):\n');
|
|
356
|
+
console.log('If you have multiple Claude configs (e.g., ~/.claude and ~/.claude-personal),');
|
|
357
|
+
console.log('each needs its own SESSION_NAME to avoid message routing conflicts.\n');
|
|
358
|
+
console.log('For each additional config, update its settings.json:');
|
|
359
|
+
console.log(' 1. Change SESSION_NAME in mcpServers.telegram.env');
|
|
360
|
+
console.log(' 2. Update hook commands to use that SESSION_NAME:\n');
|
|
361
|
+
console.log(' "command": "SESSION_NAME=personal ~/.claude/hooks/permission-hook.sh"\n');
|
|
362
|
+
console.log('Example for ~/.claude-personal/settings.json:');
|
|
363
|
+
console.log(' SESSION_NAME: "personal" (in mcpServers.telegram.env)');
|
|
364
|
+
console.log(' Hook commands: "SESSION_NAME=personal ~/.claude/hooks/..."');
|
|
365
|
+
|
|
366
|
+
console.log('\n' + 'ā'.repeat(50));
|
|
340
367
|
console.log('\n⨠Setup complete! Configure your bot token and chat ID to finish.\n');
|
|
341
368
|
}
|
|
342
369
|
|
package/package.json
CHANGED
package/src/telegram.ts
CHANGED
|
@@ -351,8 +351,7 @@ export class TelegramManager {
|
|
|
351
351
|
if (entry.type === 'assistant' && entry.message?.content) {
|
|
352
352
|
const textContent = entry.message.content.find((c: any) => c.type === 'text');
|
|
353
353
|
if (textContent?.text) {
|
|
354
|
-
lastMessage = textContent.text
|
|
355
|
-
if (textContent.text.length > 500) lastMessage += '...';
|
|
354
|
+
lastMessage = this.truncateMiddle(textContent.text, 600);
|
|
356
355
|
break;
|
|
357
356
|
}
|
|
358
357
|
}
|
|
@@ -476,6 +475,24 @@ export class TelegramManager {
|
|
|
476
475
|
});
|
|
477
476
|
}
|
|
478
477
|
|
|
478
|
+
/**
|
|
479
|
+
* Truncate text by removing the middle, keeping beginning and end
|
|
480
|
+
* This is useful because Claude's questions are usually at the end
|
|
481
|
+
*/
|
|
482
|
+
private truncateMiddle(text: string, maxLength: number): string {
|
|
483
|
+
if (text.length <= maxLength) return text;
|
|
484
|
+
|
|
485
|
+
// Keep more at the end (where questions usually are)
|
|
486
|
+
const startLength = Math.floor(maxLength * 0.3); // 30% from start
|
|
487
|
+
const endLength = Math.floor(maxLength * 0.6); // 60% from end
|
|
488
|
+
// ~10% for the ellipsis marker
|
|
489
|
+
|
|
490
|
+
const start = text.slice(0, startLength);
|
|
491
|
+
const end = text.slice(-endLength);
|
|
492
|
+
|
|
493
|
+
return `${start}\n\n[...truncated...]\n\n${end}`;
|
|
494
|
+
}
|
|
495
|
+
|
|
479
496
|
/**
|
|
480
497
|
* Format tool input for display
|
|
481
498
|
*/
|