@link-assistant/hive-mind 1.54.3 → 1.54.4
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
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@link-assistant/hive-mind",
|
|
3
|
-
"version": "1.54.
|
|
3
|
+
"version": "1.54.4",
|
|
4
4
|
"description": "AI-powered issue solver and hive mind for collaborative problem solving",
|
|
5
5
|
"main": "src/hive.mjs",
|
|
6
6
|
"type": "module",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"hive-telegram-bot": "./src/telegram-bot.mjs"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
|
-
"test": "node tests/solve-queue.test.mjs && node tests/limits-display.test.mjs && node tests/test-usage-limit.mjs && node tests/test-codex-support.mjs && node tests/test-build-cost-info-string.mjs && node tests/test-claude-code-install-method.mjs && node tests/test-issue-1616-pr-issue-link-preservation.mjs && node tests/test-telegram-message-filters.mjs && node tests/test-telegram-bot-command-aliases.mjs && node tests/test-solve-queue-command.mjs && node tests/test-queue-display-1267.mjs && node tests/test-telegram-bot-launcher.mjs",
|
|
16
|
+
"test": "node tests/solve-queue.test.mjs && node tests/limits-display.test.mjs && node tests/test-usage-limit.mjs && node tests/test-codex-support.mjs && node tests/test-build-cost-info-string.mjs && node tests/test-claude-code-install-method.mjs && node tests/test-issue-1616-pr-issue-link-preservation.mjs && node tests/test-pre-pr-failure-notifier-1640.mjs && node tests/test-telegram-message-filters.mjs && node tests/test-telegram-bot-command-aliases.mjs && node tests/test-solve-queue-command.mjs && node tests/test-queue-display-1267.mjs && node tests/test-telegram-bot-launcher.mjs",
|
|
17
17
|
"test:queue": "node tests/solve-queue.test.mjs",
|
|
18
18
|
"test:limits-display": "node tests/limits-display.test.mjs",
|
|
19
19
|
"test:usage-limit": "node tests/test-usage-limit.mjs",
|
package/src/exit-handler.lib.mjs
CHANGED
|
@@ -27,6 +27,8 @@ let logFunction = null;
|
|
|
27
27
|
let cleanupFunction = null;
|
|
28
28
|
let interruptFunction = null;
|
|
29
29
|
let interruptHandlerRan = false;
|
|
30
|
+
let preExitFunction = null;
|
|
31
|
+
let preExitHandlerRan = false;
|
|
30
32
|
|
|
31
33
|
/**
|
|
32
34
|
* Initialize the exit handler with required dependencies
|
|
@@ -36,11 +38,16 @@ let interruptHandlerRan = false;
|
|
|
36
38
|
* @param {Function} interrupt - Optional interrupt function to call on SIGINT/SIGTERM before cleanup
|
|
37
39
|
* (e.g., auto-commit uncommitted changes, upload logs)
|
|
38
40
|
*/
|
|
39
|
-
export const initializeExitHandler = (getLogPath, log, cleanup = null, interrupt = null) => {
|
|
41
|
+
export const initializeExitHandler = (getLogPath, log, cleanup = null, interrupt = null, preExit = null) => {
|
|
40
42
|
getLogPathFunction = getLogPath;
|
|
41
43
|
logFunction = log;
|
|
42
44
|
cleanupFunction = cleanup;
|
|
43
45
|
interruptFunction = interrupt;
|
|
46
|
+
preExitFunction = preExit;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const setPreExitHandler = preExit => {
|
|
50
|
+
preExitFunction = preExit;
|
|
44
51
|
};
|
|
45
52
|
|
|
46
53
|
/**
|
|
@@ -200,6 +207,20 @@ export const logActiveHandles = async (log = null) => {
|
|
|
200
207
|
export const safeExit = async (code = 0, reason = 'Process completed') => {
|
|
201
208
|
await showExitMessage(reason, code);
|
|
202
209
|
|
|
210
|
+
if (code !== 0 && preExitFunction && !preExitHandlerRan) {
|
|
211
|
+
preExitHandlerRan = true;
|
|
212
|
+
try {
|
|
213
|
+
await preExitFunction({ code, reason });
|
|
214
|
+
} catch (error) {
|
|
215
|
+
const message = error && error.message ? error.message : String(error);
|
|
216
|
+
if (logFunction) {
|
|
217
|
+
await logFunction(`⚠️ Pre-exit handler failed: ${message}`, { level: 'warning' });
|
|
218
|
+
} else {
|
|
219
|
+
console.warn(`⚠️ Pre-exit handler failed: ${message}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
203
224
|
// Issue #1431: Drain/unref active handles so the event loop exits naturally.
|
|
204
225
|
// This resolves the root causes of dangling ReadStream (stdin), Socket (undici),
|
|
205
226
|
// ChildProcess (command-stream), and WriteStream (stdout/stderr) handles.
|
|
@@ -70,6 +70,7 @@ export const handleFailure = async options => {
|
|
|
70
70
|
});
|
|
71
71
|
if (logUploadSuccess) {
|
|
72
72
|
await log(`📎 Failure log attached to ${targetLabel}`);
|
|
73
|
+
if (!hasPR && hasIssue) global.prePullRequestFailureNotificationPosted = true;
|
|
73
74
|
}
|
|
74
75
|
} catch (attachError) {
|
|
75
76
|
reportError(attachError, {
|
package/src/solve.mjs
CHANGED
|
@@ -41,6 +41,7 @@ const { formatResetTimeWithRelative } = usageLimitLib;
|
|
|
41
41
|
|
|
42
42
|
const errorHandlers = await import('./solve.error-handlers.lib.mjs');
|
|
43
43
|
const { createUncaughtExceptionHandler, createUnhandledRejectionHandler, handleMainExecutionError, handleNoPrAvailableError } = errorHandlers;
|
|
44
|
+
const { notifyIssueAboutPrePullRequestFailure } = await import('./solve.pre-pr-failure-notifier.lib.mjs');
|
|
44
45
|
|
|
45
46
|
const watchLib = await import('./solve.watch.lib.mjs');
|
|
46
47
|
const { startWatchMode } = watchLib;
|
|
@@ -132,7 +133,7 @@ const cleanupWrapper = async () => {
|
|
|
132
133
|
}
|
|
133
134
|
};
|
|
134
135
|
const interruptWrapper = createInterruptWrapper({ cleanupContext, checkForUncommittedChanges, shouldAttachLogs, attachLogToGitHub, getLogFile, sanitizeLogContent, $, log });
|
|
135
|
-
initializeExitHandler(getAbsoluteLogPath, log, cleanupWrapper, interruptWrapper);
|
|
136
|
+
initializeExitHandler(getAbsoluteLogPath, log, cleanupWrapper, interruptWrapper, ({ code, reason }) => notifyIssueAboutPrePullRequestFailure({ code, reason, argv, globalState: global, $, log, getLogFile, shouldAttachLogs, attachLogToGitHub, sanitizeLogContent, rawCommand }));
|
|
136
137
|
installGlobalExitHandlers();
|
|
137
138
|
|
|
138
139
|
// Now handle argument validation that was moved from early checks
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { getTrackedToolCommentIds, postTrackedComment, SOLUTION_DRAFT_FAILED_MARKER } from './tool-comments.lib.mjs';
|
|
2
|
+
|
|
3
|
+
const truncate = (value, maxLength = 2000) => {
|
|
4
|
+
const text = value === null || value === undefined ? '' : String(value);
|
|
5
|
+
if (text.length <= maxLength) return text;
|
|
6
|
+
return `${text.slice(0, maxLength - 22)}\n... truncated ...`;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const fence = value => truncate(value || 'Unknown error').replaceAll('```', '` ` `');
|
|
10
|
+
|
|
11
|
+
export function shouldNotifyIssueAboutPrePullRequestFailure({ code, globalState }) {
|
|
12
|
+
if (code === 0) return false;
|
|
13
|
+
if (!globalState?.issueNumber || !globalState?.owner || !globalState?.repo) return false;
|
|
14
|
+
if (globalState?.createdPR?.number) return false;
|
|
15
|
+
if (globalState.prePullRequestFailureNotificationPosted || globalState.prePullRequestFailureNotificationInProgress) return false;
|
|
16
|
+
return getTrackedToolCommentIds().size === 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function buildPrePullRequestFailureComment({ reason, owner, repo, issueNumber, argv = {}, rawCommand = null, logAttachmentAttempted = false }) {
|
|
20
|
+
const tool = argv.tool || 'claude';
|
|
21
|
+
const modelLine = argv.model ? `\n- **Requested model**: \`${argv.model}\`` : '';
|
|
22
|
+
const commandBlock = rawCommand
|
|
23
|
+
? `
|
|
24
|
+
|
|
25
|
+
### Command
|
|
26
|
+
\`\`\`bash
|
|
27
|
+
${fence(rawCommand)}
|
|
28
|
+
\`\`\``
|
|
29
|
+
: '';
|
|
30
|
+
const logLine = logAttachmentAttempted ? 'Log attachment was attempted but failed. Check the solver terminal log for the complete failure output.' : 'Logs were not attached because `--attach-logs` was not enabled.';
|
|
31
|
+
|
|
32
|
+
return `## 🚨 ${SOLUTION_DRAFT_FAILED_MARKER}
|
|
33
|
+
|
|
34
|
+
The automated solver stopped before creating a pull request, so no PR was opened for this issue.
|
|
35
|
+
|
|
36
|
+
### Failure
|
|
37
|
+
- **Repository**: \`${owner}/${repo}\`
|
|
38
|
+
- **Issue**: #${issueNumber}
|
|
39
|
+
- **Tool**: \`${tool}\`${modelLine}
|
|
40
|
+
|
|
41
|
+
**Reason**
|
|
42
|
+
\`\`\`text
|
|
43
|
+
${fence(reason)}
|
|
44
|
+
\`\`\`${commandBlock}
|
|
45
|
+
|
|
46
|
+
${logLine}
|
|
47
|
+
|
|
48
|
+
Please resolve the reported problem and rerun the solve command.`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function notifyIssueAboutPrePullRequestFailure(options) {
|
|
52
|
+
const { code, reason, argv = {}, globalState = globalThis, $, log = async () => {}, getLogFile, shouldAttachLogs = false, attachLogToGitHub, sanitizeLogContent, rawCommand = null, postComment = postTrackedComment } = options;
|
|
53
|
+
|
|
54
|
+
if (!shouldNotifyIssueAboutPrePullRequestFailure({ code, globalState })) {
|
|
55
|
+
return { notified: false, skipped: true };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const owner = globalState.owner;
|
|
59
|
+
const repo = globalState.repo;
|
|
60
|
+
const issueNumber = globalState.issueNumber;
|
|
61
|
+
globalState.prePullRequestFailureNotificationInProgress = true;
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
if (shouldAttachLogs && getLogFile && attachLogToGitHub && sanitizeLogContent) {
|
|
65
|
+
await log(`\n📄 Notifying issue #${issueNumber} about pre-PR failure with logs...`);
|
|
66
|
+
const uploaded = await attachLogToGitHub({
|
|
67
|
+
logFile: getLogFile(),
|
|
68
|
+
targetType: 'issue',
|
|
69
|
+
targetNumber: issueNumber,
|
|
70
|
+
owner,
|
|
71
|
+
repo,
|
|
72
|
+
$,
|
|
73
|
+
log,
|
|
74
|
+
sanitizeLogContent,
|
|
75
|
+
verbose: argv.verbose,
|
|
76
|
+
errorMessage: `The solver stopped before creating a pull request.\n\nReason: ${reason || 'Unknown error'}`,
|
|
77
|
+
requestedModel: argv.model,
|
|
78
|
+
tool: argv.tool || 'claude',
|
|
79
|
+
});
|
|
80
|
+
if (uploaded) {
|
|
81
|
+
globalState.prePullRequestFailureNotificationPosted = true;
|
|
82
|
+
return { notified: true, method: 'log-upload' };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
await log(`\n💬 Notifying issue #${issueNumber} about pre-PR failure...`);
|
|
87
|
+
const body = buildPrePullRequestFailureComment({
|
|
88
|
+
reason,
|
|
89
|
+
owner,
|
|
90
|
+
repo,
|
|
91
|
+
issueNumber,
|
|
92
|
+
argv,
|
|
93
|
+
rawCommand,
|
|
94
|
+
logAttachmentAttempted: shouldAttachLogs,
|
|
95
|
+
});
|
|
96
|
+
const posted = await postComment({ $, owner, repo, targetNumber: issueNumber, body });
|
|
97
|
+
if (posted.ok) {
|
|
98
|
+
globalState.prePullRequestFailureNotificationPosted = true;
|
|
99
|
+
await log(` ✅ Pre-PR failure comment posted to issue #${issueNumber}${posted.commentId ? ` (id=${posted.commentId})` : ''}`);
|
|
100
|
+
return { notified: true, method: 'comment', commentId: posted.commentId || null };
|
|
101
|
+
}
|
|
102
|
+
await log(` ⚠️ Could not post pre-PR failure comment: ${posted.stderr || 'unknown error'}`, { level: 'warning' });
|
|
103
|
+
return { notified: false, error: posted.stderr || 'unknown error' };
|
|
104
|
+
} finally {
|
|
105
|
+
globalState.prePullRequestFailureNotificationInProgress = false;
|
|
106
|
+
}
|
|
107
|
+
}
|