@yemi33/minions 0.1.556 → 0.1.557
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 -1
- package/dashboard/js/render-prs.js +2 -2
- package/dashboard/styles.css +1 -0
- package/dashboard.js +1 -0
- package/engine/ado.js +4 -0
- package/engine/github.js +4 -0
- package/engine/shared.js +1 -0
- package/engine.js +34 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.557 (2026-04-08)
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
6
|
- add pin/unpin button to inbox and KB document modals
|
|
7
7
|
|
|
8
8
|
### Fixes
|
|
9
|
+
- add max retry cap and escalation for build fix cycles (#497)
|
|
9
10
|
- defer dispatched status until spawnAgent succeeds + add _any_ routing token (#482)
|
|
10
11
|
- move pin button to modal header next to Copy button
|
|
11
12
|
- fetch actual build error logs instead of just reason string (#489)
|
|
@@ -12,8 +12,8 @@ function prRow(pr) {
|
|
|
12
12
|
const reviewSource = sq.status || effectiveReviewStatus || 'pending';
|
|
13
13
|
const reviewClass = reviewSource === 'approved' ? 'approved' : (reviewSource === 'changes-requested' || reviewSource === 'rejected') ? 'rejected' : reviewSource === 'waiting' ? 'building' : 'draft';
|
|
14
14
|
const reviewLabel = sq.status === 'waiting' ? 'reviewing (minions)' : sq.status ? sq.status + ' (minions)' : (effectiveReviewStatus || 'pending');
|
|
15
|
-
const buildClass = pr._buildStatusStale ? 'build-stale' : pr.buildStatus === 'passing' ? 'build-pass' : pr.buildStatus === 'failing' ? 'build-fail' : pr.buildStatus === 'running' ? 'building' : 'no-build';
|
|
16
|
-
const buildLabel = (pr.buildStatus || 'none') + (pr._buildStatusStale ? ' (stale)' : '');
|
|
15
|
+
const buildClass = pr.buildFixEscalated ? 'build-escalated' : pr._buildStatusStale ? 'build-stale' : pr.buildStatus === 'passing' ? 'build-pass' : pr.buildStatus === 'failing' ? 'build-fail' : pr.buildStatus === 'running' ? 'building' : 'no-build';
|
|
16
|
+
const buildLabel = pr.buildFixEscalated ? 'escalated (' + (pr.buildFixAttempts || '?') + ' fixes)' : (pr.buildStatus || 'none') + (pr._buildStatusStale ? ' (stale)' : '');
|
|
17
17
|
const statusClass = pr.status === 'merged' ? 'merged' : pr.status === 'abandoned' ? 'rejected' : pr.status === 'active' ? 'active' : 'draft';
|
|
18
18
|
const statusLabel = pr.status || 'active';
|
|
19
19
|
const url = pr.url || '#';
|
package/dashboard/styles.css
CHANGED
|
@@ -257,6 +257,7 @@
|
|
|
257
257
|
.pr-badge.build-fail { background: rgba(248,81,73,0.15); color: var(--red); border: 1px solid var(--red); }
|
|
258
258
|
.pr-badge.no-build { background: var(--surface); color: var(--muted); border: 1px solid var(--border); }
|
|
259
259
|
.pr-badge.build-stale { background: rgba(210,153,34,0.15); color: var(--orange); border: 1px dashed var(--orange); }
|
|
260
|
+
.pr-badge.build-escalated { background: rgba(248,81,73,0.25); color: var(--red); border: 2px solid var(--red); font-weight: 600; }
|
|
260
261
|
.error-details-btn { font-size: var(--text-xs); padding: var(--space-1) var(--space-3); margin-left: var(--space-2); background: rgba(248,81,73,0.15); color: var(--red); border: 1px solid var(--red); border-radius: var(--radius-lg); cursor: pointer; font-weight: 600; text-transform: uppercase; letter-spacing: 0.3px; }
|
|
261
262
|
.error-details-btn:hover { background: rgba(248,81,73,0.3); }
|
|
262
263
|
.pr-empty { color: var(--muted); font-style: italic; font-size: var(--text-md); padding: var(--space-6) 0; }
|
package/dashboard.js
CHANGED
|
@@ -3533,6 +3533,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
3533
3533
|
idleAlertMinutes: [1], shutdownTimeout: [30000], restartGracePeriod: [60000],
|
|
3534
3534
|
meetingRoundTimeout: [60000],
|
|
3535
3535
|
versionCheckInterval: [60000],
|
|
3536
|
+
maxBuildFixAttempts: [1, 10],
|
|
3536
3537
|
};
|
|
3537
3538
|
for (const [key, [min, max]] of Object.entries(numericFields)) {
|
|
3538
3539
|
if (e[key] !== undefined) {
|
package/engine/ado.js
CHANGED
|
@@ -254,6 +254,8 @@ async function pollPrStatus(config) {
|
|
|
254
254
|
delete pr.buildFailReason;
|
|
255
255
|
delete pr.buildErrorLog;
|
|
256
256
|
delete pr._buildFailNotified;
|
|
257
|
+
delete pr.buildFixAttempts;
|
|
258
|
+
delete pr.buildFixEscalated;
|
|
257
259
|
}
|
|
258
260
|
await engine().handlePostMerge(pr, project, config, newStatus);
|
|
259
261
|
}
|
|
@@ -365,6 +367,8 @@ async function pollPrStatus(config) {
|
|
|
365
367
|
if (buildStatus !== 'failing') {
|
|
366
368
|
delete pr._buildFailNotified;
|
|
367
369
|
delete pr.buildErrorLog;
|
|
370
|
+
// Reset build fix retry counter on recovery — allows fresh auto-fix cycles if build breaks again
|
|
371
|
+
if (pr.buildFixAttempts) { delete pr.buildFixAttempts; delete pr.buildFixEscalated; }
|
|
368
372
|
}
|
|
369
373
|
updated = true;
|
|
370
374
|
|
package/engine/github.js
CHANGED
|
@@ -294,6 +294,8 @@ async function pollPrStatus(config) {
|
|
|
294
294
|
delete pr.buildFailReason;
|
|
295
295
|
delete pr.buildErrorLog;
|
|
296
296
|
delete pr._buildFailNotified;
|
|
297
|
+
delete pr.buildFixAttempts;
|
|
298
|
+
delete pr.buildFixEscalated;
|
|
297
299
|
}
|
|
298
300
|
await engine().handlePostMerge(pr, project, config, newStatus);
|
|
299
301
|
}
|
|
@@ -393,6 +395,8 @@ async function pollPrStatus(config) {
|
|
|
393
395
|
if (buildStatus !== 'failing') {
|
|
394
396
|
delete pr._buildFailNotified;
|
|
395
397
|
delete pr.buildErrorLog;
|
|
398
|
+
// Reset build fix retry counter on recovery — allows fresh auto-fix cycles if build breaks again
|
|
399
|
+
if (pr.buildFixAttempts) { delete pr.buildFixAttempts; delete pr.buildFixEscalated; }
|
|
396
400
|
}
|
|
397
401
|
updated = true;
|
|
398
402
|
|
package/engine/shared.js
CHANGED
|
@@ -525,6 +525,7 @@ const ENGINE_DEFAULTS = {
|
|
|
525
525
|
logBufferSize: 50, // flush immediately when buffer exceeds this many entries
|
|
526
526
|
lockRetries: 2, // retry lock acquisition this many times after initial timeout (total attempts = 1 + lockRetries)
|
|
527
527
|
lockRetryBackoffMs: 500, // base backoff between lock retries (doubles each attempt: 500ms, 1s, 2s, ...)
|
|
528
|
+
maxBuildFixAttempts: 3, // max consecutive auto-fix dispatch cycles per PR before escalation to human
|
|
528
529
|
};
|
|
529
530
|
|
|
530
531
|
// ─── Status & Type Constants ─────────────────────────────────────────────────
|
package/engine.js
CHANGED
|
@@ -1498,6 +1498,29 @@ async function discoverFromPrs(config, project) {
|
|
|
1498
1498
|
|
|
1499
1499
|
// PRs with build failures — route to author (has session context from implementing)
|
|
1500
1500
|
if (pr.status === PR_STATUS.ACTIVE && pr.buildStatus === 'failing') {
|
|
1501
|
+
const maxBuildFix = config.engine?.maxBuildFixAttempts ?? ENGINE_DEFAULTS.maxBuildFixAttempts;
|
|
1502
|
+
|
|
1503
|
+
// Check if max retry cap reached — escalate to human instead of dispatching another fix
|
|
1504
|
+
if ((pr.buildFixAttempts || 0) >= maxBuildFix) {
|
|
1505
|
+
if (!pr.buildFixEscalated) {
|
|
1506
|
+
writeInboxAlert(`build-fix-escalated-${pr.agent || 'unassigned'}-${pr.id}`,
|
|
1507
|
+
`# Build Fix Escalation\n\n` +
|
|
1508
|
+
`**PR ${pr.id}** on branch \`${pr.branch || 'unknown'}\` has failed **${pr.buildFixAttempts}** consecutive auto-fix attempts.\n` +
|
|
1509
|
+
`**Last failure:** ${pr.buildFailReason || 'Check CI pipeline for details'}\n\n` +
|
|
1510
|
+
`Auto-fix dispatch has been suspended. Please investigate manually.\n`
|
|
1511
|
+
);
|
|
1512
|
+
try {
|
|
1513
|
+
const prPath = projectPrPath(project);
|
|
1514
|
+
mutatePullRequests(prPath, prs => {
|
|
1515
|
+
const target = prs.find(p => p.id === pr.id);
|
|
1516
|
+
if (target) target.buildFixEscalated = true;
|
|
1517
|
+
});
|
|
1518
|
+
} catch (e) { log('warn', 'mark build fix escalated: ' + e.message); }
|
|
1519
|
+
log('warn', `PR ${pr.id}: build fix escalated after ${pr.buildFixAttempts} attempts — suspending auto-dispatch`);
|
|
1520
|
+
}
|
|
1521
|
+
continue;
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1501
1524
|
const key = `build-fix-${project?.name || 'default'}-${pr.id}`;
|
|
1502
1525
|
if (isAlreadyDispatched(key) || isOnCooldown(key, cooldownMs)) continue;
|
|
1503
1526
|
const agentId = resolveAgent('fix', config, pr.agent);
|
|
@@ -1512,7 +1535,17 @@ async function discoverFromPrs(config, project) {
|
|
|
1512
1535
|
pr_id: pr.id, pr_branch: pr.branch || '',
|
|
1513
1536
|
review_note: reviewNote,
|
|
1514
1537
|
}, `Fix build failure on PR ${pr.id}`, { dispatchKey: key, source: 'pr', pr, branch: pr.branch, project: projMeta });
|
|
1515
|
-
if (item) {
|
|
1538
|
+
if (item) {
|
|
1539
|
+
newWork.push(item); setCooldown(key);
|
|
1540
|
+
// Increment build fix attempts counter
|
|
1541
|
+
try {
|
|
1542
|
+
const prPath = projectPrPath(project);
|
|
1543
|
+
mutatePullRequests(prPath, prs => {
|
|
1544
|
+
const target = prs.find(p => p.id === pr.id);
|
|
1545
|
+
if (target) target.buildFixAttempts = (target.buildFixAttempts || 0) + 1;
|
|
1546
|
+
});
|
|
1547
|
+
} catch (e) { log('warn', 'increment build fix attempts: ' + e.message); }
|
|
1548
|
+
}
|
|
1516
1549
|
|
|
1517
1550
|
// Notify the author agent about the build failure
|
|
1518
1551
|
if (pr.agent && !pr._buildFailNotified) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.557",
|
|
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"
|