@yemi33/minions 0.1.1607 → 0.1.1608

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,12 +1,13 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.1607 (2026-04-28)
3
+ ## 0.1.1608 (2026-04-28)
4
4
 
5
5
  ### Features
6
6
  - match runtime tags to actual logos (pixel-crab Claude, mascot Copilot)
7
7
  - replace runtime text tag with inline SVG logos
8
8
 
9
9
  ### Fixes
10
+ - kill agents from engine tmp pid files
10
11
  - gate live completion banner on final process exit
11
12
  - wrap CC Model input so its label/hint survive runtime hydration
12
13
  - preserve reconnect stream state
package/engine/cli.js CHANGED
@@ -1142,12 +1142,27 @@ const commands = {
1142
1142
  const config = getConfig();
1143
1143
  const shared = require('./shared');
1144
1144
 
1145
- // Kill processes via PID files (expensive — outside dispatch lock)
1146
- const pidFiles = fs.readdirSync(ENGINE_DIR).filter(f => f.startsWith('pid-'));
1145
+ // Kill processes via PID files (expensive — outside dispatch lock).
1146
+ // PID files live in engine/tmp/ (see engine/spawn-agent.js:220 derived from
1147
+ // the prompt-<id>.md sidecar path that engine.js builds in engine/tmp/).
1148
+ // Reading from ENGINE_DIR directly is a no-op: spawn-agent never writes there.
1149
+ const pidDir = path.join(ENGINE_DIR, 'tmp');
1150
+ const pidFiles = shared.safeReadDir(pidDir).filter(f => f.startsWith('pid-') && f.endsWith('.pid'));
1147
1151
  for (const f of pidFiles) {
1148
- const pid = safeRead(path.join(ENGINE_DIR, f)).trim();
1149
- try { process.kill(Number(pid)); console.log(`Killed process ${pid} (${f})`); } catch { console.log(`Process ${pid} already dead`); }
1150
- fs.unlinkSync(path.join(ENGINE_DIR, f));
1152
+ const pidPath = path.join(pidDir, f);
1153
+ const raw = safeRead(pidPath).trim();
1154
+ // Guard against falsy/zero/NaN PIDs. Empty pid files would resolve to
1155
+ // Number('') === 0, and process.kill(0) on POSIX targets the entire
1156
+ // calling process group — which would kill the engine itself.
1157
+ let pidNum = NaN;
1158
+ try { pidNum = shared.validatePid(raw); } catch { /* invalid — skip */ }
1159
+ if (pidNum > 0) {
1160
+ try { process.kill(pidNum); console.log(`Killed process ${pidNum} (${f})`); }
1161
+ catch { console.log(`Process ${pidNum} already dead`); }
1162
+ } else {
1163
+ console.log(`Skipping ${f}: invalid or empty PID`);
1164
+ }
1165
+ try { fs.unlinkSync(pidPath); } catch { /* may not exist */ }
1151
1166
  }
1152
1167
 
1153
1168
  // Atomically read and clear dispatch.active (locked read-modify-write)
@@ -341,7 +341,7 @@ function cancelPendingDispatchesForPr(prId) {
341
341
  */
342
342
  function cleanDispatchEntries(matchFn) {
343
343
  const dispatchPath = path.join(MINIONS_DIR, 'engine', 'dispatch.json');
344
- const engineDir = path.join(MINIONS_DIR, 'engine');
344
+ const tmpDir = path.join(MINIONS_DIR, 'engine', 'tmp');
345
345
  let removed = 0;
346
346
  const pidsToKill = [];
347
347
  const filesToDelete = [];
@@ -353,15 +353,17 @@ function cleanDispatchEntries(matchFn) {
353
353
  if (queue === 'active') {
354
354
  for (const d of dispatch[queue]) {
355
355
  if (!matchFn(d)) continue;
356
- const pidFile = path.join(engineDir, `pid-${d.id}.pid`);
356
+ // PID files live in engine/tmp/ (see engine/spawn-agent.js:220 — derived
357
+ // from the prompt-<id>.md path that engine.js builds in engine/tmp/).
358
+ const pidFile = path.join(tmpDir, `pid-${d.id}.pid`);
357
359
  try {
358
360
  const pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim());
359
361
  if (pid) pidsToKill.push(pid);
360
362
  } catch { /* PID file may not exist */ }
361
363
  filesToDelete.push(pidFile);
362
- filesToDelete.push(path.join(engineDir, 'tmp', `prompt-${d.id}.md`));
363
- filesToDelete.push(path.join(engineDir, 'tmp', `sysprompt-${d.id}.md`));
364
- filesToDelete.push(path.join(engineDir, 'tmp', `sysprompt-${d.id}.md.tmp`));
364
+ filesToDelete.push(path.join(tmpDir, `prompt-${d.id}.md`));
365
+ filesToDelete.push(path.join(tmpDir, `sysprompt-${d.id}.md`));
366
+ filesToDelete.push(path.join(tmpDir, `sysprompt-${d.id}.md.tmp`));
365
367
  }
366
368
  }
367
369
  dispatch[queue] = dispatch[queue].filter(d => !matchFn(d));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1607",
3
+ "version": "0.1.1608",
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"