@yemi33/minions 0.1.777 → 0.1.779
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 +10 -0
- package/dashboard/layout.html +2 -8
- package/engine/ado.js +38 -11
- package/engine/github.js +45 -23
- package/engine/shared.js +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.779 (2026-04-10)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
- auto-complete PRs when builds green + review approved
|
|
7
|
+
|
|
8
|
+
## 0.1.778 (2026-04-10)
|
|
9
|
+
|
|
10
|
+
### Fixes
|
|
11
|
+
- agent comments included in context but don't trigger fix dispatch
|
|
12
|
+
|
|
3
13
|
## 0.1.777 (2026-04-10)
|
|
4
14
|
|
|
5
15
|
### Fixes
|
package/dashboard/layout.html
CHANGED
|
@@ -32,11 +32,10 @@
|
|
|
32
32
|
<span id="cc-session-info" style="font-size:10px;color:var(--muted)">New session</span>
|
|
33
33
|
</div>
|
|
34
34
|
<div style="display:flex;align-items:center;gap:8px">
|
|
35
|
-
<button onclick="
|
|
35
|
+
<button onclick="ccNewSession()" style="background:none;border:1px solid var(--border);color:var(--muted);font-size:10px;padding:2px 8px;border-radius:3px;cursor:pointer">Clear Chat</button>
|
|
36
36
|
<button onclick="toggleCommandCenter()" style="background:none;border:none;color:var(--muted);font-size:16px;cursor:pointer;padding:2px 6px">✕</button>
|
|
37
37
|
</div>
|
|
38
38
|
</div>
|
|
39
|
-
<div id="cc-tab-bar" style="display:flex;gap:4px;padding:4px 12px;border-bottom:1px solid var(--border);overflow-x:auto;align-items:center;flex-shrink:0"></div>
|
|
40
39
|
<div id="cc-messages" style="flex:1;overflow-y:auto;padding:12px 16px;display:flex;flex-direction:column;gap:10px"></div>
|
|
41
40
|
<div style="padding:12px 16px;border-top:1px solid var(--border)">
|
|
42
41
|
<div style="display:flex;gap:8px">
|
|
@@ -99,7 +98,6 @@
|
|
|
99
98
|
<div class="modal-header">
|
|
100
99
|
<h3 id="modal-title">—</h3>
|
|
101
100
|
<div class="modal-header-actions">
|
|
102
|
-
<button class="modal-copy" id="modal-back-btn" onclick="modalGoBack()" title="Back" style="display:none">← Back</button>
|
|
103
101
|
<button class="modal-copy" id="modal-edit-btn" onclick="modalToggleEdit()" title="Edit" style="display:none"><svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor"><path d="M11.013 1.427a1.75 1.75 0 012.474 0l1.086 1.086a1.75 1.75 0 010 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 01-.927-.928l.929-3.25c.081-.286.235-.547.445-.758l8.61-8.61zM12.9 2.97L4.288 11.58l-.537 1.878 1.878-.537L14.242 4.31 12.9 2.97z"/></svg> Edit</button>
|
|
104
102
|
<button class="modal-copy" id="modal-save-btn" onclick="modalSaveEdit()" title="Save" style="display:none;color:var(--green);border-color:var(--green)"><svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor"><path d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"/></svg> Save</button>
|
|
105
103
|
<button class="modal-copy" id="modal-cancel-edit-btn" onclick="modalCancelEdit()" title="Cancel edit" style="display:none">Cancel</button>
|
|
@@ -113,14 +111,10 @@
|
|
|
113
111
|
<div id="modal-qa-thread-wrap" style="display:none">
|
|
114
112
|
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:4px">
|
|
115
113
|
<button id="qa-clear-btn" style="background:none;border:none;color:var(--muted);font-size:10px;cursor:pointer;padding:2px 6px" onclick="clearQaConversation()" title="Clear conversation">Clear</button>
|
|
116
|
-
<button
|
|
114
|
+
<button style="background:none;border:none;color:var(--muted);font-size:10px;cursor:pointer;padding:2px 6px" onclick="toggleDocChat()" id="qa-toggle-btn" title="Collapse thread">▼ Collapse</button>
|
|
117
115
|
</div>
|
|
118
116
|
<div class="modal-qa-thread" id="modal-qa-thread"></div>
|
|
119
117
|
</div>
|
|
120
|
-
<div id="qa-expand-bar" style="display:none;margin-bottom:4px">
|
|
121
|
-
<button style="background:none;border:none;color:var(--muted);font-size:10px;cursor:pointer;padding:2px 6px" onclick="toggleDocChat()">▲ Show thread</button>
|
|
122
|
-
</div>
|
|
123
|
-
<div id="qa-action-slot"></div>
|
|
124
118
|
<div class="modal-qa-selection-pill" id="modal-qa-pill" style="display:none">
|
|
125
119
|
<span class="pill-label">Selection:</span>
|
|
126
120
|
<span class="pill-text" id="modal-qa-pill-text"></span>
|
package/engine/ado.js
CHANGED
|
@@ -418,6 +418,31 @@ async function pollPrStatus(config) {
|
|
|
418
418
|
}
|
|
419
419
|
}
|
|
420
420
|
|
|
421
|
+
// Auto-complete: set auto-complete on PR when builds green + review approved
|
|
422
|
+
if (pr.status === PR_STATUS.ACTIVE && pr.reviewStatus === 'approved' && pr.buildStatus === 'passing' && !pr._autoCompleted) {
|
|
423
|
+
const autoComplete = config.engine?.autoCompletePrs !== false;
|
|
424
|
+
if (autoComplete) {
|
|
425
|
+
try {
|
|
426
|
+
const mergeStrategy = config.engine?.prMergeMethod === 'merge' ? 1 : config.engine?.prMergeMethod === 'rebase' ? 2 : 3; // 3 = squash
|
|
427
|
+
const identityUrl = `${orgBase}/_apis/connectionData?api-version=7.1`;
|
|
428
|
+
const identity = await adoFetch(identityUrl, token).catch(() => null);
|
|
429
|
+
const autoCompleteUrl = `${orgBase}/${project.adoProject}/_apis/git/repositories/${project.repositoryId}/pullrequests/${prNum}?api-version=7.1`;
|
|
430
|
+
await adoFetch(autoCompleteUrl, token, {
|
|
431
|
+
method: 'PATCH',
|
|
432
|
+
body: JSON.stringify({
|
|
433
|
+
autoCompleteSetBy: { id: identity?.authenticatedUser?.id },
|
|
434
|
+
completionOptions: { mergeStrategy, deleteSourceBranch: true, transitionWorkItems: true }
|
|
435
|
+
})
|
|
436
|
+
});
|
|
437
|
+
pr._autoCompleted = true;
|
|
438
|
+
log('info', `Auto-complete set on PR ${pr.id}: builds green + review approved`);
|
|
439
|
+
updated = true;
|
|
440
|
+
} catch (e) {
|
|
441
|
+
log('warn', `Auto-complete failed for PR ${pr.id}: ${e.message}`);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
421
446
|
return updated;
|
|
422
447
|
} catch (err) {
|
|
423
448
|
// Auth errors → mark build status stale so dashboard shows uncertainty
|
|
@@ -459,35 +484,37 @@ async function pollPrHumanComments(config) {
|
|
|
459
484
|
for (const comment of (thread.comments || [])) {
|
|
460
485
|
if (!comment.content || comment.commentType === 'system') continue;
|
|
461
486
|
const content = comment.content;
|
|
462
|
-
//
|
|
463
|
-
if (/\bMinions\s*\(/i.test(content)) continue;
|
|
464
|
-
if (/\b(Review|Fixed|Explored|Verified|Tested)\s+by\s+Minions\b/i.test(content)) continue;
|
|
465
|
-
if (/\[minions\]/i.test(content)) continue;
|
|
466
|
-
// Skip bot/service account comments
|
|
487
|
+
// Skip bots and CI noise
|
|
467
488
|
const authorName = (comment.author?.displayName || '').toLowerCase();
|
|
468
489
|
if (/\b(bot|service|build|pipeline|codecov|sonar)\b/i.test(authorName)) continue;
|
|
469
|
-
// Short comments from same author that look agent-generated
|
|
470
|
-
if (content.length < 500 && /\b(fixed|addressed|resolved|pushed|updated|rebased)\b/i.test(content) && /\b(review|feedback|comment|finding)\b/i.test(content)) continue;
|
|
471
|
-
// Automated status comments (coverage, build reports)
|
|
472
490
|
if (/^#{1,3}\s*(Coverage|Build|Test|Deploy|Pipeline)\s*(Report|Status|Result|Summary)/i.test(content)) continue;
|
|
491
|
+
// Detect agent comments (included in context, but don't trigger fix)
|
|
492
|
+
const isAgent = /\bMinions\s*\(/i.test(content) || /\bby\s+Minions\b/i.test(content) || /\[minions\]/i.test(content);
|
|
473
493
|
|
|
474
494
|
const entry = {
|
|
475
495
|
threadId: thread.id,
|
|
476
496
|
commentId: comment.id,
|
|
477
497
|
author: comment.author?.displayName || 'Human',
|
|
478
498
|
content: comment.content,
|
|
479
|
-
date: comment.publishedDate
|
|
499
|
+
date: comment.publishedDate,
|
|
500
|
+
_isAgent: isAgent
|
|
480
501
|
};
|
|
481
502
|
allHumanComments.push(entry);
|
|
482
503
|
|
|
483
|
-
//
|
|
504
|
+
// Only non-agent new comments trigger a fix (agent reviews trigger via vote)
|
|
484
505
|
const commentMs = comment.publishedDate ? new Date(comment.publishedDate).getTime() : 0;
|
|
485
|
-
if (commentMs && commentMs > cutoffMs) {
|
|
506
|
+
if (commentMs && commentMs > cutoffMs && !isAgent) {
|
|
486
507
|
newHumanComments.push(entry);
|
|
487
508
|
}
|
|
488
509
|
}
|
|
489
510
|
}
|
|
490
511
|
|
|
512
|
+
// Update cutoff even if only agent comments are new
|
|
513
|
+
const allNewDates = allHumanComments.filter(c => (new Date(c.date).getTime() || 0) > cutoffMs).map(c => c.date);
|
|
514
|
+
if (allNewDates.length > 0 && newHumanComments.length === 0) {
|
|
515
|
+
pr.humanFeedback = { ...(pr.humanFeedback || {}), lastProcessedCommentDate: allNewDates.sort().pop() };
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
491
518
|
if (newHumanComments.length === 0) return false;
|
|
492
519
|
|
|
493
520
|
// Sort all comments chronologically and build full context for the fix agent
|
package/engine/github.js
CHANGED
|
@@ -418,6 +418,22 @@ async function pollPrStatus(config) {
|
|
|
418
418
|
}
|
|
419
419
|
}
|
|
420
420
|
|
|
421
|
+
// Auto-complete: merge PR when builds green + review approved
|
|
422
|
+
if (pr.status === PR_STATUS.ACTIVE && pr.reviewStatus === 'approved' && pr.buildStatus === 'passing' && !pr._autoCompleted) {
|
|
423
|
+
const autoComplete = config.engine?.autoCompletePrs !== false; // default: on
|
|
424
|
+
if (autoComplete) {
|
|
425
|
+
try {
|
|
426
|
+
const mergeMethod = config.engine?.prMergeMethod || 'squash';
|
|
427
|
+
await execAsync(`gh pr merge ${prNum} --${mergeMethod} --repo ${slug} --delete-branch`, { timeout: 30000, encoding: 'utf-8' });
|
|
428
|
+
pr._autoCompleted = true;
|
|
429
|
+
log('info', `Auto-completed PR ${pr.id}: builds green + review approved → merged (${mergeMethod})`);
|
|
430
|
+
updated = true;
|
|
431
|
+
} catch (e) {
|
|
432
|
+
log('warn', `Auto-complete failed for PR ${pr.id}: ${e.message}`);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
421
437
|
return updated;
|
|
422
438
|
});
|
|
423
439
|
|
|
@@ -441,27 +457,25 @@ async function pollPrHumanComments(config) {
|
|
|
441
457
|
...(Array.isArray(reviewComments) ? reviewComments : []).map(c => ({ ...c, _type: 'review' }))
|
|
442
458
|
];
|
|
443
459
|
|
|
444
|
-
//
|
|
445
|
-
//
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
if (c.user?.type === 'Bot') return false;
|
|
449
|
-
const body = c.body || '';
|
|
450
|
-
// Minions agent signatures (review, fix, explore, etc.)
|
|
451
|
-
if (/\bMinions\s*\(/i.test(body)) return false;
|
|
452
|
-
if (/\b(Review|Fixed|Explored|Verified|Tested)\s+by\s+Minions\b/i.test(body)) return false;
|
|
453
|
-
if (/\[minions\]/i.test(body)) return false;
|
|
454
|
-
// Comments from the PR author account are likely agent-generated (agents use same PAT)
|
|
455
|
-
// Only skip if the comment looks automated (short, or has agent patterns)
|
|
460
|
+
// Separate: agent comments (included in context, don't trigger fix) vs human comments (trigger fix)
|
|
461
|
+
// All non-bot, non-CI comments go into context. Only non-agent comments trigger pendingFix.
|
|
462
|
+
function _isBot(c) {
|
|
463
|
+
if (c.user?.type === 'Bot') return true;
|
|
456
464
|
const login = (c.user?.login || '').toLowerCase();
|
|
457
|
-
if (
|
|
458
|
-
|
|
459
|
-
if (
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
+
if (/\b(bot|codecov|sonar|dependabot|renovate|github-actions|azure-pipelines)\b/i.test(login)) return true;
|
|
466
|
+
const body = c.body || '';
|
|
467
|
+
if (/^#{1,3}\s*(Coverage|Build|Test|Deploy|Pipeline)\s*(Report|Status|Result|Summary)/i.test(body)) return true;
|
|
468
|
+
if (/!\[.*\]\(https?:\/\/.*badge/i.test(body)) return true;
|
|
469
|
+
return false;
|
|
470
|
+
}
|
|
471
|
+
function _isAgentComment(c) {
|
|
472
|
+
const body = c.body || '';
|
|
473
|
+
if (/\bMinions\s*\(/i.test(body)) return true;
|
|
474
|
+
if (/\bby\s+Minions\b/i.test(body)) return true;
|
|
475
|
+
if (/\[minions\]/i.test(body)) return true;
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
const humanComments = allComments.filter(c => !_isBot(c));
|
|
465
479
|
|
|
466
480
|
const cutoffStr = pr.humanFeedback?.lastProcessedCommentDate || pr.created || '1970-01-01';
|
|
467
481
|
const cutoffMs = new Date(cutoffStr).getTime() || 0;
|
|
@@ -472,21 +486,29 @@ async function pollPrHumanComments(config) {
|
|
|
472
486
|
|
|
473
487
|
for (const c of humanComments) {
|
|
474
488
|
const date = c.created_at || c.updated_at || '';
|
|
489
|
+
const isAgent = _isAgentComment(c);
|
|
475
490
|
const entry = {
|
|
476
491
|
commentId: c.id,
|
|
477
492
|
author: c.user?.login || 'Human',
|
|
478
493
|
content: c.body || '',
|
|
479
|
-
date
|
|
494
|
+
date,
|
|
495
|
+
_isAgent: isAgent
|
|
480
496
|
};
|
|
481
497
|
allCommentEntries.push(entry);
|
|
482
498
|
|
|
483
|
-
//
|
|
499
|
+
// Only non-agent new comments trigger a fix (agent reviews trigger via vote, not comment)
|
|
484
500
|
const dateMs = date ? new Date(date).getTime() : 0;
|
|
485
|
-
if (dateMs && dateMs > cutoffMs) {
|
|
501
|
+
if (dateMs && dateMs > cutoffMs && !isAgent) {
|
|
486
502
|
newComments.push(entry);
|
|
487
503
|
}
|
|
488
504
|
}
|
|
489
505
|
|
|
506
|
+
// Update cutoff even if only agent comments are new (so we don't re-scan them)
|
|
507
|
+
const allNewDates = allCommentEntries.filter(c => (new Date(c.date).getTime() || 0) > cutoffMs).map(c => c.date);
|
|
508
|
+
if (allNewDates.length > 0 && newComments.length === 0) {
|
|
509
|
+
pr.humanFeedback = { ...(pr.humanFeedback || {}), lastProcessedCommentDate: allNewDates.sort().pop() };
|
|
510
|
+
return false; // agent comments only — don't trigger fix
|
|
511
|
+
}
|
|
490
512
|
if (newComments.length === 0) return false;
|
|
491
513
|
|
|
492
514
|
// Sort all comments chronologically and build full context for the fix agent
|
package/engine/shared.js
CHANGED
|
@@ -547,6 +547,8 @@ const ENGINE_DEFAULTS = {
|
|
|
547
547
|
lockRetryBackoffMs: 500, // base backoff between lock retries (doubles each attempt: 500ms, 1s, 2s, ...)
|
|
548
548
|
maxBuildFixAttempts: 3, // max consecutive auto-fix dispatch cycles per PR before escalation to human
|
|
549
549
|
buildFixGracePeriod: 600000, // 10min — wait for CI to run after build fix before re-dispatching
|
|
550
|
+
autoCompletePrs: true, // auto-merge PRs when builds green + review approved
|
|
551
|
+
prMergeMethod: 'squash', // merge method: squash, merge, rebase
|
|
550
552
|
ccModel: 'sonnet', // model for Command Center and doc-chat (sonnet, haiku, opus)
|
|
551
553
|
ccEffort: null, // effort level for CC/doc-chat (null, 'low', 'medium', 'high')
|
|
552
554
|
ccMaxTurns: 50, // max tool-use turns for CC/doc-chat before CLI stops
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.779",
|
|
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"
|