@link-assistant/hive-mind 1.45.0 → 1.45.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 +9 -0
- package/package.json +1 -1
- package/src/claude.lib.mjs +7 -7
- package/src/exit-handler.lib.mjs +22 -4
- package/src/solve.mjs +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 1.45.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 003c5ca: Fix premature finish signaling and leaked child processes (Issue #1516)
|
|
8
|
+
- Kill entire process group on stream timeout using negative PID, preventing leaked /bin/sh child processes from continuing to make commits after completion
|
|
9
|
+
- Move .gitkeep cleanup to after all completion signals (log upload, "Ready to merge" comment) so no new commits appear after the system reports "session ended"
|
|
10
|
+
- drainHandles now reports surviving child processes as errors instead of silently killing them, so root causes are investigated rather than hidden
|
|
11
|
+
|
|
3
12
|
## 1.45.0
|
|
4
13
|
|
|
5
14
|
### Minor Changes
|
package/package.json
CHANGED
package/src/claude.lib.mjs
CHANGED
|
@@ -852,22 +852,22 @@ export const executeClaudeCommand = async params => {
|
|
|
852
852
|
let lastEventTime = null;
|
|
853
853
|
let activityTimeoutId = null;
|
|
854
854
|
let isActivityTimeout = false;
|
|
855
|
-
// Issue #
|
|
856
|
-
//
|
|
855
|
+
// Issue #1516: Kill process group (-pid) so leaked /bin/sh children don't survive
|
|
856
|
+
// prettier-ignore
|
|
857
|
+
const killProcessTree = signal => { try { const pid = execCommand.pid || execCommand._pid; if (pid) { process.kill(-pid, signal); return; } } catch { /* not group leader */ } execCommand.kill(signal); };
|
|
857
858
|
const forceExitOnTimeout = async () => {
|
|
858
859
|
if (forceExitTriggered) return;
|
|
859
860
|
forceExitTriggered = true;
|
|
860
|
-
await log(`⚠️ Stream timeout — sending SIGTERM for graceful shutdown (Issue #1280, #1510)`, { verbose: true });
|
|
861
|
+
await log(`⚠️ Stream timeout — sending SIGTERM for graceful shutdown (Issue #1280, #1510, #1516)`, { verbose: true });
|
|
861
862
|
try {
|
|
862
863
|
if (execCommand.kill) {
|
|
863
|
-
|
|
864
|
+
killProcessTree('SIGTERM');
|
|
864
865
|
// Issue #1346/#1510: Follow up with SIGKILL after 5s if still alive
|
|
865
|
-
// Increased from 2s to 5s to give more time for final output capture
|
|
866
866
|
const t = setTimeout(() => {
|
|
867
867
|
try {
|
|
868
868
|
if (!execCommand.result?.code) {
|
|
869
|
-
log(`⚠️ Process did not exit after SIGTERM, sending SIGKILL`, { verbose: true });
|
|
870
|
-
|
|
869
|
+
log(`⚠️ Process tree did not exit after SIGTERM, sending SIGKILL (Issue #1516)`, { verbose: true });
|
|
870
|
+
killProcessTree('SIGKILL');
|
|
871
871
|
}
|
|
872
872
|
} catch {
|
|
873
873
|
/* exited */
|
package/src/exit-handler.lib.mjs
CHANGED
|
@@ -121,12 +121,30 @@ const drainHandles = async () => {
|
|
|
121
121
|
// undici may not be available in all Node versions — safe to ignore
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
// 3.
|
|
125
|
-
//
|
|
124
|
+
// 3. Detect surviving child processes from command-stream.
|
|
125
|
+
// Issue #1516: Surviving ChildProcess handles indicate a bug — a leaked /bin/sh
|
|
126
|
+
// child can continue executing (making commits, pushing to GitHub) after we've
|
|
127
|
+
// declared completion. Instead of silently killing them (which hides root causes),
|
|
128
|
+
// we log an error so each occurrence is investigated and the root cause is fixed.
|
|
129
|
+
// The process group kill in claude.lib.mjs (killProcessTree) should have already
|
|
130
|
+
// terminated all children; if any survive, that's a bug we need to know about.
|
|
126
131
|
try {
|
|
127
132
|
for (const handle of process._getActiveHandles()) {
|
|
128
|
-
if (handle?.constructor?.name === 'ChildProcess'
|
|
129
|
-
|
|
133
|
+
if (handle?.constructor?.name === 'ChildProcess') {
|
|
134
|
+
// Issue #1516: Report surviving child processes as errors instead of killing them.
|
|
135
|
+
// This surfaces the root cause for investigation rather than hiding it.
|
|
136
|
+
const detail = [handle.pid != null ? `pid=${handle.pid}` : null, handle.spawnfile ? `file=${handle.spawnfile}` : null, handle.killed ? 'killed=true' : 'killed=false'].filter(Boolean).join(', ');
|
|
137
|
+
const errorMsg = `❌ ERROR: Surviving ChildProcess detected at exit (${detail}). This indicates a leaked process that was not properly terminated. Investigate the root cause — do NOT suppress this error by killing the process. (Issue #1516)`;
|
|
138
|
+
if (logFunction) {
|
|
139
|
+
await logFunction(errorMsg, { level: 'error' });
|
|
140
|
+
} else {
|
|
141
|
+
console.error(errorMsg);
|
|
142
|
+
}
|
|
143
|
+
// Still unref so Node.js can exit, but do NOT kill — let the OS process
|
|
144
|
+
// continue so its effects are visible and the root cause can be diagnosed.
|
|
145
|
+
if (typeof handle.unref === 'function') {
|
|
146
|
+
handle.unref();
|
|
147
|
+
}
|
|
130
148
|
}
|
|
131
149
|
}
|
|
132
150
|
} catch {
|
package/src/solve.mjs
CHANGED
|
@@ -1175,8 +1175,7 @@ try {
|
|
|
1175
1175
|
const autoRestartEnabled = argv['autoRestartOnUncommittedChanges'] !== false;
|
|
1176
1176
|
const shouldRestart = await checkForUncommittedChanges(tempDir, owner, repo, branchName, $, log, shouldAutoCommit, autoRestartEnabled);
|
|
1177
1177
|
|
|
1178
|
-
//
|
|
1179
|
-
await cleanupClaudeFile(tempDir, branchName, claudeCommitHash, argv);
|
|
1178
|
+
// Issue #1516: cleanupClaudeFile() moved to after completion signals (before endWorkSession)
|
|
1180
1179
|
|
|
1181
1180
|
// Show summary of session and log file
|
|
1182
1181
|
await showSessionSummary(sessionId, limitReached, argv, issueUrl, tempDir, shouldAttachLogs);
|
|
@@ -1442,6 +1441,9 @@ try {
|
|
|
1442
1441
|
}
|
|
1443
1442
|
}
|
|
1444
1443
|
|
|
1444
|
+
// Issue #1516: Cleanup after all signals (was before verifyResults, caused premature commits)
|
|
1445
|
+
await cleanupClaudeFile(tempDir, branchName, claudeCommitHash, argv);
|
|
1446
|
+
|
|
1445
1447
|
// End work session using the new module
|
|
1446
1448
|
await endWorkSession({
|
|
1447
1449
|
isContinueMode,
|