@yemi33/minions 0.1.1759 → 0.1.1760

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
@@ -1,10 +1,9 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.1759 (2026-05-07)
3
+ ## 0.1.1760 (2026-05-07)
4
4
 
5
5
  ### Fixes
6
- - isolate meeting tests, kill rename-live-dir antipattern (#2142)
7
- - honor no-op completions in PR attachment contract (#2141)
6
+ - reliable engine kill + visible restart output
8
7
 
9
8
  ## 0.1.1757 (2026-05-06)
10
9
 
package/bin/minions.js CHANGED
@@ -46,6 +46,40 @@ function killByPort(port) {
46
46
  } catch {}
47
47
  }
48
48
 
49
+ /**
50
+ * Read the engine's recorded PID from engine/control.json. Returns null if
51
+ * the file is missing/corrupt or the PID isn't a positive integer.
52
+ */
53
+ function readEnginePid(minionsHome) {
54
+ try {
55
+ const data = JSON.parse(fs.readFileSync(path.join(minionsHome, 'engine', 'control.json'), 'utf8'));
56
+ const pid = Number(data && data.pid);
57
+ return Number.isInteger(pid) && pid > 0 ? pid : null;
58
+ } catch { return null; }
59
+ }
60
+
61
+ /**
62
+ * Force-kill a process and its descendants by PID. The /T flag on taskkill
63
+ * recurses into the process tree on Windows, which `process.kill()` does not.
64
+ * On POSIX, walk pgrep first so spawned children die before the parent.
65
+ */
66
+ function killPidTree(pid) {
67
+ if (!pid || pid === process.pid) return;
68
+ try {
69
+ if (process.platform === 'win32') {
70
+ execSync(`taskkill /F /T /PID ${pid}`, { stdio: 'ignore', timeout: 5000, windowsHide: true });
71
+ } 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
+ try { process.kill(pid, 'SIGKILL'); } catch {}
79
+ }
80
+ } catch {}
81
+ }
82
+
49
83
  /** Kill minions processes by command-line pattern matching (wmic on Windows, pkill on Unix). */
50
84
  function killMinionsProcesses(patterns) {
51
85
  try {
@@ -330,14 +364,12 @@ function init() {
330
364
  printPreflight(results, { label: 'Preflight checks' });
331
365
  } catch {}
332
366
 
333
- if (isUpgrade && skipStart) {
334
- console.log(`\n Upgrade complete (${pkgVersion}). Restart skipped by caller.\n`);
335
- return;
336
- }
367
+ // Update flow passes --skip-start so it can perform a single visible restart afterwards.
368
+ if (isUpgrade && skipStart) return;
337
369
 
338
370
  // Auto-start on fresh install; direct force-upgrade restarts automatically.
339
371
  if (isUpgrade) {
340
- try { execSync(`node "${path.join(MINIONS_HOME, 'engine.js')}" stop`, { stdio: 'ignore', cwd: MINIONS_HOME }); } catch {}
372
+ try { execSync(`node "${path.join(MINIONS_HOME, 'engine.js')}" stop`, { stdio: 'ignore', cwd: MINIONS_HOME, timeout: 10000, windowsHide: true }); } catch {}
341
373
  }
342
374
  console.log(isUpgrade
343
375
  ? `\n Upgrade complete (${pkgVersion}). Restarting engine and dashboard...\n`
@@ -422,11 +454,6 @@ function showChangelog(fromVersion) {
422
454
  console.log(` cat ${changelogPath}\n`);
423
455
  }
424
456
 
425
- function writeCommandOutput(stream, output) {
426
- if (!output) return;
427
- stream.write(Buffer.isBuffer(output) ? output.toString('utf8') : String(output));
428
- }
429
-
430
457
  function formatPackageCliCommand(args) {
431
458
  const initScript = path.join(PKG_ROOT, 'bin', 'minions.js');
432
459
  return `node "${initScript}" ${args.join(' ')}`;
@@ -434,17 +461,13 @@ function formatPackageCliCommand(args) {
434
461
 
435
462
  function runPackageCli(args, timeout) {
436
463
  const initScript = path.join(PKG_ROOT, 'bin', 'minions.js');
437
- const result = spawnSync(process.execPath, [initScript, ...args], {
464
+ return spawnSync(process.execPath, [initScript, ...args], {
438
465
  cwd: process.cwd(),
439
466
  env: { ...process.env, MINIONS_HOME },
440
- encoding: 'utf8',
467
+ stdio: 'inherit',
441
468
  timeout,
442
469
  windowsHide: true,
443
470
  });
444
-
445
- writeCommandOutput(process.stdout, result.stdout);
446
- writeCommandOutput(process.stderr, result.stderr);
447
- return result;
448
471
  }
449
472
 
450
473
  function runPostUpdateInit() {
@@ -615,10 +638,17 @@ if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
615
638
  // `--cli` / `--model` flags forward to `engine.js start` so the runtime
616
639
  // fleet flips before the daemon spawns (P-6b3f9c2e AC: works on restart).
617
640
  ensureInstalled();
618
- // Stop engine if running (graceful attempt)
619
- try { execSync(`node "${path.join(MINIONS_HOME, 'engine.js')}" stop`, { stdio: 'ignore', cwd: MINIONS_HOME }); } catch {}
620
- // Kill all existing engine/dashboard processes handles crashed engines and orphan dashboards
641
+ // Layered kill each step is best-effort, layered so the next still runs if
642
+ // one fails. Goal: the old engine is gone before we spawn a new one, even if
643
+ // PowerShell is unavailable, the engine is hung, or its cmdline doesn't match.
644
+ const oldEnginePid = readEnginePid(MINIONS_HOME);
645
+ // 1. Graceful stop — short timeout so a hung engine can't block what follows.
646
+ 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 and its tree (most reliable — independent of cmdline matching).
648
+ killPidTree(oldEnginePid);
649
+ // 3. Free dashboard port (catches orphan dashboards with no recorded PID).
621
650
  killByPort(7331);
651
+ // 4. Belt-and-suspenders cmdline match for anything still alive.
622
652
  killMinionsProcesses(['engine.js', 'dashboard.js']);
623
653
  const engineProc = spawn(process.execPath, [path.join(MINIONS_HOME, 'engine.js'), 'start', ...rest], {
624
654
  cwd: MINIONS_HOME, stdio: 'ignore', detached: true, windowsHide: true
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "runtime": "copilot",
3
3
  "models": null,
4
- "cachedAt": "2026-05-07T00:36:52.041Z"
4
+ "cachedAt": "2026-05-07T00:40:39.172Z"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1759",
3
+ "version": "0.1.1760",
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"