wierd one.

This commit is contained in:
lsamc 2025-09-05 15:22:53 +08:00
parent 28d280d37a
commit e91aeabdeb
18 changed files with 418 additions and 11 deletions

View File

@ -0,0 +1,9 @@
{
"permissions": {
"allow": [
"WebFetch(domain:github.com)"
],
"deny": [],
"ask": []
}
}

0
claude-hook-notify.js Executable file → Normal file
View File

0
claude-remote.js Executable file → Normal file
View File

0
fix-telegram.sh Executable file → Normal file
View File

0
setup-telegram.sh Executable file → Normal file
View File

View File

@ -254,6 +254,23 @@ class TelegramChannel extends NotificationChannel {
}
};
// Check if we need to use multi-message sending based on original response length
const fullResponse = notification.metadata?.claudeResponse || '';
const shouldUseMultiMessage = fullResponse.length > 1500; // Lower threshold for better experience
if (shouldUseMultiMessage) {
console.log(`[DEBUG] Using multi-message sending (original response: ${fullResponse.length} chars)`);
const success = await this._sendMultipleMessages(notification, sessionId, token, chatId, buttons);
if (!success) {
// Clean up failed session
await this._removeSession(sessionId);
}
return success;
}
// Use single message sending
console.log(`[DEBUG] Using single message sending (${messageText.length} chars)`);
try {
// Log the message details for debugging
console.log(`[DEBUG] =====================================================`);
@ -446,6 +463,229 @@ class TelegramChannel extends NotificationChannel {
return `${emoji} Claude Task ${status}\nToken: ${token}\nUse: /cmd ${token} <command>`;
}
/**
* Send multiple messages for long responses
* @param {Object} notification - Notification data
* @param {string} sessionId - Session ID
* @param {string} token - Session token
* @param {string} chatId - Telegram chat ID
* @param {Array} buttons - Inline keyboard buttons
* @returns {Promise<boolean>} - Success status
*/
async _sendMultipleMessages(notification, sessionId, token, chatId, buttons) {
const type = notification.type;
const emoji = type === 'completed' ? '✅' : '⏳';
const status = type === 'completed' ? 'Completed' : 'Waiting for Input';
try {
const fullResponse = notification.metadata?.claudeResponse || '';
const userQuestion = notification.metadata?.userQuestion || '';
console.log(`[DEBUG] Multi-message sending: Response length ${fullResponse.length} chars`);
// Split the response content into optimal chunks
const responseChunks = this._splitTextIntoChunks(fullResponse, 3200); // Slightly smaller for better formatting
const totalParts = Math.max(1, responseChunks.length);
console.log(`[DEBUG] Split response into ${totalParts} parts`);
// Create the first message with basic info
let firstMessage = `${emoji} *Claude Task ${status}* \\[1/${totalParts}\\]\n`;
firstMessage += `*Project:* ${this._escapeMarkdown(notification.project || 'Unknown')}\n`;
firstMessage += `*Token:* \`${token}\`\n\n`;
if (userQuestion) {
const question = userQuestion.substring(0, 150);
firstMessage += `📝 *Question:* ${this._escapeMarkdown(question)}${question.length < userQuestion.length ? '...' : ''}\n\n`;
}
// Add response header and first part
firstMessage += `🤖 *Claude Response:*\n`;
// Calculate space for first response part
const commandInstructions = `\n\n💬 *Commands:* \`/cmd ${token} <your command>\``;
const baseLength = firstMessage.length + commandInstructions.length;
const maxFirstResponseLength = 3800 - baseLength;
// Add first part of response
let firstResponsePart = '';
if (responseChunks.length > 0) {
firstResponsePart = responseChunks[0];
if (firstResponsePart.length > maxFirstResponseLength) {
// Further truncate first part if needed
firstResponsePart = firstResponsePart.substring(0, maxFirstResponseLength - 50) + '...';
}
}
firstMessage += this._escapeMarkdown(firstResponsePart);
// Add continuation indicator
if (totalParts > 1) {
firstMessage += `\n\n*\\[Continued in next message\\]*`;
}
firstMessage += commandInstructions;
// Send the first message
console.log(`[DEBUG] Sending first message (${firstMessage.length} chars)`);
const firstMessageResult = await this._sendSingleMessage(chatId, firstMessage, buttons, sessionId, 'Markdown');
if (!firstMessageResult.success) {
console.log(`[DEBUG] Failed to send first message, trying fallback`);
// Try plain text fallback for first message
const plainFirstMessage = firstMessage
.replace(/\*([^*]+)\*/g, '$1') // Remove bold
.replace(/\`([^`]+)\`/g, '$1') // Remove code
.replace(/\\(.)/g, '$1'); // Remove escapes
const fallbackResult = await this._sendSingleMessage(chatId, plainFirstMessage, buttons, sessionId, null);
if (!fallbackResult.success) {
return false;
}
}
const firstMessageId = firstMessageResult.messageId;
let successfulParts = 1;
// Send remaining parts
for (let i = 1; i < responseChunks.length; i++) {
const partNumber = i + 1;
let continuationMessage = `*\\[Part ${partNumber}/${totalParts}\\]*\n\n`;
continuationMessage += this._escapeMarkdown(responseChunks[i]);
console.log(`[DEBUG] Sending part ${partNumber}/${totalParts} (${continuationMessage.length} chars)`);
const success = await this._sendSingleMessage(
chatId,
continuationMessage,
null, // No buttons for continuation messages
sessionId,
'Markdown',
firstMessageId // Reply to first message to create thread
);
if (success.success) {
successfulParts++;
} else {
console.log(`[DEBUG] Failed to send part ${partNumber}/${totalParts}, trying plain text`);
// Try plain text fallback
const plainMessage = continuationMessage.replace(/\*([^*]+)\*/g, '$1').replace(/\\(.)/g, '$1');
const fallbackSuccess = await this._sendSingleMessage(
chatId, plainMessage, null, sessionId, null, firstMessageId
);
if (fallbackSuccess.success) {
successfulParts++;
}
}
// Add delay to prevent rate limiting
await new Promise(resolve => setTimeout(resolve, 800));
}
console.log(`[DEBUG] Multi-message sending completed: ${successfulParts}/${totalParts} parts sent successfully`);
// Send a final summary if not all parts were sent
if (successfulParts < totalParts) {
const summaryMessage = `⚠️ *Message Status:* ${successfulParts}/${totalParts} parts sent successfully\n\nSome parts may have been skipped due to formatting issues\\.`;
await this._sendSingleMessage(chatId, summaryMessage, null, sessionId, 'Markdown', firstMessageId);
}
return successfulParts > 0; // Success if at least first part was sent
} catch (error) {
console.log(`[DEBUG] Error in _sendMultipleMessages: ${error.message}`);
console.log(`[DEBUG] Stack trace:`, error.stack);
this.logger.error('Failed to send multiple messages:', error.message);
return false;
}
}
/**
* Send a single message with enhanced error handling
* @param {string} chatId - Telegram chat ID
* @param {string} messageText - Message text
* @param {Array} buttons - Inline keyboard buttons (optional)
* @param {string} sessionId - Session ID for logging
* @param {string} parseMode - Parse mode (optional)
* @param {number} replyToMessageId - Reply to message ID (optional)
* @returns {Promise<Object>} - {success: boolean, messageId: number}
*/
async _sendSingleMessage(chatId, messageText, buttons = null, sessionId = 'unknown', parseMode = null, replyToMessageId = null) {
const requestData = {
chat_id: chatId,
text: messageText
};
if (parseMode) {
requestData.parse_mode = parseMode;
}
if (buttons) {
requestData.reply_markup = {
inline_keyboard: buttons
};
}
if (replyToMessageId) {
requestData.reply_to_message_id = replyToMessageId;
}
try {
console.log(`[DEBUG] Sending message (${messageText.length} chars) to chat ${chatId}`);
const response = await axios.post(
`${this.apiBaseUrl}/bot${this.config.botToken}/sendMessage`,
requestData,
{
...this._getNetworkOptions(),
timeout: 15000
}
);
const messageId = response.data.result.message_id;
console.log(`[DEBUG] ✅ Message sent successfully, ID: ${messageId}`);
return { success: true, messageId: messageId };
} catch (error) {
const errorData = error.response?.data;
const errorMessage = errorData?.description || error.message;
const errorCode = errorData?.error_code;
console.log(`[DEBUG] ❌ Failed to send message: ${errorCode} - ${errorMessage}`);
// Try fallback without formatting
if (parseMode && errorCode === 400) {
console.log(`[DEBUG] Retrying without parse mode...`);
try {
const fallbackData = { ...requestData };
delete fallbackData.parse_mode;
fallbackData.text = this._createSafeText(messageText);
const fallbackResponse = await axios.post(
`${this.apiBaseUrl}/bot${this.config.botToken}/sendMessage`,
fallbackData,
{
...this._getNetworkOptions(),
timeout: 15000
}
);
const fallbackMessageId = fallbackResponse.data.result.message_id;
console.log(`[DEBUG] ✅ Fallback message sent successfully, ID: ${fallbackMessageId}`);
return { success: true, messageId: fallbackMessageId };
} catch (fallbackError) {
console.log(`[DEBUG] ❌ Fallback also failed: ${fallbackError.response?.data?.description || fallbackError.message}`);
}
}
return { success: false, messageId: null };
}
}
async _createSession(sessionId, notification, token) {
const session = {
id: sessionId,

0
src/daemon/taskping-daemon.js Executable file → Normal file
View File

View File

@ -907,5 +907,95 @@
"sessionId": "197cd53a-4a64-42a9-8262-8e3b429f08b8",
"tmuxSession": "claude-session",
"description": "completed - ecllipse"
},
"TJ5VIF92": {
"type": "pty",
"createdAt": 1756992584,
"expiresAt": 1757078984,
"cwd": "/home/lsamc/.local/src/Claude-Code-Remote",
"sessionId": "019ab1c3-bde2-4d00-b21e-23167fe52c16",
"tmuxSession": "claude-session",
"description": "completed - Claude-Code-Remote"
},
"J56R0D84": {
"type": "pty",
"createdAt": 1757031172,
"expiresAt": 1757117572,
"cwd": "/home/lsamc/.local/src/Claude-Code-Remote",
"sessionId": "cb99ffc3-ee1f-44be-9438-666e9b7fcd54",
"tmuxSession": "claude-session",
"description": "completed - Claude-Code-Remote"
},
"2A26K43N": {
"type": "pty",
"createdAt": 1757031544,
"expiresAt": 1757117944,
"cwd": "/home/lsamc/.local/src/Claude-Code-Remote",
"sessionId": "f930e41f-eb86-49d0-85ab-2fcc06aa27e9",
"tmuxSession": "claude-session",
"description": "completed - Claude-Code-Remote"
},
"30W8P8Y1": {
"type": "pty",
"createdAt": 1757031609,
"expiresAt": 1757118009,
"cwd": "/home/lsamc/develop/ecllipse",
"sessionId": "945a07d5-5403-433e-8f90-951e639e0c0c",
"tmuxSession": "claude-session",
"description": "completed - ecllipse"
},
"ZNE082NM": {
"type": "pty",
"createdAt": 1757031634,
"expiresAt": 1757118034,
"cwd": "/home/lsamc/develop/ecllipse",
"sessionId": "c30b0f1f-1d4f-438f-a7c8-81fb9d8ddd7c",
"tmuxSession": "claude-session",
"description": "completed - ecllipse"
},
"G73CZLO4": {
"type": "pty",
"createdAt": 1757031693,
"expiresAt": 1757118093,
"cwd": "/home/lsamc/develop/ecllipse",
"sessionId": "c4d9c060-83f4-4fc1-b83a-41e3045df66a",
"tmuxSession": "claude-session",
"description": "completed - ecllipse"
},
"6GAO026F": {
"type": "pty",
"createdAt": 1757031822,
"expiresAt": 1757118222,
"cwd": "/home/lsamc/develop/ecllipse",
"sessionId": "6feee05d-cdf5-41ab-9eb7-3e2b39be97cd",
"tmuxSession": "claude-session",
"description": "completed - ecllipse"
},
"0ZDCUMDH": {
"type": "pty",
"createdAt": 1757031847,
"expiresAt": 1757118247,
"cwd": "/home/lsamc/.local/src/Claude-Code-Remote",
"sessionId": "6b330566-d096-4862-9afe-aa32e038e9e9",
"tmuxSession": "claude-session",
"description": "completed - Claude-Code-Remote"
},
"RJMOLNH2": {
"type": "pty",
"createdAt": 1757032064,
"expiresAt": 1757118464,
"cwd": "/home/lsamc/.local/src/Claude-Code-Remote",
"sessionId": "f394b1b0-9ea2-4106-b27a-75842319ed31",
"tmuxSession": "claude-session",
"description": "completed - Claude-Code-Remote"
},
"E1E1RJD2": {
"type": "pty",
"createdAt": 1757032743,
"expiresAt": 1757119143,
"cwd": "/home/lsamc/.local/src/Claude-Code-Remote",
"sessionId": "f0acac1d-9b96-4baa-8622-cb030c300767",
"tmuxSession": "claude-session",
"description": "completed - Claude-Code-Remote"
}
}

View File

@ -613,6 +613,12 @@ class TmuxMonitor extends EventEmitter {
console.log(`[DEBUG] Total lines in buffer: ${lines.length}`);
console.log(`[DEBUG] Last 5 lines:`, lines.slice(-5));
// Save full buffer for debugging (first 50 and last 50 lines)
if (lines.length > 10) {
console.log(`[DEBUG] Buffer preview - First 10 lines:`, lines.slice(0, 10));
console.log(`[DEBUG] Buffer preview - Last 10 lines:`, lines.slice(-10));
}
let userQuestion = '';
let claudeResponse = '';
let responseLines = [];
@ -636,13 +642,17 @@ class TmuxMonitor extends EventEmitter {
for (let i = lastUserIndex + 1; i < lines.length; i++) {
const line = lines[i].trim();
// Skip empty lines and system lines
// Skip empty lines and system lines, but be more selective
if (!line ||
line.includes('? for shortcuts') ||
line.match(/^[╭╰│─]+$/) ||
line.startsWith('$') ||
line.startsWith('#') ||
line.startsWith('[')) {
line.match(/^\[.*\]$/) || // System messages in brackets
line.includes('(esc to interrupt)') || // Claude Code interrupt message
line.match(/^\+\s*Cascading/) || // Cascading status message
line.match(/^_{3,}$/)) { // Multiple underscores (display artifacts)
console.log(`[DEBUG] Skipping system line: ${line}`);
continue;
}
@ -664,29 +674,87 @@ class TmuxMonitor extends EventEmitter {
responseLines = [line.startsWith('⏺ ') ? line.substring(2).trim() : line];
console.log(`[DEBUG] Found response start at line ${i}: ${line}`);
} else if (foundResponseStart) {
// Stop if we hit another user input or prompt
if (line.startsWith('> ') || line.includes('│ > │') || line.startsWith('╭')) {
console.log(`[DEBUG] Stopping response collection at line ${i}: ${line}`);
// Only stop for clear prompt indicators, not for special characters or formatting
if (line.startsWith('> ') && line.length > 2) { // New user input
console.log(`[DEBUG] Stopping response collection at new user input: ${line}`);
break;
}
// Stop at command prompt box start (new interaction)
if (line.startsWith('╭') && line.includes('─')) {
console.log(`[DEBUG] Stopping response collection at prompt box: ${line}`);
break;
}
// Continue collecting response, ignoring formatting artifacts
responseLines.push(line);
console.log(`[DEBUG] Added response line ${responseLines.length}: ${line.substring(0, 50)}...`);
}
}
}
// Fallback: Look for any Claude response pattern in the last 20 lines
// Fallback: Look for any Claude response pattern in a larger range
if (responseLines.length === 0) {
console.log(`[DEBUG] No response found after user input, trying fallback method`);
const recentLines = lines.slice(-20);
const recentLines = lines.slice(-40); // Increased range
let inFallbackResponse = false;
for (let i = 0; i < recentLines.length; i++) {
const line = recentLines[i].trim();
if (line.startsWith('⏺ ') ||
(line.length > 10 && !line.startsWith('> ') && !line.includes('? for shortcuts'))) {
responseLines.push(line.startsWith('⏺ ') ? line.substring(2).trim() : line);
console.log(`[DEBUG] Fallback found response line: ${line}`);
// Skip problematic lines even in fallback
if (!line ||
line.includes('(esc to interrupt)') ||
line.match(/^\+\s*Cascading/) ||
line.match(/^_{3,}$/) ||
line.includes('? for shortcuts')) {
continue;
}
// Look for Claude response indicators
if (line.startsWith('⏺ ') ||
(line.length > 5 &&
!line.startsWith('> ') &&
!line.startsWith('$') &&
!line.startsWith('#') &&
!line.match(/^\[.*\]$/))) {
const cleanLine = line.startsWith('⏺ ') ? line.substring(2).trim() : line;
responseLines.push(cleanLine);
inFallbackResponse = true;
console.log(`[DEBUG] Fallback found response line: ${cleanLine.substring(0, 50)}...`);
} else if (inFallbackResponse && line.length > 0) {
// Continue collecting if we're in a response and line isn't a clear break
responseLines.push(line);
console.log(`[DEBUG] Fallback continued response: ${line.substring(0, 50)}...`);
}
}
}
// Super fallback: Get any meaningful content if still empty
if (responseLines.length === 0) {
console.log(`[DEBUG] Still no response, trying super fallback - scanning all meaningful lines`);
const meaningfulLines = [];
for (let i = Math.max(0, lastUserIndex + 1); i < lines.length; i++) {
const line = lines[i].trim();
// Collect any line that seems like content (not system/formatting)
if (line.length > 5 &&
!line.includes('? for shortcuts') &&
!line.match(/^[╭╰│─\s]+$/) &&
!line.includes('(esc to interrupt)') &&
!line.match(/^\+\s*Cascading/) &&
!line.match(/^_{3,}$/) &&
!line.startsWith('> ') &&
!line.startsWith('$') &&
!line.startsWith('#')) {
meaningfulLines.push(line);
}
}
if (meaningfulLines.length > 0) {
responseLines = meaningfulLines;
console.log(`[DEBUG] Super fallback collected ${meaningfulLines.length} meaningful lines`);
}
}

0
start-all-webhooks.js Executable file → Normal file
View File

0
start-line-webhook.js Executable file → Normal file
View File

0
start-relay-pty.js Executable file → Normal file
View File

0
start-telegram-webhook.js Executable file → Normal file
View File

0
test-complete-flow.sh Executable file → Normal file
View File

0
test-injection.js Executable file → Normal file
View File

0
test-long-email.js Executable file → Normal file
View File

0
test-telegram-notification.js Executable file → Normal file
View File

0
test-telegram-setup.sh Executable file → Normal file
View File