@yemi33/minions 0.1.1054 → 0.1.1056

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,13 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.1054 (2026-04-17)
3
+ ## 0.1.1056 (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
+ - reassign pending items from unspawned temp agents to idle named agents (#1204) (#1212)
10
+ - guard undefined agent in pending dispatch loop (closes #1206) (#1210)
9
11
  - improve fallback meeting conclusion
10
12
  - remove command center chevron
11
13
  - stamp live-output.log stub before spawn (#1198)
package/engine.js CHANGED
@@ -3483,6 +3483,66 @@ async function tickInner() {
3483
3483
  log('warn', `Duplicate dispatch ID ${item.id} in pending queue — skipping`);
3484
3484
  continue;
3485
3485
  }
3486
+ // #1206: Guard against undefined/non-string item.agent. A corrupted dispatch
3487
+ // entry (manual edit, serialization round-trip, cleared field) would otherwise
3488
+ // be handed to spawnAgent, which crashes with `TypeError: "path" argument must
3489
+ // be of type string. Received undefined` and re-queues — every tick. Try to
3490
+ // resolve a fallback via routing; if none is available, skip this tick.
3491
+ if (!item.agent || typeof item.agent !== 'string') {
3492
+ const fallback = resolveAgent(item.type || WORK_TYPE.FIX, config);
3493
+ if (!fallback) {
3494
+ log('warn', `Pending dispatch ${item.id} has no agent and routing returned no fallback — skipping`);
3495
+ continue;
3496
+ }
3497
+ log('info', `Pending dispatch ${item.id} missing agent; routed → ${fallback} (#1206 guard)`);
3498
+ item.agent = fallback;
3499
+ item.agentName = config.agents[fallback]?.name || tempAgents.get(fallback)?.name || fallback;
3500
+ item.agentRole = config.agents[fallback]?.role || tempAgents.get(fallback)?.role || 'Agent';
3501
+ // Persist so the fix survives across ticks even if this dispatch is skipped
3502
+ // later in the loop (branch lock, concurrency cap, agent busy, etc.).
3503
+ try {
3504
+ mutateDispatch((dp) => {
3505
+ const p = (dp.pending || []).find(d => d.id === item.id);
3506
+ if (p) {
3507
+ p.agent = item.agent;
3508
+ p.agentName = item.agentName;
3509
+ p.agentRole = item.agentRole;
3510
+ }
3511
+ return dp;
3512
+ });
3513
+ } catch (e) { log('warn', `Persist agent resolution for ${item.id} failed: ${e.message}`); }
3514
+ }
3515
+ // #1204: Pre-assigned unspawned temp agents never unblock naturally.
3516
+ // When a batch discovery saturates maxConcurrent, resolveAgent hands out temp
3517
+ // IDs that get stamped onto pending items. Because those temp IDs are never
3518
+ // in busyAgents (they were never spawned), the agent-busy reassignment path
3519
+ // never fires — items sit forever even when named agents go idle. Re-route
3520
+ // them eagerly before the busy check so an idle named agent can pick up.
3521
+ const isUnspawnedTemp = item.agent?.startsWith('temp-') && !busyAgents.has(item.agent);
3522
+ if (isUnspawnedTemp) {
3523
+ const altAgent = resolveAgent(item.type, config);
3524
+ if (altAgent && altAgent !== item.agent) {
3525
+ const prevAgent = item.agent;
3526
+ item.agent = altAgent;
3527
+ item.agentName = config.agents[altAgent]?.name || tempAgents.get(altAgent)?.name || altAgent;
3528
+ item.agentRole = config.agents[altAgent]?.role || tempAgents.get(altAgent)?.role || 'Agent';
3529
+ delete item._agentBusySince;
3530
+ delete item.skipReason;
3531
+ log('info', `Reassigning ${item.id} from unspawned temp ${prevAgent} to ${altAgent} — temp agent never spawned`);
3532
+ // Persist reassignment to dispatch.json so it survives restarts/ticks
3533
+ mutateDispatch((dp) => {
3534
+ const p = (dp.pending || []).find(d => d.id === item.id);
3535
+ if (p) {
3536
+ p.agent = altAgent;
3537
+ p.agentName = item.agentName;
3538
+ p.agentRole = item.agentRole;
3539
+ delete p._agentBusySince;
3540
+ delete p.skipReason;
3541
+ }
3542
+ return dp;
3543
+ });
3544
+ }
3545
+ }
3486
3546
  if (busyAgents.has(item.agent)) {
3487
3547
  // Agent busy reassignment: if item has been waiting on a busy agent past the threshold,
3488
3548
  // try to find an alternative agent via routing. Skip explicitly assigned items.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1054",
3
+ "version": "0.1.1056",
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"