@yemi33/minions 0.1.686 → 0.1.688
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 +6 -1
- package/dashboard/js/modal.js +1 -0
- package/dashboard/js/render-pipelines.js +9 -14
- package/dashboard/js/render-work-items.js +24 -19
- package/dashboard/js/utils.js +19 -0
- package/dashboard/layout.html +1 -0
- package/dashboard/styles.css +1 -1
- package/package.json +1 -1
- package/pipelines/pr-review-fix-cycle.json +42 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.688 (2026-04-09)
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
|
+
- PR review/fix cycle pipeline, fix node rendering for never-run pipelines
|
|
7
|
+
- modal back button for artifact navigation
|
|
6
8
|
- collapsible doc-chat thread in modal
|
|
7
9
|
|
|
8
10
|
### Fixes
|
|
9
11
|
- add archive fallback for artifact notes when KB entry was swept
|
|
10
12
|
- link work item artifacts to KB entries, not raw archive copies
|
|
11
13
|
|
|
14
|
+
### Other
|
|
15
|
+
- refactor: remove dead stageFlow code from pipeline card rendering
|
|
16
|
+
|
|
12
17
|
## 0.1.683 (2026-04-09)
|
|
13
18
|
|
|
14
19
|
### Features
|
package/dashboard/js/modal.js
CHANGED
|
@@ -4,6 +4,7 @@ function closeModal() {
|
|
|
4
4
|
const modalEl = document.querySelector('#modal .modal');
|
|
5
5
|
if (modalEl) modalEl.classList.remove('modal-wide');
|
|
6
6
|
document.getElementById('modal').classList.remove('open');
|
|
7
|
+
clearModalBackStack();
|
|
7
8
|
// Hide Q&A section (only shown for document modals)
|
|
8
9
|
document.getElementById('modal-qa').style.display = 'none';
|
|
9
10
|
// Remove settings buttons if present
|
|
@@ -241,10 +241,13 @@ function _buildNodeChain(stages, run, options) {
|
|
|
241
241
|
|
|
242
242
|
html += '</div>';
|
|
243
243
|
|
|
244
|
-
// Loop indicator
|
|
245
|
-
|
|
244
|
+
// Loop indicator — only for pipelines with stopWhen or condition stages (repeat-until pattern)
|
|
245
|
+
var hasStopWhen = !!pipeline?.stopWhen;
|
|
246
|
+
var hasConditionStage = (pipeline?.stages || []).some(function(s) { return s.type === 'condition'; });
|
|
247
|
+
if (hasStopWhen || hasConditionStage) {
|
|
246
248
|
var runCount = (pipeline.runs || []).length;
|
|
247
|
-
|
|
249
|
+
var cronLabel = pipeline?.trigger?.cron ? _cronToHuman(pipeline.trigger.cron) : 'until condition met';
|
|
250
|
+
html += '<div class="pl-node-loop">\u21BA Loop (' + escHtml(cronLabel) + ')';
|
|
248
251
|
if (runCount > 0) html += ' \u00b7 Run ' + runCount;
|
|
249
252
|
html += '</div>';
|
|
250
253
|
}
|
|
@@ -271,18 +274,10 @@ function renderPipelines(pipelines) {
|
|
|
271
274
|
const statusLabel = activeRun ? 'Running' : lastRun ? (lastRun.status === 'completed' ? 'Completed' : lastRun.status === 'failed' ? 'Failed' : lastRun.status === 'stopped' ? 'Stopped' : lastRun.status) : 'Never run';
|
|
272
275
|
const trigger = p.trigger?.cron ? _cronToHuman(p.trigger.cron) : 'Manual';
|
|
273
276
|
|
|
274
|
-
//
|
|
275
|
-
var stageFlow = (p.stages || []).map(function(s) {
|
|
276
|
-
var icon = { task: '\u2699', meeting: '\uD83D\uDCAC', plan: '\uD83D\uDCCB', 'merge-prs': '\uD83D\uDD00', api: '\uD83C\uDF10', wait: '\u23F8', parallel: '\u2693', schedule: '\u23F0', condition: '\u2753' }[s.type] || '\u2022';
|
|
277
|
-
var stageStatus = activeRun?.stages?.[s.id]?.status || 'pending';
|
|
278
|
-
var color = stageStatus === 'completed' ? 'var(--green)' : stageStatus === 'running' ? 'var(--blue)' : stageStatus === 'failed' ? 'var(--red)' : stageStatus === 'waiting-human' ? 'var(--yellow)' : 'var(--muted)';
|
|
279
|
-
return '<span style="color:' + color + ';font-size:11px" title="' + escHtml(s.id) + ': ' + escHtml(s.title || s.type) + ' (' + stageStatus + ')">' + icon + ' ' + escHtml(s.id) + '</span>';
|
|
280
|
-
}).join(' <span style="color:var(--border)">\u2192</span> ');
|
|
281
|
-
|
|
282
|
-
// Build step-progress indicator for pipelines with a run
|
|
277
|
+
// Build node chain (renders for all pipelines, even never-run)
|
|
283
278
|
var progressHtml = '';
|
|
284
279
|
var displayRun = activeRun || lastRun;
|
|
285
|
-
if (
|
|
280
|
+
if ((p.stages || []).length > 0) {
|
|
286
281
|
progressHtml = _buildNodeChain(p.stages || [], displayRun, { compact: true, pipeline: p });
|
|
287
282
|
}
|
|
288
283
|
|
|
@@ -330,7 +325,7 @@ function openPipelineDetail(id) {
|
|
|
330
325
|
|
|
331
326
|
// Stage detail with progress bar
|
|
332
327
|
var detailRun = activeRun || (p.runs || []).slice(-1)[0];
|
|
333
|
-
if (
|
|
328
|
+
if ((p.stages || []).length > 0) {
|
|
334
329
|
html += _buildNodeChain(p.stages || [], detailRun, { compact: false, pipeline: p });
|
|
335
330
|
}
|
|
336
331
|
// Pipeline-level monitored resources (full view in detail)
|
|
@@ -452,26 +452,31 @@ function openWorkItemDetail(id) {
|
|
|
452
452
|
var artPills = '';
|
|
453
453
|
var pillStyle = 'display:inline-flex;align-items:center;gap:3px;padding:2px 8px;border-radius:10px;font-size:10px;cursor:pointer;background:var(--surface2);border:1px solid var(--border);color:var(--text)';
|
|
454
454
|
// Output log pill removed — raw stream-json output is not human-readable
|
|
455
|
+
var artBackFn = "pushModalBack(function(){openWorkItemDetail('" + escHtml(item.id) + "')});";
|
|
455
456
|
if (arts.branch) artPills += '<span style="' + pillStyle + ';cursor:default">🌿 ' + escHtml(arts.branch) + '</span> ';
|
|
456
|
-
if (arts.plan) artPills += '<span onclick="planView(\'' + escHtml(arts.plan) + '\')" style="' + pillStyle + '">📋 Plan</span> ';
|
|
457
|
-
if (arts.prd) artPills += '<span onclick="planView(\'' + escHtml(arts.prd) + '\')" style="' + pillStyle + '">📄 PRD</span> ';
|
|
458
|
-
if (arts.sourcePlan) artPills += '<span onclick="planView(\'' + escHtml(arts.sourcePlan) + '\')" style="' + pillStyle + '">📋 Source Plan</span> ';
|
|
459
|
-
if (arts.notes && arts.notes.length > 0)
|
|
460
|
-
var
|
|
461
|
-
|
|
462
|
-
var
|
|
463
|
-
var
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
457
|
+
if (arts.plan) artPills += '<span onclick="' + artBackFn + 'planView(\'' + escHtml(arts.plan) + '\')" style="' + pillStyle + '">📋 Plan</span> ';
|
|
458
|
+
if (arts.prd) artPills += '<span onclick="' + artBackFn + 'planView(\'' + escHtml(arts.prd) + '\')" style="' + pillStyle + '">📄 PRD</span> ';
|
|
459
|
+
if (arts.sourcePlan) artPills += '<span onclick="' + artBackFn + 'planView(\'' + escHtml(arts.sourcePlan) + '\')" style="' + pillStyle + '">📋 Source Plan</span> ';
|
|
460
|
+
if (arts.notes && arts.notes.length > 0) {
|
|
461
|
+
var wiId = escHtml(item.id);
|
|
462
|
+
arts.notes.forEach(function(n) {
|
|
463
|
+
var noteFile = (n && typeof n === 'object') ? (n.file || n) : String(n || '');
|
|
464
|
+
var backFn = "pushModalBack(function(){openWorkItemDetail('" + wiId + "')});";
|
|
465
|
+
if (noteFile.startsWith('kb:')) {
|
|
466
|
+
var kbParts = noteFile.slice(3).split('/');
|
|
467
|
+
var kbCat = kbParts[0];
|
|
468
|
+
var kbFile = kbParts.slice(1).join('/');
|
|
469
|
+
var kbLabel = kbFile.replace(/\.md$/, '').slice(0, 30);
|
|
470
|
+
artPills += '<span onclick="' + backFn + 'kbOpenItem(\'' + escHtml(kbCat) + '\',\'' + escHtml(kbFile) + '\')" style="' + pillStyle + '">📚 ' + escHtml(kbLabel) + '</span> ';
|
|
471
|
+
} else if (noteFile.startsWith('archive:')) {
|
|
472
|
+
var archLabel = noteFile.slice(8).replace(/\.md$/, '').replace(/^\d{4}-\d{2}-\d{2}-/, '').slice(0, 30);
|
|
473
|
+
artPills += '<span onclick="' + backFn + 'openInboxNote(\'' + escHtml(noteFile.slice(8)) + '\')" style="' + pillStyle + ';opacity:0.7">📄 ' + escHtml(archLabel) + ' <span style="font-size:8px">(archived)</span></span> ';
|
|
474
|
+
} else {
|
|
475
|
+
var noteLabel = noteFile.replace(/\.md$/, '').slice(0, 30);
|
|
476
|
+
artPills += '<span onclick="' + backFn + 'openInboxNote(\'' + escHtml(noteFile) + '\')" style="' + pillStyle + '">📝 ' + escHtml(noteLabel) + '</span> ';
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
}
|
|
475
480
|
if (arts.skills && arts.skills.length > 0) arts.skills.forEach(function(s) { artPills += '<span onclick="openSkill(\'' + escHtml(s) + '\',\'minions\',\'\')" style="' + pillStyle + '">⚙ ' + escHtml(s) + '</span> '; });
|
|
476
481
|
if (artPills) html += field('Artifacts', '<div style="display:flex;flex-wrap:wrap;gap:4px">' + artPills + '</div>');
|
|
477
482
|
|
package/dashboard/js/utils.js
CHANGED
|
@@ -35,6 +35,25 @@ function _togglePinAndRefresh(key, source) {
|
|
|
35
35
|
else if (source === 'kb') renderKnowledgeBase();
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
// Modal navigation stack — enables back button when opening a modal from another modal
|
|
39
|
+
var _modalBackStack = [];
|
|
40
|
+
function pushModalBack(reopenFn) {
|
|
41
|
+
_modalBackStack.push(reopenFn);
|
|
42
|
+
var btn = document.getElementById('modal-back-btn');
|
|
43
|
+
if (btn) btn.style.display = '';
|
|
44
|
+
}
|
|
45
|
+
function modalGoBack() {
|
|
46
|
+
var fn = _modalBackStack.pop();
|
|
47
|
+
var btn = document.getElementById('modal-back-btn');
|
|
48
|
+
if (btn && _modalBackStack.length === 0) btn.style.display = 'none';
|
|
49
|
+
if (fn) fn();
|
|
50
|
+
}
|
|
51
|
+
function clearModalBackStack() {
|
|
52
|
+
_modalBackStack = [];
|
|
53
|
+
var btn = document.getElementById('modal-back-btn');
|
|
54
|
+
if (btn) btn.style.display = 'none';
|
|
55
|
+
}
|
|
56
|
+
|
|
38
57
|
function updateModalPinBtn() {
|
|
39
58
|
var btn = document.getElementById('modal-pin-btn');
|
|
40
59
|
if (!btn) return;
|
package/dashboard/layout.html
CHANGED
|
@@ -98,6 +98,7 @@
|
|
|
98
98
|
<div class="modal-header">
|
|
99
99
|
<h3 id="modal-title">—</h3>
|
|
100
100
|
<div class="modal-header-actions">
|
|
101
|
+
<button class="modal-copy" id="modal-back-btn" onclick="modalGoBack()" title="Back" style="display:none">← Back</button>
|
|
101
102
|
<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>
|
|
102
103
|
<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>
|
|
103
104
|
<button class="modal-copy" id="modal-cancel-edit-btn" onclick="modalCancelEdit()" title="Cancel edit" style="display:none">Cancel</button>
|
package/dashboard/styles.css
CHANGED
|
@@ -194,7 +194,7 @@
|
|
|
194
194
|
.pl-progress-label { display: flex; gap: 8px; align-items: center; margin-top: 4px; font-size: 10px; }
|
|
195
195
|
.pl-node-chain { display: flex; align-items: flex-start; gap: 2px; overflow-x: auto; padding: 8px 0; }
|
|
196
196
|
.pl-node { display: flex; flex-direction: column; align-items: center; flex-shrink: 0; }
|
|
197
|
-
.pl-node-box { padding: 4px 8px; border-radius: 6px; border:
|
|
197
|
+
.pl-node-box { padding: 4px 8px; border-radius: 6px; border: 1px solid var(--border); background: var(--surface2); text-align: center; font-size: 10px; transition: border-color 0.2s; white-space: nowrap; }
|
|
198
198
|
.pl-node-box.complete { border-color: var(--green); background: rgba(63,185,80,0.08); }
|
|
199
199
|
.pl-node-box.running { border-color: var(--blue); animation: plSegPulse 1.5s ease-in-out infinite; }
|
|
200
200
|
.pl-node-box.failed { border-color: var(--red); background: rgba(248,81,73,0.08); }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.688",
|
|
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"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "pr-review-fix-cycle",
|
|
3
|
+
"title": "PR Review & Fix Cycle",
|
|
4
|
+
"description": "Visualizes the default engine flow: review a PR, fix issues if rejected, re-review until approved and build passes.",
|
|
5
|
+
"trigger": { "manual": true },
|
|
6
|
+
"stages": [
|
|
7
|
+
{
|
|
8
|
+
"id": "review-pr",
|
|
9
|
+
"type": "task",
|
|
10
|
+
"taskType": "review",
|
|
11
|
+
"title": "Review PR",
|
|
12
|
+
"description": "Review the target PR for correctness, quality, and completeness. Provide actionable feedback if changes are needed."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "check-review-status",
|
|
16
|
+
"type": "condition",
|
|
17
|
+
"title": "Approved?",
|
|
18
|
+
"check": "allBuildsGreen",
|
|
19
|
+
"action": "stop",
|
|
20
|
+
"onMet": "Merge",
|
|
21
|
+
"onUnmet": "Fix",
|
|
22
|
+
"dependsOn": ["review-pr"]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "fix-feedback",
|
|
26
|
+
"type": "task",
|
|
27
|
+
"taskType": "fix",
|
|
28
|
+
"title": "Fix review feedback",
|
|
29
|
+
"description": "Address all review comments and push fixes to the PR branch.",
|
|
30
|
+
"dependsOn": ["check-review-status"]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "re-review",
|
|
34
|
+
"type": "task",
|
|
35
|
+
"taskType": "review",
|
|
36
|
+
"title": "Re-review after fix",
|
|
37
|
+
"description": "Re-review the PR after fixes have been applied. Verify all prior feedback was addressed.",
|
|
38
|
+
"dependsOn": ["fix-feedback"]
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"stopWhen": "allBuildsGreen"
|
|
42
|
+
}
|