@yemi33/minions 0.1.520 → 0.1.522

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,12 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.520 (2026-04-07)
3
+ ## 0.1.522 (2026-04-07)
4
+
5
+ ### Features
6
+ - test isolation — tests no longer pollute production data
7
+
8
+ ### Fixes
9
+ - reconcile failed work items that have attached PRs (#407) (#430)
4
10
 
5
11
  ### Other
6
12
  - perf: reduce curl timeout to 5s, cache getDispatch() reads
package/engine/cleanup.js CHANGED
@@ -431,7 +431,30 @@ function runCleanup(config, verbose = false) {
431
431
  }
432
432
  } catch (e) { log('warn', 'KB watchdog check: ' + e.message); }
433
433
 
434
- // 6. Migrate legacy work-item statuses to canonical 'done'
434
+ // 6a. Reconcile failed work items that have an attached PR (#407)
435
+ // If a work item is 'failed' but already has _pr, it should be 'done'.
436
+ for (const project of projects) {
437
+ try {
438
+ const wiPath = projectWorkItemsPath(project);
439
+ const items = safeJson(wiPath) || [];
440
+ let reconciled = 0;
441
+ for (const item of items) {
442
+ if (item.status === shared.WI_STATUS.FAILED && item._pr) {
443
+ item.status = shared.WI_STATUS.DONE;
444
+ if (item.failReason) delete item.failReason;
445
+ if (item.failedAt) delete item.failedAt;
446
+ if (!item.completedAt) item.completedAt = shared.ts();
447
+ reconciled++;
448
+ }
449
+ }
450
+ if (reconciled > 0) {
451
+ safeWrite(wiPath, items);
452
+ log('info', `Reconciled ${reconciled} failed-with-PR item(s) → done in ${project.name}`);
453
+ }
454
+ } catch (e) { log('warn', 'reconcile failed-with-PR: ' + e.message); }
455
+ }
456
+
457
+ // 6b. Migrate legacy work-item statuses to canonical 'done'
435
458
  // in-pr, implemented, complete → done (one-time correction per item)
436
459
  const LEGACY_DONE_ALIASES = new Set(['in-pr', 'implemented', 'complete']);
437
460
  for (const project of projects) {
@@ -1012,6 +1012,7 @@ function createReviewFeedbackForAuthor(reviewerAgentId, pr, config) {
1012
1012
  }
1013
1013
 
1014
1014
  function updateMetrics(agentId, dispatchItem, result, taskUsage, prsCreatedCount, model) {
1015
+ if (!agentId || agentId.startsWith('temp-') || agentId === 'agent1' || agentId === 'reviewer' || agentId.startsWith('_test')) return;
1015
1016
 
1016
1017
  const metricsPath = path.join(ENGINE_DIR, 'metrics.json');
1017
1018
  mutateJsonFileLocked(metricsPath, metrics => {
@@ -1371,7 +1372,8 @@ function syncPrdFromPrs(config) {
1371
1372
  for (const project of allProjects) {
1372
1373
  const wiPath = shared.projectWorkItemsPath(project);
1373
1374
  const items = safeJson(wiPath) || [];
1374
- const hasReconcilable = items.some(wi => (wi.status === WI_STATUS.PENDING || wi.status === WI_STATUS.FAILED) && !wi._pr);
1375
+ const hasReconcilable = items.some(wi =>
1376
+ (wi.status === WI_STATUS.PENDING && !wi._pr) || wi.status === WI_STATUS.FAILED);
1375
1377
  if (!hasReconcilable) continue;
1376
1378
  let reconciled = 0;
1377
1379
  const reconciledItems = mutateJsonFileLocked(wiPath, data => {
@@ -1388,7 +1390,7 @@ function syncPrdFromPrs(config) {
1388
1390
  }
1389
1391
  }
1390
1392
  if (totalReconciled > 0) {
1391
- log('info', `PR sync: reconciled ${totalReconciled} pending work item(s) to done`);
1393
+ log('info', `PR sync: reconciled ${totalReconciled} work item(s) to done`);
1392
1394
  }
1393
1395
  } catch (err) {
1394
1396
  // Non-fatal — log and continue
package/engine/llm.js CHANGED
@@ -7,11 +7,12 @@ const path = require('path');
7
7
  const shared = require('./shared');
8
8
  const { safeWrite, safeUnlink, uid, runFile, cleanChildEnv, parseStreamJsonOutput, mutateJsonFileLocked } = shared;
9
9
 
10
- const MINIONS_DIR = path.resolve(__dirname, '..');
11
- const ENGINE_DIR = __dirname;
10
+ const MINIONS_DIR = shared.MINIONS_DIR;
11
+ const ENGINE_DIR = path.join(MINIONS_DIR, 'engine');
12
12
 
13
13
  function trackEngineUsage(category, usage) {
14
14
  if (!usage) return;
15
+ if (category && (category.startsWith('_test') || category.startsWith('test-'))) return;
15
16
  try {
16
17
  const metricsPath = path.join(ENGINE_DIR, 'metrics.json');
17
18
  mutateJsonFileLocked(metricsPath, (metrics) => {
package/engine/shared.js CHANGED
@@ -6,7 +6,7 @@
6
6
  const fs = require('fs');
7
7
  const path = require('path');
8
8
 
9
- const MINIONS_DIR = path.resolve(__dirname, '..');
9
+ const MINIONS_DIR = process.env.MINIONS_TEST_DIR || path.resolve(__dirname, '..');
10
10
  const PR_LINKS_PATH = path.join(MINIONS_DIR, 'engine', 'pr-links.json');
11
11
  const LOG_PATH = path.join(__dirname, 'log.json');
12
12
 
package/engine.js CHANGED
@@ -878,6 +878,16 @@ function reconcileItemsWithPrs(items, allPrs, { onlyIds } = {}) {
878
878
  if (wi.status !== WI_STATUS.PENDING && wi.status !== WI_STATUS.FAILED) continue;
879
879
  if (onlyIds && !onlyIds.has(wi.id)) continue;
880
880
 
881
+ // Short-circuit: failed item already has a PR attached — mark done directly (#407)
882
+ if (wi.status === WI_STATUS.FAILED && wi._pr) {
883
+ wi.status = WI_STATUS.DONE;
884
+ if (wi.failReason) delete wi.failReason;
885
+ if (wi.failedAt) delete wi.failedAt;
886
+ if (!wi.completedAt) wi.completedAt = ts();
887
+ reconciled++;
888
+ continue;
889
+ }
890
+
881
891
  let exactPr = allPrs.find(pr => (pr.prdItems || []).includes(wi.id));
882
892
  if (!exactPr) {
883
893
  const linkedPrId = Object.keys(prLinks).find(prId => prLinks[prId] === wi.id);
@@ -893,7 +903,7 @@ function reconcileItemsWithPrs(items, allPrs, { onlyIds } = {}) {
893
903
  // Clear failure artifacts if reconciling a previously failed item
894
904
  if (wi.failReason) delete wi.failReason;
895
905
  if (wi.failedAt) delete wi.failedAt;
896
- if (!wi.completedAt) wi.completedAt = new Date().toISOString();
906
+ if (!wi.completedAt) wi.completedAt = ts();
897
907
  reconciled++;
898
908
  }
899
909
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.520",
3
+ "version": "0.1.522",
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"