@yemi33/minions 0.1.2407 → 0.1.2408

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.
@@ -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
- // Meetings total comes from /api/meetings-total; list from /state/meetings.
66
- if (window._lastMeetingsTotal === undefined) return null;
67
- const total = window._lastMeetingsTotal ?? 0;
68
- const list = window._lastMeetings || [];
69
- return total + '|' + list.reduce(function(s, m) { return s + (m.round || 0); }, 0);
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]) changes[page] = true;
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) { if (s && typeof s.total === 'number') window._lastMeetingsTotal = s.total; })
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
package/dashboard.js CHANGED
@@ -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: 'Total meeting count (sidebar activity-dot signal cheaper than fetching /api/meetings)', handler: (req, res) => {
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.2407",
3
+ "version": "0.1.2408",
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"