@yemi33/minions 0.1.1059 → 0.1.1060

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,11 +1,12 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.1059 (2026-04-17)
3
+ ## 0.1.1060 (2026-04-17)
4
4
 
5
5
  ### Features
6
6
  - seed realActivityMap at spawn time, stamp pid in live-output (#1200)
7
7
 
8
8
  ### Fixes
9
+ - cap temp-agent creation at maxConcurrent per tick (#1219)
9
10
  - reassign pending items from unspawned temp agents to idle named agents (#1204) (#1212)
10
11
  - guard undefined agent in pending dispatch loop (closes #1206) (#1210)
11
12
  - improve fallback meeting conclusion
@@ -14,6 +15,7 @@
14
15
  - harden settings save and migrate pr poll config
15
16
 
16
17
  ### Other
18
+ - Use PAT for publish merges
17
19
  - test(queries): add unit tests for invalidateDispatchCache/getInbox/getAgentCharter (#1214)
18
20
  - test(shared): add unit tests for truncateTextBytes/tailTextBytes/execSilent/trackReviewMetric/parseCanonicalPrId (#1215)
19
21
  - Fix publish workflow merge
package/engine/routing.js CHANGED
@@ -102,6 +102,20 @@ function isAgentIdle(agentId) {
102
102
  const _claimedAgents = new Set();
103
103
  function resetClaimedAgents() { _claimedAgents.clear(); }
104
104
 
105
+ // Per-tick temp-agent creation budget. Defaults to Infinity (unbounded) so
106
+ // routing.js in isolation keeps previous behaviour. The engine calls
107
+ // setTempBudget() once per tick with `maxConcurrent - activeCount` to ensure
108
+ // temp agents count against maxConcurrent exactly like named agents.
109
+ // Without this, a batch discovery (e.g. PR-poll sweep over many failing PRs)
110
+ // would register one temp agent per pending item, overwhelming the OS and
111
+ // causing mass orphans when the dispatch loop spawns them on later ticks.
112
+ // Closes #1209.
113
+ let _tempBudget = Infinity;
114
+ function setTempBudget(n) {
115
+ _tempBudget = (typeof n === 'number' && n >= 0 && Number.isFinite(n)) ? n : Infinity;
116
+ }
117
+ function getTempBudget() { return _tempBudget; }
118
+
105
119
  function resolveAgent(workType, config, authorAgent = null) {
106
120
  const routes = getRoutingTableCached();
107
121
  const route = routes[workType] || routes['implement'];
@@ -144,6 +158,16 @@ function resolveAgent(workType, config, authorAgent = null) {
144
158
 
145
159
  // No idle configured agent — try temp agent if enabled
146
160
  if (config.engine?.allowTempAgents) {
161
+ // Enforce per-tick temp-agent budget so temps count against maxConcurrent.
162
+ // Without this guard, a mass-discovery pass (e.g. 20 PR build failures) would
163
+ // register one temp agent per pending item regardless of concurrency cap,
164
+ // leaking orphan temp IDs into tempAgents/dispatch and, over subsequent ticks,
165
+ // spawning far more processes than maxConcurrent allows (#1209).
166
+ if (_tempBudget <= 0) {
167
+ log('info', `Temp agent refused for ${workType} — per-tick budget exhausted (maxConcurrent reached)`);
168
+ return null;
169
+ }
170
+ _tempBudget--;
147
171
  const tempId = `temp-${shared.uid()}`;
148
172
  _claimedAgents.add(tempId);
149
173
  tempAgents.set(tempId, { name: `Temp-${tempId.slice(5, 9)}`, role: 'Temporary Agent', createdAt: ts() });
@@ -166,4 +190,6 @@ module.exports = {
166
190
  _claimedAgents,
167
191
  resetClaimedAgents,
168
192
  resolveAgent,
193
+ setTempBudget,
194
+ getTempBudget,
169
195
  };
package/engine.js CHANGED
@@ -122,7 +122,7 @@ const { getConfig, getControl, getDispatch, getNotes,
122
122
 
123
123
  const { getRouting, parseRoutingTable, getRoutingTableCached, getMonthlySpend,
124
124
  getAgentErrorRate, isAgentIdle, resolveAgent, resetClaimedAgents,
125
- tempAgents } = require('./engine/routing');
125
+ setTempBudget, tempAgents } = require('./engine/routing');
126
126
 
127
127
  // ─── Playbook, system prompt, agent context (extracted to engine/playbook.js) ─
128
128
 
@@ -3434,6 +3434,18 @@ async function tickInner() {
3434
3434
  }
3435
3435
 
3436
3436
  // 3. Discover new work from sources
3437
+ // Cap temp-agent creation at (maxConcurrent - activeCount) for this tick so
3438
+ // temps count against maxConcurrent like named agents. Without this, a mass
3439
+ // discovery pass (e.g. 20 PR build failures) would stamp a fresh temp agent
3440
+ // onto every pending item regardless of concurrency cap, and those temps
3441
+ // would spawn over subsequent ticks — overwhelming the OS and mass-orphaning
3442
+ // the dispatches (#1209).
3443
+ {
3444
+ const dispatchPre = getDispatch();
3445
+ const activeCountPre = (dispatchPre.active || []).length;
3446
+ const maxC = config.engine?.maxConcurrent ?? ENGINE_DEFAULTS.maxConcurrent;
3447
+ setTempBudget(Math.max(0, maxC - activeCountPre));
3448
+ }
3437
3449
  let discoveryOk = true;
3438
3450
  try { await discoverWork(config); } catch (e) { log('warn', 'discoverWork: ' + e.message); discoveryOk = false; }
3439
3451
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1059",
3
+ "version": "0.1.1060",
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"