@yemi33/minions 0.1.2407 → 0.1.2409
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/dashboard/js/command-center.js +20 -1
- package/dashboard/js/refresh.js +24 -7
- package/dashboard/shared/cc-suggestions.js +33 -0
- package/dashboard/slim/js/chat.js +5 -5
- package/dashboard/slim/styles.css +22 -0
- package/dashboard/styles.css +14 -0
- package/dashboard-build.js +1 -1
- package/dashboard.js +3 -6
- package/engine/meeting.js +20 -1
- package/package.json +1 -1
|
@@ -626,6 +626,18 @@ function ccAbort() {
|
|
|
626
626
|
}
|
|
627
627
|
}
|
|
628
628
|
|
|
629
|
+
function _ccRenderSuggestedPrompts() {
|
|
630
|
+
var el = document.getElementById('cc-messages');
|
|
631
|
+
var tab = _ccActiveTab();
|
|
632
|
+
if (!el || !tab || tab.messages.length !== 0 || tab._sending || el.children.length !== 0) return;
|
|
633
|
+
renderCcSuggestedPrompts(el, function(prompt) {
|
|
634
|
+
var input = document.getElementById('cc-input');
|
|
635
|
+
if (!input) return;
|
|
636
|
+
input.value = prompt;
|
|
637
|
+
ccSend();
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
|
|
629
641
|
function toggleCommandCenter() {
|
|
630
642
|
_ccOpen = !_ccOpen;
|
|
631
643
|
// Opening CC means the operator found it — retire the first-use coachmark.
|
|
@@ -667,6 +679,7 @@ function ccNewTab(skipServerReset) {
|
|
|
667
679
|
_ccActiveTabId = tabId;
|
|
668
680
|
// New tab starts with null sessionId — server creates fresh session on first message
|
|
669
681
|
document.getElementById('cc-messages').innerHTML = '';
|
|
682
|
+
_ccRenderSuggestedPrompts();
|
|
670
683
|
ccRenderTabBar();
|
|
671
684
|
ccUpdateSessionIndicator();
|
|
672
685
|
ccSaveState();
|
|
@@ -696,6 +709,7 @@ function ccSwitchTab(id) {
|
|
|
696
709
|
for (var i = 0; i < tab.messages.length; i++) {
|
|
697
710
|
ccAddMessage(tab.messages[i].role, tab.messages[i].html, true, null, tab.messages[i]);
|
|
698
711
|
}
|
|
712
|
+
_ccRenderSuggestedPrompts();
|
|
699
713
|
// If this tab is still processing, restore the full streaming UX (tools, partial text, thinking)
|
|
700
714
|
if (tab._sending) {
|
|
701
715
|
var dotPulse = '<span style="display:inline-flex;gap:3px;margin-left:6px;vertical-align:middle"><span style="width:4px;height:4px;background:var(--blue);border-radius:50%;animation:dotPulse 1.2s infinite"></span><span style="width:4px;height:4px;background:var(--blue);border-radius:50%;animation:dotPulse 1.2s infinite;animation-delay:0.2s"></span><span style="width:4px;height:4px;background:var(--blue);border-radius:50%;animation:dotPulse 1.2s infinite;animation-delay:0.4s"></span></span>';
|
|
@@ -887,7 +901,11 @@ function ccRestoreMessages() {
|
|
|
887
901
|
var el = document.getElementById('cc-messages');
|
|
888
902
|
var tab = _ccActiveTab();
|
|
889
903
|
if (!tab) return;
|
|
890
|
-
if (el.children.length > 0
|
|
904
|
+
if (el.children.length > 0) return;
|
|
905
|
+
if (tab.messages.length === 0) {
|
|
906
|
+
_ccRenderSuggestedPrompts();
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
891
909
|
for (var i = 0; i < tab.messages.length; i++) {
|
|
892
910
|
ccAddMessage(tab.messages[i].role, tab.messages[i].html, true, null, tab.messages[i]);
|
|
893
911
|
}
|
|
@@ -982,6 +1000,7 @@ function ccAddMessage(role, html, skipSave, targetTabId, meta) {
|
|
|
982
1000
|
var isVisible = !targetTabId || targetTabId === _ccActiveTabId;
|
|
983
1001
|
if (isVisible) {
|
|
984
1002
|
var el = document.getElementById('cc-messages');
|
|
1003
|
+
clearCcSuggestedPrompts(el);
|
|
985
1004
|
var div = document.createElement('div');
|
|
986
1005
|
div.className = isAssistant ? 'cc-msg-assistant' : isAction ? 'cc-msg-action' : '';
|
|
987
1006
|
if (messageId) {
|
package/dashboard/js/refresh.js
CHANGED
|
@@ -62,11 +62,11 @@ const _pageCounters = {
|
|
|
62
62
|
return ws.length + '|' + ws.reduce(function(m, w) { return Math.max(m, new Date(w.last_triggered || 0).getTime() || 0); }, 0);
|
|
63
63
|
},
|
|
64
64
|
meetings: function(d) {
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
return
|
|
65
|
+
// One server summary owns both the active count and signature. Do not mix
|
|
66
|
+
// independently resolving total/list requests or include terminal history.
|
|
67
|
+
if (!window._lastMeetingsSummary) return null;
|
|
68
|
+
const summary = window._lastMeetingsSummary;
|
|
69
|
+
return (summary.active || 0) + '|' + (summary.sig || '');
|
|
70
70
|
},
|
|
71
71
|
pipelines: function(d) {
|
|
72
72
|
if (!Array.isArray(window._lastPipelines)) return null;
|
|
@@ -97,13 +97,17 @@ const _pageCounters = {
|
|
|
97
97
|
},
|
|
98
98
|
};
|
|
99
99
|
let _prevCounts = {};
|
|
100
|
+
function _isPageActivityRelevant(page, meetingSummary) {
|
|
101
|
+
return page !== 'meetings' || Number(meetingSummary?.active) > 0;
|
|
102
|
+
}
|
|
100
103
|
function _detectPageChanges(data) {
|
|
101
104
|
var changes = {};
|
|
102
105
|
for (var page in _pageCounters) {
|
|
103
106
|
var sig = _pageCounters[page](data);
|
|
104
107
|
if (sig === null) continue; // cache not ready yet — skip both compare and record
|
|
105
108
|
var sigStr = String(sig);
|
|
106
|
-
if (_prevCounts[page] !== undefined && sigStr !== _prevCounts[page]
|
|
109
|
+
if (_prevCounts[page] !== undefined && sigStr !== _prevCounts[page]
|
|
110
|
+
&& _isPageActivityRelevant(page, window._lastMeetingsSummary)) changes[page] = true;
|
|
107
111
|
_prevCounts[page] = sigStr;
|
|
108
112
|
}
|
|
109
113
|
return changes;
|
|
@@ -425,6 +429,18 @@ function _fireCrossSliceRender(key, value) {
|
|
|
425
429
|
return true;
|
|
426
430
|
}
|
|
427
431
|
|
|
432
|
+
let _meetingsSummaryRequestSeq = 0;
|
|
433
|
+
function _applyMeetingsSummary(requestSeq, summary) {
|
|
434
|
+
if (requestSeq !== _meetingsSummaryRequestSeq) return false;
|
|
435
|
+
if (!summary || typeof summary.active !== 'number' || typeof summary.sig !== 'string') return false;
|
|
436
|
+
window._lastMeetingsSummary = summary;
|
|
437
|
+
if (!_isPageActivityRelevant('meetings', summary)) {
|
|
438
|
+
const link = document.querySelector('.sidebar-link[data-page="meetings"]');
|
|
439
|
+
if (link) clearNotifBadge(link);
|
|
440
|
+
}
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
|
|
428
444
|
function _refreshSidebarCounterSummaries() {
|
|
429
445
|
fetch('/api/qa-runs-summary')
|
|
430
446
|
.then(function (r) { return r.ok ? r.json() : null; })
|
|
@@ -437,9 +453,10 @@ function _refreshSidebarCounterSummaries() {
|
|
|
437
453
|
.then(function (r) { return r.ok ? r.json() : null; })
|
|
438
454
|
.then(function (s) { if (s && typeof s === 'object') window._lastQaSessionsSummary = s; })
|
|
439
455
|
.catch(function () { /* sidebar badge degrades to empty */ });
|
|
456
|
+
const meetingsSummarySeq = ++_meetingsSummaryRequestSeq;
|
|
440
457
|
fetch('/api/meetings-total')
|
|
441
458
|
.then(function (r) { return r.ok ? r.json() : null; })
|
|
442
|
-
.then(function (s) {
|
|
459
|
+
.then(function (s) { _applyMeetingsSummary(meetingsSummarySeq, s); })
|
|
443
460
|
.catch(function () { /* optional */ });
|
|
444
461
|
// /api/verify-guides is now fetched in parallel with /api/prd inside the
|
|
445
462
|
// prdProgress block so renderPrd's guideByPlan lookup uses the SAME tick's
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Shared suggested-prompt definition and DOM renderer for classic and Slim CC.
|
|
2
|
+
// Add future prompts to this list; both surfaces pick them up automatically.
|
|
3
|
+
var CC_SUGGESTED_PROMPTS = [
|
|
4
|
+
'Update me on status of Minions',
|
|
5
|
+
];
|
|
6
|
+
|
|
7
|
+
function clearCcSuggestedPrompts(container) {
|
|
8
|
+
if (!container) return;
|
|
9
|
+
var current = container.querySelector('.cc-suggestions');
|
|
10
|
+
if (current) current.remove();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function renderCcSuggestedPrompts(container, onSelect) {
|
|
14
|
+
if (!container || typeof onSelect !== 'function') return null;
|
|
15
|
+
clearCcSuggestedPrompts(container);
|
|
16
|
+
|
|
17
|
+
var group = document.createElement('div');
|
|
18
|
+
group.className = 'cc-suggestions';
|
|
19
|
+
group.setAttribute('role', 'group');
|
|
20
|
+
group.setAttribute('aria-label', 'Suggested prompts');
|
|
21
|
+
|
|
22
|
+
CC_SUGGESTED_PROMPTS.forEach(function(prompt) {
|
|
23
|
+
var button = document.createElement('button');
|
|
24
|
+
button.type = 'button';
|
|
25
|
+
button.className = 'cc-suggestion';
|
|
26
|
+
button.textContent = prompt;
|
|
27
|
+
button.addEventListener('click', function() { onSelect(prompt); });
|
|
28
|
+
group.appendChild(button);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
container.appendChild(group);
|
|
32
|
+
return group;
|
|
33
|
+
}
|
|
@@ -307,6 +307,7 @@
|
|
|
307
307
|
}
|
|
308
308
|
|
|
309
309
|
function clearEmpty() {
|
|
310
|
+
clearCcSuggestedPrompts(msgsEl);
|
|
310
311
|
var empty = msgsEl.querySelector('.chat-empty');
|
|
311
312
|
if (empty) empty.remove();
|
|
312
313
|
}
|
|
@@ -627,10 +628,10 @@
|
|
|
627
628
|
msgsEl.innerHTML = '';
|
|
628
629
|
queueEl = null; // detached by the innerHTML reset; renderQueue rebuilds it
|
|
629
630
|
if (!messages.length) {
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
631
|
+
renderCcSuggestedPrompts(msgsEl, function(prompt) {
|
|
632
|
+
inputEl.value = prompt;
|
|
633
|
+
sendMessage();
|
|
634
|
+
});
|
|
634
635
|
} else {
|
|
635
636
|
for (var i = 0; i < messages.length; i++) {
|
|
636
637
|
var m = messages[i];
|
|
@@ -752,4 +753,3 @@
|
|
|
752
753
|
loadState();
|
|
753
754
|
rerenderHistory();
|
|
754
755
|
renderTabBar();
|
|
755
|
-
|
|
@@ -368,6 +368,28 @@
|
|
|
368
368
|
text-align: center;
|
|
369
369
|
margin-top: 24px;
|
|
370
370
|
}
|
|
371
|
+
.cc-suggestions {
|
|
372
|
+
display: flex;
|
|
373
|
+
justify-content: center;
|
|
374
|
+
width: 100%;
|
|
375
|
+
margin: var(--space-8) auto;
|
|
376
|
+
}
|
|
377
|
+
.cc-suggestion {
|
|
378
|
+
appearance: none;
|
|
379
|
+
max-width: 100%;
|
|
380
|
+
padding: var(--space-4) var(--space-6);
|
|
381
|
+
border: 1px solid var(--border);
|
|
382
|
+
border-radius: 999px;
|
|
383
|
+
background: var(--surface2);
|
|
384
|
+
color: var(--text);
|
|
385
|
+
font: inherit;
|
|
386
|
+
font-size: var(--text-lg);
|
|
387
|
+
line-height: 1.4;
|
|
388
|
+
cursor: pointer;
|
|
389
|
+
transition: border-color 0.15s, color 0.15s, background 0.15s;
|
|
390
|
+
}
|
|
391
|
+
.cc-suggestion:hover { border-color: var(--blue); color: var(--blue); background: var(--surface); }
|
|
392
|
+
.cc-suggestion:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
|
|
371
393
|
.chat-msg {
|
|
372
394
|
max-width: 90%;
|
|
373
395
|
/* Uniform bubble padding across variants (#2); 20px horizontal gives
|
package/dashboard/styles.css
CHANGED
|
@@ -1171,6 +1171,20 @@
|
|
|
1171
1171
|
normal spacing relative to non-action neighbors (parent flex gap:10px). */
|
|
1172
1172
|
#cc-messages > .cc-msg-action + .cc-msg-action { margin-top: -8px; }
|
|
1173
1173
|
|
|
1174
|
+
.cc-suggestions {
|
|
1175
|
+
display: flex; flex-direction: column; align-items: stretch; gap: var(--space-3);
|
|
1176
|
+
width: 100%; margin: var(--space-7) auto 0;
|
|
1177
|
+
}
|
|
1178
|
+
.cc-suggestion {
|
|
1179
|
+
appearance: none; width: 100%; padding: var(--space-4) var(--space-5);
|
|
1180
|
+
border: 1px solid var(--border); border-radius: var(--radius-md);
|
|
1181
|
+
background: var(--surface2); color: var(--text); font: inherit;
|
|
1182
|
+
font-size: var(--text-md); line-height: 1.4; text-align: left; cursor: pointer;
|
|
1183
|
+
transition: border-color var(--transition-base), color var(--transition-base);
|
|
1184
|
+
}
|
|
1185
|
+
.cc-suggestion:hover { border-color: var(--blue); color: var(--blue); }
|
|
1186
|
+
.cc-suggestion:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
|
|
1187
|
+
|
|
1174
1188
|
/* Command Center tab bar */
|
|
1175
1189
|
.cc-tab-scroll { display: flex; gap: 4px; align-items: center; overflow-x: auto; overflow-y: hidden; flex: 1 1 auto; min-width: 0; scrollbar-width: thin; }
|
|
1176
1190
|
.cc-tab { padding: 4px 10px; font-size: var(--text-sm); border: 1px solid var(--border); border-bottom: none; border-radius: 6px 6px 0 0; background: var(--surface2); color: var(--muted); cursor: pointer; white-space: nowrap; max-width: 140px; display: inline-flex; align-items: center; gap: 2px; flex-shrink: 0; margin-bottom: -1px; position: relative; }
|
package/dashboard-build.js
CHANGED
|
@@ -8,7 +8,7 @@ const shared = require('./engine/shared');
|
|
|
8
8
|
const { safeRead } = shared;
|
|
9
9
|
|
|
10
10
|
const MINIONS_DIR = __dirname;
|
|
11
|
-
const DASHBOARD_SHARED_JS = ['pr-merge-state', 'pr-filters'];
|
|
11
|
+
const DASHBOARD_SHARED_JS = ['pr-merge-state', 'pr-filters', 'cc-suggestions'];
|
|
12
12
|
|
|
13
13
|
function buildDashboardHtml() {
|
|
14
14
|
const dashDir = path.join(MINIONS_DIR, 'dashboard');
|
package/dashboard.js
CHANGED
|
@@ -1840,7 +1840,7 @@ function buildDashboardHtml() {
|
|
|
1840
1840
|
'confirm-dialog', 'modal', 'modal-qa', 'settings', 'qa', 'fre', 'refresh'
|
|
1841
1841
|
];
|
|
1842
1842
|
let jsHtml = '';
|
|
1843
|
-
for (const f of ['pr-merge-state', 'pr-filters']) {
|
|
1843
|
+
for (const f of ['pr-merge-state', 'pr-filters', 'cc-suggestions']) {
|
|
1844
1844
|
const content = safeRead(path.join(dashDir, 'shared', f + '.js'));
|
|
1845
1845
|
jsHtml += `\n// ─── shared/${f}.js ────────────────────────────────────────\n${content}\n`;
|
|
1846
1846
|
}
|
|
@@ -13498,14 +13498,11 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
13498
13498
|
builder: () => qaSessionsMod.summarizeActiveSessionsForStatus(),
|
|
13499
13499
|
});
|
|
13500
13500
|
}},
|
|
13501
|
-
{ method: 'GET', path: '/api/meetings-total', desc: '
|
|
13501
|
+
{ method: 'GET', path: '/api/meetings-total', desc: 'Meeting summary {total, active, sig}; active-only fields drive the sidebar activity dot', handler: (req, res) => {
|
|
13502
13502
|
return serveFreshJson(req, res, {
|
|
13503
13503
|
tag: 'meetings-total',
|
|
13504
13504
|
inputs: [path.join(MINIONS_DIR, 'meetings')],
|
|
13505
|
-
builder: () =>
|
|
13506
|
-
const meetings = meetingMod.getMeetings();
|
|
13507
|
-
return { total: Array.isArray(meetings) ? meetings.length : 0 };
|
|
13508
|
-
},
|
|
13505
|
+
builder: () => meetingMod.summarizeMeetingsForStatus(),
|
|
13509
13506
|
});
|
|
13510
13507
|
}},
|
|
13511
13508
|
{ method: 'GET', path: '/api/browser-presence', desc: 'Whether a dashboard browser tab was recently active', handler: (req, res) => {
|
package/engine/meeting.js
CHANGED
|
@@ -399,6 +399,25 @@ function getMeetings() {
|
|
|
399
399
|
return result;
|
|
400
400
|
}
|
|
401
401
|
|
|
402
|
+
function summarizeMeetingsForStatus() {
|
|
403
|
+
const meetings = getMeetings();
|
|
404
|
+
const activeEntries = [];
|
|
405
|
+
for (const meeting of meetings) {
|
|
406
|
+
if (!meeting || typeof meeting !== 'object') continue;
|
|
407
|
+
const status = String(meeting.status || '').toLowerCase();
|
|
408
|
+
if (!ACTIVE_MEETING_STATUSES.has(status)) continue;
|
|
409
|
+
const roundValue = Number(meeting.round);
|
|
410
|
+
const round = Number.isFinite(roundValue) ? roundValue : 0;
|
|
411
|
+
activeEntries.push((meeting.id || '') + ':' + status + ':' + round);
|
|
412
|
+
}
|
|
413
|
+
activeEntries.sort();
|
|
414
|
+
return {
|
|
415
|
+
total: meetings.length,
|
|
416
|
+
active: activeEntries.length,
|
|
417
|
+
sig: activeEntries.join(','),
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
402
421
|
function getMeeting(id) {
|
|
403
422
|
const filePath = path.join(MEETINGS_DIR, id + '.json');
|
|
404
423
|
const m = safeJson(filePath);
|
|
@@ -1023,7 +1042,7 @@ function checkMeetingTimeouts(config) {
|
|
|
1023
1042
|
}
|
|
1024
1043
|
}
|
|
1025
1044
|
module.exports = {
|
|
1026
|
-
MEETINGS_DIR, getMeetings, getMeeting, saveMeeting, mutateMeeting, createMeeting,
|
|
1045
|
+
MEETINGS_DIR, getMeetings, summarizeMeetingsForStatus, getMeeting, saveMeeting, mutateMeeting, createMeeting,
|
|
1027
1046
|
invalidateMeetingsCache,
|
|
1028
1047
|
discoverMeetingWork, collectMeetingFindings, checkMeetingTimeouts,
|
|
1029
1048
|
addMeetingNote, advanceMeetingRound, endMeeting, archiveMeeting, unarchiveMeeting, deleteMeeting,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2409",
|
|
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"
|