claude-telegram-mirror 0.1.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/README.md +331 -0
- package/dist/bot/commands.d.ts +41 -0
- package/dist/bot/commands.d.ts.map +1 -0
- package/dist/bot/commands.js +231 -0
- package/dist/bot/commands.js.map +1 -0
- package/dist/bot/formatting.d.ts +62 -0
- package/dist/bot/formatting.d.ts.map +1 -0
- package/dist/bot/formatting.js +295 -0
- package/dist/bot/formatting.js.map +1 -0
- package/dist/bot/telegram.d.ts +93 -0
- package/dist/bot/telegram.d.ts.map +1 -0
- package/dist/bot/telegram.js +378 -0
- package/dist/bot/telegram.js.map +1 -0
- package/dist/bot/types.d.ts +28 -0
- package/dist/bot/types.d.ts.map +1 -0
- package/dist/bot/types.js +5 -0
- package/dist/bot/types.js.map +1 -0
- package/dist/bridge/daemon.d.ts +93 -0
- package/dist/bridge/daemon.d.ts.map +1 -0
- package/dist/bridge/daemon.js +626 -0
- package/dist/bridge/daemon.js.map +1 -0
- package/dist/bridge/index.d.ts +10 -0
- package/dist/bridge/index.d.ts.map +1 -0
- package/dist/bridge/index.js +9 -0
- package/dist/bridge/index.js.map +1 -0
- package/dist/bridge/injector.d.ts +97 -0
- package/dist/bridge/injector.d.ts.map +1 -0
- package/dist/bridge/injector.js +289 -0
- package/dist/bridge/injector.js.map +1 -0
- package/dist/bridge/session.d.ts +108 -0
- package/dist/bridge/session.d.ts.map +1 -0
- package/dist/bridge/session.js +381 -0
- package/dist/bridge/session.js.map +1 -0
- package/dist/bridge/socket.d.ts +97 -0
- package/dist/bridge/socket.d.ts.map +1 -0
- package/dist/bridge/socket.js +436 -0
- package/dist/bridge/socket.js.map +1 -0
- package/dist/bridge/types.d.ts +38 -0
- package/dist/bridge/types.d.ts.map +1 -0
- package/dist/bridge/types.js +5 -0
- package/dist/bridge/types.js.map +1 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +332 -0
- package/dist/cli.js.map +1 -0
- package/dist/hooks/handler.d.ts +94 -0
- package/dist/hooks/handler.d.ts.map +1 -0
- package/dist/hooks/handler.js +431 -0
- package/dist/hooks/handler.js.map +1 -0
- package/dist/hooks/index.d.ts +8 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +7 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/installer.d.ts +46 -0
- package/dist/hooks/installer.d.ts.map +1 -0
- package/dist/hooks/installer.js +317 -0
- package/dist/hooks/installer.js.map +1 -0
- package/dist/hooks/types.d.ts +88 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +6 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/service/doctor.d.ts +10 -0
- package/dist/service/doctor.d.ts.map +1 -0
- package/dist/service/doctor.js +424 -0
- package/dist/service/doctor.js.map +1 -0
- package/dist/service/manager.d.ts +48 -0
- package/dist/service/manager.d.ts.map +1 -0
- package/dist/service/manager.js +584 -0
- package/dist/service/manager.js.map +1 -0
- package/dist/service/setup.d.ts +10 -0
- package/dist/service/setup.d.ts.map +1 -0
- package/dist/service/setup.js +266 -0
- package/dist/service/setup.js.map +1 -0
- package/dist/utils/chunker.d.ts +24 -0
- package/dist/utils/chunker.d.ts.map +1 -0
- package/dist/utils/chunker.js +123 -0
- package/dist/utils/chunker.js.map +1 -0
- package/dist/utils/config.d.ts +48 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +154 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +28 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +88 -0
- package/postinstall.cjs +76 -0
- package/scripts/claude-wrapper.sh +122 -0
- package/scripts/doctor.sh +433 -0
- package/scripts/get-chat-id.sh +64 -0
- package/scripts/global-hooks.sh +39 -0
- package/scripts/install.sh +831 -0
- package/scripts/start-daemon.sh +49 -0
- package/scripts/telegram-hook.sh +449 -0
- package/scripts/uninstall.sh +261 -0
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge Daemon
|
|
3
|
+
* Central coordinator for Claude Code ↔ Telegram bridge
|
|
4
|
+
*/
|
|
5
|
+
import { EventEmitter } from 'events';
|
|
6
|
+
import { TelegramBot } from '../bot/telegram.js';
|
|
7
|
+
import { registerCommands, registerApprovalHandlers, registerToolDetailsHandler } from '../bot/commands.js';
|
|
8
|
+
import { SocketServer } from './socket.js';
|
|
9
|
+
import { SessionManager } from './session.js';
|
|
10
|
+
import { InputInjector } from './injector.js';
|
|
11
|
+
import { loadConfig } from '../utils/config.js';
|
|
12
|
+
import { formatAgentResponse, formatToolExecution, formatApprovalRequest, formatError, formatSessionStart, formatSessionEnd } from '../bot/formatting.js';
|
|
13
|
+
import logger from '../utils/logger.js';
|
|
14
|
+
/**
|
|
15
|
+
* Bridge Daemon Class
|
|
16
|
+
* Orchestrates all components
|
|
17
|
+
*/
|
|
18
|
+
export class BridgeDaemon extends EventEmitter {
|
|
19
|
+
config;
|
|
20
|
+
bot;
|
|
21
|
+
socket;
|
|
22
|
+
sessions;
|
|
23
|
+
injector;
|
|
24
|
+
running = false;
|
|
25
|
+
cleanupInterval = null;
|
|
26
|
+
sessionThreads = new Map(); // sessionId -> threadId
|
|
27
|
+
sessionTmuxTargets = new Map(); // sessionId -> tmux target
|
|
28
|
+
recentTelegramInputs = new Set(); // Track recent inputs from Telegram to avoid echo
|
|
29
|
+
toolInputCache = new Map(); // Cache tool inputs for details button
|
|
30
|
+
compactingSessions = new Set(); // Track sessions currently compacting
|
|
31
|
+
constructor(config) {
|
|
32
|
+
super();
|
|
33
|
+
this.config = config || loadConfig();
|
|
34
|
+
this.bot = new TelegramBot(this.config);
|
|
35
|
+
this.socket = new SocketServer(this.config.socketPath);
|
|
36
|
+
this.sessions = new SessionManager();
|
|
37
|
+
this.injector = new InputInjector();
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Start the daemon
|
|
41
|
+
*/
|
|
42
|
+
async start() {
|
|
43
|
+
if (this.running) {
|
|
44
|
+
logger.warn('Daemon already running');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
logger.info('Starting bridge daemon...');
|
|
48
|
+
// Start socket server
|
|
49
|
+
await this.socket.listen();
|
|
50
|
+
// Initialize input injector for Telegram → CLI
|
|
51
|
+
const injectorReady = await this.injector.init();
|
|
52
|
+
if (injectorReady) {
|
|
53
|
+
logger.info('Input injector ready', {
|
|
54
|
+
method: this.injector.getMethod(),
|
|
55
|
+
tmuxSession: this.injector.getTmuxSession()
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
logger.warn('Input injection not available - Telegram → CLI disabled');
|
|
60
|
+
}
|
|
61
|
+
// Setup message routing
|
|
62
|
+
this.setupSocketHandlers();
|
|
63
|
+
this.setupBotHandlers();
|
|
64
|
+
// Register bot commands
|
|
65
|
+
registerCommands(this.bot.getBot(), {
|
|
66
|
+
getActiveSessions: async () => {
|
|
67
|
+
return this.sessions.getActiveSessions().map(s => ({
|
|
68
|
+
id: s.id,
|
|
69
|
+
startedAt: s.startedAt,
|
|
70
|
+
projectDir: s.metadata?.projectDir
|
|
71
|
+
}));
|
|
72
|
+
},
|
|
73
|
+
abortSession: async (sessionId) => {
|
|
74
|
+
this.sessions.endSession(sessionId, 'aborted');
|
|
75
|
+
this.socket.broadcast({
|
|
76
|
+
type: 'command',
|
|
77
|
+
sessionId,
|
|
78
|
+
timestamp: new Date().toISOString(),
|
|
79
|
+
content: 'abort'
|
|
80
|
+
});
|
|
81
|
+
return true;
|
|
82
|
+
},
|
|
83
|
+
sendToSession: async (sessionId, text) => {
|
|
84
|
+
return this.socket.broadcast({
|
|
85
|
+
type: 'user_input',
|
|
86
|
+
sessionId,
|
|
87
|
+
timestamp: new Date().toISOString(),
|
|
88
|
+
content: text
|
|
89
|
+
}), true;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
// Register tool details handler (tap "Details" button on tool use messages)
|
|
93
|
+
registerToolDetailsHandler(this.bot.getBot(), (toolUseId) => {
|
|
94
|
+
const cached = this.toolInputCache.get(toolUseId);
|
|
95
|
+
if (!cached)
|
|
96
|
+
return undefined;
|
|
97
|
+
return { tool: cached.tool, input: cached.input };
|
|
98
|
+
});
|
|
99
|
+
// Register approval handlers
|
|
100
|
+
registerApprovalHandlers(this.bot.getBot(), async (approvalId, action) => {
|
|
101
|
+
const approval = this.sessions.getApproval(approvalId);
|
|
102
|
+
if (!approval) {
|
|
103
|
+
logger.warn('Approval not found', { approvalId });
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (action === 'abort') {
|
|
107
|
+
this.sessions.endSession(approval.sessionId, 'aborted');
|
|
108
|
+
this.sessions.resolveApproval(approvalId, 'rejected');
|
|
109
|
+
this.socket.broadcast({
|
|
110
|
+
type: 'command',
|
|
111
|
+
sessionId: approval.sessionId,
|
|
112
|
+
timestamp: new Date().toISOString(),
|
|
113
|
+
content: 'abort'
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
this.sessions.resolveApproval(approvalId, action === 'approve' ? 'approved' : 'rejected');
|
|
118
|
+
this.socket.broadcast({
|
|
119
|
+
type: 'approval_response',
|
|
120
|
+
sessionId: approval.sessionId,
|
|
121
|
+
timestamp: new Date().toISOString(),
|
|
122
|
+
content: action,
|
|
123
|
+
metadata: { approvalId }
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
// Start bot
|
|
128
|
+
await this.bot.start();
|
|
129
|
+
// Start cleanup interval (every 5 minutes)
|
|
130
|
+
this.cleanupInterval = setInterval(() => {
|
|
131
|
+
this.sessions.expireOldApprovals();
|
|
132
|
+
}, 5 * 60 * 1000);
|
|
133
|
+
this.running = true;
|
|
134
|
+
logger.info('Bridge daemon started');
|
|
135
|
+
// Send startup notification
|
|
136
|
+
await this.bot.sendMessage('🟢 *Bridge Daemon Started*\n\n' +
|
|
137
|
+
'Claude Code sessions will now be mirrored here.', { parseMode: 'Markdown' });
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Setup socket message handlers (CLI → Telegram)
|
|
141
|
+
*/
|
|
142
|
+
setupSocketHandlers() {
|
|
143
|
+
this.socket.on('message', async (msg) => {
|
|
144
|
+
logger.debug('Received socket message', { type: msg.type, sessionId: msg.sessionId });
|
|
145
|
+
// Update session activity
|
|
146
|
+
const session = this.sessions.getSession(msg.sessionId);
|
|
147
|
+
if (session) {
|
|
148
|
+
this.sessions.updateActivity(msg.sessionId);
|
|
149
|
+
}
|
|
150
|
+
switch (msg.type) {
|
|
151
|
+
case 'session_start':
|
|
152
|
+
await this.handleSessionStart(msg);
|
|
153
|
+
break;
|
|
154
|
+
case 'session_end':
|
|
155
|
+
await this.handleSessionEnd(msg);
|
|
156
|
+
break;
|
|
157
|
+
case 'agent_response':
|
|
158
|
+
await this.ensureSessionExists(msg);
|
|
159
|
+
await this.handleAgentResponse(msg);
|
|
160
|
+
break;
|
|
161
|
+
case 'tool_start':
|
|
162
|
+
await this.ensureSessionExists(msg);
|
|
163
|
+
await this.handleToolStart(msg);
|
|
164
|
+
break;
|
|
165
|
+
case 'tool_result':
|
|
166
|
+
await this.ensureSessionExists(msg);
|
|
167
|
+
await this.handleToolResult(msg);
|
|
168
|
+
break;
|
|
169
|
+
case 'user_input':
|
|
170
|
+
await this.ensureSessionExists(msg);
|
|
171
|
+
await this.handleUserInput(msg);
|
|
172
|
+
break;
|
|
173
|
+
case 'approval_request':
|
|
174
|
+
await this.ensureSessionExists(msg);
|
|
175
|
+
await this.handleApprovalRequest(msg);
|
|
176
|
+
break;
|
|
177
|
+
case 'error':
|
|
178
|
+
await this.ensureSessionExists(msg);
|
|
179
|
+
await this.handleError(msg);
|
|
180
|
+
break;
|
|
181
|
+
case 'turn_complete':
|
|
182
|
+
// Claude fires Stop after every turn, not when session ends
|
|
183
|
+
// Just log it and update activity - don't close the topic
|
|
184
|
+
logger.debug('Turn complete', { sessionId: msg.sessionId });
|
|
185
|
+
// Check if we were compacting - if so, send completion notification
|
|
186
|
+
if (this.compactingSessions.has(msg.sessionId)) {
|
|
187
|
+
await this.handleCompactComplete(msg.sessionId);
|
|
188
|
+
}
|
|
189
|
+
break;
|
|
190
|
+
case 'pre_compact':
|
|
191
|
+
await this.ensureSessionExists(msg);
|
|
192
|
+
await this.handlePreCompact(msg);
|
|
193
|
+
break;
|
|
194
|
+
default:
|
|
195
|
+
logger.debug('Unknown message type', { type: msg.type });
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
this.socket.on('connect', (clientId) => {
|
|
199
|
+
logger.debug('Hook client connected', { clientId });
|
|
200
|
+
});
|
|
201
|
+
this.socket.on('disconnect', (clientId) => {
|
|
202
|
+
logger.debug('Hook client disconnected', { clientId });
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Check if text is a stop/interrupt command
|
|
207
|
+
*/
|
|
208
|
+
isStopCommand(text) {
|
|
209
|
+
const normalized = text.trim().toLowerCase();
|
|
210
|
+
return normalized === 'stop' ||
|
|
211
|
+
normalized === '/stop' ||
|
|
212
|
+
normalized === 'cancel' ||
|
|
213
|
+
normalized === '/cancel' ||
|
|
214
|
+
normalized === 'abort' ||
|
|
215
|
+
normalized === '/abort' ||
|
|
216
|
+
normalized === 'ctrl+c' ||
|
|
217
|
+
normalized === 'ctrl-c' ||
|
|
218
|
+
normalized === '^c';
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Setup bot message handlers (Telegram → CLI)
|
|
222
|
+
*/
|
|
223
|
+
setupBotHandlers() {
|
|
224
|
+
// Handle text messages (forward to CLI)
|
|
225
|
+
this.bot.onMessage(async (text, chatId, threadId) => {
|
|
226
|
+
let session = null;
|
|
227
|
+
if (threadId) {
|
|
228
|
+
// Message is in a specific topic - ONLY process if we own that topic
|
|
229
|
+
// This is critical for multi-bot architecture: each bot ignores topics it didn't create
|
|
230
|
+
session = this.sessions.getSessionByThreadId(threadId);
|
|
231
|
+
if (!session) {
|
|
232
|
+
// This topic is not in our sessions.db - belongs to another bot/system
|
|
233
|
+
// Silently ignore - another daemon will handle it
|
|
234
|
+
logger.debug('Ignoring message for unknown topic (multi-bot)', { threadId, chatId });
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
// Message is in General topic (no threadId) - use chatId fallback
|
|
240
|
+
session = this.sessions.getSessionByChatId(chatId);
|
|
241
|
+
if (!session) {
|
|
242
|
+
// No active session - maybe user is just chatting
|
|
243
|
+
logger.debug('Message received but no session attached', { chatId });
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// Get the tmux info for this session
|
|
248
|
+
// First check memory cache, then fallback to database (handles daemon restart)
|
|
249
|
+
let tmuxTarget = this.sessionTmuxTargets.get(session.id);
|
|
250
|
+
let tmuxSocket;
|
|
251
|
+
if (!tmuxTarget) {
|
|
252
|
+
// Cache miss - restore from database (e.g., after daemon restart)
|
|
253
|
+
const tmuxInfo = this.sessions.getTmuxInfo(session.id);
|
|
254
|
+
tmuxTarget = tmuxInfo.target || undefined;
|
|
255
|
+
tmuxSocket = tmuxInfo.socket || undefined;
|
|
256
|
+
if (tmuxTarget) {
|
|
257
|
+
// Repopulate cache for future requests
|
|
258
|
+
this.sessionTmuxTargets.set(session.id, tmuxTarget);
|
|
259
|
+
logger.info('Restored tmux info from database', { sessionId: session.id, tmuxTarget, tmuxSocket });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
// Have target in cache, get socket from session data
|
|
264
|
+
tmuxSocket = session.tmuxSocket;
|
|
265
|
+
}
|
|
266
|
+
if (tmuxTarget) {
|
|
267
|
+
this.injector.setTmuxSession(tmuxTarget, tmuxSocket);
|
|
268
|
+
}
|
|
269
|
+
// Check for stop/interrupt command - send Ctrl+C to tmux
|
|
270
|
+
if (this.isStopCommand(text)) {
|
|
271
|
+
const sessionThreadId = this.getSessionThreadId(session.id);
|
|
272
|
+
const stopped = await this.injector.sendKey('Ctrl-C');
|
|
273
|
+
if (stopped) {
|
|
274
|
+
logger.info('Sent interrupt signal (Ctrl+C) to CLI', { sessionId: session.id });
|
|
275
|
+
await this.bot.sendMessage('🛑 *Interrupt sent* (Ctrl+C)\n\n_Claude should stop the current operation._', { parseMode: 'Markdown' }, sessionThreadId);
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
logger.warn('Failed to send interrupt signal', { sessionId: session.id });
|
|
279
|
+
await this.bot.sendMessage('⚠️ *Could not send interrupt*\n\nNo tmux session found.', { parseMode: 'Markdown' }, sessionThreadId);
|
|
280
|
+
}
|
|
281
|
+
return; // Don't inject "stop" as text
|
|
282
|
+
}
|
|
283
|
+
// Track this input so we don't echo it back when the hook fires
|
|
284
|
+
const inputKey = `${session.id}:${text.trim()}`;
|
|
285
|
+
this.recentTelegramInputs.add(inputKey);
|
|
286
|
+
// Auto-remove after 10 seconds
|
|
287
|
+
setTimeout(() => this.recentTelegramInputs.delete(inputKey), 10000);
|
|
288
|
+
// Inject input into Claude Code via tmux
|
|
289
|
+
const injected = await this.injector.inject(text);
|
|
290
|
+
if (injected) {
|
|
291
|
+
logger.info('Injected input to CLI', { sessionId: session.id, method: this.injector.getMethod() });
|
|
292
|
+
// Silently inject - no confirmation needed, user already sees their message
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
logger.warn('Failed to inject input', { sessionId: session.id });
|
|
296
|
+
// Only notify on failure
|
|
297
|
+
const sessionThreadId = this.getSessionThreadId(session.id);
|
|
298
|
+
await this.bot.sendMessage(`⚠️ *Could not send input to CLI*\n\nNo tmux session found. Make sure Claude Code is running in tmux.`, { parseMode: 'Markdown' }, sessionThreadId);
|
|
299
|
+
}
|
|
300
|
+
// Also broadcast to socket for logging/other listeners
|
|
301
|
+
this.socket.broadcast({
|
|
302
|
+
type: 'user_input',
|
|
303
|
+
sessionId: session.id,
|
|
304
|
+
timestamp: new Date().toISOString(),
|
|
305
|
+
content: text
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
// ============ Message Handlers ============
|
|
310
|
+
async handleSessionStart(msg) {
|
|
311
|
+
const hostname = msg.metadata?.hostname;
|
|
312
|
+
const projectDir = msg.metadata?.projectDir;
|
|
313
|
+
const tmuxTarget = msg.metadata?.tmuxTarget;
|
|
314
|
+
const tmuxSocket = msg.metadata?.tmuxSocket;
|
|
315
|
+
// Use Claude's native session_id from the message
|
|
316
|
+
// This ensures all events from the same Claude session map to the same Telegram thread
|
|
317
|
+
const sessionId = this.sessions.createSession(this.config.chatId, projectDir, undefined, hostname, msg.sessionId, // Use Claude's session_id!
|
|
318
|
+
tmuxTarget, // Persist tmux target to database
|
|
319
|
+
tmuxSocket // Persist tmux socket path to database
|
|
320
|
+
);
|
|
321
|
+
// Also cache in memory for fast lookups
|
|
322
|
+
if (tmuxTarget) {
|
|
323
|
+
this.sessionTmuxTargets.set(sessionId, tmuxTarget);
|
|
324
|
+
logger.info('Session tmux info stored', { sessionId, tmuxTarget, tmuxSocket });
|
|
325
|
+
}
|
|
326
|
+
// Check if session already has a thread (e.g., daemon restarted but session continues)
|
|
327
|
+
let threadId = this.sessions.getSessionThread(sessionId);
|
|
328
|
+
if (threadId) {
|
|
329
|
+
// Reuse existing thread - don't create a new topic
|
|
330
|
+
this.sessionThreads.set(sessionId, threadId);
|
|
331
|
+
logger.info('Reusing existing session thread', { sessionId, threadId });
|
|
332
|
+
}
|
|
333
|
+
else if (this.config.useThreads) {
|
|
334
|
+
// Create a new forum topic only if none exists
|
|
335
|
+
const topicName = this.formatTopicName(sessionId, hostname, projectDir);
|
|
336
|
+
threadId = await this.bot.createForumTopic(topicName, 0); // Blue color (index 0)
|
|
337
|
+
if (threadId) {
|
|
338
|
+
this.sessions.setSessionThread(sessionId, threadId);
|
|
339
|
+
this.sessionThreads.set(sessionId, threadId);
|
|
340
|
+
logger.info('Session thread created', { sessionId, threadId });
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
// Broadcast session registered (with Claude's session ID)
|
|
344
|
+
this.socket.broadcast({
|
|
345
|
+
type: 'session_start',
|
|
346
|
+
sessionId,
|
|
347
|
+
timestamp: new Date().toISOString(),
|
|
348
|
+
content: 'Session registered',
|
|
349
|
+
metadata: { threadId }
|
|
350
|
+
});
|
|
351
|
+
// Build session info message
|
|
352
|
+
let sessionInfo = formatSessionStart(sessionId, projectDir, hostname);
|
|
353
|
+
if (tmuxTarget) {
|
|
354
|
+
sessionInfo += `\n📺 tmux: \`${tmuxTarget}\``;
|
|
355
|
+
}
|
|
356
|
+
// Notify user (in the thread if available)
|
|
357
|
+
await this.bot.sendMessage(sessionInfo, { parseMode: 'Markdown' }, threadId || undefined);
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Format topic name for a session
|
|
361
|
+
*/
|
|
362
|
+
formatTopicName(sessionId, hostname, projectDir) {
|
|
363
|
+
const parts = [];
|
|
364
|
+
// Add hostname if available
|
|
365
|
+
if (hostname) {
|
|
366
|
+
parts.push(hostname);
|
|
367
|
+
}
|
|
368
|
+
// Add project directory basename
|
|
369
|
+
if (projectDir) {
|
|
370
|
+
const basename = projectDir.split('/').pop() || projectDir;
|
|
371
|
+
parts.push(basename);
|
|
372
|
+
}
|
|
373
|
+
// Add short session ID
|
|
374
|
+
const shortId = sessionId.replace('session-', '').substring(0, 8);
|
|
375
|
+
parts.push(shortId);
|
|
376
|
+
return parts.join(' • ') || `Session ${shortId}`;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Ensure a session exists (create on-the-fly if needed)
|
|
380
|
+
* This handles the case where events arrive before session_start.
|
|
381
|
+
*
|
|
382
|
+
* IMPORTANT: This function ONLY creates the session entry in the database.
|
|
383
|
+
* Topic creation is the responsibility of handleSessionStart() alone.
|
|
384
|
+
* Messages arriving before the topic is created will go to General.
|
|
385
|
+
*/
|
|
386
|
+
async ensureSessionExists(msg) {
|
|
387
|
+
const existing = this.sessions.getSession(msg.sessionId);
|
|
388
|
+
if (existing) {
|
|
389
|
+
// Session already exists - nothing to do
|
|
390
|
+
// Topic creation is handleSessionStart's responsibility
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
// Create session on-the-fly with Claude's session_id
|
|
394
|
+
// The topic will be created when session_start arrives
|
|
395
|
+
logger.info('Creating session on-the-fly (no topic yet)', { sessionId: msg.sessionId });
|
|
396
|
+
const hostname = msg.metadata?.hostname;
|
|
397
|
+
const projectDir = msg.metadata?.projectDir;
|
|
398
|
+
const tmuxTarget = msg.metadata?.tmuxTarget;
|
|
399
|
+
const tmuxSocket = msg.metadata?.tmuxSocket;
|
|
400
|
+
this.sessions.createSession(this.config.chatId, projectDir, undefined, hostname, msg.sessionId, tmuxTarget, // Persist tmux target to database
|
|
401
|
+
tmuxSocket // Persist tmux socket path to database
|
|
402
|
+
);
|
|
403
|
+
// Also cache in memory for fast lookups
|
|
404
|
+
if (tmuxTarget) {
|
|
405
|
+
this.sessionTmuxTargets.set(msg.sessionId, tmuxTarget);
|
|
406
|
+
}
|
|
407
|
+
// NOTE: No topic creation here - that's handleSessionStart's job
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Get thread ID for a session
|
|
411
|
+
*/
|
|
412
|
+
getSessionThreadId(sessionId) {
|
|
413
|
+
// Check in-memory cache first
|
|
414
|
+
let threadId = this.sessionThreads.get(sessionId);
|
|
415
|
+
if (threadId)
|
|
416
|
+
return threadId;
|
|
417
|
+
// Fallback to database
|
|
418
|
+
const dbThreadId = this.sessions.getSessionThread(sessionId);
|
|
419
|
+
if (dbThreadId) {
|
|
420
|
+
this.sessionThreads.set(sessionId, dbThreadId);
|
|
421
|
+
return dbThreadId;
|
|
422
|
+
}
|
|
423
|
+
return undefined;
|
|
424
|
+
}
|
|
425
|
+
async handleSessionEnd(msg) {
|
|
426
|
+
const session = this.sessions.getSession(msg.sessionId);
|
|
427
|
+
if (session) {
|
|
428
|
+
const duration = Date.now() - session.startedAt.getTime();
|
|
429
|
+
const threadId = this.getSessionThreadId(msg.sessionId);
|
|
430
|
+
// Send end message in the session's thread
|
|
431
|
+
await this.bot.sendMessage(formatSessionEnd(msg.sessionId, duration), { parseMode: 'Markdown' }, threadId);
|
|
432
|
+
// Close the forum topic if it exists
|
|
433
|
+
if (threadId) {
|
|
434
|
+
await this.bot.closeForumTopic(threadId);
|
|
435
|
+
this.sessionThreads.delete(msg.sessionId);
|
|
436
|
+
}
|
|
437
|
+
// Clean up tmux target
|
|
438
|
+
this.sessionTmuxTargets.delete(msg.sessionId);
|
|
439
|
+
this.sessions.endSession(msg.sessionId);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
async handleAgentResponse(msg) {
|
|
443
|
+
const threadId = this.getSessionThreadId(msg.sessionId);
|
|
444
|
+
await this.bot.sendMessage(formatAgentResponse(msg.content), { parseMode: 'Markdown' }, threadId);
|
|
445
|
+
}
|
|
446
|
+
async handleToolStart(msg) {
|
|
447
|
+
// Only show tool starts in verbose mode to avoid noise
|
|
448
|
+
if (!this.config.verbose)
|
|
449
|
+
return;
|
|
450
|
+
const toolName = msg.metadata?.tool || 'Unknown';
|
|
451
|
+
const toolInput = msg.metadata?.input;
|
|
452
|
+
const threadId = this.getSessionThreadId(msg.sessionId);
|
|
453
|
+
// Format brief preview based on tool type
|
|
454
|
+
let preview = '';
|
|
455
|
+
if (toolInput) {
|
|
456
|
+
if (toolName === 'Read' && toolInput.file_path) {
|
|
457
|
+
preview = ` \`${this.truncatePath(toolInput.file_path)}\``;
|
|
458
|
+
}
|
|
459
|
+
else if (toolName === 'Write' && toolInput.file_path) {
|
|
460
|
+
preview = ` \`${this.truncatePath(toolInput.file_path)}\``;
|
|
461
|
+
}
|
|
462
|
+
else if (toolName === 'Edit' && toolInput.file_path) {
|
|
463
|
+
preview = ` \`${this.truncatePath(toolInput.file_path)}\``;
|
|
464
|
+
}
|
|
465
|
+
else if (toolName === 'Bash' && toolInput.command) {
|
|
466
|
+
const cmd = toolInput.command.slice(0, 50);
|
|
467
|
+
preview = `\n\`${cmd}${toolInput.command.length > 50 ? '...' : ''}\``;
|
|
468
|
+
}
|
|
469
|
+
else if (toolName === 'Grep' && toolInput.pattern) {
|
|
470
|
+
preview = ` \`${toolInput.pattern}\``;
|
|
471
|
+
}
|
|
472
|
+
else if (toolName === 'Glob' && toolInput.pattern) {
|
|
473
|
+
preview = ` \`${toolInput.pattern}\``;
|
|
474
|
+
}
|
|
475
|
+
else if (toolName === 'Task' && toolInput.description) {
|
|
476
|
+
preview = ` ${toolInput.description}`;
|
|
477
|
+
}
|
|
478
|
+
else if (toolName === 'WebFetch' && toolInput.url) {
|
|
479
|
+
preview = ` \`${toolInput.url.slice(0, 40)}...\``;
|
|
480
|
+
}
|
|
481
|
+
else if (toolName === 'WebSearch' && toolInput.query) {
|
|
482
|
+
preview = ` "${toolInput.query}"`;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
// Generate unique ID for this tool use
|
|
486
|
+
const toolUseId = `tool_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
487
|
+
// Store tool input for detail retrieval (with 5 min expiry)
|
|
488
|
+
this.toolInputCache.set(toolUseId, {
|
|
489
|
+
tool: toolName,
|
|
490
|
+
input: toolInput,
|
|
491
|
+
timestamp: Date.now()
|
|
492
|
+
});
|
|
493
|
+
setTimeout(() => this.toolInputCache.delete(toolUseId), 5 * 60 * 1000);
|
|
494
|
+
// Send with "Details" button if there's any input to show
|
|
495
|
+
if (toolInput && Object.keys(toolInput).length > 0) {
|
|
496
|
+
await this.bot.sendWithButtons(`🔧 *Running:* \`${toolName}\`${preview}`, [{ text: '📋 Details', callbackData: `tooldetails:${toolUseId}` }], { parseMode: 'Markdown' }, threadId);
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
await this.bot.sendMessage(`🔧 *Running:* \`${toolName}\`${preview}`, { parseMode: 'Markdown' }, threadId);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Truncate file path to show basename and parent
|
|
504
|
+
*/
|
|
505
|
+
truncatePath(path) {
|
|
506
|
+
const parts = path.split('/');
|
|
507
|
+
if (parts.length <= 3)
|
|
508
|
+
return path;
|
|
509
|
+
return `.../${parts.slice(-2).join('/')}`;
|
|
510
|
+
}
|
|
511
|
+
async handleToolResult(msg) {
|
|
512
|
+
if (!this.config.verbose)
|
|
513
|
+
return;
|
|
514
|
+
const toolName = msg.metadata?.tool || 'Unknown';
|
|
515
|
+
const toolInput = msg.metadata?.input;
|
|
516
|
+
const toolOutput = msg.content;
|
|
517
|
+
const threadId = this.getSessionThreadId(msg.sessionId);
|
|
518
|
+
await this.bot.sendMessage(formatToolExecution(toolName, toolInput, toolOutput, this.config.verbose), { parseMode: 'Markdown' }, threadId);
|
|
519
|
+
}
|
|
520
|
+
async handleUserInput(msg) {
|
|
521
|
+
const source = msg.metadata?.source || 'cli';
|
|
522
|
+
// Skip if this was explicitly marked as from Telegram
|
|
523
|
+
if (source === 'telegram') {
|
|
524
|
+
logger.debug('Skipping echo for telegram input (source=telegram)');
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
// Check if this input was recently sent from Telegram (deduplication)
|
|
528
|
+
const inputKey = `${msg.sessionId}:${msg.content?.trim()}`;
|
|
529
|
+
if (this.recentTelegramInputs.has(inputKey)) {
|
|
530
|
+
logger.debug('Skipping echo for telegram input (dedup match)', { inputKey });
|
|
531
|
+
this.recentTelegramInputs.delete(inputKey); // Clean up
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
// Wait for thread to be available (session_start creates thread async)
|
|
535
|
+
let threadId = this.getSessionThreadId(msg.sessionId);
|
|
536
|
+
if (!threadId) {
|
|
537
|
+
// Retry a few times with small delay - thread might be creating
|
|
538
|
+
for (let i = 0; i < 5; i++) {
|
|
539
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
540
|
+
threadId = this.getSessionThreadId(msg.sessionId);
|
|
541
|
+
if (threadId)
|
|
542
|
+
break;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
logger.debug('handleUserInput', { sessionId: msg.sessionId, threadId, source, content: msg.content?.substring(0, 50) });
|
|
546
|
+
// Show user input in Telegram (from CLI only)
|
|
547
|
+
await this.bot.sendMessage(`👤 *User (cli):*\n${msg.content}`, { parseMode: 'Markdown' }, threadId);
|
|
548
|
+
}
|
|
549
|
+
async handleApprovalRequest(msg) {
|
|
550
|
+
const approvalId = this.sessions.createApproval(msg.sessionId, msg.content);
|
|
551
|
+
const threadId = this.getSessionThreadId(msg.sessionId);
|
|
552
|
+
await this.bot.sendWithButtons(formatApprovalRequest(msg.content), [
|
|
553
|
+
{ text: '✅ Approve', callbackData: `approve:${approvalId}` },
|
|
554
|
+
{ text: '❌ Reject', callbackData: `reject:${approvalId}` },
|
|
555
|
+
{ text: '🛑 Abort', callbackData: `abort:${approvalId}` }
|
|
556
|
+
], { parseMode: 'Markdown' }, threadId);
|
|
557
|
+
}
|
|
558
|
+
async handleError(msg) {
|
|
559
|
+
const threadId = this.getSessionThreadId(msg.sessionId);
|
|
560
|
+
await this.bot.sendMessage(formatError(msg.content), { parseMode: 'Markdown' }, threadId);
|
|
561
|
+
}
|
|
562
|
+
async handlePreCompact(msg) {
|
|
563
|
+
const trigger = msg.metadata?.trigger || 'auto';
|
|
564
|
+
const threadId = this.getSessionThreadId(msg.sessionId);
|
|
565
|
+
// Mark session as compacting
|
|
566
|
+
this.compactingSessions.add(msg.sessionId);
|
|
567
|
+
// Send notification based on trigger type
|
|
568
|
+
const message = trigger === 'manual'
|
|
569
|
+
? '🔄 *Compacting session context...*\n\n_User requested /compact_'
|
|
570
|
+
: '⏳ *Context limit reached*\n\n_Summarizing conversation, please wait..._';
|
|
571
|
+
await this.bot.sendMessage(message, { parseMode: 'Markdown' }, threadId);
|
|
572
|
+
logger.info('PreCompact notification sent', { sessionId: msg.sessionId, trigger });
|
|
573
|
+
}
|
|
574
|
+
async handleCompactComplete(sessionId) {
|
|
575
|
+
// Clear compacting state
|
|
576
|
+
this.compactingSessions.delete(sessionId);
|
|
577
|
+
const threadId = this.getSessionThreadId(sessionId);
|
|
578
|
+
await this.bot.sendMessage('✅ *Compaction complete*\n\n_Resuming session..._', { parseMode: 'Markdown' }, threadId);
|
|
579
|
+
logger.info('Compact complete notification sent', { sessionId });
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Stop the daemon
|
|
583
|
+
*/
|
|
584
|
+
async stop() {
|
|
585
|
+
if (!this.running)
|
|
586
|
+
return;
|
|
587
|
+
logger.info('Stopping bridge daemon...');
|
|
588
|
+
// Clear cleanup interval
|
|
589
|
+
if (this.cleanupInterval) {
|
|
590
|
+
clearInterval(this.cleanupInterval);
|
|
591
|
+
this.cleanupInterval = null;
|
|
592
|
+
}
|
|
593
|
+
// Send shutdown notification
|
|
594
|
+
try {
|
|
595
|
+
await this.bot.sendMessage('🔴 *Bridge Daemon Stopped*\n\n' +
|
|
596
|
+
'Session mirroring is now disabled.', { parseMode: 'Markdown' });
|
|
597
|
+
}
|
|
598
|
+
catch (error) {
|
|
599
|
+
logger.warn('Failed to send shutdown notification', { error });
|
|
600
|
+
}
|
|
601
|
+
// Stop components
|
|
602
|
+
await this.bot.stop();
|
|
603
|
+
await this.socket.close();
|
|
604
|
+
this.sessions.close();
|
|
605
|
+
this.running = false;
|
|
606
|
+
logger.info('Bridge daemon stopped');
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Check if daemon is running
|
|
610
|
+
*/
|
|
611
|
+
isRunning() {
|
|
612
|
+
return this.running;
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Get daemon status
|
|
616
|
+
*/
|
|
617
|
+
getStatus() {
|
|
618
|
+
return {
|
|
619
|
+
running: this.running,
|
|
620
|
+
clients: this.socket.getClientCount(),
|
|
621
|
+
sessions: this.sessions.getStats()
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
export default BridgeDaemon;
|
|
626
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../src/bridge/daemon.ts"],"names":[],"mappings":"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"}
|