@yemi33/minions 0.1.981 → 0.1.982

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.981 (2026-04-15)
3
+ ## 0.1.982 (2026-04-15)
4
4
 
5
5
  ### Features
6
6
  - gate build failure auto-fix behind autoFixBuilds flag
@@ -25,6 +25,7 @@
25
25
  - add /api/work-items/reopen endpoint and reopen-work-item CC action (#982)
26
26
 
27
27
  ### Fixes
28
+ - restore rereview and human-fix dispatch
28
29
  - build fix sets fixDispatched to block same-tick conflict fix
29
30
  - ENGINE_DEFAULTS undefined in tick + playbook empty-var false positives
30
31
  - defer review setCooldown to post-gating in discoverWork
@@ -44,7 +45,6 @@
44
45
  - CC streaming 'tabId' TDZ error on new tab first message
45
46
  - fix tabId scope and close-event lock race in CC handlers
46
47
  - defer setCooldown to post-gating in discoverWork
47
- - fix CC queued message 'already processing' and thinking UX stacking
48
48
 
49
49
  ### Other
50
50
  - refactor(watches): rename maxTriggers→stopAfter, add onNotMet per-poll action
@@ -90,6 +90,13 @@ function setCooldownFailure(key) {
90
90
  saveCooldowns();
91
91
  }
92
92
 
93
+ function clearCooldown(key) {
94
+ if (!dispatchCooldowns.has(key)) return false;
95
+ dispatchCooldowns.delete(key);
96
+ saveCooldowns();
97
+ return true;
98
+ }
99
+
93
100
  function isAlreadyDispatched(key) {
94
101
  const dispatch = queries.getDispatch();
95
102
  // Check pending and active
@@ -130,6 +137,7 @@ module.exports = {
130
137
  setCooldownWithContext,
131
138
  getCoalescedContexts,
132
139
  setCooldownFailure,
140
+ clearCooldown,
133
141
  isAlreadyDispatched,
134
142
  isBranchActive,
135
143
  };
package/engine.js CHANGED
@@ -1500,7 +1500,7 @@ function updateSnapshot(config) {
1500
1500
 
1501
1501
  const { COOLDOWN_PATH, dispatchCooldowns, loadCooldowns, saveCooldowns,
1502
1502
  isOnCooldown, setCooldown, setCooldownWithContext, getCoalescedContexts,
1503
- setCooldownFailure, isAlreadyDispatched, isBranchActive } = require('./engine/cooldown');
1503
+ setCooldownFailure, clearCooldown, isAlreadyDispatched, isBranchActive } = require('./engine/cooldown');
1504
1504
 
1505
1505
 
1506
1506
 
@@ -1984,6 +1984,47 @@ async function discoverFromPrs(config, project) {
1984
1984
  if (item) { newWork.push(item); }
1985
1985
  }
1986
1986
 
1987
+ // Re-review after fix: trigger when a fix was pushed after the last minions review,
1988
+ // or when no minions review has completed yet (e.g. human-feedback-only fix path).
1989
+ const fixedAfterReview = !!(pr.minionsReview?.fixedAt &&
1990
+ (!pr.lastReviewedAt || pr.minionsReview.fixedAt > pr.lastReviewedAt));
1991
+ const needsReReview = autoReview && reviewStatus === 'waiting' &&
1992
+ fixedAfterReview && !evalEscalated;
1993
+ if (needsReReview) {
1994
+ const key = `rereview-${project?.name || 'default'}-${pr.id}`;
1995
+ // Skip isAlreadyDispatched — fixedAfterReview/lastReviewedAt already dedupe; the 1hr
1996
+ // completed-dispatch window would block legitimate re-reviews within the hour after a fix
1997
+ if (isOnCooldown(key, cooldownMs)) continue;
1998
+
1999
+ // Pre-dispatch live vote check — cached 'waiting' may be stale if reviewer already acted
2000
+ try {
2001
+ const checkFn = project.repoHost === 'github' ? ghCheckLiveReview : adoCheckLiveReview;
2002
+ const liveStatus = await checkFn(pr, project);
2003
+ if (liveStatus && liveStatus !== 'waiting') {
2004
+ log('info', `Pre-dispatch vote check: ${pr.id} is ${liveStatus} (cached was waiting) — skipping re-review`);
2005
+ if (pr.reviewStatus !== 'approved') pr.reviewStatus = liveStatus;
2006
+ try {
2007
+ mutateJsonFileLocked(projectPrPath(project), data => {
2008
+ if (!Array.isArray(data)) return data;
2009
+ const target = data.find(p => p.id === pr.id);
2010
+ if (target && target.reviewStatus !== 'approved') target.reviewStatus = liveStatus;
2011
+ return data;
2012
+ });
2013
+ } catch {}
2014
+ continue;
2015
+ }
2016
+ } catch (e) { log('warn', `Pre-dispatch vote check for ${pr.id}: ${e.message}`); }
2017
+
2018
+ const agentId = resolveAgent('review', config);
2019
+ if (!agentId) continue;
2020
+
2021
+ const item = buildPrDispatch(agentId, config, project, pr, 'review', {
2022
+ pr_id: pr.id, pr_number: prNumber, pr_title: pr.title || '', pr_branch: pr.branch || '',
2023
+ pr_author: pr.agent || '', pr_url: pr.url || '',
2024
+ }, `Review ${pr.id}: ${pr.title}`, { dispatchKey: key, source: 'pr', pr, branch: pr.branch, project: projMeta });
2025
+ if (item) { newWork.push(item); }
2026
+ }
2027
+
1987
2028
  // PRs with changes requested → route back to author for fix
1988
2029
  let fixDispatched = false;
1989
2030
  if (reviewStatus === 'changes-requested' && !awaitingReReview && !evalEscalated) {
@@ -2013,7 +2054,15 @@ async function discoverFromPrs(config, project) {
2013
2054
  const hasCoalescedFeedback = (dispatchCooldowns.get(humanFixKey)?.pendingContexts || []).length > 0;
2014
2055
  if ((pr.humanFeedback?.pendingFix || hasCoalescedFeedback) && !awaitingReReview && !fixDispatched) {
2015
2056
  const key = humanFixKey;
2016
- if (isAlreadyDispatched(key) || isOnCooldown(key, cooldownMs)) {
2057
+ let staleCoalesced = [];
2058
+ const alreadyDispatched = isAlreadyDispatched(key);
2059
+ const blockedByCooldown = isOnCooldown(key, cooldownMs);
2060
+ if (blockedByCooldown && !alreadyDispatched) {
2061
+ staleCoalesced = getCoalescedContexts(key);
2062
+ clearCooldown(key);
2063
+ log('info', `Cleared stale cooldown for ${key} — no matching dispatch history`);
2064
+ }
2065
+ if (alreadyDispatched || isOnCooldown(key, cooldownMs)) {
2017
2066
  // Coalesce: save feedback for next dispatch
2018
2067
  if (pr.humanFeedback?.feedbackContent) {
2019
2068
  setCooldownWithContext(key, { feedbackContent: pr.humanFeedback.feedbackContent, timestamp: ts() });
@@ -2023,7 +2072,7 @@ async function discoverFromPrs(config, project) {
2023
2072
  const agentId = resolveAgent('fix', config, pr.agent);
2024
2073
  if (!agentId) continue;
2025
2074
 
2026
- const coalesced = getCoalescedContexts(key);
2075
+ const coalesced = [...staleCoalesced, ...getCoalescedContexts(key)];
2027
2076
  let reviewNote = pr.humanFeedback.feedbackContent || 'See PR thread comments';
2028
2077
  if (coalesced.length > 0) {
2029
2078
  const earlier = coalesced.map(c => c.feedbackContent).filter(Boolean).join('\n\n---\n\n');
@@ -2035,7 +2084,7 @@ async function discoverFromPrs(config, project) {
2035
2084
  reviewer: 'Human Reviewer',
2036
2085
  review_note: reviewNote,
2037
2086
  }, `Fix ${pr.id}: ${pr.title || ''} — human feedback`, { dispatchKey: key, source: 'pr-human-feedback', pr, branch: pr.branch, project: projMeta });
2038
- if (item) { newWork.push(item); setCooldown(key); fixDispatched = true; }
2087
+ if (item) { newWork.push(item); fixDispatched = true; }
2039
2088
  }
2040
2089
 
2041
2090
  // PRs with build failures — route to author (has session context from implementing)
@@ -3561,4 +3610,3 @@ if (require.main === module) {
3561
3610
  const [cmd, ...args] = process.argv.slice(2);
3562
3611
  handleCommand(cmd, args);
3563
3612
  }
3564
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.981",
3
+ "version": "0.1.982",
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"