@yemi33/minions 0.1.1569 → 0.1.1571

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,14 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.1569 (2026-04-27)
3
+ ## 0.1.1571 (2026-04-27)
4
4
 
5
5
  ### Fixes
6
+ - break work-items.json watcher tick storm
7
+
8
+ ## 0.1.1570 (2026-04-27)
9
+
10
+ ### Fixes
11
+ - gate retry redispatches
6
12
  - avoid duplicate review retry loops
7
13
 
8
14
  ## 0.1.1568 (2026-04-27)
package/engine/timeout.js CHANGED
@@ -398,6 +398,10 @@ function checkTimeouts(config) {
398
398
  allWiPaths.push(projectWorkItemsPath(project));
399
399
  }
400
400
  for (const wiPath of allWiPaths) {
401
+ // skipWriteIfUnchanged is critical — checkTimeouts runs every tick, and
402
+ // without this gate the file's mtime updates on every call (no real
403
+ // change), tripping the cli.js work-items.json watcher → triggering tick
404
+ // → calling checkTimeouts → ... a 5-6s loop of "File change detected".
401
405
  mutateJsonFileLocked(wiPath, (items) => {
402
406
  if (!items || !Array.isArray(items)) return items;
403
407
  let changed = false;
@@ -438,7 +442,7 @@ function checkTimeouts(config) {
438
442
  }
439
443
  }
440
444
  return items;
441
- }, { defaultValue: [] });
445
+ }, { defaultValue: [], skipWriteIfUnchanged: true });
442
446
  }
443
447
  }
444
448
 
package/engine.js CHANGED
@@ -2360,6 +2360,19 @@ function discoverFromWorkItems(config, project) {
2360
2360
  skipped.gated++; continue;
2361
2361
  }
2362
2362
  }
2363
+ // Min retry gap (#1770): even when isRetry bypasses the completed-dedup, a
2364
+ // tight retry loop on the same WI burns _retryCount inside one tick window.
2365
+ // Honor a configurable minimum interval since the last retry so an idempotent
2366
+ // agent (e.g. review bailing because a duplicate review already exists)
2367
+ // cannot flip a successfully-posted review into status=failed.
2368
+ if (isRetry && item._lastRetryAt) {
2369
+ const minGap = ENGINE_DEFAULTS.minRetryGapMs;
2370
+ const lastAt = Date.parse(item._lastRetryAt);
2371
+ if (Number.isFinite(lastAt) && (Date.now() - lastAt) < minGap) {
2372
+ if (item._pendingReason !== 'retry_cooldown') { item._pendingReason = 'retry_cooldown'; needsWrite = true; }
2373
+ skipped.gated++; continue;
2374
+ }
2375
+ }
2363
2376
  if (isOnCooldown(key, cooldownMs)) {
2364
2377
  if (item._pendingReason !== 'cooldown') { item._pendingReason = 'cooldown'; needsWrite = true; }
2365
2378
  skipped.gated++; continue;
@@ -2804,6 +2817,14 @@ function discoverCentralWorkItems(config) {
2804
2817
  continue;
2805
2818
  }
2806
2819
  }
2820
+ // Min retry gap (#1770): symmetric with discoverFromWorkItems — even when
2821
+ // isRetry bypasses the completed-dedup, enforce a min interval since
2822
+ // _lastRetryAt so a tight retry loop can't burn _retryCount in one tick.
2823
+ if (isRetry && item._lastRetryAt) {
2824
+ const minGap = ENGINE_DEFAULTS.minRetryGapMs;
2825
+ const lastAt = Date.parse(item._lastRetryAt);
2826
+ if (Number.isFinite(lastAt) && (Date.now() - lastAt) < minGap) continue;
2827
+ }
2807
2828
  if (isOnCooldown(key, 0)) continue;
2808
2829
 
2809
2830
  const workType = item.type || 'implement';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1569",
3
+ "version": "0.1.1571",
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"