@yemi33/minions 0.1.973 → 0.1.975
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 +2 -2
- package/engine/lifecycle.js +36 -31
- package/engine.js +3 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.975 (2026-04-14)
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
6
|
- flush queued CC messages as single combined request
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
- replace magic string 'active' with PR_STATUS.ACTIVE in lifecycle.js (#969)
|
|
26
26
|
|
|
27
27
|
### Fixes
|
|
28
|
+
- move review verdict check before updateWorkItemStatus(DONE)
|
|
28
29
|
- skip isAlreadyDispatched in needsReReview to allow re-review within 1hr
|
|
29
30
|
- loop queue flush so messages queued during combined send aren't orphaned
|
|
30
31
|
- set lastPushedAt on fix completion to unblock re-review without poller
|
|
@@ -44,7 +45,6 @@
|
|
|
44
45
|
- add autoFixConflicts to boolean settings persist list
|
|
45
46
|
- tighten build query guard to require mergeCommitId
|
|
46
47
|
- restore sourceVersion filter after refs/pull merge ref switch
|
|
47
|
-
- use refs/pull/{id}/merge for build status scoping
|
|
48
48
|
|
|
49
49
|
### Other
|
|
50
50
|
- refactor(dashboard): extract _releaseCCTab helper and CC_LOCK_WAIT_MS constant
|
package/engine/lifecycle.js
CHANGED
|
@@ -940,8 +940,6 @@ function updatePrAfterFix(pr, project, source) {
|
|
|
940
940
|
if (!target) return prs;
|
|
941
941
|
// Never downgrade from approved — fix was dispatched but PR is already approved
|
|
942
942
|
if (target.reviewStatus !== 'approved') target.reviewStatus = 'waiting';
|
|
943
|
-
// Advance lastPushedAt so alreadyReviewed resets immediately, without waiting for the poller
|
|
944
|
-
target.lastPushedAt = ts();
|
|
945
943
|
// Always clear pendingFix — a fix dispatch (regardless of source) addresses all pending feedback
|
|
946
944
|
if (target.humanFeedback) target.humanFeedback.pendingFix = false;
|
|
947
945
|
if (source === 'pr-human-feedback') {
|
|
@@ -1599,6 +1597,41 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
1599
1597
|
// If decomposition produced nothing, fall through to mark parent as done
|
|
1600
1598
|
}
|
|
1601
1599
|
|
|
1600
|
+
// Verify review work items include a verdict — must run BEFORE updateWorkItemStatus(DONE),
|
|
1601
|
+
// same pattern as plan-to-prd (#893): updateWorkItemStatus deletes _retryCount, so the check
|
|
1602
|
+
// must read/increment it before that happens. Also sets skipDoneStatus so completedAt isn't
|
|
1603
|
+
// written and then left dangling when status is reset to pending for retry.
|
|
1604
|
+
if (effectiveSuccess && type === WORK_TYPE.REVIEW && meta?.item?.id) {
|
|
1605
|
+
const verdict = parseReviewVerdict(resultSummary);
|
|
1606
|
+
if (!verdict) {
|
|
1607
|
+
skipDoneStatus = true;
|
|
1608
|
+
const wiPath = resolveWorkItemPath(meta);
|
|
1609
|
+
if (wiPath) {
|
|
1610
|
+
try {
|
|
1611
|
+
mutateJsonFileLocked(wiPath, data => {
|
|
1612
|
+
if (!Array.isArray(data)) return data;
|
|
1613
|
+
const w = data.find(i => i.id === meta.item.id);
|
|
1614
|
+
if (!w) return data;
|
|
1615
|
+
const retries = w._retryCount || 0;
|
|
1616
|
+
if (retries < ENGINE_DEFAULTS.maxRetries) {
|
|
1617
|
+
w.status = WI_STATUS.PENDING;
|
|
1618
|
+
w._retryCount = retries + 1;
|
|
1619
|
+
delete w.dispatched_at;
|
|
1620
|
+
delete w.completedAt;
|
|
1621
|
+
log('warn', `Review ${meta.item.id} completed without verdict — auto-retry ${retries + 1}/${ENGINE_DEFAULTS.maxRetries}`);
|
|
1622
|
+
} else {
|
|
1623
|
+
w.status = WI_STATUS.FAILED;
|
|
1624
|
+
w.failReason = 'No review verdict after ' + ENGINE_DEFAULTS.maxRetries + ' attempts';
|
|
1625
|
+
w.failedAt = ts();
|
|
1626
|
+
log('warn', `Review ${meta.item.id} failed — no verdict after ${ENGINE_DEFAULTS.maxRetries} retries`);
|
|
1627
|
+
}
|
|
1628
|
+
return data;
|
|
1629
|
+
});
|
|
1630
|
+
} catch (err) { log('warn', `review verdict check: ${err.message}`); }
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1602
1635
|
// Verify plan-to-prd actually created the PRD file before marking done (#893)
|
|
1603
1636
|
// Must run BEFORE updateWorkItemStatus(DONE) — otherwise _retryCount is deleted and retries never advance
|
|
1604
1637
|
if (effectiveSuccess && type === WORK_TYPE.PLAN_TO_PRD && meta?.item?.id) {
|
|
@@ -1772,35 +1805,7 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
1772
1805
|
|
|
1773
1806
|
// Old plan-to-prd PRD check removed — moved before updateWorkItemStatus(DONE) to fix #893
|
|
1774
1807
|
// (retryCount was being deleted by done-marking before the check could read it)
|
|
1775
|
-
|
|
1776
|
-
// Verify review work items include a verdict — mirrors the PRD file existence check pattern.
|
|
1777
|
-
// If agent completed (exit 0) but output has no VERDICT: APPROVE/REQUEST_CHANGES, the review
|
|
1778
|
-
// is incomplete. Auto-retry up to maxRetries, then fail.
|
|
1779
|
-
if (effectiveSuccess && type === WORK_TYPE.REVIEW && meta?.item?.id) {
|
|
1780
|
-
const verdict = parseReviewVerdict(resultSummary);
|
|
1781
|
-
if (!verdict) {
|
|
1782
|
-
const wiPath = resolveWorkItemPath(meta);
|
|
1783
|
-
if (wiPath) {
|
|
1784
|
-
mutateJsonFileLocked(wiPath, data => {
|
|
1785
|
-
if (!Array.isArray(data)) return data;
|
|
1786
|
-
const w = data.find(i => i.id === meta.item.id);
|
|
1787
|
-
if (!w) return data;
|
|
1788
|
-
const retries = w._retryCount || 0;
|
|
1789
|
-
if (retries < ENGINE_DEFAULTS.maxRetries) {
|
|
1790
|
-
w.status = WI_STATUS.PENDING;
|
|
1791
|
-
w._retryCount = retries + 1;
|
|
1792
|
-
delete w.dispatched_at;
|
|
1793
|
-
log('warn', `Review ${meta.item.id} completed without verdict — auto-retry ${retries + 1}/${ENGINE_DEFAULTS.maxRetries}`);
|
|
1794
|
-
} else {
|
|
1795
|
-
w.status = WI_STATUS.FAILED;
|
|
1796
|
-
w.failReason = 'No review verdict after ' + ENGINE_DEFAULTS.maxRetries + ' attempts';
|
|
1797
|
-
log('warn', `Review ${meta.item.id} failed — no verdict after ${ENGINE_DEFAULTS.maxRetries} retries`);
|
|
1798
|
-
}
|
|
1799
|
-
return data;
|
|
1800
|
-
});
|
|
1801
|
-
}
|
|
1802
|
-
}
|
|
1803
|
-
}
|
|
1808
|
+
// Review verdict check similarly moved before updateWorkItemStatus(DONE) — same root cause.
|
|
1804
1809
|
|
|
1805
1810
|
if (type === WORK_TYPE.REVIEW) await updatePrAfterReview(agentId, meta?.pr, meta?.project, config, resultSummary);
|
|
1806
1811
|
if (type === WORK_TYPE.FIX) {
|
package/engine.js
CHANGED
|
@@ -1984,11 +1984,12 @@ async function discoverFromPrs(config, project) {
|
|
|
1984
1984
|
if (item) { newWork.push(item); }
|
|
1985
1985
|
}
|
|
1986
1986
|
|
|
1987
|
-
// Re-review after fix:
|
|
1987
|
+
// Re-review after fix: only trigger when fixedAt > lastReviewedAt (not a broad !alreadyReviewed
|
|
1988
|
+
// fallback — that caused infinite re-review loops on GitHub where self-approval is blocked)
|
|
1988
1989
|
const fixedAfterReview = !!(pr.minionsReview?.fixedAt &&
|
|
1989
1990
|
pr.lastReviewedAt && pr.minionsReview.fixedAt > pr.lastReviewedAt);
|
|
1990
1991
|
const needsReReview = autoReview && reviewStatus === 'waiting' &&
|
|
1991
|
-
|
|
1992
|
+
fixedAfterReview && !evalEscalated;
|
|
1992
1993
|
if (needsReReview) {
|
|
1993
1994
|
const key = `review-${project?.name || 'default'}-${pr.id}`;
|
|
1994
1995
|
// Skip isAlreadyDispatched — fixedAfterReview/alreadyReviewed already dedup; the 1hr
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.975",
|
|
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"
|