@yemi33/minions 0.1.915 → 0.1.917
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,8 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.917 (2026-04-13)
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
|
+
- CC tab unread dot + reopened badge on work items
|
|
6
7
|
- fix dep re-merge failure on retry with existing commits (#977)
|
|
7
8
|
- audit and harden log buffering implementation (#971)
|
|
8
9
|
- replace magic string 'active' with PR_STATUS.ACTIVE in lifecycle.js (#969)
|
|
@@ -17,6 +18,7 @@
|
|
|
17
18
|
- add red dot notification on CC tab when response completes (#934) (#946)
|
|
18
19
|
|
|
19
20
|
### Fixes
|
|
21
|
+
- PRD item status stuck at dispatched when fix completes (#989)
|
|
20
22
|
- dep merge ancestor pruning + pre-flight simulation (#958) (#979)
|
|
21
23
|
- add MAX_TURNS failure class and fix enum count test (#983)
|
|
22
24
|
- prevent Create Plan from meeting saving doc-chat context bleed (#980)
|
|
@@ -90,6 +90,8 @@ function toggleCommandCenter() {
|
|
|
90
90
|
// Ensure at least one tab exists
|
|
91
91
|
if (_ccTabs.length === 0) ccNewTab(true);
|
|
92
92
|
clearNotifBadge(document.getElementById('cc-toggle-btn'));
|
|
93
|
+
var activeTabOnOpen = _ccActiveTab();
|
|
94
|
+
if (activeTabOnOpen) activeTabOnOpen._unread = false;
|
|
93
95
|
ccRenderTabBar();
|
|
94
96
|
document.getElementById('cc-input').focus();
|
|
95
97
|
ccRestoreMessages();
|
|
@@ -129,6 +131,7 @@ function ccSwitchTab(id) {
|
|
|
129
131
|
if (!tab) return;
|
|
130
132
|
// If there is an active request, keep it running but switch view
|
|
131
133
|
_ccActiveTabId = id;
|
|
134
|
+
tab._unread = false;
|
|
132
135
|
var el = document.getElementById('cc-messages');
|
|
133
136
|
el.innerHTML = '';
|
|
134
137
|
// Re-render messages from the tab's data
|
|
@@ -247,6 +250,7 @@ function ccRenderTabBar() {
|
|
|
247
250
|
var isActive = t.id === _ccActiveTabId;
|
|
248
251
|
html += '<div class="cc-tab' + (isActive ? ' active' : '') + (t._sending ? ' working' : '') + '" onclick="ccSwitchTab(\'' + t.id + '\')" title="' + escHtml(t.title) + '">';
|
|
249
252
|
html += '<span class="cc-tab-text">' + escHtml(t.title) + '</span>';
|
|
253
|
+
if (t._unread) html += '<span class="notif-badge done"></span>';
|
|
250
254
|
html += '<span class="cc-tab-close" onclick="event.stopPropagation();ccCloseTab(\'' + t.id + '\')">×</span>';
|
|
251
255
|
html += '</div>';
|
|
252
256
|
}
|
|
@@ -661,6 +665,8 @@ async function _ccDoSend(message, skipUserMsg, forceTabId) {
|
|
|
661
665
|
} finally {
|
|
662
666
|
if (activeTab) { activeTab._sending = false; activeTab._abortController = null; activeTab._429retries = 0; delete activeTab._streamedText; delete activeTab._toolsUsed; delete activeTab._sendStartedAt; }
|
|
663
667
|
_ccSending = (_ccTabs.some(function(t) { return t._sending; }));
|
|
668
|
+
// Mark tab unread if response completed on a background tab or while drawer is closed
|
|
669
|
+
if (activeTab && !_wasAborted && (activeTab.id !== _ccActiveTabId || !_ccOpen)) activeTab._unread = true;
|
|
664
670
|
ccRenderTabBar();
|
|
665
671
|
try { clearInterval(phaseTimer); } catch { /* may not be defined if error before reader */ }
|
|
666
672
|
try { localStorage.removeItem('cc-sending'); } catch {}
|
|
@@ -48,6 +48,7 @@ function wiRow(item) {
|
|
|
48
48
|
'<td>' + typeBadge(item.type) + '</td>' +
|
|
49
49
|
'<td>' + priBadge(item.priority) + '</td>' +
|
|
50
50
|
'<td>' + statusBadge(item.status || 'pending') +
|
|
51
|
+
(item._reopened ? ' <span style="font-size:9px;color:var(--purple);margin-left:4px" title="This item was reopened from a previously completed state">reopened</span>' : '') +
|
|
51
52
|
(item._pendingReason && item.status === 'pending' && item._pendingReason !== 'already_dispatched' ? ' <span style="font-size:9px;color:var(--muted);margin-left:4px" title="Pending reason: ' + escHtml(item._pendingReason) + '">' + escHtml(item._pendingReason.replace(/_/g, ' ')) + '</span>' : '') +
|
|
52
53
|
(item._pendingReason === 'already_dispatched' && item.status === 'pending' ? ' <span style="font-size:9px;color:var(--blue);margin-left:4px" title="In dispatch queue, waiting to be assigned">queued</span>' : '') +
|
|
53
54
|
(item._skipReason && item.status === 'pending' ? ' <span style="font-size:9px;color:var(--yellow);margin-left:4px" title="Dispatch blocked: ' + escHtml(item._skipReason) + (item._blockedBy ? ' (by ' + escHtml(item._blockedBy) + ')' : '') + '">' + escHtml(item._skipReason.replace(/_/g, ' ')) + (item._blockedBy ? ' <span style="color:var(--muted)">(' + escHtml(item._blockedBy) + ')</span>' : '') + '</span>' : '') +
|
|
@@ -431,7 +432,8 @@ function openWorkItemDetail(id) {
|
|
|
431
432
|
|
|
432
433
|
let html = '<div style="display:flex;flex-direction:column;gap:4px;font-size:13px">';
|
|
433
434
|
html += '<div style="display:flex;gap:8px;align-items:center;margin-bottom:8px">' +
|
|
434
|
-
badge(statusCls, item.status || 'pending') +
|
|
435
|
+
badge(statusCls, item.status || 'pending') +
|
|
436
|
+
(item._reopened ? ' <span style="font-size:9px;color:var(--purple);margin-left:4px" title="This item was reopened from a previously completed state">reopened</span>' : '') + ' ' +
|
|
435
437
|
'<span class="dispatch-type ' + (item.type || 'implement') + '">' + escHtml(item.type || 'implement') + '</span>' +
|
|
436
438
|
'<span class="prd-item-priority ' + (item.priority || '') + '">' + escHtml(item.priority || 'medium') + '</span>' +
|
|
437
439
|
'</div>';
|
package/engine/lifecycle.js
CHANGED
|
@@ -617,6 +617,8 @@ function updateWorkItemStatus(meta, status, reason) {
|
|
|
617
617
|
}
|
|
618
618
|
|
|
619
619
|
const _VALID_PRD_STATUSES = new Set([...Object.values(WI_STATUS), 'missing']);
|
|
620
|
+
// (#984) PRD statuses that are stale when the work item is actually done
|
|
621
|
+
const _STALE_PRD_STATUSES = new Set([WI_STATUS.DISPATCHED, WI_STATUS.FAILED, WI_STATUS.PENDING]);
|
|
620
622
|
function syncPrdItemStatus(itemId, status, sourcePlan) {
|
|
621
623
|
if (!itemId) return;
|
|
622
624
|
if (!_VALID_PRD_STATUSES.has(status)) return;
|
|
@@ -637,11 +639,12 @@ function syncPrdItemStatus(itemId, status, sourcePlan) {
|
|
|
637
639
|
} catch (err) { log('warn', `PRD status sync: ${err.message}`); }
|
|
638
640
|
}
|
|
639
641
|
|
|
640
|
-
// ─── PRD Backward-Scan Reconciliation (#929)
|
|
641
|
-
// Proactive counterpart to syncPrdItemStatus. Scans all active PRDs and
|
|
642
|
-
// "missing" items to "updated" when a done work item already exists
|
|
643
|
-
//
|
|
644
|
-
//
|
|
642
|
+
// ─── PRD Backward-Scan Reconciliation (#929, #984) ─────────────────────────
|
|
643
|
+
// Proactive counterpart to syncPrdItemStatus. Scans all active PRDs and:
|
|
644
|
+
// 1. Promotes "missing" items to "updated" when a done work item already exists (#929)
|
|
645
|
+
// 2. Promotes stale "dispatched"/"failed"/"pending" items to "done" when the work item
|
|
646
|
+
// is actually done (#984) — catches cases where fix work items complete with a
|
|
647
|
+
// different ID than the original PRD feature, leaving the PRD status stale.
|
|
645
648
|
|
|
646
649
|
function reconcilePrdStatuses(config) {
|
|
647
650
|
if (!fs.existsSync(PRD_DIR)) return;
|
|
@@ -674,6 +677,14 @@ function reconcilePrdStatuses(config) {
|
|
|
674
677
|
modified = true;
|
|
675
678
|
log('info', `PRD backward-scan: promoted ${feature.id} from missing→updated in ${file} (done work item exists)`);
|
|
676
679
|
}
|
|
680
|
+
// (#984) Stale status: PRD item stuck at dispatched/failed/pending while WI is done —
|
|
681
|
+
// happens when fix work items complete with a different ID than the original PRD feature
|
|
682
|
+
else if (_STALE_PRD_STATUSES.has(feature.status) && doneWiById.has(feature.id)) {
|
|
683
|
+
const prev = feature.status;
|
|
684
|
+
feature.status = WI_STATUS.DONE;
|
|
685
|
+
modified = true;
|
|
686
|
+
log('info', `PRD backward-scan: promoted ${feature.id} from ${prev}→done in ${file} (done work item exists)`);
|
|
687
|
+
}
|
|
677
688
|
}
|
|
678
689
|
|
|
679
690
|
if (modified) {
|
|
@@ -1790,7 +1801,23 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
1790
1801
|
}
|
|
1791
1802
|
|
|
1792
1803
|
if (type === WORK_TYPE.REVIEW) await updatePrAfterReview(agentId, meta?.pr, meta?.project, config, resultSummary);
|
|
1793
|
-
if (type === WORK_TYPE.FIX)
|
|
1804
|
+
if (type === WORK_TYPE.FIX) {
|
|
1805
|
+
updatePrAfterFix(meta?.pr, meta?.project, meta?.source);
|
|
1806
|
+
// (#984) Sync PRD status for PR-linked features: fix work items have a different ID
|
|
1807
|
+
// than the original PRD feature, so syncPrdItemStatus(fixWiId, ...) finds nothing.
|
|
1808
|
+
// Use the PR's prdItems to propagate done status when the original work item is done.
|
|
1809
|
+
if (effectiveSuccess && meta?.pr?.prdItems?.length) {
|
|
1810
|
+
try {
|
|
1811
|
+
const allWis = queries.getWorkItems(config);
|
|
1812
|
+
for (const prdItemId of meta.pr.prdItems) {
|
|
1813
|
+
const wi = allWis.find(w => w.id === prdItemId);
|
|
1814
|
+
if (wi && DONE_STATUSES.has(wi.status) && wi.sourcePlan) {
|
|
1815
|
+
syncPrdItemStatus(prdItemId, WI_STATUS.DONE, wi.sourcePlan);
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
} catch (err) { log('warn', `PRD sync after fix: ${err.message}`); }
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1794
1821
|
checkForLearnings(agentId, config.agents[agentId], dispatchItem.task);
|
|
1795
1822
|
if (effectiveSuccess) {
|
|
1796
1823
|
extractSkillsFromOutput(stdout, agentId, dispatchItem, config);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.917",
|
|
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"
|