@yemi33/minions 0.1.455 → 0.1.456
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 +5 -0
- package/engine/ado.js +28 -0
- package/engine/github.js +28 -0
- package/engine.js +23 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/engine/ado.js
CHANGED
|
@@ -482,11 +482,39 @@ async function reconcilePrs(config) {
|
|
|
482
482
|
}
|
|
483
483
|
}
|
|
484
484
|
|
|
485
|
+
/**
|
|
486
|
+
* Fetch live review status for a single PR from ADO (synchronous).
|
|
487
|
+
* Returns 'approved', 'changes-requested', 'waiting', or 'pending'.
|
|
488
|
+
* Returns null if the check fails (token unavailable, API error).
|
|
489
|
+
* Used as a pre-dispatch gate to avoid dispatching reviews for already-approved PRs.
|
|
490
|
+
*/
|
|
491
|
+
function checkLiveReviewStatus(pr, project) {
|
|
492
|
+
try {
|
|
493
|
+
const token = getAdoToken();
|
|
494
|
+
if (!token) return null;
|
|
495
|
+
const orgBase = shared.getAdoOrgBase(project);
|
|
496
|
+
const prNum = (pr.id || '').replace(/^PR-/, '');
|
|
497
|
+
const url = `${orgBase}/${project.adoProject}/_apis/git/repositories/${project.repositoryId}/pullrequests/${prNum}?api-version=7.1`;
|
|
498
|
+
const result = exec(`curl -s -H "Authorization: Bearer ${token}" "${url}"`, { encoding: 'utf-8', timeout: 15000, windowsHide: true });
|
|
499
|
+
const prData = JSON.parse(result);
|
|
500
|
+
const votes = (prData.reviewers || []).map(r => r.vote).filter(v => v !== undefined);
|
|
501
|
+
if (votes.length === 0) return 'pending';
|
|
502
|
+
if (votes.some(v => v === -10)) return 'changes-requested';
|
|
503
|
+
if (votes.some(v => v >= 5)) return 'approved';
|
|
504
|
+
if (votes.some(v => v === -5)) return 'waiting';
|
|
505
|
+
return 'pending';
|
|
506
|
+
} catch (e) {
|
|
507
|
+
log('warn', `Live review check for ${pr.id}: ${e.message}`);
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
485
512
|
module.exports = {
|
|
486
513
|
getAdoToken,
|
|
487
514
|
adoFetch,
|
|
488
515
|
pollPrStatus,
|
|
489
516
|
pollPrHumanComments,
|
|
490
517
|
reconcilePrs,
|
|
518
|
+
checkLiveReviewStatus,
|
|
491
519
|
};
|
|
492
520
|
|
package/engine/github.js
CHANGED
|
@@ -466,9 +466,37 @@ async function reconcilePrs(config) {
|
|
|
466
466
|
}
|
|
467
467
|
}
|
|
468
468
|
|
|
469
|
+
/**
|
|
470
|
+
* Fetch live review status for a single PR from GitHub. Returns 'approved', 'changes-requested',
|
|
471
|
+
* 'waiting', or 'pending'. Returns null if the check fails.
|
|
472
|
+
*/
|
|
473
|
+
function checkLiveReviewStatus(pr, project) {
|
|
474
|
+
try {
|
|
475
|
+
const slug = getRepoSlug(project);
|
|
476
|
+
if (!slug) return null;
|
|
477
|
+
const prNum = (pr.id || '').replace(/^PR-/, '');
|
|
478
|
+
const reviews = ghApi(`/pulls/${prNum}/reviews`, slug);
|
|
479
|
+
if (!reviews || !Array.isArray(reviews)) return null;
|
|
480
|
+
const latestByUser = new Map();
|
|
481
|
+
for (const r of reviews) {
|
|
482
|
+
if (r.state === 'COMMENTED') continue;
|
|
483
|
+
latestByUser.set(r.user?.login || '', r.state);
|
|
484
|
+
}
|
|
485
|
+
const states = [...latestByUser.values()];
|
|
486
|
+
if (states.some(s => s === 'CHANGES_REQUESTED')) return 'changes-requested';
|
|
487
|
+
if (states.some(s => s === 'APPROVED')) return 'approved';
|
|
488
|
+
if (states.length > 0) return 'pending';
|
|
489
|
+
return 'pending';
|
|
490
|
+
} catch (e) {
|
|
491
|
+
log('warn', `Live review check for ${pr.id}: ${e.message}`);
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
469
496
|
module.exports = {
|
|
470
497
|
pollPrStatus,
|
|
471
498
|
pollPrHumanComments,
|
|
472
499
|
reconcilePrs,
|
|
500
|
+
checkLiveReviewStatus,
|
|
473
501
|
};
|
|
474
502
|
|
package/engine.js
CHANGED
|
@@ -830,8 +830,8 @@ function reconcileItemsWithPrs(items, allPrs, { onlyIds } = {}) {
|
|
|
830
830
|
// ─── Inbox Consolidation (extracted to engine/consolidation.js) ──────────────
|
|
831
831
|
|
|
832
832
|
const { consolidateInbox } = require('./engine/consolidation');
|
|
833
|
-
const { pollPrStatus, pollPrHumanComments, reconcilePrs } = require('./engine/ado');
|
|
834
|
-
const { pollPrStatus: ghPollPrStatus, pollPrHumanComments: ghPollPrHumanComments, reconcilePrs: ghReconcilePrs } = require('./engine/github');
|
|
833
|
+
const { pollPrStatus, pollPrHumanComments, reconcilePrs, checkLiveReviewStatus: adoCheckLiveReview } = require('./engine/ado');
|
|
834
|
+
const { pollPrStatus: ghPollPrStatus, pollPrHumanComments: ghPollPrHumanComments, reconcilePrs: ghReconcilePrs, checkLiveReviewStatus: ghCheckLiveReview } = require('./engine/github');
|
|
835
835
|
|
|
836
836
|
// ─── State Snapshot ─────────────────────────────────────────────────────────
|
|
837
837
|
|
|
@@ -1291,6 +1291,27 @@ function discoverFromPrs(config, project) {
|
|
|
1291
1291
|
if (needsReview) {
|
|
1292
1292
|
const key = `review-${project?.name || 'default'}-${pr.id}`;
|
|
1293
1293
|
if (isAlreadyDispatched(key) || isOnCooldown(key, cooldownMs)) continue;
|
|
1294
|
+
|
|
1295
|
+
// Pre-dispatch live vote check — cached reviewStatus may be stale (poll lag ~6 min)
|
|
1296
|
+
try {
|
|
1297
|
+
const checkFn = project.repoHost === 'github' ? ghCheckLiveReview : adoCheckLiveReview;
|
|
1298
|
+
const liveStatus = checkFn(pr, project);
|
|
1299
|
+
if (liveStatus && liveStatus !== 'pending') {
|
|
1300
|
+
log('info', `Pre-dispatch vote check: ${pr.id} is ${liveStatus} (cached was pending) — skipping review`);
|
|
1301
|
+
pr.reviewStatus = liveStatus;
|
|
1302
|
+
// Persist so next tick doesn't re-check
|
|
1303
|
+
try {
|
|
1304
|
+
mutateJsonFileLocked(projectPrPath(project), data => {
|
|
1305
|
+
if (!Array.isArray(data)) return data;
|
|
1306
|
+
const target = data.find(p => p.id === pr.id);
|
|
1307
|
+
if (target) target.reviewStatus = liveStatus;
|
|
1308
|
+
return data;
|
|
1309
|
+
});
|
|
1310
|
+
} catch {}
|
|
1311
|
+
continue;
|
|
1312
|
+
}
|
|
1313
|
+
} catch (e) { log('warn', `Pre-dispatch vote check for ${pr.id}: ${e.message}`); }
|
|
1314
|
+
|
|
1294
1315
|
const agentId = resolveAgent('review', config);
|
|
1295
1316
|
if (!agentId) continue;
|
|
1296
1317
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.456",
|
|
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"
|