@link-assistant/hive-mind 1.38.0 → 1.38.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/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/src/telegram-bot.mjs +37 -39
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
package/src/telegram-bot.mjs
CHANGED
|
@@ -558,25 +558,26 @@ function validateGitHubUrl(args, options = {}) {
|
|
|
558
558
|
return { valid: true, parsed, normalizedUrl: url };
|
|
559
559
|
}
|
|
560
560
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
*
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
561
|
+
// Issue #1460/#1497: safeReply - try Markdown first, fall back to plain text on parsing errors
|
|
562
|
+
async function safeReply(ctx, text, options = {}) {
|
|
563
|
+
try {
|
|
564
|
+
return await ctx.reply(text, { parse_mode: 'Markdown', ...options });
|
|
565
|
+
} catch (error) {
|
|
566
|
+
const isParsingError = error.message && (error.message.includes("can't parse entities") || error.message.includes("Can't parse entities") || error.message.includes("can't find end of") || (error.message.includes('Bad Request') && error.message.includes('400')));
|
|
567
|
+
if (!isParsingError) throw error;
|
|
568
|
+
console.error(`[telegram-bot] safeReply: Markdown parsing failed: ${error.message}`);
|
|
569
|
+
console.error(`[telegram-bot] safeReply: Failing message (${Buffer.byteLength(text, 'utf-8')} bytes): ${text}`);
|
|
570
|
+
const plainText = text
|
|
571
|
+
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1 ($2)')
|
|
572
|
+
.replace(/\\_/g, '_')
|
|
573
|
+
.replace(/\\\*/g, '*')
|
|
574
|
+
.replace(/\*([^*]+)\*/g, '$1')
|
|
575
|
+
.replace(/`([^`]+)`/g, '$1');
|
|
576
|
+
return await ctx.reply(plainText, { ...options, parse_mode: undefined });
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Execute a start-screen command and update the initial message with the result
|
|
580
581
|
async function executeAndUpdateMessage(ctx, startingMessage, commandName, args, infoBlock) {
|
|
581
582
|
const result = await executeStartScreen(commandName, args);
|
|
582
583
|
const { chat, message_id } = startingMessage;
|
|
@@ -914,8 +915,7 @@ async function handleSolveCommand(ctx) {
|
|
|
914
915
|
if (VERBOSE) {
|
|
915
916
|
console.log('[VERBOSE] Multiple GitHub URLs found in replied message');
|
|
916
917
|
}
|
|
917
|
-
await ctx
|
|
918
|
-
parse_mode: 'Markdown',
|
|
918
|
+
await safeReply(ctx, `❌ ${escapeMarkdown(extraction.error)}`, {
|
|
919
919
|
reply_to_message_id: ctx.message.message_id,
|
|
920
920
|
});
|
|
921
921
|
return;
|
|
@@ -931,7 +931,7 @@ async function handleSolveCommand(ctx) {
|
|
|
931
931
|
if (VERBOSE) {
|
|
932
932
|
console.log('[VERBOSE] No GitHub URL found in replied message');
|
|
933
933
|
}
|
|
934
|
-
await ctx
|
|
934
|
+
await safeReply(ctx, '❌ No GitHub issue/PR link found in the replied message.\n\nExample: Reply to a message containing a GitHub issue link with `/solve`\n\nOr with options: `/solve --model opus`', { reply_to_message_id: ctx.message.message_id });
|
|
935
935
|
return;
|
|
936
936
|
}
|
|
937
937
|
}
|
|
@@ -943,7 +943,7 @@ async function handleSolveCommand(ctx) {
|
|
|
943
943
|
errorMsg += `\n\n💡 Did you mean: \`${validation.suggestion}\``;
|
|
944
944
|
}
|
|
945
945
|
errorMsg += '\n\nExample: `/solve https://github.com/owner/repo/issues/123`\n\nOr reply to a message containing a GitHub link with `/solve`';
|
|
946
|
-
await ctx
|
|
946
|
+
await safeReply(ctx, errorMsg, { reply_to_message_id: ctx.message.message_id });
|
|
947
947
|
return;
|
|
948
948
|
}
|
|
949
949
|
|
|
@@ -963,19 +963,19 @@ async function handleSolveCommand(ctx) {
|
|
|
963
963
|
// Validate model name with helpful error message (before yargs validation)
|
|
964
964
|
const modelError = validateModelInArgs(args, solveTool);
|
|
965
965
|
if (modelError) {
|
|
966
|
-
await ctx
|
|
966
|
+
await safeReply(ctx, `❌ ${escapeMarkdown(modelError)}`, { reply_to_message_id: ctx.message.message_id });
|
|
967
967
|
return;
|
|
968
968
|
}
|
|
969
969
|
// Issue #1482: Validate --base-branch early to reject URLs and invalid branch names
|
|
970
970
|
const branchError = validateBranchInArgs(args);
|
|
971
971
|
if (branchError) {
|
|
972
|
-
await ctx
|
|
972
|
+
await safeReply(ctx, `❌ ${escapeMarkdown(branchError)}`, { reply_to_message_id: ctx.message.message_id });
|
|
973
973
|
return;
|
|
974
974
|
}
|
|
975
975
|
// Issue #1092: Detect malformed flag patterns like "-- model" (space after --)
|
|
976
976
|
const { malformed, errors: malformedErrors } = detectMalformedFlags(args);
|
|
977
977
|
if (malformed.length > 0) {
|
|
978
|
-
await ctx
|
|
978
|
+
await safeReply(ctx, `❌ ${escapeMarkdown(malformedErrors.join('\n'))}\n\nPlease check your option syntax.`, { reply_to_message_id: ctx.message.message_id });
|
|
979
979
|
return;
|
|
980
980
|
}
|
|
981
981
|
// Validate merged arguments using solve's yargs config
|
|
@@ -994,8 +994,7 @@ async function handleSolveCommand(ctx) {
|
|
|
994
994
|
|
|
995
995
|
testYargs.parse(args);
|
|
996
996
|
} catch (error) {
|
|
997
|
-
await ctx
|
|
998
|
-
parse_mode: 'Markdown',
|
|
997
|
+
await safeReply(ctx, `❌ Invalid options: ${escapeMarkdown(error.message || String(error))}\n\nUse /help to see available options`, {
|
|
999
998
|
reply_to_message_id: ctx.message.message_id,
|
|
1000
999
|
});
|
|
1001
1000
|
return;
|
|
@@ -1019,7 +1018,7 @@ async function handleSolveCommand(ctx) {
|
|
|
1019
1018
|
const existingItem = solveQueue.findByUrl(normalizedUrl);
|
|
1020
1019
|
if (existingItem) {
|
|
1021
1020
|
const statusText = existingItem.status === 'starting' || existingItem.status === 'started' ? 'being processed' : 'already in the queue';
|
|
1022
|
-
await ctx
|
|
1021
|
+
await safeReply(ctx, `❌ This URL is ${statusText}.\n\nURL: ${escapeMarkdown(normalizedUrl)}\nStatus: ${existingItem.status}\n\n💡 Use /solve\\_queue to check the queue status.`, { reply_to_message_id: ctx.message.message_id });
|
|
1023
1022
|
return;
|
|
1024
1023
|
}
|
|
1025
1024
|
|
|
@@ -1031,18 +1030,18 @@ async function handleSolveCommand(ctx) {
|
|
|
1031
1030
|
// their command cannot be processed (e.g., disk full, server maintenance pending).
|
|
1032
1031
|
// See: https://github.com/link-assistant/hive-mind/issues/1267
|
|
1033
1032
|
if (check.rejected) {
|
|
1034
|
-
await ctx
|
|
1033
|
+
await safeReply(ctx, `❌ Solve command rejected.\n\n${infoBlock}\n\n🚫 Reason: ${escapeMarkdown(check.rejectReason || 'Unknown')}`, { reply_to_message_id: ctx.message.message_id });
|
|
1035
1034
|
return;
|
|
1036
1035
|
}
|
|
1037
1036
|
|
|
1038
1037
|
if (check.canStart && queueStats.queued === 0) {
|
|
1039
|
-
const startingMessage = await ctx
|
|
1038
|
+
const startingMessage = await safeReply(ctx, `🚀 Starting solve command...\n\n${infoBlock}`, { reply_to_message_id: ctx.message.message_id });
|
|
1040
1039
|
await executeAndUpdateMessage(ctx, startingMessage, 'solve', args, infoBlock);
|
|
1041
1040
|
} else {
|
|
1042
1041
|
const queueItem = solveQueue.enqueue({ url: normalizedUrl, args, ctx, requester, infoBlock, tool: solveTool });
|
|
1043
1042
|
let queueMessage = `📋 Solve command queued (position #${queueStats.queued + 1})\n\n${infoBlock}`;
|
|
1044
|
-
if (check.reason) queueMessage += `\n\n⏳ Waiting: ${check.reason}`;
|
|
1045
|
-
const queuedMessage = await ctx
|
|
1043
|
+
if (check.reason) queueMessage += `\n\n⏳ Waiting: ${escapeMarkdown(check.reason)}`;
|
|
1044
|
+
const queuedMessage = await safeReply(ctx, queueMessage, { reply_to_message_id: ctx.message.message_id });
|
|
1046
1045
|
queueItem.messageInfo = { chatId: queuedMessage.chat.id, messageId: queuedMessage.message_id };
|
|
1047
1046
|
if (!solveQueue.executeCallback) solveQueue.executeCallback = createQueueExecuteCallback(executeStartScreen);
|
|
1048
1047
|
}
|
|
@@ -1122,7 +1121,7 @@ async function handleHiveCommand(ctx) {
|
|
|
1122
1121
|
let errorMsg = `❌ ${validation.error}`;
|
|
1123
1122
|
if (validation.suggestion) errorMsg += `\n\n💡 Did you mean: \`${escapeMarkdown(validation.suggestion)}\``;
|
|
1124
1123
|
errorMsg += '\n\nExample: `/hive https://github.com/owner/repo`';
|
|
1125
|
-
await ctx
|
|
1124
|
+
await safeReply(ctx, errorMsg, { reply_to_message_id: ctx.message.message_id });
|
|
1126
1125
|
return;
|
|
1127
1126
|
}
|
|
1128
1127
|
// Normalize issues_list/pulls_list to base repo URL, or use cleaned URL
|
|
@@ -1149,13 +1148,13 @@ async function handleHiveCommand(ctx) {
|
|
|
1149
1148
|
// Validate model name with helpful error message (before yargs validation)
|
|
1150
1149
|
const hiveModelError = validateModelInArgs(args, hiveTool);
|
|
1151
1150
|
if (hiveModelError) {
|
|
1152
|
-
await ctx
|
|
1151
|
+
await safeReply(ctx, `❌ ${escapeMarkdown(hiveModelError)}`, { reply_to_message_id: ctx.message.message_id });
|
|
1153
1152
|
return;
|
|
1154
1153
|
}
|
|
1155
1154
|
// Issue #1482: Validate branch flags early to reject URLs and invalid branch names
|
|
1156
1155
|
const hiveBranchError = validateBranchInArgs(args);
|
|
1157
1156
|
if (hiveBranchError) {
|
|
1158
|
-
await ctx
|
|
1157
|
+
await safeReply(ctx, `❌ ${escapeMarkdown(hiveBranchError)}`, { reply_to_message_id: ctx.message.message_id });
|
|
1159
1158
|
return;
|
|
1160
1159
|
}
|
|
1161
1160
|
|
|
@@ -1175,8 +1174,7 @@ async function handleHiveCommand(ctx) {
|
|
|
1175
1174
|
|
|
1176
1175
|
testYargs.parse(args);
|
|
1177
1176
|
} catch (error) {
|
|
1178
|
-
await ctx
|
|
1179
|
-
parse_mode: 'Markdown',
|
|
1177
|
+
await safeReply(ctx, `❌ Invalid options: ${escapeMarkdown(error.message || String(error))}\n\nUse /help to see available options`, {
|
|
1180
1178
|
reply_to_message_id: ctx.message.message_id,
|
|
1181
1179
|
});
|
|
1182
1180
|
return;
|
|
@@ -1193,7 +1191,7 @@ async function handleHiveCommand(ctx) {
|
|
|
1193
1191
|
infoBlock += `${userOptionsRaw ? '\n' : '\n\n'}🔒 Locked options: ${escapeMarkdown(hiveOverrides.join(' '))}`;
|
|
1194
1192
|
}
|
|
1195
1193
|
|
|
1196
|
-
const startingMessage = await ctx
|
|
1194
|
+
const startingMessage = await safeReply(ctx, `🚀 Starting hive command...\n\n${infoBlock}`, { reply_to_message_id: ctx.message.message_id });
|
|
1197
1195
|
await executeAndUpdateMessage(ctx, startingMessage, 'hive', args, infoBlock);
|
|
1198
1196
|
}
|
|
1199
1197
|
|