fixed telegram bug on not displaying things
This commit is contained in:
parent
f608aed3c2
commit
28d280d37a
|
|
@ -78,6 +78,105 @@ class TelegramChannel extends NotificationChannel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escape special characters for Telegram Markdown
|
||||||
|
* @param {string} text - Text to escape
|
||||||
|
* @returns {string} - Escaped text
|
||||||
|
*/
|
||||||
|
_escapeMarkdown(text) {
|
||||||
|
if (!text) return '';
|
||||||
|
// Minimal escaping to avoid message rejection
|
||||||
|
// Over-escaping causes Telegram to reject the message
|
||||||
|
return text
|
||||||
|
.replace(/\*/g, '\\*') // Escape asterisks
|
||||||
|
.replace(/_/g, '\\_') // Escape underscores
|
||||||
|
.replace(/\[/g, '\\[') // Escape square brackets
|
||||||
|
.replace(/\]/g, '\\]') // Escape square brackets
|
||||||
|
.replace(/`/g, '\\`'); // Escape backticks
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a safe plain text version without markdown formatting
|
||||||
|
* @param {string} text - Text to make safe
|
||||||
|
* @returns {string} - Safe text
|
||||||
|
*/
|
||||||
|
_createSafeText(text) {
|
||||||
|
if (!text) return '';
|
||||||
|
// Remove problematic characters entirely to ensure message sends
|
||||||
|
return text
|
||||||
|
.replace(/[_*\[\]()~`>#+=|{}.!\\-]/g, '') // Remove special chars
|
||||||
|
.replace(/\s+/g, ' ') // Collapse multiple spaces
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate message length including formatting
|
||||||
|
* @param {string} message - Message to calculate
|
||||||
|
* @returns {number} - Message length
|
||||||
|
*/
|
||||||
|
_calculateMessageLength(message) {
|
||||||
|
return message.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split long text into chunks that fit Telegram limits
|
||||||
|
* @param {string} text - Text to split
|
||||||
|
* @param {number} maxLength - Maximum length per chunk
|
||||||
|
* @returns {string[]} - Array of text chunks
|
||||||
|
*/
|
||||||
|
_splitTextIntoChunks(text, maxLength = 3000) {
|
||||||
|
if (text.length <= maxLength) {
|
||||||
|
return [text];
|
||||||
|
}
|
||||||
|
|
||||||
|
const chunks = [];
|
||||||
|
let currentChunk = '';
|
||||||
|
const lines = text.split('\n');
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
// If adding this line would exceed the limit
|
||||||
|
if (currentChunk.length + line.length + 1 > maxLength) {
|
||||||
|
if (currentChunk) {
|
||||||
|
chunks.push(currentChunk.trim());
|
||||||
|
currentChunk = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If single line is too long, split it by words
|
||||||
|
if (line.length > maxLength) {
|
||||||
|
const words = line.split(' ');
|
||||||
|
let wordChunk = '';
|
||||||
|
|
||||||
|
for (const word of words) {
|
||||||
|
if (wordChunk.length + word.length + 1 > maxLength) {
|
||||||
|
if (wordChunk) {
|
||||||
|
chunks.push(wordChunk.trim());
|
||||||
|
wordChunk = word;
|
||||||
|
} else {
|
||||||
|
// Single word is too long, truncate it
|
||||||
|
chunks.push(word.substring(0, maxLength - 3) + '...');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wordChunk += (wordChunk ? ' ' : '') + word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wordChunk) {
|
||||||
|
currentChunk = wordChunk;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentChunk = line;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentChunk += (currentChunk ? '\n' : '') + line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentChunk) {
|
||||||
|
chunks.push(currentChunk.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
async _getBotUsername() {
|
async _getBotUsername() {
|
||||||
if (this.botUsername) {
|
if (this.botUsername) {
|
||||||
return this.botUsername;
|
return this.botUsername;
|
||||||
|
|
@ -156,16 +255,100 @@ class TelegramChannel extends NotificationChannel {
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Log the message details for debugging
|
||||||
|
console.log(`[DEBUG] =====================================================`);
|
||||||
|
console.log(`[DEBUG] Sending Telegram message, length: ${messageText.length}`);
|
||||||
|
console.log(`[DEBUG] Chat ID: ${chatId}`);
|
||||||
|
console.log(`[DEBUG] Session ID: ${sessionId}`);
|
||||||
|
console.log(`[DEBUG] Message preview:`, messageText.substring(0, 200) + '...');
|
||||||
|
console.log(`[DEBUG] =====================================================`);
|
||||||
|
|
||||||
const response = await axios.post(
|
const response = await axios.post(
|
||||||
`${this.apiBaseUrl}/bot${this.config.botToken}/sendMessage`,
|
`${this.apiBaseUrl}/bot${this.config.botToken}/sendMessage`,
|
||||||
requestData,
|
requestData,
|
||||||
this._getNetworkOptions()
|
{
|
||||||
|
...this._getNetworkOptions(),
|
||||||
|
timeout: 15000 // 15 second timeout
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log(`[DEBUG] ✅ Telegram message sent successfully!`);
|
||||||
this.logger.info(`Telegram message sent successfully, Session: ${sessionId}`);
|
this.logger.info(`Telegram message sent successfully, Session: ${sessionId}`);
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error('Failed to send Telegram message:', error.response?.data || error.message);
|
// Enhanced error logging
|
||||||
|
const errorData = error.response?.data;
|
||||||
|
const errorMessage = errorData?.description || error.message;
|
||||||
|
const errorCode = errorData?.error_code;
|
||||||
|
|
||||||
|
console.log(`[DEBUG] ❌ Telegram send error occurred:`);
|
||||||
|
console.log(`[DEBUG] Error Code: ${errorCode}`);
|
||||||
|
console.log(`[DEBUG] Error Message: ${errorMessage}`);
|
||||||
|
console.log(`[DEBUG] Full error response:`, JSON.stringify(errorData, null, 2));
|
||||||
|
console.log(`[DEBUG] Original message length: ${messageText.length}`);
|
||||||
|
|
||||||
|
this.logger.error(`Failed to send Telegram message (${errorCode}): ${errorMessage}`);
|
||||||
|
|
||||||
|
// Try multiple fallback strategies
|
||||||
|
console.log(`[DEBUG] Attempting fallback strategies...`);
|
||||||
|
|
||||||
|
// Strategy 1: Try without parse_mode (plain text)
|
||||||
|
try {
|
||||||
|
console.log(`[DEBUG] Trying Strategy 1: Plain text without markdown`);
|
||||||
|
const plainTextMessage = this._generateMinimalMessage(notification, token,
|
||||||
|
notification.type === 'completed' ? '✅' : '⏳',
|
||||||
|
notification.type === 'completed' ? 'Completed' : 'Waiting');
|
||||||
|
|
||||||
|
await axios.post(
|
||||||
|
`${this.apiBaseUrl}/bot${this.config.botToken}/sendMessage`,
|
||||||
|
{
|
||||||
|
chat_id: chatId,
|
||||||
|
text: plainTextMessage,
|
||||||
|
reply_markup: {
|
||||||
|
inline_keyboard: buttons
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...this._getNetworkOptions(),
|
||||||
|
timeout: 15000
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`[DEBUG] ✅ Strategy 1 succeeded: Plain text message sent`);
|
||||||
|
this.logger.info(`Telegram plain text fallback message sent successfully, Session: ${sessionId}`);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (fallbackError1) {
|
||||||
|
console.log(`[DEBUG] ❌ Strategy 1 failed:`, fallbackError1.response?.data?.description || fallbackError1.message);
|
||||||
|
|
||||||
|
// Strategy 2: Try absolute minimal message without buttons
|
||||||
|
try {
|
||||||
|
console.log(`[DEBUG] Trying Strategy 2: Minimal message without buttons`);
|
||||||
|
const minimalMessage = `Claude Task Ready\\nToken: ${token}`;
|
||||||
|
|
||||||
|
await axios.post(
|
||||||
|
`${this.apiBaseUrl}/bot${this.config.botToken}/sendMessage`,
|
||||||
|
{
|
||||||
|
chat_id: chatId,
|
||||||
|
text: minimalMessage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...this._getNetworkOptions(),
|
||||||
|
timeout: 15000
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`[DEBUG] ✅ Strategy 2 succeeded: Minimal message sent`);
|
||||||
|
this.logger.info(`Telegram minimal fallback message sent successfully, Session: ${sessionId}`);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (fallbackError2) {
|
||||||
|
console.log(`[DEBUG] ❌ Strategy 2 failed:`, fallbackError2.response?.data?.description || fallbackError2.message);
|
||||||
|
console.log(`[DEBUG] ❌ All fallback strategies failed`);
|
||||||
|
this.logger.error('All Telegram fallback strategies failed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clean up failed session
|
// Clean up failed session
|
||||||
await this._removeSession(sessionId);
|
await this._removeSession(sessionId);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -177,35 +360,92 @@ class TelegramChannel extends NotificationChannel {
|
||||||
const emoji = type === 'completed' ? '✅' : '⏳';
|
const emoji = type === 'completed' ? '✅' : '⏳';
|
||||||
const status = type === 'completed' ? 'Completed' : 'Waiting for Input';
|
const status = type === 'completed' ? 'Completed' : 'Waiting for Input';
|
||||||
|
|
||||||
let messageText = `${emoji} *Claude Task ${status}*\n`;
|
try {
|
||||||
messageText += `*Project:* ${notification.project}\n`;
|
// Method 1: Try with minimal markdown formatting
|
||||||
messageText += `*Session Token:* \`${token}\`\n\n`;
|
let messageText = this._generateFormattedMessage(notification, token, emoji, status);
|
||||||
|
|
||||||
if (notification.metadata) {
|
if (messageText.length <= 4000) {
|
||||||
if (notification.metadata.userQuestion) {
|
console.log(`[DEBUG] Generated formatted message length: ${messageText.length}`);
|
||||||
messageText += `📝 *Your Question:*\n${notification.metadata.userQuestion.substring(0, 200)}`;
|
return messageText;
|
||||||
if (notification.metadata.userQuestion.length > 200) {
|
|
||||||
messageText += '...';
|
|
||||||
}
|
|
||||||
messageText += '\n\n';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notification.metadata.claudeResponse) {
|
// Method 2: If too long, try plain text version
|
||||||
messageText += `🤖 *Claude Response:*\n${notification.metadata.claudeResponse.substring(0, 300)}`;
|
console.log(`[DEBUG] Formatted message too long (${messageText.length}), trying plain text`);
|
||||||
if (notification.metadata.claudeResponse.length > 300) {
|
messageText = this._generatePlainTextMessage(notification, token, emoji, status);
|
||||||
messageText += '...';
|
|
||||||
}
|
if (messageText.length <= 4000) {
|
||||||
messageText += '\n\n';
|
console.log(`[DEBUG] Generated plain text message length: ${messageText.length}`);
|
||||||
|
return messageText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method 3: If still too long, use minimal fallback
|
||||||
|
console.log(`[DEBUG] Plain text still too long (${messageText.length}), using minimal fallback`);
|
||||||
|
return this._generateMinimalMessage(notification, token, emoji, status);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`[DEBUG] Error generating message: ${error.message}, using safe fallback`);
|
||||||
|
return this._generateMinimalMessage(notification, token, emoji, status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_generateFormattedMessage(notification, token, emoji, status) {
|
||||||
|
let messageText = `${emoji} *Claude Task ${status}*\n`;
|
||||||
|
messageText += `*Project:* ${notification.project || 'Unknown'}\n`;
|
||||||
|
messageText += `*Token:* \`${token}\`\n\n`;
|
||||||
|
|
||||||
|
// Add user question if available (limited length)
|
||||||
|
if (notification.metadata?.userQuestion) {
|
||||||
|
const question = notification.metadata.userQuestion.substring(0, 150);
|
||||||
|
messageText += `📝 *Question:* ${this._escapeMarkdown(question)}${question.length < notification.metadata.userQuestion.length ? '...' : ''}\n\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
messageText += `💬 *To send a new command:*\n`;
|
// Add Claude response if available (limited length)
|
||||||
messageText += `Reply with: \`/cmd ${token} <your command>\`\n`;
|
if (notification.metadata?.claudeResponse) {
|
||||||
messageText += `Example: \`/cmd ${token} Please analyze this code\``;
|
const maxResponseLength = 3000 - messageText.length - 200; // Reserve space for instructions
|
||||||
|
let response = notification.metadata.claudeResponse;
|
||||||
|
|
||||||
|
if (response.length > maxResponseLength) {
|
||||||
|
response = response.substring(0, maxResponseLength - 10) + '...';
|
||||||
|
}
|
||||||
|
|
||||||
|
messageText += `🤖 *Response:*\n${this._escapeMarkdown(response)}\n\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
messageText += `💬 Use: \`/cmd ${token} <command>\``;
|
||||||
return messageText;
|
return messageText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_generatePlainTextMessage(notification, token, emoji, status) {
|
||||||
|
let messageText = `${emoji} Claude Task ${status}\n`;
|
||||||
|
messageText += `Project: ${notification.project || 'Unknown'}\n`;
|
||||||
|
messageText += `Token: ${token}\n\n`;
|
||||||
|
|
||||||
|
// Add user question (plain text, limited)
|
||||||
|
if (notification.metadata?.userQuestion) {
|
||||||
|
const question = this._createSafeText(notification.metadata.userQuestion.substring(0, 150));
|
||||||
|
messageText += `Question: ${question}${question.length < notification.metadata.userQuestion.length ? '...' : ''}\n\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Claude response (plain text, limited)
|
||||||
|
if (notification.metadata?.claudeResponse) {
|
||||||
|
const maxResponseLength = 3000 - messageText.length - 100;
|
||||||
|
let response = this._createSafeText(notification.metadata.claudeResponse);
|
||||||
|
|
||||||
|
if (response.length > maxResponseLength) {
|
||||||
|
response = response.substring(0, maxResponseLength - 10) + '...';
|
||||||
|
}
|
||||||
|
|
||||||
|
messageText += `Response: ${response}\n\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
messageText += `Use: /cmd ${token} <command>`;
|
||||||
|
return messageText;
|
||||||
|
}
|
||||||
|
|
||||||
|
_generateMinimalMessage(notification, token, emoji, status) {
|
||||||
|
return `${emoji} Claude Task ${status}\nToken: ${token}\nUse: /cmd ${token} <command>`;
|
||||||
|
}
|
||||||
|
|
||||||
async _createSession(sessionId, notification, token) {
|
async _createSession(sessionId, notification, token) {
|
||||||
const session = {
|
const session = {
|
||||||
id: sessionId,
|
id: sessionId,
|
||||||
|
|
|
||||||
|
|
@ -817,5 +817,95 @@
|
||||||
"sessionId": "dbd1f477-0550-463b-b147-fcdf78720177",
|
"sessionId": "dbd1f477-0550-463b-b147-fcdf78720177",
|
||||||
"tmuxSession": "claude-session",
|
"tmuxSession": "claude-session",
|
||||||
"description": "completed - ecllipse"
|
"description": "completed - ecllipse"
|
||||||
|
},
|
||||||
|
"IS1F9FN9": {
|
||||||
|
"type": "pty",
|
||||||
|
"createdAt": 1756991169,
|
||||||
|
"expiresAt": 1757077569,
|
||||||
|
"cwd": "/home/lsamc/.local/src/Claude-Code-Remote",
|
||||||
|
"sessionId": "2fa9255d-eb9a-4b37-8852-8204d5730d42",
|
||||||
|
"tmuxSession": "claude-session",
|
||||||
|
"description": "completed - Claude-Code-Remote"
|
||||||
|
},
|
||||||
|
"CJRIHOH9": {
|
||||||
|
"type": "pty",
|
||||||
|
"createdAt": 1756991395,
|
||||||
|
"expiresAt": 1757077795,
|
||||||
|
"cwd": "/home/lsamc/develop/ecllipse",
|
||||||
|
"sessionId": "c5d96613-00de-459c-a8f0-52f020d135fc",
|
||||||
|
"tmuxSession": "claude-session",
|
||||||
|
"description": "completed - ecllipse"
|
||||||
|
},
|
||||||
|
"19318YCF": {
|
||||||
|
"type": "pty",
|
||||||
|
"createdAt": 1756991584,
|
||||||
|
"expiresAt": 1757077984,
|
||||||
|
"cwd": "/home/lsamc/develop/ecllipse",
|
||||||
|
"sessionId": "ffba11b1-0aaf-4639-ba4f-6db27249ae22",
|
||||||
|
"tmuxSession": "claude-session",
|
||||||
|
"description": "completed - ecllipse"
|
||||||
|
},
|
||||||
|
"KTP2NLKA": {
|
||||||
|
"type": "pty",
|
||||||
|
"createdAt": 1756991689,
|
||||||
|
"expiresAt": 1757078089,
|
||||||
|
"cwd": "/home/lsamc/develop/ecllipse",
|
||||||
|
"sessionId": "c4b49e6a-c4ca-446a-b28c-09863478c9fc",
|
||||||
|
"tmuxSession": "claude-session",
|
||||||
|
"description": "completed - ecllipse"
|
||||||
|
},
|
||||||
|
"3HB36PXA": {
|
||||||
|
"type": "pty",
|
||||||
|
"createdAt": 1756991822,
|
||||||
|
"expiresAt": 1757078222,
|
||||||
|
"cwd": "/home/lsamc/develop/ecllipse",
|
||||||
|
"sessionId": "9a14ee0e-cf2d-44f5-bec8-548853fc97e1",
|
||||||
|
"tmuxSession": "claude-session",
|
||||||
|
"description": "completed - ecllipse"
|
||||||
|
},
|
||||||
|
"WLR6CVMN": {
|
||||||
|
"type": "pty",
|
||||||
|
"createdAt": 1756991860,
|
||||||
|
"expiresAt": 1757078260,
|
||||||
|
"cwd": "/home/lsamc/.local/src/Claude-Code-Remote",
|
||||||
|
"sessionId": "22cd07f1-34c2-4f58-b470-d7e7d235a92b",
|
||||||
|
"tmuxSession": "claude-session",
|
||||||
|
"description": "completed - Claude-Code-Remote"
|
||||||
|
},
|
||||||
|
"634ZIJ55": {
|
||||||
|
"type": "pty",
|
||||||
|
"createdAt": 1756991894,
|
||||||
|
"expiresAt": 1757078294,
|
||||||
|
"cwd": "/home/lsamc/develop/ecllipse",
|
||||||
|
"sessionId": "7016be36-709a-48c5-8f64-2589aae4e5e9",
|
||||||
|
"tmuxSession": "claude-session",
|
||||||
|
"description": "completed - ecllipse"
|
||||||
|
},
|
||||||
|
"HG4Z82VG": {
|
||||||
|
"type": "pty",
|
||||||
|
"createdAt": 1756991984,
|
||||||
|
"expiresAt": 1757078384,
|
||||||
|
"cwd": "/home/lsamc/develop/ecllipse",
|
||||||
|
"sessionId": "c42a911c-2b47-4b41-8280-c62889ab2384",
|
||||||
|
"tmuxSession": "claude-session",
|
||||||
|
"description": "completed - ecllipse"
|
||||||
|
},
|
||||||
|
"OIO9DPTN": {
|
||||||
|
"type": "pty",
|
||||||
|
"createdAt": 1756992035,
|
||||||
|
"expiresAt": 1757078435,
|
||||||
|
"cwd": "/home/lsamc/develop/ecllipse",
|
||||||
|
"sessionId": "e29d64f2-19f5-4e5b-92c8-6bd1b766bc0d",
|
||||||
|
"tmuxSession": "claude-session",
|
||||||
|
"description": "completed - ecllipse"
|
||||||
|
},
|
||||||
|
"PWB2DEYR": {
|
||||||
|
"type": "pty",
|
||||||
|
"createdAt": 1756992167,
|
||||||
|
"expiresAt": 1757078567,
|
||||||
|
"cwd": "/home/lsamc/develop/ecllipse",
|
||||||
|
"sessionId": "197cd53a-4a64-42a9-8262-8e3b429f08b8",
|
||||||
|
"tmuxSession": "claude-session",
|
||||||
|
"description": "completed - ecllipse"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test script for extractConversation function fix
|
|
||||||
* Tests the improved response detection logic
|
|
||||||
*/
|
|
||||||
|
|
||||||
const TmuxMonitor = require('./src/utils/tmux-monitor');
|
|
||||||
|
|
||||||
// Create test tmux buffer content that mimics actual Claude Code output
|
|
||||||
const testBuffer1 = `
|
|
||||||
Welcome to Claude Code
|
|
||||||
? for shortcuts
|
|
||||||
───────────────────────────
|
|
||||||
|
|
||||||
> what does this project do?
|
|
||||||
|
|
||||||
I'll help you understand what this project does. Let me analyze the codebase structure first.
|
|
||||||
|
|
||||||
<function_calls>
|
|
||||||
<invoke name="Read">
|
|
||||||
<parameter name="file_path">/path/to/file.js
|
|
||||||
Loading…
Reference in New Issue