@yemi33/minions 0.1.1005 → 0.1.1006

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.1005 (2026-04-16)
3
+ ## 0.1.1006 (2026-04-16)
4
4
 
5
5
  ### Features
6
+ - cap pendingContexts in cooldowns.json to prevent bloat (#1126)
6
7
  - fix stopAfter=0 watch expiry — run forever for all conditions (#1117)
7
8
  - fix doc-chat Clear chat not persisting session deletion to localStorage (#1102)
8
9
  - remove DEFAULTS alias from timeout.js (#1101)
@@ -22,7 +23,6 @@
22
23
  - reassign tasks when preferred agent is busy too long
23
24
  - wire agentBusyReassignMs into settings UI and persist
24
25
  - ADO throttle detection, poll guards, and dashboard banner (#1051)
25
- - gate auto-fix conflict dispatch behind autoFixConflicts flag
26
26
 
27
27
  ### Fixes
28
28
  - harden repo-scoped PR identity handling
package/engine/cleanup.js CHANGED
@@ -8,7 +8,7 @@ const path = require('path');
8
8
  const shared = require('./shared');
9
9
  const queries = require('./queries');
10
10
 
11
- const { exec, execSilent, log, ts } = shared;
11
+ const { exec, execSilent, log, ts, ENGINE_DEFAULTS } = shared;
12
12
  const { safeJson, safeWrite, safeReadDir, mutateWorkItems, getProjects, projectWorkItemsPath, projectPrPath,
13
13
  sanitizeBranch, KB_CATEGORIES } = shared;
14
14
  const { getDispatch, getAgentStatus } = queries;
@@ -597,11 +597,23 @@ function runCleanup(config, verbose = false) {
597
597
  } catch (e) { log('warn', 'prune doc-sessions: ' + e.message); }
598
598
 
599
599
  // 11. Cap cooldowns.json — keep at most 500 entries (on top of 24h TTL in cooldown.js)
600
+ // Also trim pendingContexts arrays to ENGINE_DEFAULTS.maxPendingContexts to prevent bloat.
600
601
  cleaned.cooldowns = 0;
602
+ cleaned.pendingContextsTrimmed = 0;
601
603
  try {
602
604
  const cooldownPath = path.join(ENGINE_DIR, 'cooldowns.json');
603
605
  const cooldowns = safeJson(cooldownPath);
604
606
  if (cooldowns && typeof cooldowns === 'object') {
607
+ let dirty = false;
608
+ // Trim oversized pendingContexts arrays (one-time migration + ongoing cap)
609
+ const pendingCtxCap = ENGINE_DEFAULTS.maxPendingContexts;
610
+ for (const v of Object.values(cooldowns)) {
611
+ if (Array.isArray(v.pendingContexts) && v.pendingContexts.length > pendingCtxCap) {
612
+ v.pendingContexts = v.pendingContexts.slice(-pendingCtxCap);
613
+ cleaned.pendingContextsTrimmed++;
614
+ dirty = true;
615
+ }
616
+ }
605
617
  const entries = Object.entries(cooldowns);
606
618
  const COOLDOWN_CAP = 500;
607
619
  if (entries.length > COOLDOWN_CAP) {
@@ -610,6 +622,8 @@ function runCleanup(config, verbose = false) {
610
622
  const keep = Object.fromEntries(entries.slice(0, COOLDOWN_CAP));
611
623
  cleaned.cooldowns = entries.length - COOLDOWN_CAP;
612
624
  safeWrite(cooldownPath, keep);
625
+ } else if (dirty) {
626
+ safeWrite(cooldownPath, cooldowns);
613
627
  }
614
628
  }
615
629
  } catch (e) { log('warn', 'cap cooldowns: ' + e.message); }
@@ -653,8 +667,8 @@ function runCleanup(config, verbose = false) {
653
667
  }
654
668
  } catch { /* optional — file may not exist */ }
655
669
 
656
- if (cleaned.ccSessions + cleaned.docSessions + cleaned.cooldowns + cleaned.pidFiles > 0) {
657
- log('info', `Cleanup (resources): ${cleaned.ccSessions} cc-sessions, ${cleaned.docSessions} doc-sessions, ${cleaned.cooldowns} cooldowns, ${cleaned.pidFiles} PID files`);
670
+ if (cleaned.ccSessions + cleaned.docSessions + cleaned.cooldowns + cleaned.pidFiles + cleaned.pendingContextsTrimmed > 0) {
671
+ log('info', `Cleanup (resources): ${cleaned.ccSessions} cc-sessions, ${cleaned.docSessions} doc-sessions, ${cleaned.cooldowns} cooldowns, ${cleaned.pendingContextsTrimmed} pendingCtx trimmed, ${cleaned.pidFiles} PID files`);
658
672
  }
659
673
 
660
674
  return cleaned;
@@ -7,7 +7,7 @@ const path = require('path');
7
7
  const shared = require('./shared');
8
8
  const queries = require('./queries');
9
9
 
10
- const { safeJson, safeWrite, log } = shared;
10
+ const { safeJson, safeWrite, log, ENGINE_DEFAULTS } = shared;
11
11
  const { ENGINE_DIR } = queries;
12
12
 
13
13
  const COOLDOWN_PATH = path.join(ENGINE_DIR, 'cooldowns.json');
@@ -37,6 +37,13 @@ function saveCooldowns() {
37
37
  for (const [k, v] of dispatchCooldowns) {
38
38
  if (now - v.timestamp > 24 * 60 * 60 * 1000) dispatchCooldowns.delete(k);
39
39
  }
40
+ // Trim pendingContexts arrays before writing to prevent bloat
41
+ const cap = ENGINE_DEFAULTS.maxPendingContexts;
42
+ for (const [, v] of dispatchCooldowns) {
43
+ if (Array.isArray(v.pendingContexts) && v.pendingContexts.length > cap) {
44
+ v.pendingContexts = v.pendingContexts.slice(-cap);
45
+ }
46
+ }
40
47
  const obj = Object.fromEntries(dispatchCooldowns);
41
48
  try {
42
49
  safeWrite(COOLDOWN_PATH, obj);
@@ -61,8 +68,11 @@ function setCooldown(key) {
61
68
 
62
69
  function setCooldownWithContext(key, context) {
63
70
  const existing = dispatchCooldowns.get(key);
64
- const pendingContexts = existing?.pendingContexts || [];
71
+ let pendingContexts = existing?.pendingContexts || [];
65
72
  if (context) pendingContexts.push(context);
73
+ // Cap to last N entries to prevent unbounded growth (cooldowns.json bloat)
74
+ const cap = ENGINE_DEFAULTS.maxPendingContexts;
75
+ if (pendingContexts.length > cap) pendingContexts = pendingContexts.slice(-cap);
66
76
  dispatchCooldowns.set(key, {
67
77
  timestamp: Date.now(),
68
78
  failures: existing?.failures || 0,
package/engine/shared.js CHANGED
@@ -569,6 +569,7 @@ const ENGINE_DEFAULTS = {
569
569
  ccModel: 'sonnet', // model for Command Center and doc-chat (sonnet, haiku, opus)
570
570
  ccEffort: null, // effort level for CC/doc-chat (null, 'low', 'medium', 'high')
571
571
  heartbeatTimeouts: {}, // populated after WORK_TYPE is defined (below)
572
+ maxPendingContexts: 20, // cap pendingContexts arrays in cooldowns.json to prevent unbounded growth
572
573
  ccMaxTurns: 50, // max tool-use turns for CC/doc-chat before CLI stops
573
574
  // Teams integration — config.teams shape: { enabled, appId, appPassword, certPath, privateKeyPath, tenantId, notifyEvents, ccMirror, inboxPollInterval }
574
575
  // Auth modes: (1) appId + appPassword (client secret), or (2) appId + certPath + privateKeyPath + tenantId (certificate)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1005",
3
+ "version": "0.1.1006",
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"