@yemi33/minions 0.1.804 → 0.1.806

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,6 +1,6 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.804 (2026-04-10)
3
+ ## 0.1.806 (2026-04-10)
4
4
 
5
5
  ### Features
6
6
  - configurable ignored comment authors — auto-filtered, never trigger fixes
@@ -9,6 +9,8 @@
9
9
  - cap review→fix cycles at evalMaxIterations (default 3)
10
10
 
11
11
  ### Fixes
12
+ - adoFetch supports method/body for PATCH requests (auto-complete)
13
+ - prevent false [process-exit] detection from tool result content
12
14
  - allow PRD item retry when work item is missing (closes #781) (#807)
13
15
  - handle force-pushed dep branches on retry (closes #738) (#806)
14
16
  - project-scoped skill work items instruct wrong file path format (closes #790) (#804)
package/engine/ado.js CHANGED
@@ -60,21 +60,26 @@ async function getAdoToken() {
60
60
  return null;
61
61
  }
62
62
 
63
- async function adoFetch(url, token, _retryCount = 0) {
63
+ async function adoFetch(url, token, opts = {}) {
64
+ const _retryCount = typeof opts === 'number' ? opts : (opts._retryCount || 0); // backward compat
65
+ const method = (typeof opts === 'object' && opts.method) || 'GET';
66
+ const body = (typeof opts === 'object' && opts.body) || undefined;
64
67
  const MAX_RETRIES = 1;
65
68
  const res = await fetch(url, {
66
- headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }
69
+ method,
70
+ headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
71
+ signal: AbortSignal.timeout(30000),
72
+ body,
67
73
  });
68
- if (!res.ok) throw new Error(`ADO API ${res.status}: ${res.statusText}`);
74
+ if (!res.ok) throw new Error(`ADO API ${method} ${res.status}: ${res.statusText}`);
69
75
  const text = await res.text();
70
76
  if (!text || text.trimStart().startsWith('<')) {
71
- // Invalidate cached token — it's likely expired
72
77
  _adoTokenCache = { token: null, expiresAt: 0 };
73
78
  if (_retryCount < MAX_RETRIES) {
74
79
  const freshToken = await getAdoToken();
75
80
  if (freshToken) {
76
81
  log('info', 'ADO token expired mid-session — refreshed and retrying');
77
- return adoFetch(url, freshToken, _retryCount + 1);
82
+ return adoFetch(url, freshToken, { ...opts, _retryCount: _retryCount + 1 });
78
83
  }
79
84
  }
80
85
  throw new Error(`ADO returned HTML instead of JSON (likely auth redirect) for ${url.split('?')[0]}`);
@@ -85,7 +90,8 @@ async function adoFetch(url, token, _retryCount = 0) {
85
90
  /** Fetch raw text from ADO API (for build logs which aren't JSON). */
86
91
  async function adoFetchText(url, token) {
87
92
  const res = await fetch(url, {
88
- headers: { 'Authorization': `Bearer ${token}` }
93
+ headers: { 'Authorization': `Bearer ${token}` },
94
+ signal: AbortSignal.timeout(30000),
89
95
  });
90
96
  if (!res.ok) throw new Error(`ADO API ${res.status}: ${res.statusText}`);
91
97
  return res.text();
package/engine/timeout.js CHANGED
@@ -193,7 +193,7 @@ function checkTimeouts(config) {
193
193
  fs.closeSync(fd);
194
194
  liveLog = buf.toString('utf8');
195
195
  } catch { /* ENOENT or read failure — liveLog stays undefined */ }
196
- if (liveLog && (liveLog.includes('"type":"result"') || liveLog.includes('[process-exit]'))) {
196
+ if (liveLog && (liveLog.includes('"type":"result"') || liveLog.includes('\n[process-exit]'))) {
197
197
  completedViaOutput = true;
198
198
  const isSuccess = liveLog.includes('"subtype":"success"');
199
199
  log('info', `Agent ${item.agent} (${item.id}) completed via output detection (${isSuccess ? 'success' : 'error'})`);
@@ -237,7 +237,7 @@ function checkTimeouts(config) {
237
237
  if (liveLog) {
238
238
  // If the output contains a result event or process-exit sentinel, the agent is done.
239
239
  // Don't extend timeout for stale blocking tool calls from before the result (#716).
240
- if (liveLog.includes('"type":"result"') || liveLog.includes('[process-exit]')) {
240
+ if (liveLog.includes('"type":"result"') || liveLog.includes('\n[process-exit]')) {
241
241
  // Agent completed but close event didn't fire — let orphan/hung detection handle it.
242
242
  // Don't set isBlocking — use base heartbeat timeout.
243
243
  } else {
package/engine.js CHANGED
@@ -2698,16 +2698,27 @@ let tickCount = 0;
2698
2698
  const completedPlanCache = new Set();
2699
2699
 
2700
2700
  let tickRunning = false;
2701
+ let _tickStartedAt = 0;
2702
+ const TICK_TIMEOUT_MS = 300000; // 5 min — force-release tick lock if stuck
2701
2703
 
2702
2704
  async function tick() {
2703
- if (tickRunning) return; // prevent overlapping ticks
2705
+ if (tickRunning) {
2706
+ if (_tickStartedAt && Date.now() - _tickStartedAt > TICK_TIMEOUT_MS) {
2707
+ log('error', `Tick hung for ${Math.round((Date.now() - _tickStartedAt) / 1000)}s — force-releasing lock`);
2708
+ tickRunning = false;
2709
+ _tickStartedAt = 0;
2710
+ }
2711
+ return;
2712
+ }
2704
2713
  tickRunning = true;
2714
+ _tickStartedAt = Date.now();
2705
2715
  try {
2706
2716
  await tickInner();
2707
2717
  } catch (e) {
2708
2718
  log('error', `Tick error: ${e.message}`);
2709
2719
  } finally {
2710
2720
  tickRunning = false;
2721
+ _tickStartedAt = 0;
2711
2722
  }
2712
2723
  }
2713
2724
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.804",
3
+ "version": "0.1.806",
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"