@yemi33/minions 0.1.1019 → 0.1.1021

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,5 +1,42 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.1021 (2026-04-16)
4
+
5
+ ### Features
6
+ - route implement items to dedicated implement playbook (#1115)
7
+
8
+ ### Fixes
9
+ - mark PR abandoned on 404 instead of silently retrying each tick
10
+ - replace undefined PROJECTS with config.projects in checkWatches (#1108)
11
+ - write permission for publish workflow
12
+ - run tests inline and post check runs for publish PRs
13
+ - add maxBuffer to all GitHub CLI spawns + paginate PR list (#1130)
14
+ - add required CI checks for PRs + update publish for auto-merge
15
+ - revert to PR merge now that stale status check is removed
16
+ - guard live review check against undefined vote/state values (#1132)
17
+ - push version bump directly to master instead of via PR
18
+ - add push-triggered CI for chore/publish branches
19
+ - publish workflow chore PRs failing to merge
20
+ - harden KB ordering
21
+ - harden audited state transitions
22
+
23
+ ### Other
24
+ - chore: test publish after removing stale status check
25
+ - chore: trigger publish test
26
+ - chore: test publish workflow fix
27
+ - chore: trigger publish workflow test
28
+
29
+ ## 0.1.1020 (2026-04-16)
30
+
31
+ ### Features
32
+ - route implement items to dedicated implement playbook (#1115)
33
+
34
+ ### Fixes
35
+ - add maxBuffer to all GitHub CLI spawns + paginate PR list (#1130)
36
+ - replace undefined PROJECTS with config.projects in checkWatches (#1108)
37
+ - write permission for publish workflow
38
+ - run tests inline and post check runs for publish PRs
39
+
3
40
  ## 0.1.1019 (2026-04-16)
4
41
 
5
42
  ### Features
package/engine/github.js CHANGED
@@ -20,6 +20,11 @@ function engine() {
20
20
  let _dispatch = null;
21
21
  function dispatchModule() { if (!_dispatch) _dispatch = require('./dispatch'); return _dispatch; }
22
22
 
23
+ // ─── Constants ──────────────────────────────────────────────────────────────
24
+
25
+ // 10 MB — prevents maxBuffer exceeded errors on repos with many open PRs.
26
+ // Node.js default is 1 MB which overflows when GitHub API returns 100+ PR objects.
27
+ const GH_MAX_BUFFER = 10 * 1024 * 1024;
23
28
  // ─── Helpers ────────────────────────────────────────────────────────────────
24
29
 
25
30
  function isGitHub(project) {
@@ -83,11 +88,19 @@ const isGhThrottled = () => _ghThrottle.isThrottled();
83
88
  /** Returns a snapshot of the current GitHub throttle state. */
84
89
  const getGhThrottleState = () => _ghThrottle.getState();
85
90
 
86
- /** Run a `gh api` call and parse JSON result. Returns null on failure. */
87
- async function ghApi(endpoint, slug) {
91
+ /** Sentinel returned by ghApi when the resource does not exist (HTTP 404). */
92
+ const GH_NOT_FOUND = Object.freeze({ _notFound: true });
93
+
94
+ /** Run a `gh api` call and parse JSON result. Returns null on failure, GH_NOT_FOUND on 404.
95
+ * @param {string} endpoint - API endpoint (e.g. '/pulls?state=open')
96
+ * @param {string} slug - owner/repo slug
97
+ * @param {object} [opts] - Options: { paginate: boolean, timeout: number }
98
+ */
99
+ async function ghApi(endpoint, slug, opts = {}) {
88
100
  try {
89
- const cmd = `gh api "repos/${slug}${endpoint}"`;
90
- const result = await execAsync(cmd, { timeout: 30000, encoding: 'utf-8' });
101
+ const paginateFlag = opts.paginate ? ' --paginate' : '';
102
+ const cmd = `gh api${paginateFlag} "repos/${slug}${endpoint}"`;
103
+ const result = await execAsync(cmd, { timeout: opts.timeout || 30000, encoding: 'utf-8', maxBuffer: GH_MAX_BUFFER });
91
104
  const parsed = JSON.parse(result);
92
105
  _ghThrottle.recordSuccess();
93
106
  return parsed;
@@ -100,6 +113,10 @@ async function ghApi(endpoint, slug) {
100
113
  const retryAfterMs = secMatch ? parseInt(secMatch[1], 10) * 1000 : 0;
101
114
  _ghThrottle.recordThrottle(retryAfterMs);
102
115
  }
116
+ if (/HTTP 404|Not Found/i.test(msg)) {
117
+ log('warn', `GitHub API error (${endpoint}): ${e.message}`);
118
+ return GH_NOT_FOUND;
119
+ }
103
120
  log('warn', `GitHub API error (${endpoint}): ${e.message}`);
104
121
  return null;
105
122
  }
@@ -152,7 +169,7 @@ async function fetchGhBuildErrorLog(slug, failedRuns) {
152
169
  // Always fetch job log — annotations alone often lack test failure details
153
170
  try {
154
171
  const cmd = `gh api "repos/${slug}/actions/jobs/${run.id}/logs" 2>&1`;
155
- const result = await execAsync(cmd, { timeout: 15000, encoding: 'utf-8' });
172
+ const result = await execAsync(cmd, { timeout: 15000, encoding: 'utf-8', maxBuffer: GH_MAX_BUFFER });
156
173
  if (result && !result.includes('Not Found')) {
157
174
  logParts.push(`--- ${run.name || 'Check'} (log) ---\n${result}`);
158
175
  }
@@ -295,6 +312,15 @@ async function pollPrStatus(config) {
295
312
  const totalUpdated = await forEachActiveGhPr(config, async (project, pr, prNum, slug) => {
296
313
  const prData = await ghApi(`/pulls/${prNum}`, slug);
297
314
  if (!prData) return false;
315
+ if (prData === GH_NOT_FOUND) {
316
+ // PR no longer exists — mark abandoned so it stops being polled
317
+ if (pr.status !== PR_STATUS.ABANDONED) {
318
+ pr.status = PR_STATUS.ABANDONED;
319
+ log('info', `PR ${pr.id} returned 404 — marking abandoned`);
320
+ return true;
321
+ }
322
+ return false;
323
+ }
298
324
 
299
325
  let updated = false;
300
326
 
@@ -471,7 +497,7 @@ async function pollPrStatus(config) {
471
497
  if (autoComplete) {
472
498
  try {
473
499
  const mergeMethod = ['squash', 'merge', 'rebase'].includes(config.engine?.prMergeMethod) ? config.engine.prMergeMethod : 'squash';
474
- await execAsync(`gh pr merge ${prNum} --${mergeMethod} --repo ${slug} --delete-branch`, { timeout: 30000, encoding: 'utf-8' });
500
+ await execAsync(`gh pr merge ${prNum} --${mergeMethod} --repo ${slug} --delete-branch`, { timeout: 30000, encoding: 'utf-8', maxBuffer: GH_MAX_BUFFER });
475
501
  pr._autoCompleted = true;
476
502
  log('info', `Auto-completed PR ${pr.id}: builds green + review approved → merged (${mergeMethod})`);
477
503
  updated = true;
@@ -612,8 +638,8 @@ async function reconcilePrs(config) {
612
638
  } catch { continue; }
613
639
  }
614
640
 
615
- // Fetch open PRs
616
- const prsData = await ghApi('/pulls?state=open&per_page=100', slug);
641
+ // Fetch open PRs — paginate to handle repos with >100 open PRs
642
+ const prsData = await ghApi('/pulls?state=open&per_page=100', slug, { paginate: true, timeout: 60000 });
617
643
  if (!prsData || !Array.isArray(prsData)) {
618
644
  recordSlugFailure(slug);
619
645
  continue;
@@ -760,4 +786,5 @@ module.exports = {
760
786
  resetSlugBackoff,
761
787
  _ghPollBackoff,
762
788
  _ghThrottle, // exported for testing
789
+ GH_MAX_BUFFER, // exported for testing
763
790
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1019",
3
+ "version": "0.1.1021",
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"