@yemi33/minions 0.1.410 → 0.1.412

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,18 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.410 (2026-04-06)
3
+ ## 0.1.412 (2026-04-06)
4
+
5
+ ### Fixes
6
+ - resolve npm path from Node binary dir — not PATH
7
+
8
+ ## 0.1.411 (2026-04-06)
4
9
 
5
10
  ### Fixes
6
11
  - steering messages retry instead of being silently dropped
7
12
 
13
+ ### Other
14
+ - refactor: simplify steering — remove redundant session read, fix TOCTOU
15
+
8
16
  ## 0.1.409 (2026-04-06)
9
17
 
10
18
  ### Fixes
package/dashboard.js CHANGED
@@ -179,12 +179,13 @@ async function checkNpmVersion() {
179
179
  const now = Date.now();
180
180
  if (_npmVersionCache && (now - _npmVersionCacheTs) < NPM_CHECK_INTERVAL) return _npmVersionCache;
181
181
  try {
182
- // Use npm view — respects user's .npmrc proxy/registry config (unlike raw https.get)
182
+ // Use npm view — respects user's .npmrc proxy/registry config
183
+ // Resolve npm path from Node binary location — detached processes may not have PATH
183
184
  const { execFile } = require('child_process');
184
- // On Windows, detached processes may not have npm on PATH — use npm.cmd explicitly
185
- const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
185
+ const nodeDir = require('path').dirname(process.execPath);
186
+ const npmPath = require('path').join(nodeDir, process.platform === 'win32' ? 'npm.cmd' : 'npm');
186
187
  const version = await new Promise((resolve, reject) => {
187
- execFile(npmCmd, ['view', PKG_NAME, 'version'], { timeout: 15000, windowsHide: true, env: process.env }, (err, stdout) => {
188
+ execFile(npmPath, ['view', PKG_NAME, 'version'], { timeout: 15000, windowsHide: true }, (err, stdout) => {
188
189
  if (err) reject(err); else resolve((stdout || '').trim());
189
190
  });
190
191
  });
package/engine/timeout.js CHANGED
@@ -58,18 +58,16 @@ function checkSteering(config) {
58
58
  const activeProcesses = engine().activeProcesses;
59
59
  for (const [id, info] of activeProcesses) {
60
60
  const steerPath = path.join(AGENTS_DIR, info.agentId, 'steer.md');
61
- if (!fs.existsSync(steerPath)) continue;
61
+ let steerMtime;
62
+ try { steerMtime = fs.statSync(steerPath).mtimeMs; } catch { continue; } // ENOENT = no steering message
62
63
 
63
64
  const sessionId = info.sessionId;
64
65
  if (!sessionId) {
65
66
  // No sessionId yet — check stale (>5 min means it'll never arrive)
66
- try {
67
- const age = Date.now() - fs.statSync(steerPath).mtimeMs;
68
- if (age > 300000) {
69
- log('warn', `Steering: no sessionId for ${info.agentId} after 5m — deleting stale message`);
70
- try { fs.unlinkSync(steerPath); } catch {}
71
- }
72
- } catch {}
67
+ if (Date.now() - steerMtime > 300000) {
68
+ log('warn', `Steering: no sessionId for ${info.agentId} after 5m — deleting stale message`);
69
+ try { fs.unlinkSync(steerPath); } catch {}
70
+ }
73
71
  // Leave steer.md in place — retry next tick when sessionId may be available
74
72
  continue;
75
73
  }
package/engine.js CHANGED
@@ -462,12 +462,14 @@ function spawnAgent(dispatchItem, config) {
462
462
  }
463
463
 
464
464
  // Session resume: reuse last session if same branch and recent enough (< 2 hours)
465
+ let cachedSessionId = null;
465
466
  // Only resume when the context is relevant — same branch means the agent is
466
467
  // continuing work on the same PR/feature (e.g., author fixing their own build failure)
467
468
  if (!agentId.startsWith('temp-')) {
468
469
  try {
469
470
  const sessionFile = safeJson(path.join(AGENTS_DIR, agentId, 'session.json'));
470
471
  if (sessionFile?.sessionId && sessionFile.savedAt) {
472
+ cachedSessionId = sessionFile.sessionId;
471
473
  const sessionAge = Date.now() - new Date(sessionFile.savedAt).getTime();
472
474
  const sameBranch = branchName && sessionFile.branch && sessionFile.branch === branchName;
473
475
  if (sessionAge < 2 * 60 * 60 * 1000 && sameBranch) {
@@ -655,10 +657,12 @@ function spawnAgent(dispatchItem, config) {
655
657
  }
656
658
 
657
659
  // Parse output and run all post-completion hooks
658
- const { resultSummary } = runPostCompletionHooks(dispatchItem, agentId, code, stdout, config);
660
+ const { resultSummary, autoRecovered } = runPostCompletionHooks(dispatchItem, agentId, code, stdout, config);
659
661
 
660
662
  // Move from active to completed in dispatch (single source of truth for agent status)
661
- completeDispatch(id, code === 0 ? DISPATCH_RESULT.SUCCESS : DISPATCH_RESULT.ERROR, '', resultSummary);
663
+ // autoRecovered: agent failed (e.g. heartbeat timeout) but created PRs treat as success
664
+ const effectiveResult = (code === 0 || autoRecovered) ? DISPATCH_RESULT.SUCCESS : DISPATCH_RESULT.ERROR;
665
+ completeDispatch(id, effectiveResult, '', resultSummary);
662
666
 
663
667
  // Cleanup temp files (including PID file now that dispatch is complete)
664
668
  try { fs.unlinkSync(sysPromptPath); } catch { /* cleanup */ }
@@ -696,13 +700,7 @@ function spawnAgent(dispatchItem, config) {
696
700
  }, 3000);
697
701
 
698
702
  // Track process — even if PID isn't available yet (async on Windows)
699
- // Pre-load sessionId from session.json so steering works immediately on resume
700
- let initialSessionId = null;
701
- try {
702
- const sj = safeJson(path.join(AGENTS_DIR, agentId, 'session.json'));
703
- if (sj?.sessionId && sj.dispatchId === id) initialSessionId = sj.sessionId;
704
- } catch {}
705
- activeProcesses.set(id, { proc, agentId, startedAt, sessionId: initialSessionId });
703
+ activeProcesses.set(id, { proc, agentId, startedAt, sessionId: cachedSessionId });
706
704
 
707
705
  // Log PID and persist to registry
708
706
  if (proc.pid) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.410",
3
+ "version": "0.1.412",
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"