@yemi33/minions 0.1.668 → 0.1.669

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,8 +1,9 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.668 (2026-04-09)
3
+ ## 0.1.669 (2026-04-09)
4
4
 
5
5
  ### Fixes
6
+ - interrupt blocking tool calls immediately on steering (closes #627) (#632)
6
7
  - reduce Bash blocking grace and errored task dedup window (closes #593) (#630)
7
8
 
8
9
  ## 0.1.667 (2026-04-09)
package/engine/timeout.js CHANGED
@@ -54,9 +54,28 @@ function checkIdleThreshold(config) {
54
54
 
55
55
  // ─── Steering Checker ────────────────────────────────────────────────────────
56
56
 
57
+ // How long to wait for a steered agent to exit before retrying the kill
58
+ const STEERING_KILL_RETRY_MS = 30000;
59
+
57
60
  function checkSteering(config) {
58
61
  const activeProcesses = engine().activeProcesses;
59
62
  for (const [id, info] of activeProcesses) {
63
+ // Recovery: if steering kill hasn't resulted in process exit within 30s, force-retry.
64
+ // This catches cases where killImmediate silently failed (e.g., orphaned subprocess
65
+ // on Unix where SIGKILL only hit spawn-agent.js, not the Claude CLI tree).
66
+ if (info._steeringAt && Date.now() - info._steeringAt > STEERING_KILL_RETRY_MS) {
67
+ if (!info._steeringRetried) {
68
+ log('warn', `Steering: ${info.agentId} (${id}) didn't exit ${STEERING_KILL_RETRY_MS / 1000}s after kill — retrying`);
69
+ shared.killImmediate(info.proc);
70
+ // On Unix, also try to kill children that may have been orphaned
71
+ if (process.platform !== 'win32' && info.proc?.pid) {
72
+ try { shared.exec(`pkill -KILL -P ${info.proc.pid}`, { timeout: 3000 }); } catch { /* children may already be dead */ }
73
+ }
74
+ info._steeringRetried = true;
75
+ }
76
+ continue;
77
+ }
78
+
60
79
  // Skip if already being steered (prevents double-kill race)
61
80
  if (info._steeringMessage || info._steeringAt) continue;
62
81
 
@@ -64,19 +83,34 @@ function checkSteering(config) {
64
83
  let steerMtime;
65
84
  try { steerMtime = fs.statSync(steerPath).mtimeMs; } catch { continue; } // ENOENT = no steering message
66
85
 
86
+ // Read and consume the message immediately — always delete to prevent stale messages
87
+ const message = safeRead(steerPath);
88
+ try { fs.unlinkSync(steerPath); } catch { /* cleanup */ }
89
+ if (!message) continue;
90
+
67
91
  const sessionId = info.sessionId;
68
92
  if (!sessionId) {
69
- if (Date.now() - steerMtime > 300000) {
70
- log('warn', `Steering: no sessionId for ${info.agentId} after 5m deleting stale message`);
71
- try { fs.unlinkSync(steerPath); } catch {}
72
- }
93
+ // No session to resume kill agent and deliver message via inbox for retry.
94
+ // Previously this silently skipped for up to 5m then deleted the message (#627).
95
+ log('info', `Steering: no sessionId for ${info.agentId} (${id}) killing and forwarding message to inbox`);
96
+
97
+ // Write steering message to agent inbox so it survives the retry
98
+ const inboxDir = path.join(AGENTS_DIR, info.agentId, 'inbox');
99
+ try { fs.mkdirSync(inboxDir, { recursive: true }); } catch {}
100
+ safeWrite(path.join(inboxDir, `steering-${Date.now()}.md`), `# Steering Message (Forwarded)\n\nOriginal steering from human:\n\n${message}\n`);
101
+
102
+ // Append to live output so user sees confirmation in the dashboard
103
+ try {
104
+ const liveLogPath = path.join(AGENTS_DIR, info.agentId, 'live-output.log');
105
+ fs.appendFileSync(liveLogPath, `\n[steering] Message received but no session to resume. Killing agent — your message will be delivered on retry.\n`);
106
+ } catch { /* optional */ }
107
+
108
+ shared.killImmediate(info.proc);
109
+ info._steeringAt = Date.now();
110
+ info._steeringNoSession = true;
73
111
  continue;
74
112
  }
75
113
 
76
- const message = safeRead(steerPath);
77
- try { fs.unlinkSync(steerPath); } catch { /* cleanup */ }
78
- if (!message) continue;
79
-
80
114
  log('info', `Steering: killing ${info.agentId} (${id}) for session resume with human message`);
81
115
 
82
116
  shared.killImmediate(info.proc);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.668",
3
+ "version": "0.1.669",
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"