@yemi33/minions 0.1.814 → 0.1.816

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.814 (2026-04-11)
3
+ ## 0.1.816 (2026-04-11)
4
4
 
5
5
  ### Features
6
6
  - Bidirectional Teams integration for Command Center (#764)
@@ -13,6 +13,8 @@
13
13
  - cap review→fix cycles at evalMaxIterations (default 3)
14
14
 
15
15
  ### Fixes
16
+ - handle local-only dependency branches in dep merge (closes #782) (#825)
17
+ - reset PRD item status when work item is deleted (closes #779) (#823)
16
18
  - add smoke test for checkTimeouts ReferenceError regression (closes #775) (#822)
17
19
  - replace safeWrite with mutateDispatch in CLI kill handler (#654)
18
20
  - CC queue drain uses combined flush, not one-at-a-time while loop (#818)
@@ -31,8 +33,6 @@
31
33
  - remove redundant 'PR' prefix from dispatch labels (id already has it)
32
34
  - include PR title in all dispatch labels and escalation alerts
33
35
  - never downgrade reviewStatus from 'approved' unless explicitly rejected
34
- - warn on invalid pipeline JSON instead of silently dropping + add test
35
- - repair invalid JSON in daily-arch-improvement pipeline
36
36
 
37
37
  ## 0.1.782 (2026-04-10)
38
38
 
package/dashboard.js CHANGED
@@ -1210,6 +1210,14 @@ const server = http.createServer(async (req, res) => {
1210
1210
  if (cleaned) safeWrite(cooldownPath, cooldowns);
1211
1211
  } catch (e) { console.error('cooldown cleanup:', e.message); }
1212
1212
 
1213
+ // Reset PRD item status so it doesn't stay 'dispatched' with no work item (#779)
1214
+ if (item && item.sourcePlan) {
1215
+ try {
1216
+ const lifecycle = require('./engine/lifecycle');
1217
+ lifecycle.syncPrdItemStatus(id, WI_STATUS.PENDING, item.sourcePlan);
1218
+ } catch (e) { console.error('PRD status reset on delete:', e.message); }
1219
+ }
1220
+
1213
1221
  invalidateStatusCache();
1214
1222
  return jsonReply(res, 200, { ok: true, id, dispatchRemoved });
1215
1223
  } catch (e) { return jsonReply(res, 400, { error: e.message }); }
package/engine/cleanup.js CHANGED
@@ -582,6 +582,41 @@ function runCleanup(config, verbose = false) {
582
582
  }
583
583
  } catch (e) { log('warn', 'migrate PRD legacy statuses: ' + e.message); }
584
584
 
585
+ // Reset orphaned PRD item statuses — dispatched/failed with no matching work item (#779)
586
+ cleaned.orphanedPrdStatuses = 0;
587
+ try {
588
+ const wiIds = new Set();
589
+ for (const project of projects) {
590
+ const items = safeJson(projectWorkItemsPath(project)) || [];
591
+ for (const wi of items) { if (wi?.id) wiIds.add(wi.id); }
592
+ }
593
+ try {
594
+ const centralWi = safeJson(path.join(MINIONS_DIR, 'work-items.json')) || [];
595
+ for (const wi of centralWi) { if (wi?.id) wiIds.add(wi.id); }
596
+ } catch { /* optional */ }
597
+
598
+ let orphanPrdEntries;
599
+ try { orphanPrdEntries = fs.readdirSync(PRD_DIR).filter(f => f.endsWith('.json')); }
600
+ catch { orphanPrdEntries = []; }
601
+ for (const pf of orphanPrdEntries) {
602
+ const prdPath = path.join(PRD_DIR, pf);
603
+ const prd = safeJson(prdPath);
604
+ if (!prd?.missing_features) continue;
605
+ let reset = 0;
606
+ for (const feat of prd.missing_features) {
607
+ if ((feat.status === shared.WI_STATUS.DISPATCHED || feat.status === shared.WI_STATUS.FAILED) && !wiIds.has(feat.id)) {
608
+ feat.status = shared.WI_STATUS.PENDING;
609
+ reset++;
610
+ }
611
+ }
612
+ if (reset > 0) {
613
+ safeWrite(prdPath, prd);
614
+ log('info', `Reset ${reset} orphaned PRD item status(es) → pending in ${pf}`);
615
+ cleaned.orphanedPrdStatuses += reset;
616
+ }
617
+ }
618
+ } catch (e) { log('warn', 'orphan PRD status reset: ' + e.message); }
619
+
585
620
  // 10. Prune CC tab sessions — cap at 50 entries, remove oldest beyond cap
586
621
  cleaned.ccSessions = 0;
587
622
  try {
@@ -606,7 +641,7 @@ function runCleanup(config, verbose = false) {
606
641
  const entries = Object.entries(docSessions);
607
642
  const DOC_SESSIONS_CAP = 100;
608
643
  if (entries.length > DOC_SESSIONS_CAP) {
609
- entries.sort((a, b) => new Date(b[1].lastActiveAt || 0) - new Date(a[1].lastActiveAt || 0));
644
+ entries.sort((a, b) => new Date(b.lastActiveAt || 0) - new Date(a.lastActiveAt || 0));
610
645
  const keep = Object.fromEntries(entries.slice(0, DOC_SESSIONS_CAP));
611
646
  cleaned.docSessions = entries.length - DOC_SESSIONS_CAP;
612
647
  safeWrite(docSessionsPath, keep);
package/engine/queries.js CHANGED
@@ -953,7 +953,9 @@ function getPrdInfo(config) {
953
953
  for (const item of items) {
954
954
  const wi = wiById[item.id];
955
955
  // Work item status is source of truth when available (PRD JSON may lag behind)
956
- const rawStatus = wi ? (wi.status || item.status) : item.status;
956
+ // If PRD says dispatched/failed but no work item exists, treat as pending (orphaned — #779)
957
+ const rawStatus = wi ? (wi.status || item.status)
958
+ : ((item.status === WI_STATUS.DISPATCHED || item.status === WI_STATUS.FAILED) ? WI_STATUS.PENDING : item.status);
957
959
  item.status = statusDisplay[rawStatus] || rawStatus || 'missing';
958
960
  // Attach execution metadata for display (agent, PR link, fail reason)
959
961
  if (wi) {
package/engine.js CHANGED
@@ -471,22 +471,39 @@ async function spawnAgent(dispatchItem, config) {
471
471
  );
472
472
  const hasFetchFailures = fetchResults.some(r => r.status === 'rejected');
473
473
  const allPrsForFetch = hasFetchFailures ? shared.getProjects(config).reduce((acc, p) => acc.concat(safeJson(shared.projectPrPath(p)) || []), []) : [];
474
+ // Track branches recovered by local-only push so they can be merged
475
+ const recoveredBranches = new Set();
474
476
  for (let i = 0; i < fetchResults.length; i++) {
475
477
  if (fetchResults[i].status === 'rejected') {
476
478
  const failedBranch = fetchable[i].branch;
477
479
  const failedPrId = fetchable[i].prId;
480
+ const errMsg = fetchResults[i].reason?.message || '';
478
481
  const pr = allPrsForFetch.find(p => p.id === failedPrId);
479
482
  if (pr && (pr.status === 'merged' || pr.status === 'closed')) {
480
483
  log('info', `Dependency ${failedBranch} (${failedPrId}) already merged — skipping, changes already in main`);
481
484
  continue;
482
485
  }
486
+ // If remote ref missing, check if branch exists locally and push it (#782)
487
+ if (errMsg.includes('couldn\'t find remote ref') || errMsg.includes('not found in upstream')) {
488
+ try {
489
+ await execAsync(`git rev-parse --verify "refs/heads/${failedBranch}"`, { ..._gitOpts, cwd: rootDir });
490
+ // Branch exists locally — push it to origin
491
+ log('info', `Dependency ${failedBranch} exists locally but not on remote — pushing to origin`);
492
+ await execAsync(`git push origin "${failedBranch}"`, { ..._gitOpts, cwd: rootDir, timeout: 60000 });
493
+ log('info', `Successfully pushed local-only dependency branch ${failedBranch} to origin`);
494
+ recoveredBranches.add(failedBranch);
495
+ continue;
496
+ } catch (localErr) {
497
+ log('warn', `Dependency ${failedBranch} not found locally or push failed: ${localErr.message}`);
498
+ }
499
+ }
483
500
  _failedRefCache.add(failedBranch);
484
- log('warn', `Failed to fetch dependency ${failedBranch}: ${fetchResults[i].reason?.message}`);
501
+ log('warn', `Failed to fetch dependency ${failedBranch}: ${errMsg}`);
485
502
  depMergeFailed = true;
486
503
  }
487
504
  }
488
- // Merge successfully-fetched branches sequentially (merges modify the worktree)
489
- const fetched = fetchable.filter((_, i) => fetchResults[i].status === 'fulfilled');
505
+ // Merge successfully-fetched + recovered (local-only pushed) branches sequentially
506
+ const fetched = fetchable.filter((_, i) => fetchResults[i].status === 'fulfilled' || recoveredBranches.has(fetchable[i].branch));
490
507
  if (!depMergeFailed) {
491
508
  for (const { branch: depBranch, prId } of fetched) {
492
509
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.814",
3
+ "version": "0.1.816",
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"