@yemi33/minions 0.1.1760 → 0.1.1762
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 +10 -0
- package/bin/minions.js +10 -13
- package/engine/copilot-models.json +1 -1
- package/engine.js +9 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.1762 (2026-05-07)
|
|
4
|
+
|
|
5
|
+
### Fixes
|
|
6
|
+
- detach agent process group so engine death never kills agents
|
|
7
|
+
|
|
8
|
+
## 0.1.1761 (2026-05-07)
|
|
9
|
+
|
|
10
|
+
### Fixes
|
|
11
|
+
- kill engine PID only, not its tree, to preserve in-flight agents
|
|
12
|
+
|
|
3
13
|
## 0.1.1760 (2026-05-07)
|
|
4
14
|
|
|
5
15
|
### Fixes
|
package/bin/minions.js
CHANGED
|
@@ -59,22 +59,18 @@ function readEnginePid(minionsHome) {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
|
-
* Force-kill a process
|
|
63
|
-
*
|
|
64
|
-
*
|
|
62
|
+
* Force-kill a single process by PID — does NOT recurse into children.
|
|
63
|
+
* This preserves the engine→agent invariant: agents are independent processes
|
|
64
|
+
* spawned as children of the engine, but they must survive engine restarts so
|
|
65
|
+
* they can be re-attached on next start (CLAUDE.md timeouts/liveness section).
|
|
66
|
+
* Tree-kill (`taskkill /T`, `pgrep -P` walk) would orphan in-flight work.
|
|
65
67
|
*/
|
|
66
|
-
function
|
|
68
|
+
function killPidOnly(pid) {
|
|
67
69
|
if (!pid || pid === process.pid) return;
|
|
68
70
|
try {
|
|
69
71
|
if (process.platform === 'win32') {
|
|
70
|
-
execSync(`taskkill /F /
|
|
72
|
+
execSync(`taskkill /F /PID ${pid}`, { stdio: 'ignore', timeout: 5000, windowsHide: true });
|
|
71
73
|
} else {
|
|
72
|
-
try {
|
|
73
|
-
const out = execSync(`pgrep -P ${pid}`, { encoding: 'utf8', timeout: 3000 });
|
|
74
|
-
for (const c of out.split(/\r?\n/).map(s => Number(s.trim())).filter(n => Number.isInteger(n) && n > 0)) {
|
|
75
|
-
try { process.kill(c, 'SIGKILL'); } catch {}
|
|
76
|
-
}
|
|
77
|
-
} catch {}
|
|
78
74
|
try { process.kill(pid, 'SIGKILL'); } catch {}
|
|
79
75
|
}
|
|
80
76
|
} catch {}
|
|
@@ -644,8 +640,9 @@ if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
|
|
|
644
640
|
const oldEnginePid = readEnginePid(MINIONS_HOME);
|
|
645
641
|
// 1. Graceful stop — short timeout so a hung engine can't block what follows.
|
|
646
642
|
try { execSync(`node "${path.join(MINIONS_HOME, 'engine.js')}" stop`, { stdio: 'ignore', cwd: MINIONS_HOME, timeout: 10000, windowsHide: true }); } catch {}
|
|
647
|
-
// 2. Force-kill the recorded engine PID
|
|
648
|
-
|
|
643
|
+
// 2. Force-kill the recorded engine PID (NOT the tree — agent children must
|
|
644
|
+
// survive so the new engine can re-attach them via PID files).
|
|
645
|
+
killPidOnly(oldEnginePid);
|
|
649
646
|
// 3. Free dashboard port (catches orphan dashboards with no recorded PID).
|
|
650
647
|
killByPort(7331);
|
|
651
648
|
// 4. Belt-and-suspenders cmdline match for anything still alive.
|
package/engine.js
CHANGED
|
@@ -1094,10 +1094,17 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
1094
1094
|
|
|
1095
1095
|
let proc;
|
|
1096
1096
|
try {
|
|
1097
|
+
// `detached: true` puts the agent in its own process group (POSIX) / job
|
|
1098
|
+
// object (Windows), so when the engine dies — gracefully via stop, abruptly
|
|
1099
|
+
// via taskkill, or because of a crash — the agent keeps running and can be
|
|
1100
|
+
// re-attached on next start via PID file + live-output.log. We do NOT call
|
|
1101
|
+
// proc.unref(): the engine still tracks exit while it's alive; detached
|
|
1102
|
+
// only kicks in when the engine itself goes away.
|
|
1097
1103
|
proc = runFile(process.execPath, spawnArgs, {
|
|
1098
1104
|
cwd,
|
|
1099
1105
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1100
1106
|
env: childEnv,
|
|
1107
|
+
detached: true,
|
|
1101
1108
|
});
|
|
1102
1109
|
} catch (spawnErr) {
|
|
1103
1110
|
// Synchronous spawn failure — record it to the (already-stamped) log so the
|
|
@@ -1308,10 +1315,12 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
1308
1315
|
}
|
|
1309
1316
|
let resumeProc;
|
|
1310
1317
|
try {
|
|
1318
|
+
// detached so the resumed steering session also survives engine death (matches initial spawn)
|
|
1311
1319
|
resumeProc = runFile(process.execPath, [spawnScript, steerPromptPath, sysPromptPath, ...resumeArgs], {
|
|
1312
1320
|
cwd,
|
|
1313
1321
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1314
1322
|
env: childEnv,
|
|
1323
|
+
detached: true,
|
|
1315
1324
|
});
|
|
1316
1325
|
} catch (e) {
|
|
1317
1326
|
log('warn', `Steering: spawn failed for ${agentId}: ${e.message}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1762",
|
|
4
4
|
"description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
|
|
5
5
|
"bin": {
|
|
6
6
|
"minions": "bin/minions.js"
|