@link-assistant/hive-mind 2.8.1 → 2.8.2

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,11 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 2.8.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 44202ff: Explain invalid pull request base/head conflicts before attempting to retarget the pull request.
8
+
3
9
  ## 2.8.1
4
10
 
5
11
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/hive-mind",
3
- "version": "2.8.1",
3
+ "version": "2.8.2",
4
4
  "description": "AI-powered issue solver and hive mind for collaborative problem solving",
5
5
  "main": "src/hive.mjs",
6
6
  "type": "module",
@@ -204,6 +204,40 @@ export async function getPullRequestBaseBranch({ owner, repo, prNumber, $, log }
204
204
  return baseBranch;
205
205
  }
206
206
 
207
+ async function getPullRequestBranchRange({ owner, repo, prNumber, $, log }) {
208
+ if (typeof $ !== 'function') {
209
+ throw new Error('Cannot verify pull request branches without a command runner');
210
+ }
211
+
212
+ const result = await ghWithRateLimitRetry(() => $`gh pr view ${prNumber} --repo ${owner}/${repo} --json baseRefName,headRefName`, {
213
+ label: 'gh pr view baseRefName,headRefName',
214
+ log,
215
+ });
216
+ if (result.code !== 0) {
217
+ const details = commandOutput(result) || 'unknown error';
218
+ throw new Error(`Could not verify pull request branches for #${prNumber}: ${details}`);
219
+ }
220
+
221
+ let branchRange;
222
+ try {
223
+ branchRange = JSON.parse(String(result.stdout || '').trim());
224
+ } catch {
225
+ throw new Error(`Could not verify pull request branches for #${prNumber}: gh returned invalid JSON`);
226
+ }
227
+
228
+ const baseBranch = normalizeBranchName(branchRange?.baseRefName);
229
+ const headBranch = normalizeBranchName(branchRange?.headRefName);
230
+ if (!baseBranch || !headBranch) {
231
+ throw new Error(`Could not verify pull request branches for #${prNumber}: gh returned an empty baseRefName or headRefName`);
232
+ }
233
+
234
+ return { baseBranch, headBranch };
235
+ }
236
+
237
+ function buildBaseEqualsHeadBranchMessage({ prNumber, expectedBaseBranch, currentBaseBranch }) {
238
+ return `Invalid --base-branch '${expectedBaseBranch}' for PR #${prNumber}: it is the pull request's head branch (the source/work branch), so it cannot also be the base branch (the target branch). The pull request currently targets '${currentBaseBranch}'. Rerun with --base-branch ${currentBaseBranch} to preserve that target, choose another target branch, or omit --base-branch to keep the existing pull request target. Manual intervention is required; no pull request changes were made.`;
239
+ }
240
+
207
241
  export async function ensurePullRequestBaseBranch({ owner, repo, prNumber, argv = {}, log = async () => {}, formatAligned = fallbackFormatAligned, $, onMismatch = 'restore', operation = 'verify' }) {
208
242
  const expectedBaseBranch = getExpectedPullRequestBaseBranch({ argv });
209
243
  if (!expectedBaseBranch) {
@@ -214,7 +248,7 @@ export async function ensurePullRequestBaseBranch({ owner, repo, prNumber, argv
214
248
  return { checked: false, restored: false, reason: 'missing_pull_request_context' };
215
249
  }
216
250
 
217
- const currentBaseBranch = await getPullRequestBaseBranch({ owner, repo, prNumber, $, log });
251
+ const { baseBranch: currentBaseBranch, headBranch } = await getPullRequestBranchRange({ owner, repo, prNumber, $, log });
218
252
  if (currentBaseBranch === expectedBaseBranch) {
219
253
  await log(formatAligned('🎯', 'Base branch locked:', `${expectedBaseBranch} (verified)`, 2), { verbose: true });
220
254
  return {
@@ -227,6 +261,16 @@ export async function ensurePullRequestBaseBranch({ owner, repo, prNumber, argv
227
261
 
228
262
  await log(formatAligned('⚠️', 'Base branch changed:', `PR #${prNumber} targets ${currentBaseBranch}, expected ${expectedBaseBranch}`, 2), { level: 'warning' });
229
263
 
264
+ if (headBranch === expectedBaseBranch) {
265
+ throw new Error(
266
+ buildBaseEqualsHeadBranchMessage({
267
+ prNumber,
268
+ expectedBaseBranch,
269
+ currentBaseBranch,
270
+ })
271
+ );
272
+ }
273
+
230
274
  if (onMismatch === 'throw' || onMismatch === 'fail') {
231
275
  throw new Error(
232
276
  buildPullRequestBaseBranchMismatchMessage({
@@ -249,7 +293,7 @@ export async function ensurePullRequestBaseBranch({ owner, repo, prNumber, argv
249
293
  throw new Error(`Could not restore pull request #${prNumber} base branch to ${expectedBaseBranch}: ${details}`);
250
294
  }
251
295
 
252
- const restoredBaseBranch = await getPullRequestBaseBranch({ owner, repo, prNumber, $, log });
296
+ const { baseBranch: restoredBaseBranch } = await getPullRequestBranchRange({ owner, repo, prNumber, $, log });
253
297
  if (restoredBaseBranch !== expectedBaseBranch) {
254
298
  throw new Error(`Pull request #${prNumber} still targets ${restoredBaseBranch} after attempting to restore ${expectedBaseBranch}`);
255
299
  }