@link-assistant/hive-mind 1.25.2 → 1.25.3

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,17 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 1.25.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 0ed3ccb: fix: prevent --auto-restart-until-mergeable infinite loop when no CI/CD is configured (Issue #1345)
8
+
9
+ Previously, when a repository had no GitHub Actions workflows configured, `--auto-restart-until-mergeable` would loop indefinitely because `getDetailedCIStatus()` returned `{ status: 'no_checks' }` and the code always treated this as a transient race condition (checks haven't started yet).
10
+
11
+ Now the fix correctly handles the `no_checks` case by also checking `checkPRMergeable()`. If GitHub reports the PR as `MERGEABLE` (`mergeStateStatus: CLEAN`), the repository has no required CI checks and the process exits immediately with an appropriate message ("No CI/CD checks are configured for this repository — PR is mergeable"). If the PR is not yet mergeable, the existing wait behavior is preserved.
12
+
13
+ Full case study analysis including timeline reconstruction from logs in `docs/case-studies/issue-1345/`.
14
+
3
15
  ## 1.25.2
4
16
 
5
17
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/hive-mind",
3
- "version": "1.25.2",
3
+ "version": "1.25.3",
4
4
  "description": "AI-powered issue solver and hive mind for collaborative problem solving",
5
5
  "main": "src/hive.mjs",
6
6
  "type": "module",
@@ -187,12 +187,32 @@ const getMergeBlockers = async (owner, repo, prNumber, verbose = false) => {
187
187
  const ciStatus = await getDetailedCIStatus(owner, repo, prNumber, verbose);
188
188
 
189
189
  if (ciStatus.status === 'no_checks') {
190
- // No CI checks exist yet - race condition after push, treat as pending
191
- blockers.push({
192
- type: 'ci_pending',
193
- message: 'CI/CD checks have not started yet (waiting for checks to appear)',
194
- details: [],
195
- });
190
+ // No CI checks exist yet - this could be:
191
+ // 1. A race condition after push (checks haven't started yet) - wait
192
+ // 2. A repository with no CI/CD configured at all - should be mergeable immediately
193
+ //
194
+ // Issue #1345: Distinguish by checking the PR's mergeability status.
195
+ // If GitHub says the PR is MERGEABLE (mergeStateStatus === 'CLEAN'),
196
+ // then no CI is required and we should not block indefinitely.
197
+ // Otherwise (e.g. mergeStateStatus === 'BLOCKED'), treat as pending race condition.
198
+ const earlyMergeStatus = await checkPRMergeable(owner, repo, prNumber, verbose);
199
+ if (earlyMergeStatus.mergeable) {
200
+ // PR is already mergeable with no CI checks - the repo has no CI/CD configured.
201
+ // Do NOT add a ci_pending blocker. The mergeability check below will also
202
+ // confirm this is mergeable, so blockers will be empty → PR IS MERGEABLE path.
203
+ if (verbose) {
204
+ console.log(`[VERBOSE] /merge: PR #${prNumber} has no CI checks and is already MERGEABLE - no CI/CD configured`);
205
+ }
206
+ // Return early with no CI blocker, mergeability already confirmed
207
+ return { blockers, ciStatus, noCiConfigured: true };
208
+ } else {
209
+ // PR is not yet mergeable despite no checks - treat as pending race condition
210
+ blockers.push({
211
+ type: 'ci_pending',
212
+ message: 'CI/CD checks have not started yet (waiting for checks to appear)',
213
+ details: [],
214
+ });
215
+ }
196
216
  } else if (ciStatus.status === 'pending') {
197
217
  // CI is still running or queued - wait for completion
198
218
  const pendingNames = [...ciStatus.pendingChecks, ...ciStatus.queuedChecks].map(c => c.name);
@@ -272,7 +292,7 @@ const getMergeBlockers = async (owner, repo, prNumber, verbose = false) => {
272
292
  });
273
293
  }
274
294
 
275
- return blockers;
295
+ return { blockers, ciStatus, noCiConfigured: false };
276
296
  };
277
297
 
278
298
  /**
@@ -341,7 +361,7 @@ export const watchUntilMergeable = async params => {
341
361
 
342
362
  try {
343
363
  // Get merge blockers
344
- const blockers = await getMergeBlockers(owner, repo, prNumber, argv.verbose);
364
+ const { blockers, noCiConfigured } = await getMergeBlockers(owner, repo, prNumber, argv.verbose);
345
365
 
346
366
  // Check for new comments from non-bot users
347
367
  const { hasNewComments, comments } = await checkForNonBotComments(owner, repo, prNumber, issueNumber, lastCheckTime, argv.verbose);
@@ -364,7 +384,9 @@ export const watchUntilMergeable = async params => {
364
384
 
365
385
  // Post success comment
366
386
  try {
367
- const commentBody = `## 🎉 Auto-merged\n\nThis pull request has been automatically merged by hive-mind after all CI checks passed and the PR became mergeable.\n\n---\n*Auto-merged by hive-mind with --auto-merge flag*`;
387
+ // Issue #1345: Differentiate message when no CI is configured
388
+ const ciLine = noCiConfigured ? '- No CI/CD checks are configured for this repository' : '- All CI checks have passed';
389
+ const commentBody = `## 🎉 Auto-merged\n\nThis pull request has been automatically merged by hive-mind.\n${ciLine}\n\n---\n*Auto-merged by hive-mind with --auto-merge flag*`;
368
390
  await $`gh pr comment ${prNumber} --repo ${owner}/${repo} --body ${commentBody}`;
369
391
  } catch {
370
392
  // Don't fail if comment posting fails
@@ -386,7 +408,9 @@ export const watchUntilMergeable = async params => {
386
408
  const readyToMergeSignature = '## ✅ Ready to merge';
387
409
  const hasExistingComment = await checkForExistingComment(owner, repo, prNumber, readyToMergeSignature, argv.verbose);
388
410
  if (!hasExistingComment) {
389
- const commentBody = `## Ready to merge\n\nThis pull request is now ready to be merged:\n- All CI checks have passed\n- No merge conflicts\n- No pending changes\n\n---\n*Monitored by hive-mind with --auto-restart-until-mergeable flag*`;
411
+ // Issue #1345: Differentiate message when no CI is configured
412
+ const ciLine = noCiConfigured ? '- No CI/CD checks are configured for this repository' : '- All CI checks have passed';
413
+ const commentBody = `## ✅ Ready to merge\n\nThis pull request is now ready to be merged:\n${ciLine}\n- No merge conflicts\n- No pending changes\n\n---\n*Monitored by hive-mind with --auto-restart-until-mergeable flag*`;
390
414
  await $`gh pr comment ${prNumber} --repo ${owner}/${repo} --body ${commentBody}`;
391
415
  } else {
392
416
  await log(formatAligned('', 'Skipping duplicate "Ready to merge" comment', '', 2));