@link-assistant/hive-mind 2.12.0 → 2.12.2
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 +14 -0
- package/package.json +4 -1
- package/src/claude.connection.lib.mjs +209 -0
- package/src/claude.lib.mjs +6 -202
- package/src/codex.lib.mjs +0 -128
- package/src/github-rate-limit.lib.mjs +3 -0
- package/src/github-url-parser.lib.mjs +255 -0
- package/src/github.lib.mjs +22 -343
- package/src/hive.mjs +0 -152
- package/src/interactive-mode.lib.mjs +0 -43
- package/src/isolation-runner.lib.mjs +14 -174
- package/src/limits.lib.mjs +0 -89
- package/src/models/index.mjs +0 -15
- package/src/session-monitor.lib.mjs +14 -172
- package/src/solve.auto-merge.lib.mjs +70 -164
- package/src/solve.mjs +31 -193
- package/src/solve.repository.lib.mjs +0 -83
- package/src/solve.results.lib.mjs +0 -90
- package/src/solve.session.lib.mjs +52 -19
- package/src/solve.tool-uncommitted.lib.mjs +22 -0
- package/src/telegram-bot.mjs +0 -66
- package/src/telegram-merge-queue.lib.mjs +3 -155
- package/src/telegram-solve-queue.lib.mjs +9 -168
- package/src/use-m-bootstrap.lib.mjs +6 -5
- package/src/use-with-retry.lib.mjs +128 -2
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
* @module interactive-mode.lib.mjs
|
|
34
34
|
* @experimental
|
|
35
35
|
*/
|
|
36
|
-
|
|
37
36
|
import { CONFIG, createCollapsible, createRawJsonSection, createRedactedRawJsonSection, escapeMarkdown, execFileAsync, formatCost, formatDuration, getToolIcon, safeJsonStringify, sanitizeUnicode, truncateMiddle } from './interactive-mode.shared.lib.mjs';
|
|
38
37
|
import { createCodexEventHandlers } from './interactive-codex-events.lib.mjs';
|
|
39
38
|
import { createSystemLifecycleHandlers } from './interactive-system-events.lib.mjs';
|
|
@@ -116,7 +115,6 @@ export const createInteractiveHandler = options => {
|
|
|
116
115
|
editsSucceeded: 0,
|
|
117
116
|
editsFailed: 0,
|
|
118
117
|
};
|
|
119
|
-
|
|
120
118
|
const imageRenderer = createImageRenderer({ owner, repo, prNumber, mediaRef, log, verbose, execFile: execFileFn, enabled: imageUploadEnabled, uploader: injectedImageUploader, state }); // Issue #1843
|
|
121
119
|
|
|
122
120
|
/**
|
|
@@ -141,7 +139,6 @@ export const createInteractiveHandler = options => {
|
|
|
141
139
|
await log(`⚠️ Interactive mode: getAllKnownLocalTokens failed: ${err.message}`, { verbose: true });
|
|
142
140
|
}
|
|
143
141
|
}
|
|
144
|
-
|
|
145
142
|
let hits;
|
|
146
143
|
try {
|
|
147
144
|
hits = await containsKnownToken(body, knownTokens);
|
|
@@ -177,7 +174,6 @@ export const createInteractiveHandler = options => {
|
|
|
177
174
|
throw error;
|
|
178
175
|
}
|
|
179
176
|
};
|
|
180
|
-
|
|
181
177
|
/**
|
|
182
178
|
* Post a comment to the PR (with rate limiting)
|
|
183
179
|
* @param {string} body - Comment body
|
|
@@ -201,7 +197,6 @@ export const createInteractiveHandler = options => {
|
|
|
201
197
|
|
|
202
198
|
const now = Date.now();
|
|
203
199
|
const timeSinceLastComment = now - state.lastCommentTime;
|
|
204
|
-
|
|
205
200
|
if (timeSinceLastComment < CONFIG.MIN_COMMENT_INTERVAL) {
|
|
206
201
|
// Queue the comment for later with toolId/taskId for tracking
|
|
207
202
|
state.commentQueue.push({ body: safeBody, toolId, taskId, onPosted });
|
|
@@ -240,7 +235,6 @@ export const createInteractiveHandler = options => {
|
|
|
240
235
|
// set so --auto-attach-solution-summary correctly excludes it from the
|
|
241
236
|
// AI-authored-comment check. Tracking is a no-op when commentId is null.
|
|
242
237
|
trackToolCommentId(commentId);
|
|
243
|
-
|
|
244
238
|
if (commentId && typeof onPosted === 'function') {
|
|
245
239
|
try {
|
|
246
240
|
await onPosted(commentId);
|
|
@@ -277,7 +271,6 @@ export const createInteractiveHandler = options => {
|
|
|
277
271
|
}
|
|
278
272
|
return false;
|
|
279
273
|
}
|
|
280
|
-
|
|
281
274
|
// Issue #1745: sanitize before sending. editComment is the path that
|
|
282
275
|
// leaked TELEGRAM_BOT_TOKEN in xlab2016/space_db_private#20.
|
|
283
276
|
const safeBody = await sanitizeAndWarn(body);
|
|
@@ -317,7 +310,6 @@ export const createInteractiveHandler = options => {
|
|
|
317
310
|
}
|
|
318
311
|
|
|
319
312
|
state.isProcessing = true;
|
|
320
|
-
|
|
321
313
|
while (state.commentQueue.length > 0) {
|
|
322
314
|
const now = Date.now();
|
|
323
315
|
const timeSinceLastComment = now - state.lastCommentTime;
|
|
@@ -332,7 +324,6 @@ export const createInteractiveHandler = options => {
|
|
|
332
324
|
const { body, toolId, taskId, onPosted } = queueItem;
|
|
333
325
|
// Post the comment (don't pass toolId/taskId to avoid re-queueing)
|
|
334
326
|
const commentId = await postComment(body, null, null, onPosted);
|
|
335
|
-
|
|
336
327
|
// If this was a tool use comment, update the pending call with the comment ID
|
|
337
328
|
if (toolId && commentId) {
|
|
338
329
|
const pendingCall = state.pendingToolCalls.get(toolId);
|
|
@@ -388,7 +379,6 @@ export const createInteractiveHandler = options => {
|
|
|
388
379
|
}
|
|
389
380
|
return;
|
|
390
381
|
}
|
|
391
|
-
|
|
392
382
|
state.sessionId = data.session_id;
|
|
393
383
|
state.startTime = Date.now();
|
|
394
384
|
|
|
@@ -400,7 +390,6 @@ export const createInteractiveHandler = options => {
|
|
|
400
390
|
const mcpServersList = formatInteractiveMcpServersList(mcpServers);
|
|
401
391
|
const mcpDiagnostics = getInteractiveMcpDiagnostics(mcpServers, tools);
|
|
402
392
|
const mcpDiagnosticsBlock = mcpDiagnostics.length > 0 ? `\n${mcpDiagnostics.map(message => `> ${message}`).join('\n')}\n` : '';
|
|
403
|
-
|
|
404
393
|
// Format slash commands
|
|
405
394
|
const slashCommands = data.slash_commands || [];
|
|
406
395
|
const slashCommandsList = slashCommands.length > 0 ? slashCommands.map(c => `\`/${c}\``).join(', ') : '_None_';
|
|
@@ -429,7 +418,6 @@ ${mcpDiagnosticsBlock}
|
|
|
429
418
|
${createRawJsonSection(data)}`;
|
|
430
419
|
|
|
431
420
|
await postComment(comment);
|
|
432
|
-
|
|
433
421
|
if (verbose) {
|
|
434
422
|
await log(`🔌 Interactive mode: Session initialized (${state.sessionId})`, { verbose: true });
|
|
435
423
|
}
|
|
@@ -458,7 +446,6 @@ ${createRawJsonSection(data)}`;
|
|
|
458
446
|
${createRawJsonSection(data)}`;
|
|
459
447
|
|
|
460
448
|
await postComment(comment);
|
|
461
|
-
|
|
462
449
|
if (verbose) {
|
|
463
450
|
await log(`💬 Interactive mode: Assistant text (${text.length} chars)`, { verbose: true });
|
|
464
451
|
}
|
|
@@ -478,7 +465,6 @@ ${createRawJsonSection(data)}`;
|
|
|
478
465
|
|
|
479
466
|
// Register this tool use for potential standalone result rendering
|
|
480
467
|
state.toolUseRegistry.set(toolId, { toolName, toolIcon });
|
|
481
|
-
|
|
482
468
|
// Format tool input based on tool type
|
|
483
469
|
let inputDisplay;
|
|
484
470
|
const input = toolUse.input || {};
|
|
@@ -548,7 +534,6 @@ ${createRawJsonSection(data)}`;
|
|
|
548
534
|
const KEEP_START = 15;
|
|
549
535
|
const KEEP_END = 15;
|
|
550
536
|
const skipped = todos.length - KEEP_START - KEEP_END;
|
|
551
|
-
|
|
552
537
|
const startTodos = todos.slice(0, KEEP_START).map(t => `- [${t.status === 'completed' ? 'x' : ' '}] ${t.content}`);
|
|
553
538
|
const endTodos = todos.slice(-KEEP_END).map(t => `- [${t.status === 'completed' ? 'x' : ' '}] ${t.content}`);
|
|
554
539
|
|
|
@@ -605,7 +590,6 @@ ${createRawJsonSection(data)}`;
|
|
|
605
590
|
toolName,
|
|
606
591
|
toolIcon,
|
|
607
592
|
});
|
|
608
|
-
|
|
609
593
|
// Post the comment, passing toolId for queue tracking
|
|
610
594
|
const commentId = await postComment(comment, toolId);
|
|
611
595
|
|
|
@@ -633,7 +617,6 @@ ${createRawJsonSection(data)}`;
|
|
|
633
617
|
*/
|
|
634
618
|
const handleToolResult = async (data, toolResult) => {
|
|
635
619
|
state.toolResultCount++;
|
|
636
|
-
|
|
637
620
|
const toolUseId = toolResult.tool_use_id || 'unknown';
|
|
638
621
|
const isError = toolResult.is_error || false;
|
|
639
622
|
const statusIcon = isError ? '❌' : '✅';
|
|
@@ -661,7 +644,6 @@ ${createRawJsonSection(data)}`;
|
|
|
661
644
|
keepStart: 25,
|
|
662
645
|
keepEnd: 25,
|
|
663
646
|
});
|
|
664
|
-
|
|
665
647
|
// Issue #1843: render images this result read/produced (used by both paths).
|
|
666
648
|
const imagesSection = await imageRenderer.section([toolResult.content, data.tool_use_result], imageRenderer.toolLabel(toolUseId));
|
|
667
649
|
const imagesBlock = imagesSection ? `${imagesSection}\n\n` : '';
|
|
@@ -693,7 +675,6 @@ ${createRawJsonSection(data)}`;
|
|
|
693
675
|
await processQueue();
|
|
694
676
|
state.isProcessing = wasProcessing;
|
|
695
677
|
}
|
|
696
|
-
|
|
697
678
|
// Check again after queue flush
|
|
698
679
|
commentId = pendingCall.commentId;
|
|
699
680
|
|
|
@@ -716,7 +697,6 @@ ${createRawJsonSection(data)}`;
|
|
|
716
697
|
}
|
|
717
698
|
}
|
|
718
699
|
}
|
|
719
|
-
|
|
720
700
|
if (commentId) {
|
|
721
701
|
// Create merged comment with both call and result
|
|
722
702
|
const mergedComment = `## ${toolIcon} ${toolName} tool use
|
|
@@ -748,7 +728,6 @@ ${createRedactedRawJsonSection([toolData, data])}`;
|
|
|
748
728
|
});
|
|
749
729
|
}
|
|
750
730
|
}
|
|
751
|
-
|
|
752
731
|
// Clean up the pending call since we're posting separately
|
|
753
732
|
state.pendingToolCalls.delete(toolUseId);
|
|
754
733
|
}
|
|
@@ -769,7 +748,6 @@ ${imagesBlock}---
|
|
|
769
748
|
${createRedactedRawJsonSection(data)}`;
|
|
770
749
|
|
|
771
750
|
await postComment(comment);
|
|
772
|
-
|
|
773
751
|
if (verbose) {
|
|
774
752
|
const contentLength = content.length;
|
|
775
753
|
await log(`📋 Interactive mode: Tool result posted as separate comment (${contentLength} chars)`, {
|
|
@@ -799,7 +777,6 @@ ${createRedactedRawJsonSection(data)}`;
|
|
|
799
777
|
let statsTable = '| Metric | Value |\n|--------|-------|\n';
|
|
800
778
|
statsTable += `| **Status** | ${statusText} |\n`;
|
|
801
779
|
statsTable += `| **Session ID** | \`${data.session_id || 'unknown'}\` |\n`;
|
|
802
|
-
|
|
803
780
|
if (data.duration_ms) {
|
|
804
781
|
statsTable += `| **Duration** | ${formatDuration(data.duration_ms)} |\n`;
|
|
805
782
|
}
|
|
@@ -856,7 +833,6 @@ ${createRawJsonSection(data)}`;
|
|
|
856
833
|
await log(`🏁 Interactive mode: Session ${statusText.toLowerCase()}`, { verbose: true });
|
|
857
834
|
}
|
|
858
835
|
};
|
|
859
|
-
|
|
860
836
|
/**
|
|
861
837
|
* Handle system.task_started event (Agent subtask started)
|
|
862
838
|
* Creates a progress comment that will be updated by task_progress events
|
|
@@ -895,7 +871,6 @@ ${promptSection}
|
|
|
895
871
|
---
|
|
896
872
|
|
|
897
873
|
${createRawJsonSection(data)}`;
|
|
898
|
-
|
|
899
874
|
// Track this task BEFORE posting
|
|
900
875
|
state.pendingTasks.set(taskId, {
|
|
901
876
|
commentId: null,
|
|
@@ -923,7 +898,6 @@ ${createRawJsonSection(data)}`;
|
|
|
923
898
|
await log(`🤖 Interactive mode: Agent task started - ${description} (task: ${taskId})`, { verbose: true });
|
|
924
899
|
}
|
|
925
900
|
};
|
|
926
|
-
|
|
927
901
|
/**
|
|
928
902
|
* Handle system.task_progress event (Agent subtask progress update)
|
|
929
903
|
* Updates the existing task comment instead of creating a new one
|
|
@@ -941,7 +915,6 @@ ${createRawJsonSection(data)}`;
|
|
|
941
915
|
pendingTask.progressCount++;
|
|
942
916
|
pendingTask.lastProgressDescription = description;
|
|
943
917
|
pendingTask.allEvents.push(data);
|
|
944
|
-
|
|
945
918
|
let commentId = pendingTask.commentId;
|
|
946
919
|
|
|
947
920
|
// Wait for comment ID if not yet available — flush queue first to avoid timeout
|
|
@@ -969,7 +942,6 @@ ${createRawJsonSection(data)}`;
|
|
|
969
942
|
return `- 🔀 ${agentTag} ${toolIcon} ${e.description || 'Working...'}`;
|
|
970
943
|
})
|
|
971
944
|
.join('\n');
|
|
972
|
-
|
|
973
945
|
const durationText = usage.duration_ms ? formatDuration(usage.duration_ms) : '';
|
|
974
946
|
const toolUsesText = usage.tool_uses ? `${usage.tool_uses} tool calls` : '';
|
|
975
947
|
const statsText = [durationText, toolUsesText].filter(Boolean).join(' | ');
|
|
@@ -1003,7 +975,6 @@ ${createRawJsonSection(pendingTask.allEvents.slice(-3))}`;
|
|
|
1003
975
|
await log(`🤖 Interactive mode: Task progress - ${description} (task: ${taskId}, tool: ${lastToolName})`, { verbose: true });
|
|
1004
976
|
}
|
|
1005
977
|
};
|
|
1006
|
-
|
|
1007
978
|
/**
|
|
1008
979
|
* Handle system.task_notification event (Agent subtask completed/failed)
|
|
1009
980
|
* Updates the existing task comment with final status
|
|
@@ -1024,7 +995,6 @@ ${createRawJsonSection(pendingTask.allEvents.slice(-3))}`;
|
|
|
1024
995
|
pendingTask.allEvents.push(data);
|
|
1025
996
|
|
|
1026
997
|
let commentId = pendingTask.commentId;
|
|
1027
|
-
|
|
1028
998
|
// Wait for comment ID if not yet available — flush queue first to avoid timeout
|
|
1029
999
|
if (!commentId && pendingTask.commentIdPromise) {
|
|
1030
1000
|
if (state.commentQueue.length > 0) {
|
|
@@ -1055,7 +1025,6 @@ ${createRawJsonSection(pendingTask.allEvents.slice(-3))}`;
|
|
|
1055
1025
|
const toolUsesText = usage.tool_uses ? `${usage.tool_uses} tool calls` : '';
|
|
1056
1026
|
const tokensText = usage.total_tokens ? `${usage.total_tokens.toLocaleString()} tokens` : '';
|
|
1057
1027
|
const statsText = [durationText, toolUsesText, tokensText].filter(Boolean).join(' | ');
|
|
1058
|
-
|
|
1059
1028
|
const updatedComment = `## 🤖🔀 Agent task: ${escapeMarkdown(pendingTask.description)}
|
|
1060
1029
|
|
|
1061
1030
|
| Property | Value |
|
|
@@ -1070,7 +1039,6 @@ ${progressSteps ? createCollapsible(`📋 Progress steps (${pendingTask.progress
|
|
|
1070
1039
|
---
|
|
1071
1040
|
|
|
1072
1041
|
${createRawJsonSection([pendingTask.allEvents[0], data])}`;
|
|
1073
|
-
|
|
1074
1042
|
await editComment(commentId, updatedComment);
|
|
1075
1043
|
}
|
|
1076
1044
|
|
|
@@ -1098,7 +1066,6 @@ ${createRawJsonSection(data)}`;
|
|
|
1098
1066
|
});
|
|
1099
1067
|
}
|
|
1100
1068
|
};
|
|
1101
|
-
|
|
1102
1069
|
const { handleThinkingTokens, finalizeThinkingGroup, handleSystemStatus, handleCompactBoundary, handleTaskUpdated } = createSystemLifecycleHandlers({
|
|
1103
1070
|
state,
|
|
1104
1071
|
owner,
|
|
@@ -1131,7 +1098,6 @@ ${createRawJsonSection(data)}`;
|
|
|
1131
1098
|
handleAssistantText,
|
|
1132
1099
|
imageRenderer,
|
|
1133
1100
|
});
|
|
1134
|
-
|
|
1135
1101
|
/**
|
|
1136
1102
|
* Handle unrecognized event types
|
|
1137
1103
|
* @param {Object} data - Event data
|
|
@@ -1145,7 +1111,6 @@ ${createRawJsonSection(data)}`;
|
|
|
1145
1111
|
This event type is not yet supported by interactive mode.
|
|
1146
1112
|
|
|
1147
1113
|
${createRawJsonSection(data)}`;
|
|
1148
|
-
|
|
1149
1114
|
await postComment(comment);
|
|
1150
1115
|
|
|
1151
1116
|
if (verbose) {
|
|
@@ -1164,7 +1129,6 @@ ${createRawJsonSection(data)}`;
|
|
|
1164
1129
|
return;
|
|
1165
1130
|
}
|
|
1166
1131
|
state.eventsProcessed++;
|
|
1167
|
-
|
|
1168
1132
|
const isThinkingTokenEvent = data.type === 'system' && data.subtype === 'thinking_tokens';
|
|
1169
1133
|
if (!isThinkingTokenEvent) {
|
|
1170
1134
|
await finalizeThinkingGroup();
|
|
@@ -1203,7 +1167,6 @@ ${createRawJsonSection(data)}`;
|
|
|
1203
1167
|
case 'rate_limit_event':
|
|
1204
1168
|
await handleRateLimitEvent(data);
|
|
1205
1169
|
break;
|
|
1206
|
-
|
|
1207
1170
|
case 'assistant':
|
|
1208
1171
|
if (data.message && data.message.content) {
|
|
1209
1172
|
const content = Array.isArray(data.message.content) ? data.message.content : [data.message.content];
|
|
@@ -1221,7 +1184,6 @@ ${createRawJsonSection(data)}`;
|
|
|
1221
1184
|
case 'user':
|
|
1222
1185
|
if (data.message && data.message.content) {
|
|
1223
1186
|
const content = Array.isArray(data.message.content) ? data.message.content : [data.message.content];
|
|
1224
|
-
|
|
1225
1187
|
for (const item of content) {
|
|
1226
1188
|
if (item.type === 'tool_result') {
|
|
1227
1189
|
await handleToolResult(data, item);
|
|
@@ -1241,7 +1203,6 @@ ${createRawJsonSection(data)}`;
|
|
|
1241
1203
|
case 'turn.completed':
|
|
1242
1204
|
await handleCodexTurnCompleted(data);
|
|
1243
1205
|
break;
|
|
1244
|
-
|
|
1245
1206
|
case 'error':
|
|
1246
1207
|
await handleCodexError(data);
|
|
1247
1208
|
break;
|
|
@@ -1273,7 +1234,6 @@ ${createRawJsonSection(data)}`;
|
|
|
1273
1234
|
default:
|
|
1274
1235
|
await handleUnrecognized(data);
|
|
1275
1236
|
}
|
|
1276
|
-
|
|
1277
1237
|
// Process any queued comments
|
|
1278
1238
|
await processQueue();
|
|
1279
1239
|
};
|
|
@@ -1331,7 +1291,6 @@ ${createRawJsonSection(data)}`;
|
|
|
1331
1291
|
},
|
|
1332
1292
|
};
|
|
1333
1293
|
};
|
|
1334
|
-
|
|
1335
1294
|
/**
|
|
1336
1295
|
* Check if interactive mode is supported for the given tool
|
|
1337
1296
|
*
|
|
@@ -1362,7 +1321,6 @@ export const validateInteractiveModeConfig = async (argv, log) => {
|
|
|
1362
1321
|
await log(' Interactive mode will be disabled for this session.', { level: 'warning' });
|
|
1363
1322
|
return false;
|
|
1364
1323
|
}
|
|
1365
|
-
|
|
1366
1324
|
await log('🔌 Interactive mode: ENABLED (experimental)', { level: 'info' });
|
|
1367
1325
|
await log(` ${argv.tool || 'claude'} output will be posted as PR comments in real-time.`, { level: 'info' });
|
|
1368
1326
|
|
|
@@ -1383,7 +1341,6 @@ export const utils = {
|
|
|
1383
1341
|
execFileAsync,
|
|
1384
1342
|
CONFIG,
|
|
1385
1343
|
};
|
|
1386
|
-
|
|
1387
1344
|
// Export all functions
|
|
1388
1345
|
export default {
|
|
1389
1346
|
createInteractiveHandler,
|